From 07d0b4587d68f6fc3c8d6a4654503e4c70c5de52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Tue, 7 Jul 2026 00:04:13 -0400 Subject: [PATCH] Promote AgentCompany-New to the repository root and retire the old app The legacy application - its src, tests, landing site, promo assets, docs, release tooling, CI workflows, and root configs - leaves the tree; it stays reachable in history. Everything under AgentCompany-New moves up unchanged: same package name, so the production userData/database path is untouched, and e2e/build scripts already resolved paths relative to the project. The developer cred.txt stays gitignored at its new location. Full verify:ci passes from the new root. --- .env.example | 6 - .env.release.example | 35 - .github/workflows/build.yml | 291 - .github/workflows/remote-boss-platforms.yml | 76 - .../workflows/remote-release-platforms.yml | 173 - .gitignore | 101 +- AgentCompany-New/.gitignore | 9 - AgentCompany-New/electron-builder.yml | 41 - AgentCompany-New/electron.vite.config.ts | 51 - AgentCompany-New/eslint.config.mjs | 33 - AgentCompany-New/package.json | 65 - AgentCompany-New/pnpm-lock.yaml | 5269 --------------- AgentCompany-New/src/main/database/schema.ts | 149 - AgentCompany-New/src/main/index.ts | 57 - AgentCompany-New/src/preload/index.ts | 103 - AgentCompany-New/src/renderer/env.d.ts | 7 - AgentCompany-New/src/renderer/index.html | 16 - .../tests/e2e/playwright.config.ts | 9 - AgentCompany-New/tsconfig.json | 29 - AgentCompany-New/vitest.config.ts | 8 - CONTRIBUTING.md | 111 - README.md | 255 - assets/entitlements.mac.plist | 18 - assets/icon-app.svg | 8 - assets/icon.icns | Bin 151372 -> 0 bytes assets/icon.ico | Bin 24205 -> 0 bytes assets/icon.png | Bin 33139 -> 0 bytes assets/icon.svg | 7 - assets/tray-icon.png | Bin 738 -> 0 bytes assets/tray-icon@2x.png | Bin 1554 -> 0 bytes assets/tray-iconTemplate.png | Bin 320 -> 0 bytes assets/tray-iconTemplate@2x.png | Bin 676 -> 0 bytes .../remotion-best-practices/SKILL.md | 61 - .../remotion-best-practices/rules/3d.md | 86 - .../rules/animations.md | 27 - .../remotion-best-practices/rules/assets.md | 78 - .../rules/assets/charts-bar-chart.tsx | 173 - .../assets/text-animations-typewriter.tsx | 100 - .../assets/text-animations-word-highlight.tsx | 103 - .../rules/audio-visualization.md | 198 - .../remotion-best-practices/rules/audio.md | 169 - .../rules/calculate-metadata.md | 134 - .../rules/can-decode.md | 81 - .../remotion-best-practices/rules/charts.md | 120 - .../rules/compositions.md | 154 - .../rules/display-captions.md | 184 - .../rules/extract-frames.md | 229 - .../remotion-best-practices/rules/ffmpeg.md | 38 - .../remotion-best-practices/rules/fonts.md | 152 - .../rules/get-audio-duration.md | 58 - .../rules/get-video-dimensions.md | 68 - .../rules/get-video-duration.md | 60 - .../remotion-best-practices/rules/gifs.md | 141 - .../remotion-best-practices/rules/images.md | 134 - .../rules/import-srt-captions.md | 69 - .../rules/light-leaks.md | 73 - .../remotion-best-practices/rules/lottie.md | 70 - .../remotion-best-practices/rules/maps.md | 412 -- .../rules/measuring-dom-nodes.md | 34 - .../rules/measuring-text.md | 140 - .../rules/parameters.md | 109 - .../rules/sequencing.md | 118 - .../remotion-best-practices/rules/sfx.md | 30 - .../rules/subtitles.md | 36 - .../remotion-best-practices/rules/tailwind.md | 11 - .../rules/text-animations.md | 20 - .../remotion-best-practices/rules/timing.md | 179 - .../rules/transcribe-captions.md | 70 - .../rules/transitions.md | 197 - .../rules/transparent-videos.md | 106 - .../remotion-best-practices/rules/trimming.md | 51 - .../remotion-best-practices/rules/videos.md | 171 - .../rules/voiceover.md | 99 - .../basic-for-all/deep-research/SKILL.md | 281 - .../basic-for-all/my-writing-style/README.md | 71 - .../basic-for-all/my-writing-style/SKILL.md | 206 - .../my-writing-style/scripts/improve.py | 426 -- .../my-writing-style/scripts/observe.py | 309 - builtin-skills/basic-for-all/nopua/SKILL.md | 456 -- .../systematic-debugging/CREATION-LOG.md | 119 - .../systematic-debugging/SKILL.md | 296 - .../condition-based-waiting-example.ts | 158 - .../condition-based-waiting.md | 115 - .../systematic-debugging/defense-in-depth.md | 122 - .../systematic-debugging/find-polluter.sh | 63 - .../root-cause-tracing.md | 169 - .../systematic-debugging/test-academic.md | 14 - .../systematic-debugging/test-pressure-1.md | 58 - .../systematic-debugging/test-pressure-2.md | 68 - .../systematic-debugging/test-pressure-3.md | 69 - .../document-process/docx/LICENSE.txt | 30 - builtin-skills/document-process/docx/SKILL.md | 590 -- .../document-process/docx/scripts/__init__.py | 1 - .../docx/scripts/accept_changes.py | 135 - .../document-process/docx/scripts/comment.py | 318 - .../docx/scripts/office/helpers/__init__.py | 0 .../docx/scripts/office/helpers/merge_runs.py | 199 - .../office/helpers/simplify_redlines.py | 197 - .../docx/scripts/office/pack.py | 159 - .../schemas/ISO-IEC29500-4_2016/dml-chart.xsd | 1499 ----- .../ISO-IEC29500-4_2016/dml-chartDrawing.xsd | 146 - .../ISO-IEC29500-4_2016/dml-diagram.xsd | 1085 --- .../ISO-IEC29500-4_2016/dml-lockedCanvas.xsd | 11 - .../schemas/ISO-IEC29500-4_2016/dml-main.xsd | 3081 --------- .../ISO-IEC29500-4_2016/dml-picture.xsd | 23 - .../dml-spreadsheetDrawing.xsd | 185 - .../dml-wordprocessingDrawing.xsd | 287 - .../schemas/ISO-IEC29500-4_2016/pml.xsd | 1676 ----- .../shared-additionalCharacteristics.xsd | 28 - .../shared-bibliography.xsd | 144 - .../shared-commonSimpleTypes.xsd | 174 - .../shared-customXmlDataProperties.xsd | 25 - .../shared-customXmlSchemaProperties.xsd | 18 - .../shared-documentPropertiesCustom.xsd | 59 - .../shared-documentPropertiesExtended.xsd | 56 - .../shared-documentPropertiesVariantTypes.xsd | 195 - .../ISO-IEC29500-4_2016/shared-math.xsd | 582 -- .../shared-relationshipReference.xsd | 25 - .../schemas/ISO-IEC29500-4_2016/sml.xsd | 4439 ------------- .../schemas/ISO-IEC29500-4_2016/vml-main.xsd | 570 -- .../ISO-IEC29500-4_2016/vml-officeDrawing.xsd | 509 -- .../vml-presentationDrawing.xsd | 12 - .../vml-spreadsheetDrawing.xsd | 108 - .../vml-wordprocessingDrawing.xsd | 96 - .../schemas/ISO-IEC29500-4_2016/wml.xsd | 3646 ---------- .../schemas/ISO-IEC29500-4_2016/xml.xsd | 116 - .../ecma/fouth-edition/opc-contentTypes.xsd | 42 - .../ecma/fouth-edition/opc-coreProperties.xsd | 50 - .../schemas/ecma/fouth-edition/opc-digSig.xsd | 49 - .../ecma/fouth-edition/opc-relationships.xsd | 33 - .../docx/scripts/office/schemas/mce/mc.xsd | 75 - .../office/schemas/microsoft/wml-2010.xsd | 560 -- .../office/schemas/microsoft/wml-2012.xsd | 67 - .../office/schemas/microsoft/wml-2018.xsd | 14 - .../office/schemas/microsoft/wml-cex-2018.xsd | 20 - .../office/schemas/microsoft/wml-cid-2016.xsd | 13 - .../microsoft/wml-sdtdatahash-2020.xsd | 4 - .../schemas/microsoft/wml-symex-2015.xsd | 8 - .../docx/scripts/office/soffice.py | 183 - .../docx/scripts/office/unpack.py | 132 - .../docx/scripts/office/validate.py | 111 - .../scripts/office/validators/__init__.py | 15 - .../docx/scripts/office/validators/base.py | 847 --- .../docx/scripts/office/validators/docx.py | 446 -- .../docx/scripts/office/validators/pptx.py | 275 - .../scripts/office/validators/redlining.py | 247 - .../docx/scripts/templates/comments.xml | 3 - .../scripts/templates/commentsExtended.xml | 3 - .../scripts/templates/commentsExtensible.xml | 3 - .../docx/scripts/templates/commentsIds.xml | 3 - .../docx/scripts/templates/people.xml | 3 - .../document-process/minimax-docx/.gitignore | 3 - .../document-process/minimax-docx/.setup.log | 0 .../document-process/minimax-docx/LICENSE | 21 - .../document-process/minimax-docx/SKILL.md | 274 - .../assets/styles/academic_styles.xml | 250 - .../assets/styles/corporate_styles.xml | 284 - .../assets/styles/default_styles.xml | 449 -- .../assets/xsd/aesthetic-rules.xsd | 470 -- .../assets/xsd/business-rules.xsd | 130 - .../minimax-docx/assets/xsd/common-types.xsd | 159 - .../minimax-docx/assets/xsd/wml-subset.xsd | 589 -- .../minimax-docx/references/cjk_typography.md | 357 - .../cjk_university_template_guide.md | 184 - .../minimax-docx/references/comments_guide.md | 191 - .../references/design_good_bad_examples.md | 829 --- .../references/design_principles.md | 819 --- .../references/openxml_element_order.md | 308 - .../references/openxml_encyclopedia_part1.md | 4061 ------------ .../references/openxml_encyclopedia_part2.md | 2820 -------- .../references/openxml_encyclopedia_part3.md | 3381 ---------- .../references/openxml_namespaces.md | 82 - .../minimax-docx/references/openxml_units.md | 72 - .../references/scenario_a_create.md | 284 - .../references/scenario_b_edit_content.md | 295 - .../references/scenario_c_apply_template.md | 456 -- .../references/track_changes_guide.md | 200 - .../references/troubleshooting.md | 506 -- .../references/typography_guide.md | 294 - .../references/xsd_validation_guide.md | 158 - .../minimax-docx/scripts/doc_to_docx.sh | 40 - .../minimax-docx/scripts/docx_preview.sh | 37 - .../MiniMaxAIDocx.Cli.csproj | 19 - .../dotnet/MiniMaxAIDocx.Cli/Program.cs | 18 - .../Commands/AnalyzeCommand.cs | 147 - .../Commands/ApplyTemplateCommand.cs | 322 - .../Commands/CreateCommand.cs | 324 - .../Commands/DiffCommand.cs | 155 - .../Commands/EditContentCommand.cs | 487 -- .../Commands/FixOrderCommand.cs | 108 - .../Commands/MergeRunsCommand.cs | 122 - .../Commands/ValidateCommand.cs | 107 - .../MiniMaxAIDocx.Core.csproj | 15 - .../OpenXml/CommentSynchronizer.cs | 169 - .../OpenXml/ElementOrder.cs | 80 - .../OpenXml/NamespaceConstants.cs | 42 - .../MiniMaxAIDocx.Core/OpenXml/RunMerger.cs | 81 - .../OpenXml/StyleAnalyzer.cs | 81 - .../OpenXml/TrackChangesHelper.cs | 99 - .../OpenXml/UnitConverter.cs | 23 - .../Samples/AestheticRecipeSamples.cs | 1832 ------ .../Samples/AestheticRecipeSamples_Batch1.cs | 910 --- .../Samples/AestheticRecipeSamples_Batch2.cs | 999 --- .../Samples/AestheticRecipeSamples_Batch3.cs | 1048 --- .../Samples/AestheticRecipeSamples_Batch4.cs | 1038 --- .../Samples/CharacterFormattingSamples.cs | 1020 --- .../Samples/DocumentCreationSamples.cs | 1121 ---- .../Samples/FieldAndTocSamples.cs | 624 -- .../Samples/FootnoteAndCommentSamples.cs | 675 -- .../Samples/HeaderFooterSamples.cs | 838 --- .../Samples/ImageSamples.cs | 917 --- .../Samples/ListAndNumberingSamples.cs | 826 --- .../Samples/ParagraphFormattingSamples.cs | 1199 ---- .../Samples/StyleSystemSamples.cs | 1487 ----- .../Samples/TableSamples.cs | 1163 ---- .../Samples/TrackChangesSamples.cs | 595 -- .../Typography/CjkHelper.cs | 39 - .../Typography/FontDefaults.cs | 24 - .../Typography/PageSizes.cs | 20 - .../Validation/BusinessRuleValidator.cs | 224 - .../Validation/GateCheckValidator.cs | 148 - .../Validation/ValidationResult.cs | 23 - .../Validation/XsdValidator.cs | 69 - .../scripts/dotnet/MiniMaxAIDocx.slnx | 4 - .../minimax-docx/scripts/env_check.sh | 196 - .../minimax-docx/scripts/setup.ps1 | 274 - .../minimax-docx/scripts/setup.sh | 504 -- .../document-process/minimax-pdf/README.md | 222 - .../document-process/minimax-pdf/SKILL.md | 192 - .../minimax-pdf/design/design.md | 381 -- .../minimax-pdf/scripts/cover.py | 1579 ----- .../minimax-pdf/scripts/fill_inspect.py | 200 - .../minimax-pdf/scripts/fill_write.py | 242 - .../minimax-pdf/scripts/make.sh | 491 -- .../minimax-pdf/scripts/merge.py | 112 - .../minimax-pdf/scripts/palette.py | 521 -- .../minimax-pdf/scripts/reformat_parse.py | 374 -- .../minimax-pdf/scripts/render_body.py | 1052 --- .../minimax-pdf/scripts/render_cover.js | 111 - .../document-process/minimax-xlsx/SKILL.md | 138 - .../minimax-xlsx/references/create.md | 691 -- .../minimax-xlsx/references/edit.md | 684 -- .../minimax-xlsx/references/fix.md | 37 - .../minimax-xlsx/references/format.md | 768 --- .../references/ooxml-cheatsheet.md | 231 - .../minimax-xlsx/references/read-analyze.md | 97 - .../minimax-xlsx/references/validate.md | 772 --- .../minimax-xlsx/scripts/formula_check.py | 422 -- .../scripts/libreoffice_recalc.py | 248 - .../scripts/shared_strings_builder.py | 163 - .../minimax-xlsx/scripts/style_audit.py | 575 -- .../minimax-xlsx/scripts/xlsx_add_column.py | 395 -- .../minimax-xlsx/scripts/xlsx_insert_row.py | 274 - .../minimax-xlsx/scripts/xlsx_pack.py | 87 - .../minimax-xlsx/scripts/xlsx_reader.py | 362 - .../minimax-xlsx/scripts/xlsx_shift_rows.py | 396 -- .../minimax-xlsx/scripts/xlsx_unpack.py | 130 - .../minimal_xlsx/[Content_Types].xml | 9 - .../templates/minimal_xlsx/_rels/.rels | 6 - .../minimal_xlsx/xl/_rels/workbook.xml.rels | 19 - .../minimal_xlsx/xl/sharedStrings.xml | 33 - .../templates/minimal_xlsx/xl/styles.xml | 160 - .../templates/minimal_xlsx/xl/workbook.xml | 30 - .../minimal_xlsx/xl/worksheets/sheet1.xml | 70 - .../my-writing-style/README.md | 71 - .../my-writing-style/SKILL.md | 206 - .../my-writing-style/scripts/improve.py | 426 -- .../my-writing-style/scripts/observe.py | 309 - .../document-process/pptx-generator/SKILL.md | 249 - .../references/design-system.md | 392 -- .../pptx-generator/references/editing.md | 162 - .../pptx-generator/references/pitfalls.md | 112 - .../pptx-generator/references/pptxgenjs.md | 420 -- .../pptx-generator/references/slide-types.md | 413 -- .../wechat-article-writer/SKILL.md | 62 - .../writing-clearly-and-concisely/README.md | 157 - .../writing-clearly-and-concisely/SKILL.md | 93 - .../elements-of-style/01-introductory.md | 3 - .../02-elementary-rules-of-usage.md | 214 - ...03-elementary-principles-of-composition.md | 398 -- .../04-a-few-matters-of-form.md | 89 - ...-words-and-expressions-commonly-misused.md | 348 - .../signs-of-ai-writing.md | 901 --- .../document-process/xlsx/LICENSE.txt | 30 - builtin-skills/document-process/xlsx/SKILL.md | 292 - .../xlsx/scripts/office/helpers/__init__.py | 0 .../xlsx/scripts/office/helpers/merge_runs.py | 199 - .../office/helpers/simplify_redlines.py | 197 - .../xlsx/scripts/office/pack.py | 159 - .../schemas/ISO-IEC29500-4_2016/dml-chart.xsd | 1499 ----- .../ISO-IEC29500-4_2016/dml-chartDrawing.xsd | 146 - .../ISO-IEC29500-4_2016/dml-diagram.xsd | 1085 --- .../ISO-IEC29500-4_2016/dml-lockedCanvas.xsd | 11 - .../schemas/ISO-IEC29500-4_2016/dml-main.xsd | 3081 --------- .../ISO-IEC29500-4_2016/dml-picture.xsd | 23 - .../dml-spreadsheetDrawing.xsd | 185 - .../dml-wordprocessingDrawing.xsd | 287 - .../schemas/ISO-IEC29500-4_2016/pml.xsd | 1676 ----- .../shared-additionalCharacteristics.xsd | 28 - .../shared-bibliography.xsd | 144 - .../shared-commonSimpleTypes.xsd | 174 - .../shared-customXmlDataProperties.xsd | 25 - .../shared-customXmlSchemaProperties.xsd | 18 - .../shared-documentPropertiesCustom.xsd | 59 - .../shared-documentPropertiesExtended.xsd | 56 - .../shared-documentPropertiesVariantTypes.xsd | 195 - .../ISO-IEC29500-4_2016/shared-math.xsd | 582 -- .../shared-relationshipReference.xsd | 25 - .../schemas/ISO-IEC29500-4_2016/sml.xsd | 4439 ------------- .../schemas/ISO-IEC29500-4_2016/vml-main.xsd | 570 -- .../ISO-IEC29500-4_2016/vml-officeDrawing.xsd | 509 -- .../vml-presentationDrawing.xsd | 12 - .../vml-spreadsheetDrawing.xsd | 108 - .../vml-wordprocessingDrawing.xsd | 96 - .../schemas/ISO-IEC29500-4_2016/wml.xsd | 3646 ---------- .../schemas/ISO-IEC29500-4_2016/xml.xsd | 116 - .../ecma/fouth-edition/opc-contentTypes.xsd | 42 - .../ecma/fouth-edition/opc-coreProperties.xsd | 50 - .../schemas/ecma/fouth-edition/opc-digSig.xsd | 49 - .../ecma/fouth-edition/opc-relationships.xsd | 33 - .../xlsx/scripts/office/schemas/mce/mc.xsd | 75 - .../office/schemas/microsoft/wml-2010.xsd | 560 -- .../office/schemas/microsoft/wml-2012.xsd | 67 - .../office/schemas/microsoft/wml-2018.xsd | 14 - .../office/schemas/microsoft/wml-cex-2018.xsd | 20 - .../office/schemas/microsoft/wml-cid-2016.xsd | 13 - .../microsoft/wml-sdtdatahash-2020.xsd | 4 - .../schemas/microsoft/wml-symex-2015.xsd | 8 - .../xlsx/scripts/office/soffice.py | 183 - .../xlsx/scripts/office/unpack.py | 132 - .../xlsx/scripts/office/validate.py | 111 - .../scripts/office/validators/__init__.py | 15 - .../xlsx/scripts/office/validators/base.py | 847 --- .../xlsx/scripts/office/validators/docx.py | 446 -- .../xlsx/scripts/office/validators/pptx.py | 275 - .../scripts/office/validators/redlining.py | 247 - .../document-process/xlsx/scripts/recalc.py | 184 - .../frontend-design/canvas-design/LICENSE.txt | 202 - .../frontend-design/canvas-design/SKILL.md | 130 - .../canvas-fonts/ArsenalSC-OFL.txt | 93 - .../canvas-fonts/ArsenalSC-Regular.ttf | Bin 165848 -> 0 bytes .../canvas-fonts/BigShoulders-Bold.ttf | Bin 94528 -> 0 bytes .../canvas-fonts/BigShoulders-OFL.txt | 93 - .../canvas-fonts/BigShoulders-Regular.ttf | Bin 94396 -> 0 bytes .../canvas-fonts/Boldonse-OFL.txt | 93 - .../canvas-fonts/Boldonse-Regular.ttf | Bin 77168 -> 0 bytes .../canvas-fonts/BricolageGrotesque-Bold.ttf | Bin 90952 -> 0 bytes .../canvas-fonts/BricolageGrotesque-OFL.txt | 93 - .../BricolageGrotesque-Regular.ttf | Bin 90920 -> 0 bytes .../canvas-fonts/CrimsonPro-Bold.ttf | Bin 107352 -> 0 bytes .../canvas-fonts/CrimsonPro-Italic.ttf | Bin 108828 -> 0 bytes .../canvas-fonts/CrimsonPro-OFL.txt | 93 - .../canvas-fonts/CrimsonPro-Regular.ttf | Bin 106696 -> 0 bytes .../canvas-design/canvas-fonts/DMMono-OFL.txt | 93 - .../canvas-fonts/DMMono-Regular.ttf | Bin 48852 -> 0 bytes .../canvas-fonts/EricaOne-OFL.txt | 94 - .../canvas-fonts/EricaOne-Regular.ttf | Bin 24872 -> 0 bytes .../canvas-fonts/GeistMono-Bold.ttf | Bin 78304 -> 0 bytes .../canvas-fonts/GeistMono-OFL.txt | 93 - .../canvas-fonts/GeistMono-Regular.ttf | Bin 78232 -> 0 bytes .../canvas-design/canvas-fonts/Gloock-OFL.txt | 93 - .../canvas-fonts/Gloock-Regular.ttf | Bin 95156 -> 0 bytes .../canvas-fonts/IBMPlexMono-Bold.ttf | Bin 136008 -> 0 bytes .../canvas-fonts/IBMPlexMono-OFL.txt | 93 - .../canvas-fonts/IBMPlexMono-Regular.ttf | Bin 133796 -> 0 bytes .../canvas-fonts/IBMPlexSerif-Bold.ttf | Bin 161000 -> 0 bytes .../canvas-fonts/IBMPlexSerif-BoldItalic.ttf | Bin 169840 -> 0 bytes .../canvas-fonts/IBMPlexSerif-Italic.ttf | Bin 170004 -> 0 bytes .../canvas-fonts/IBMPlexSerif-Regular.ttf | Bin 160380 -> 0 bytes .../canvas-fonts/InstrumentSans-Bold.ttf | Bin 68084 -> 0 bytes .../InstrumentSans-BoldItalic.ttf | Bin 70004 -> 0 bytes .../canvas-fonts/InstrumentSans-Italic.ttf | Bin 69900 -> 0 bytes .../canvas-fonts/InstrumentSans-OFL.txt | 93 - .../canvas-fonts/InstrumentSans-Regular.ttf | Bin 68028 -> 0 bytes .../canvas-fonts/InstrumentSerif-Italic.ttf | Bin 70868 -> 0 bytes .../canvas-fonts/InstrumentSerif-Regular.ttf | Bin 69312 -> 0 bytes .../canvas-fonts/Italiana-OFL.txt | 93 - .../canvas-fonts/Italiana-Regular.ttf | Bin 27184 -> 0 bytes .../canvas-fonts/JetBrainsMono-Bold.ttf | Bin 114828 -> 0 bytes .../canvas-fonts/JetBrainsMono-OFL.txt | 93 - .../canvas-fonts/JetBrainsMono-Regular.ttf | Bin 114904 -> 0 bytes .../canvas-design/canvas-fonts/Jura-Light.ttf | Bin 154308 -> 0 bytes .../canvas-fonts/Jura-Medium.ttf | Bin 154488 -> 0 bytes .../canvas-design/canvas-fonts/Jura-OFL.txt | 93 - .../canvas-fonts/LibreBaskerville-OFL.txt | 93 - .../canvas-fonts/LibreBaskerville-Regular.ttf | Bin 147584 -> 0 bytes .../canvas-design/canvas-fonts/Lora-Bold.ttf | Bin 133828 -> 0 bytes .../canvas-fonts/Lora-BoldItalic.ttf | Bin 140332 -> 0 bytes .../canvas-fonts/Lora-Italic.ttf | Bin 139328 -> 0 bytes .../canvas-design/canvas-fonts/Lora-OFL.txt | 93 - .../canvas-fonts/Lora-Regular.ttf | Bin 133888 -> 0 bytes .../canvas-fonts/NationalPark-Bold.ttf | Bin 79208 -> 0 bytes .../canvas-fonts/NationalPark-OFL.txt | 93 - .../canvas-fonts/NationalPark-Regular.ttf | Bin 76424 -> 0 bytes .../canvas-fonts/NothingYouCouldDo-OFL.txt | 93 - .../NothingYouCouldDo-Regular.ttf | Bin 32020 -> 0 bytes .../canvas-fonts/Outfit-Bold.ttf | Bin 55392 -> 0 bytes .../canvas-design/canvas-fonts/Outfit-OFL.txt | 93 - .../canvas-fonts/Outfit-Regular.ttf | Bin 54912 -> 0 bytes .../canvas-fonts/PixelifySans-Medium.ttf | Bin 51072 -> 0 bytes .../canvas-fonts/PixelifySans-OFL.txt | 93 - .../canvas-fonts/PoiretOne-OFL.txt | 93 - .../canvas-fonts/PoiretOne-Regular.ttf | Bin 45244 -> 0 bytes .../canvas-fonts/RedHatMono-Bold.ttf | Bin 34420 -> 0 bytes .../canvas-fonts/RedHatMono-OFL.txt | 93 - .../canvas-fonts/RedHatMono-Regular.ttf | Bin 34488 -> 0 bytes .../canvas-fonts/Silkscreen-OFL.txt | 93 - .../canvas-fonts/Silkscreen-Regular.ttf | Bin 31960 -> 0 bytes .../canvas-fonts/SmoochSans-Medium.ttf | Bin 59704 -> 0 bytes .../canvas-fonts/SmoochSans-OFL.txt | 93 - .../canvas-fonts/Tektur-Medium.ttf | Bin 76248 -> 0 bytes .../canvas-design/canvas-fonts/Tektur-OFL.txt | 93 - .../canvas-fonts/Tektur-Regular.ttf | Bin 75604 -> 0 bytes .../canvas-fonts/WorkSans-Bold.ttf | Bin 191304 -> 0 bytes .../canvas-fonts/WorkSans-BoldItalic.ttf | Bin 175772 -> 0 bytes .../canvas-fonts/WorkSans-Italic.ttf | Bin 174280 -> 0 bytes .../canvas-fonts/WorkSans-OFL.txt | 93 - .../canvas-fonts/WorkSans-Regular.ttf | Bin 188916 -> 0 bytes .../canvas-fonts/YoungSerif-OFL.txt | 93 - .../canvas-fonts/YoungSerif-Regular.ttf | Bin 105136 -> 0 bytes .../frontend-design/design-dna/LICENSE | 21 - .../frontend-design/design-dna/README.md | 109 - .../design-dna/README.zh-CN.md | 99 - .../frontend-design/design-dna/SKILL.md | 104 - .../docs/example-style-transfer.png | Bin 55016 -> 0 bytes .../design-dna/references/generation-guide.md | 209 - .../design-dna/references/schema.md | 366 -- .../design-taste-frontend/SKILL.md | 226 - .../frontend-design/frontend-design/SKILL.md | 42 - .../high-end-visual-design/SKILL.md | 98 - .../frontend-design/senior-frontend/SKILL.md | 473 -- .../references/frontend_best_practices.md | 806 --- .../references/nextjs_optimization_guide.md | 724 -- .../references/react_patterns.md | 746 --- .../scripts/bundle_analyzer.py | 407 -- .../scripts/component_generator.py | 329 - .../scripts/frontend_scaffolder.py | 1005 --- .../stitch-design-taste/DESIGN.md | 121 - .../stitch-design-taste/SKILL.md | 184 - .../app-icon-generator/.skillfish.json | 10 - .../iOS-Dev/app-icon-generator/SKILL.md | 526 -- .../iOS-Dev/app-store-screenshots/SKILL.md | 647 -- .../iOS-Dev/app-store-screenshots/mockup.png | Bin 95347 -> 0 bytes .../iOS-Dev/icon-generator/SKILL.md | 48 - .../icon-generator/references/icon-sizes.md | 39 - .../references/unreal-engine.md | 29 - .../icon-generator/references/web-ui-ux.md | 56 - .../icon-generator/scripts/generate_icons.py | 274 - .../iOS-Dev/ios-swift-development/SKILL.md | 101 - .../references/mvvm-architecture-setup.md | 60 - .../network-service-with-urlsession.md | 99 - .../references/swiftui-views.md | 112 - .../scripts/validate-api.sh | 18 - .../templates/api-scaffold.yaml | 22 - .../iOS-Dev/mobile-development/SKILL.md | 261 - .../assets/mobile_config.yaml | 35 - .../references/MOBILE_GUIDE.md | 73 - .../scripts/pwa_validator.py | 60 - .../marketing/clean-general/SKILL.md | 97 - .../marketing/my-writing-style/README.md | 71 - .../marketing/my-writing-style/SKILL.md | 206 - .../my-writing-style/scripts/improve.py | 426 -- .../my-writing-style/scripts/observe.py | 309 - .../marketing/wechat-article-writer/SKILL.md | 62 - .../writing-clearly-and-concisely/README.md | 157 - .../writing-clearly-and-concisely/SKILL.md | 93 - .../elements-of-style/01-introductory.md | 3 - .../02-elementary-rules-of-usage.md | 214 - ...03-elementary-principles-of-composition.md | 398 -- .../04-a-few-matters-of-form.md | 89 - ...-words-and-expressions-commonly-misused.md | 348 - .../signs-of-ai-writing.md | 901 --- builtin-skills/my-writing-style/README.md | 71 - builtin-skills/my-writing-style/SKILL.md | 206 - .../my-writing-style/scripts/improve.py | 426 -- .../my-writing-style/scripts/observe.py | 309 - .../ai-coding-discipline/SKILL.md | 215 - .../api-design-principles/SKILL.md | 518 -- .../assets/api-design-checklist.md | 155 - .../assets/rest-api-template.py | 182 - .../references/graphql-schema-design.md | 583 -- .../references/rest-best-practices.md | 408 -- .../clean-architecture/SKILL.md | 113 - .../assets/templates/_template.md | 40 - .../clean-architecture/metadata.json | 14 - .../references/_sections.md | 46 - .../references/adapt-anti-corruption-layer.md | 112 - .../references/adapt-controller-thin.md | 101 - .../references/adapt-gateway-abstraction.md | 119 - .../references/adapt-mapper-translation.md | 119 - .../references/adapt-presenter-formats.md | 109 - .../bound-boundary-cost-awareness.md | 105 - .../references/bound-defer-decisions.md | 105 - .../references/bound-humble-object.md | 108 - .../references/bound-main-component.md | 106 - .../references/bound-partial-boundaries.md | 84 - .../bound-service-internal-architecture.md | 94 - .../references/comp-common-closure.md | 62 - .../references/comp-common-reuse.md | 71 - .../comp-reuse-release-equivalence.md | 70 - .../references/comp-screaming-architecture.md | 77 - .../references/comp-stable-dependencies.md | 69 - .../references/dep-acyclic-dependencies.md | 84 - .../dep-data-crossing-boundaries.md | 61 - .../references/dep-interface-ownership.md | 60 - .../references/dep-inward-only.md | 69 - .../references/dep-no-framework-imports.md | 69 - .../references/dep-stable-abstractions.md | 76 - .../entity-encapsulate-invariants.md | 83 - .../entity-no-persistence-awareness.md | 90 - .../references/entity-pure-business-rules.md | 68 - .../references/entity-rich-not-anemic.md | 106 - .../references/entity-value-objects.md | 100 - .../references/frame-di-container-edge.md | 116 - .../references/frame-domain-purity.md | 121 - .../references/frame-logging-abstraction.md | 127 - .../references/frame-orm-in-infrastructure.md | 103 - .../references/frame-web-in-infrastructure.md | 132 - .../references/test-boundary-verification.md | 106 - .../references/test-layer-isolation.md | 121 - .../references/test-testable-design.md | 104 - .../references/test-tests-are-architecture.md | 106 - .../usecase-explicit-dependencies.md | 104 - .../references/usecase-input-output-ports.md | 98 - .../usecase-no-presentation-logic.md | 101 - .../usecase-orchestrates-not-implements.md | 102 - .../usecase-single-responsibility.md | 96 - .../usecase-transaction-boundary.md | 80 - .../software-engineer/clean-code/SKILL.md | 128 - .../clean-code/assets/templates/_template.md | 30 - .../clean-code/metadata.json | 12 - .../clean-code/references/_sections.md | 56 - .../references/bound-learning-tests.md | 59 - .../references/bound-wrap-third-party.md | 77 - .../clean-code/references/class-cohesion.md | 66 - .../references/class-isolate-from-change.md | 76 - .../references/class-organize-for-change.md | 70 - .../references/class-separate-concerns.md | 74 - .../clean-code/references/class-small.md | 63 - .../cmt-avoid-commented-out-code.md | 48 - .../references/cmt-avoid-redundant.md | 68 - .../references/cmt-explain-intent.md | 54 - .../references/cmt-express-in-code.md | 58 - .../references/cmt-warning-consequences.md | 66 - .../references/emerge-expressiveness.md | 52 - .../references/emerge-simple-design.md | 59 - .../clean-code/references/err-avoid-null.md | 78 - .../references/err-define-by-caller-needs.md | 67 - .../references/err-provide-context.md | 53 - .../references/err-use-exceptions.md | 88 - .../references/err-write-try-catch-first.md | 53 - .../references/fmt-horizontal-alignment.md | 59 - .../clean-code/references/fmt-indentation.md | 60 - .../clean-code/references/fmt-team-rules.md | 67 - .../references/fmt-vertical-formatting.md | 72 - .../references/func-abstraction-level.md | 68 - .../func-command-query-separation.md | 57 - .../clean-code/references/func-dry.md | 70 - .../references/func-minimize-arguments.md | 56 - .../references/func-no-side-effects.md | 67 - .../clean-code/references/func-one-thing.md | 77 - .../clean-code/references/func-small.md | 71 - .../references/name-avoid-disinformation.md | 44 - .../references/name-avoid-encodings.md | 66 - .../clean-code/references/name-class-noun.md | 54 - .../references/name-intention-revealing.md | 47 - .../name-meaningful-distinctions.md | 54 - .../clean-code/references/name-method-verb.md | 55 - .../references/name-pronounceable.md | 38 - .../clean-code/references/name-searchable.md | 39 - .../references/obj-avoid-hybrids.md | 69 - .../references/obj-data-abstraction.md | 51 - .../references/obj-data-object-asymmetry.md | 72 - .../clean-code/references/obj-dto.md | 63 - .../references/obj-law-of-demeter.md | 45 - .../references/test-build-operate-check.md | 78 - .../clean-code/references/test-first-law.md | 68 - .../references/test-first-principles.md | 80 - .../clean-code/references/test-keep-clean.md | 75 - .../clean-code/references/test-one-assert.md | 65 - .../software-engineer/clean-comments/SKILL.md | 52 - .../clean-functions/SKILL.md | 66 - .../software-engineer/clean-general/SKILL.md | 97 - .../software-engineer/clean-names/SKILL.md | 136 - .../software-engineer/clean-tests/SKILL.md | 196 - .../coding-guidelines/SKILL.md | 95 - .../coding-guidelines/clippy-lints/_index.md | 16 - .../coding-guidelines/index/rules-index.md | 6 - .../ddia-principles/SKILL.md | 421 -- .../devops-engineer/SKILL.md | 144 - .../references/deployment-strategies.md | 241 - .../references/docker-patterns.md | 113 - .../references/github-actions.md | 139 - .../references/incident-response.md | 331 - .../devops-engineer/references/kubernetes.md | 154 - .../references/platform-engineering.md | 417 -- .../references/release-automation.md | 527 -- .../references/terraform-iac.md | 141 - .../e2e-testing-patterns/SKILL.md | 535 -- .../mobile-development/SKILL.md | 261 - .../assets/mobile_config.yaml | 35 - .../references/MOBILE_GUIDE.md | 73 - .../scripts/pwa_validator.py | 60 - .../openapi-spec-generation/.skillfish.json | 10 - .../openapi-spec-generation/SKILL.md | 1017 --- .../optimize-cicd-pipeline/SKILL.md | 36 - .../senior-architect/SKILL.md | 343 - .../references/architecture_patterns.md | 470 -- .../references/system_design_workflows.md | 536 -- .../references/tech_decision_guide.md | 412 -- .../scripts/architecture_diagram_generator.py | 660 -- .../scripts/dependency_analyzer.py | 615 -- .../scripts/project_architect.py | 749 --- docs/agents/domain.md | 36 - docs/agents/issue-tracker.md | 22 - docs/agents/triage-labels.md | 15 - docs/architecture/workspace-concurrency.md | 120 - .../B1.1-pi-version-upgrade-trace.md | 110 - docs/proposals/B2-tasks-state-machine.md | 311 - docs/proposals/B4-single-writer-actor.md | 252 - docs/proposals/B5.1-llm-as-judge-followup.md | 277 - .../C1-appdatabase-passthrough-removal.md | 267 - .../proposals/C2-service-graph-runtime-bus.md | 260 - docs/proposals/C3-real-tokenizer-followup.md | 45 - docs/proposals/C4-followup.md | 89 - .../C4-initial-user-turn-semantic-cue.md | 250 - docs/proposals/C6.2-error-taxonomy-phase2.md | 211 - .../C7-prompt-builder-conditional-assembly.md | 280 - .../M10-agent-runtime-hooks-aggregation.md | 264 - .../M11-credential-manager-unification.md | 251 - docs/proposals/M12-renderer-state-audit.md | 252 - docs/proposals/M2-ipc-contracts.md | 258 - docs/proposals/M5-monorepo-split.md | 279 - docs/proposals/M7-ceo-mode-state-machine.md | 270 - .../M8-worker-module-consolidation.md | 250 - .../M9-browser-automation-utility-process.md | 268 - docs/proposals/_BLOCKED-BY-CONSTRAINT.md | 218 - docs/rebuild/05-design-system-and-flows.md | 321 - .../AI-Internal-Realtime-Message.jpeg | Bin 770540 -> 0 bytes docs/screenshots/Approval-by-Human.jpeg | Bin 233031 -> 0 bytes docs/screenshots/Auto-OrgChart-Team.jpeg | Bin 344657 -> 0 bytes docs/screenshots/Auto-Task.jpeg | Bin 475674 -> 0 bytes docs/screenshots/Dashboard.jpeg | Bin 461199 -> 0 bytes docs/screenshots/Document-Center.jpeg | Bin 221097 -> 0 bytes docs/screenshots/Onboarding.jpeg | Bin 620378 -> 0 bytes electron-builder.yml | 67 +- electron.vite.config.ts | 37 +- eslint.config.mjs | 155 +- landing/.gitignore | 5 - landing/README.md | 14 - landing/_headers | 21 - landing/app/globals.css | 128 - landing/app/layout.tsx | 203 - landing/app/page.tsx | 34 - landing/components/ascii-background.tsx | 158 - landing/components/download-section.tsx | 105 - landing/components/faq.tsx | 109 - landing/components/features.tsx | 191 - landing/components/footer.tsx | 91 - landing/components/hero.tsx | 129 - landing/components/how-it-works.tsx | 149 - landing/components/icon-mark.tsx | 24 - landing/components/navbar.tsx | 132 - landing/components/release-links.generated.ts | 109 - landing/components/runtimes-bar.tsx | 117 - landing/components/site-constants.ts | 2 - landing/components/theme-provider.tsx | 76 - landing/components/theme-toggle.tsx | 42 - landing/functions/api/download-stats.ts | 34 - landing/functions/api/download.ts | 73 - landing/functions/types.ts | 17 - landing/lib/downloads.ts | 28 - landing/lib/platform-support.ts | 106 - landing/lib/product-narrative.ts | 80 - landing/migrations/0001_download_counter.sql | 18 - landing/next-env.d.ts | 6 - landing/next.config.ts | 11 - landing/package-lock.json | 1762 ----- landing/package.json | 29 - landing/postcss.config.mjs | 5 - landing/preview-dark.html | 810 --- landing/preview.html | 814 --- landing/public/_headers | 21 - landing/public/assets/icon.svg | 7 - landing/public/favicon.ico | Bin 24205 -> 0 bytes landing/public/icon.png | Bin 33139 -> 0 bytes .../AI-Internal-Realtime-Message.jpeg | Bin 770540 -> 0 bytes .../public/screenshots/Approval-by-Human.jpeg | Bin 233031 -> 0 bytes .../screenshots/Auto-OrgChart-Team.jpeg | Bin 344657 -> 0 bytes landing/public/screenshots/Auto-Task.jpeg | Bin 475674 -> 0 bytes landing/public/screenshots/Dashboard.jpeg | Bin 461199 -> 0 bytes .../public/screenshots/Document-Center.jpeg | Bin 221097 -> 0 bytes landing/public/screenshots/Onboarding.jpeg | Bin 620378 -> 0 bytes landing/tsconfig.json | 36 - landing/wrangler.toml | 11 - package.json | 112 +- pnpm-lock.yaml | 5853 +++-------------- ...pnpm-workspace.yaml => pnpm-workspace.yaml | 0 promo-video/agentcompany-promo.mp4 | Bin 3753553 -> 0 bytes .../assets/AI-Internal-Realtime-Message.jpeg | Bin 770540 -> 0 bytes promo-video/assets/Approval-by-Human.jpeg | Bin 233031 -> 0 bytes promo-video/assets/Auto-OrgChart-Team.jpeg | Bin 344657 -> 0 bytes promo-video/assets/Auto-Task.jpeg | Bin 475674 -> 0 bytes promo-video/assets/Dashboard.jpeg | Bin 461199 -> 0 bytes promo-video/assets/Document-Center.jpeg | Bin 221097 -> 0 bytes promo-video/assets/Onboarding.jpeg | Bin 620378 -> 0 bytes promo-video/assets/icon.png | Bin 33139 -> 0 bytes promo-video/assets/icon.svg | 7 - promo-video/index.html | 1019 --- promo-video/snapshots/frame-00-at-0.5s.png | Bin 157916 -> 0 bytes promo-video/snapshots/frame-01-at-5.0s.png | Bin 216017 -> 0 bytes promo-video/snapshots/frame-02-at-7.0s.png | Bin 50924 -> 0 bytes promo-video/snapshots/frame-03-at-11.5s.png | Bin 81984 -> 0 bytes promo-video/snapshots/frame-04-at-17.0s.png | Bin 756485 -> 0 bytes promo-video/snapshots/frame-05-at-22.5s.png | Bin 107784 -> 0 bytes promo-video/snapshots/frame-06-at-28.5s.png | Bin 177482 -> 0 bytes .../entitlements.mac.plist | 0 .../resources => resources}/icon.png | Bin scripts/README.md | 48 - scripts/build-all-platforms.mjs | 118 - scripts/build-desktop.mjs | 93 - scripts/build/emit-builder-config.mjs | 117 - scripts/build/prepare-env.mjs | 93 - scripts/build/run-electron-builder.mjs | 94 - scripts/codemod/README.md | 108 - .../remove-appdatabase-passthrough.mjs | 412 -- scripts/electron-builder-mac-sign.mjs | 132 - .../scripts => scripts}/ensure-electron.cjs | 0 scripts/generate-landing-release-links.mjs | 241 - scripts/icons/generate-icons.py | 204 - scripts/patch-electron-name.sh | 34 - scripts/postinstall.mjs | 34 - scripts/release-boss.mjs | 246 - scripts/release-local-mac.mjs | 200 - scripts/release-local-winlinux.mjs | 223 - scripts/release-local.mjs | 306 - scripts/release-local/r2.mjs | 262 - scripts/release-public-cloudflare.mjs | 350 - scripts/release-website.mjs | 126 - scripts/release/lib/d1-migrations.mjs | 129 - scripts/release/lib/dotenv.mjs | 18 - scripts/release/lib/process.mjs | 46 - scripts/release/lib/snapshot.mjs | 77 - scripts/release/lib/workflow.mjs | 116 - scripts/resume-release-public.mjs | 103 - src/main/agent-auth.ts | 119 - src/main/agent-permissions.ts | 321 - src/main/agent-role-helpers.ts | 229 - .../agent-runtime/agent-event-projection.ts | 127 - src/main/agent-runtime/agent-hooks.ts | 128 - .../agent-runtime/agent-message-schema.ts | 100 - src/main/agent-runtime/artifact-baseline.ts | 97 - .../agent-runtime/artifact-change-detector.ts | 139 - src/main/agent-runtime/artifact-git.ts | 14 - src/main/agent-runtime/artifact-logging.ts | 25 - .../agent-runtime/artifact-path-filter.ts | 52 - .../artifact-projection-events.ts | 97 - src/main/agent-runtime/artifact-projector.ts | 63 - src/main/agent-runtime/artifact-types.ts | 55 - .../agent-runtime/artifact-work-products.ts | 113 - src/main/agent-runtime/context-compactor.ts | 328 - src/main/agent-runtime/cost-writer.ts | 68 - src/main/agent-runtime/hook-handlers.ts | 117 - src/main/agent-runtime/hook-rpc.ts | 27 - .../inbound-correlation-registry.ts | 62 - src/main/agent-runtime/inbox-projection.ts | 111 - src/main/agent-runtime/index.ts | 4 - .../internal-tools/file-approval-handler.ts | 190 - .../internal-tools/hire-agent-handler.ts | 305 - .../agent-runtime/internal-tools/router.ts | 64 - .../runtime-artifact-reconciler.ts | 79 - src/main/agent-runtime/runtime-bridge.ts | 506 -- .../agent-runtime/runtime-message-injector.ts | 173 - .../agent-runtime/runtime-thread-projector.ts | 172 - .../agent-runtime/sqlite-session-store.ts | 62 - src/main/api-server.ts | 4 - src/main/api-server/deprecation-counter.ts | 36 - src/main/api-server/index.ts | 40 - src/main/api-server/routes-agent-control.ts | 169 - src/main/api-server/routes-agents-standup.ts | 181 - src/main/api-server/routes-agents.ts | 314 - src/main/api-server/routes-approvals.ts | 286 - src/main/api-server/routes-files.ts | 402 -- src/main/api-server/routes-meetings.ts | 158 - src/main/api-server/routes-messages.ts | 179 - src/main/api-server/routes-misc.ts | 301 - src/main/api-server/routes-runs.ts | 95 - src/main/api-server/routes-tasks.ts | 384 -- src/main/api-server/routes-work-graph.ts | 282 - src/main/api-server/server-core.ts | 412 -- src/main/app-lifecycle-service.ts | 76 - .../src => src}/main/app/coalesce.ts | 0 .../src => src}/main/app/create-window.ts | 0 .../src => src}/main/app/external-url.ts | 0 .../src => src}/main/app/ipc-handlers.ts | 0 .../main/app/provider-background-worker.ts | 0 .../src => src}/main/app/startup-recovery.ts | 0 .../src => src}/main/app/task-queue-worker.ts | 0 .../src => src}/main/app/window-security.ts | 0 src/main/approval-policy-definitions.ts | 97 - src/main/approval-policy.ts | 38 - src/main/automation-service.ts | 2 - .../automation/automation-action-handlers.ts | 401 -- .../automation/automation-action-runtime.ts | 62 - .../automation/automation-action-schemas.ts | 131 - src/main/automation/automation-actions.ts | 30 - .../automation/automation-approval-handler.ts | 375 -- src/main/automation/automation-conditions.ts | 58 - src/main/automation/automation-handlers.ts | 165 - .../automation/automation-run-completion.ts | 475 -- src/main/automation/automation-workflow.ts | 248 - src/main/automation/index.ts | 224 - src/main/automation/types.ts | 58 - src/main/bootstrap-application.ts | 212 - .../bootstrap/backfill-workspace-artifacts.ts | 226 - src/main/bootstrap/prepare-database.ts | 14 - src/main/bootstrap/prepare-logger.ts | 16 - src/main/bootstrap/prepare-services.ts | 142 - .../bootstrap/recover-interrupted-tasks.ts | 73 - src/main/bootstrap/recover-scheduled-posts.ts | 49 - .../bootstrap/run-startup-health-checks.ts | 28 - src/main/bootstrap/wire-api-server.ts | 143 - src/main/boss-seed.ts | 7 - src/main/browser-action-service.ts | 203 - src/main/browser-manager.ts | 360 - src/main/browser/browser-action-auth.ts | 49 - src/main/browser/browser-action-cdp.ts | 251 - src/main/browser/browser-action-errors.ts | 33 - src/main/browser/browser-action-executor.ts | 361 - src/main/browser/browser-screenshot-policy.ts | 7 - src/main/browser/browser-types.ts | 183 - src/main/browser/browser-url-helpers.ts | 128 - src/main/browser/platform-selectors.ts | 135 - src/main/budget-enforcement-service.ts | 237 - src/main/checkpoint-engine.ts | 171 - src/main/connector-auth-service.ts | 170 - src/main/connector-definitions-docs.ts | 38 - src/main/connector-definitions-lookup.ts | 9 - src/main/connector-definitions.ts | 105 - src/main/connector-definitions/apikey.ts | 177 - src/main/connector-definitions/cloud.ts | 47 - src/main/connector-definitions/index.ts | 12 - src/main/connector-definitions/local.ts | 41 - src/main/connector-definitions/oauth.ts | 74 - src/main/connector-health-service.ts | 172 - src/main/connector-matching.ts | 29 - src/main/connector-model-policy.ts | 121 - src/main/connectors.ts | 143 - src/main/constants.ts | 18 - src/main/credentials/credential-resolver.ts | 218 - src/main/credentials/credential-store.ts | 180 - src/main/credentials/index.ts | 4 - src/main/credentials/oauth-login-service.ts | 158 - src/main/credentials/types.ts | 32 - src/main/database-base.ts | 427 -- src/main/database.ts | 56 - src/main/database/activity.ts | 65 - src/main/database/agent-permissions.ts | 151 - src/main/database/agents-crud.ts | 348 - src/main/database/agents-hierarchy.ts | 331 - src/main/database/agents.ts | 35 - src/main/database/approvals.ts | 428 -- src/main/database/automation.ts | 142 - src/main/database/backup.ts | 257 - src/main/database/budget.ts | 255 - src/main/database/company-crud.ts | 177 - src/main/database/company-metrics.ts | 370 -- src/main/database/company-settings.ts | 64 - src/main/database/company.ts | 24 - src/main/database/config-revisions.ts | 126 - .../src => src}/main/database/connection.ts | 0 src/main/database/connectors-crud.ts | 191 - src/main/database/cost-entries.ts | 52 - src/main/database/crash-recovery-helpers.ts | 80 - src/main/database/credentials.ts | 178 - .../database/document-lifecycle-events.ts | 205 - src/main/database/documents-work-products.ts | 475 -- src/main/database/documents.ts | 226 - src/main/database/entity-crud.ts | 308 - src/main/database/helpers.ts | 53 - src/main/database/inbox-projections.ts | 50 - src/main/database/index.ts | 1 - src/main/database/knowledge.ts | 281 - src/main/database/messages.ts | 409 -- .../main/database/migrations/001-initial.ts | 0 .../database/migrations/002-collaboration.ts | 0 .../database/migrations/003-onboarding.ts | 0 .../database/migrations/004-files-posts.ts | 0 .../migrations/005-chat-read-state.ts | 0 .../main/database/migrations/006-app-state.ts | 0 .../migrations/007-skill-hardening.ts | 0 .../migrations/008-provider-health.ts | 0 .../migrations/009-social-governance.ts | 0 .../migrations/010-file-handoff-security.ts | 0 .../migrations/011-board-interventions.ts | 0 .../migrations/012-compliance-controls.ts | 0 .../migrations/013-search-documents.ts | 0 .../migrations/014-provider-policy-usage.ts | 0 .../migrations/015-identity-access.ts | 0 .../database/migrations/016-org-governance.ts | 0 .../migrations/017-operations-controls.ts | 0 .../database/migrations/018-sdlc-controls.ts | 0 .../database/migrations/019-audit-replay.ts | 0 .../migrations/020-rollback-snapshots.ts | 0 .../migrations/021-provider-auth-broker.ts | 0 .../022-provider-rate-limit-observations.ts | 0 .../023-provider-request-runtime.ts | 0 .../024-task-run-provider-request.ts | 0 .../migrations/025-chat-message-delivery.ts | 0 .../026-browser-platform-governance.ts | 0 .../migrations/027-social-audit-records.ts | 0 .../028-migration-cutover-journal.ts | 0 .../migrations/029-file-handoff-records.ts | 0 .../migrations/030-approval-source-refs.ts | 0 .../031-provider-request-workspace.ts | 0 .../migrations/032-browser-action-metadata.ts | 0 .../033-audit-event-immutability.ts | 0 .../migrations/034-provider-auth-sessions.ts | 0 .../migrations/035-task-run-isolation.ts | 0 .../migrations/036-additional-connectors.ts | 0 .../migrations/037-custom-providers.ts | 0 .../038-provider-auth-profile-cascade.ts | 0 .../039-audit-immutability-org-teardown.ts | 0 .../040-documents-knowledge-automation.ts | 0 .../migrations/041-task-subtasks-delete.ts | 0 .../042-approval-notes-meetings-sprints.ts | 0 .../migrations/043-composio-integration.ts | 0 .../migrations/044-mention-wake-state.ts | 0 .../migrations/045-connector-grants.ts | 0 src/main/database/migrations/baseline-v56.ts | 263 - src/main/database/migrations/legacy-to-v56.ts | 433 -- src/main/database/migrations/types.ts | 47 - .../database/migrations/v57-task-leases.ts | 121 - .../migrations/v58-approval-policies.ts | 110 - .../migrations/v59-social-company-scope.ts | 163 - .../v60-filesystem-task-workspaces.ts | 130 - src/main/database/model-capabilities-crud.ts | 126 - src/main/database/run-events.ts | 82 - src/main/database/run-logs.ts | 96 - src/main/database/runs.ts | 374 -- src/main/database/schema.ts | 304 +- src/main/database/session-entries.ts | 147 - src/main/database/settings.ts | 236 - src/main/database/skills.ts | 165 - src/main/database/snapshot.ts | 223 - src/main/database/social.ts | 219 - src/main/database/task-assignment.ts | 138 - src/main/database/task-checkout.ts | 76 - src/main/database/task-queries.ts | 177 - src/main/database/task-review-guard.ts | 18 - src/main/database/task-sessions-crud.ts | 133 - src/main/database/task-status-rules.ts | 41 - src/main/database/tasks-crud.ts | 272 - src/main/database/tasks-status.ts | 256 - src/main/database/tasks-update.ts | 255 - src/main/database/tasks.ts | 36 - src/main/database/threads.ts | 370 -- src/main/database/wakeup.ts | 239 - src/main/database/workspaces.ts | 208 - src/main/default-automation-rules.ts | 170 - src/main/desktop-shell-menu.ts | 272 - src/main/desktop-shell-service.ts | 45 - src/main/desktop-shell-window.ts | 310 - src/main/document-lifecycle-handlers.ts | 75 - src/main/document-lifecycle-processor.ts | 220 - src/main/document-lifecycle.ts | 224 - src/main/errors/handlers.ts | 69 - src/main/errors/index.ts | 21 - src/main/errors/taxonomy.ts | 230 - src/main/execution-mode-reconciler.ts | 154 - src/main/execution-policy.ts | 76 - src/main/external-url-policy.ts | 54 - src/main/hire-hook.ts | 112 - src/main/host-environment-service.ts | 109 - src/main/index.ts | 82 +- src/main/install-main-warning-suppressions.ts | 18 - src/main/ipc-agent-coordination-handlers.ts | 97 - .../ipc-automation-operations-handlers.ts | 106 - src/main/ipc-browser-handlers.ts | 143 - src/main/ipc-budget-handlers.ts | 94 - .../document-handlers.ts | 76 - src/main/ipc-company-operations/index.ts | 12 - .../knowledge-entry-handlers.ts | 50 - .../meeting-handlers.ts | 56 - .../reference-tables.ts | 15 - .../ipc-company-operations/sprint-handlers.ts | 53 - src/main/ipc-company-operations/types.ts | 15 - src/main/ipc-core-admin-handlers.ts | 163 - src/main/ipc-core-agent-graph-handlers.ts | 325 - src/main/ipc-core-common.ts | 48 - src/main/ipc-core-handlers.ts | 14 - src/main/ipc-core-operations-handlers.ts | 242 - src/main/ipc-core-read-handlers.ts | 309 - src/main/ipc-core-task-graph-handlers.ts | 226 - src/main/ipc-core-work-graph-handlers.ts | 42 - src/main/ipc-credentials-handlers.ts | 312 - src/main/ipc-domain-common.ts | 68 - src/main/ipc-domain-handlers.ts | 34 - src/main/ipc-oauth-handlers.ts | 64 - src/main/ipc-onboarding-handlers.ts | 22 - src/main/ipc-recovery-handlers.ts | 48 - src/main/ipc-skill-handlers.ts | 187 - src/main/ipc-support.ts | 174 - src/main/ipc-thread-handlers.ts | 49 - src/main/main-process-setup.ts | 58 - src/main/main-runtime-support.ts | 276 - src/main/main-runtime.ts | 101 - src/main/main-warning-suppression-rules.ts | 53 - src/main/messaging/dispatch.ts | 399 -- src/main/messaging/index.ts | 11 - src/main/messaging/normalize.ts | 77 - src/main/model-capability-seed.ts | 287 - src/main/model-dispatch.ts | 221 - src/main/model-resolver.ts | 264 - src/main/notification-service.ts | 226 - src/main/onboarding-service.ts | 344 - src/main/orchestration-service.ts | 1 - src/main/orchestration/heartbeat.ts | 428 -- src/main/orchestration/index.ts | 46 - src/main/orchestration/initial-user-turn.ts | 181 - .../orchestration/internal-tool-selector.ts | 65 - src/main/orchestration/resolve-workspace.ts | 225 - src/main/orchestration/run-dispatch.ts | 179 - src/main/orchestration/scheduler.ts | 371 -- src/main/orchestration/task-runner.ts | 364 - src/main/orchestration/turn-context.ts | 406 -- src/main/orchestration/types.ts | 90 - .../api-docs/agent-control.en.md | 10 - src/main/prompt-builder/api-docs/agents.en.md | 37 - .../prompt-builder/api-docs/approvals.en.md | 54 - src/main/prompt-builder/api-docs/files.en.md | 65 - .../api-docs/goals-projects.en.md | 21 - src/main/prompt-builder/api-docs/header.en.md | 53 - .../prompt-builder/api-docs/knowledge.en.md | 13 - .../prompt-builder/api-docs/meetings.en.md | 19 - .../prompt-builder/api-docs/messages.en.md | 33 - .../prompt-builder/api-docs/sprints.en.md | 14 - src/main/prompt-builder/api-docs/tasks.en.md | 74 - src/main/prompt-builder/api-endpoints.ts | 78 - src/main/prompt-builder/api-section.ts | 118 - src/main/prompt-builder/assets.d.ts | 4 - .../prompt-builder/capability-registry.ts | 42 - .../ceo-modes/awaiting-hire.en.md | 7 - .../ceo-modes/awaiting-org.en.md | 7 - .../prompt-builder/ceo-modes/operating.en.md | 80 - .../ceo-modes/proactive-footer.en.md | 10 - .../prompt-builder/ceo-modes/resolve-mode.ts | 114 - .../ceo-modes/team-building.en.md | 45 - src/main/prompt-builder/context-injection.ts | 172 - .../customer_support.en.md | 9 - .../department-guidelines/engineering.en.md | 12 - .../department-guidelines/finance.en.md | 25 - .../department-guidelines/hr.en.md | 28 - .../department-guidelines/marketing.en.md | 9 - .../department-guidelines/operations.en.md | 9 - .../department-guidelines/sales.en.md | 9 - src/main/prompt-builder/index.ts | 90 - src/main/prompt-builder/messages/index.ts | 13 - .../prompt-builder/messages/operating-en.ts | 247 - src/main/prompt-builder/messages/system-en.ts | 290 - .../operating-instructions-ceo.ts | 73 - .../prompt-builder/operating-instructions.ts | 66 - src/main/prompt-builder/skill-injection.ts | 26 - src/main/prompt-builder/sop-section.ts | 80 - .../prompt-builder/sops/sop-001-standup.en.md | 7 - .../sops/sop-002-task-lifecycle.en.md | 11 - .../sops/sop-003-delegation.en.md | 8 - .../sops/sop-004-code-review.en.md | 7 - .../prompt-builder/sops/sop-005-hiring.en.md | 8 - .../sops/sop-006-escalation.en.md | 6 - .../sops/sop-007-communication.en.md | 27 - .../sops/sop-008-cross-department.en.md | 30 - .../sops/sop-009-documents.en.md | 13 - .../prompt-builder/sops/sop-010-budget.en.md | 7 - .../prompt-builder/sops/sop-011-quality.en.md | 6 - .../prompt-builder/sops/sop-012-cadence.en.md | 7 - .../sops/sop-013-incident.en.md | 8 - .../sops/sop-014-hiring-pipeline.en.md | 9 - .../sops/sop-015-knowledge.en.md | 7 - src/main/prompt-builder/system-prompt.ts | 293 - src/main/prompt-builder/wake-reasons/en.ts | 146 - src/main/prompt-builder/wake-reasons/index.ts | 18 - src/main/run-attempt-policy.ts | 118 - src/main/run-housekeeping.ts | 138 - src/main/run-usage-status.ts | 70 - src/main/service-graph-pi-runtime.ts | 56 - src/main/service-graph.ts | 248 - .../create-background-services.ts | 90 - .../service-graph/create-desktop-shell.ts | 79 - .../service-graph/create-leaf-services.ts | 46 - src/main/service-graph/create-lifecycle.ts | 122 - .../create-runtime-orchestration-service.ts | 192 - .../main/services/agent-connector-tools.ts | 0 .../main/services/agent-deliverable-tools.ts | 0 .../main/services/agent-message-presence.ts | 0 .../main/services/agent-read-messages.ts | 0 .../main/services/agent-run-loop.ts | 0 .../main/services/agent-tool-args.ts | 0 .../src => src}/main/services/agent-tools.ts | 0 .../main/services/approval-service.ts | 0 .../main/services/audit-service.ts | 0 .../main/services/auth-broker-service.ts | 0 .../main/services/automation-service.ts | 0 .../services/board-intervention-service.ts | 0 .../main/services/chat-agent-wake-service.ts | 0 .../main/services/chat-mentions.ts | 0 .../services/chat-message-mutation-service.ts | 0 .../main/services/chat-message-structure.ts | 0 .../main/services/chat-service-internal.ts | 0 .../src => src}/main/services/chat-service.ts | 0 .../main/services/chat-slash-router.ts | 0 .../main/services/compliance-service.ts | 0 .../main/services/composio/composio-client.ts | 0 .../composio/composio-connection-service.ts | 0 .../services/composio/composio-credentials.ts | 0 .../services/composio/composio-tool-bridge.ts | 0 .../services/composio/connector-grants.ts | 0 .../main/services/deliverable-writer.ts | 0 .../main/services/document-service.ts | 0 .../main/services/file-handoff-service.ts | 0 .../src => src}/main/services/file-service.ts | 0 .../main/services/files/file-object-store.ts | 0 .../main/services/files/workspace-path.ts | 0 .../src => src}/main/services/goal-kickoff.ts | 0 .../main/services/identity-access-service.ts | 0 .../main/services/knowledge-service.ts | 0 .../main/services/meeting-service.ts | 0 .../migration-cutover-journal-service.ts | 0 .../main/services/migration-service.ts | 0 .../services/migration-validation-summary.ts | 0 .../services/oauth/anthropic-claude-flow.ts | 0 .../services/oauth/github-copilot-flow.ts | 0 .../services/oauth/google-antigravity-flow.ts | 0 .../services/oauth/oauth-callback-server.ts | 0 .../main/services/oauth/oauth-flows.ts | 0 .../main/services/oauth/oauth-page.ts | 0 .../main/services/oauth/oauth-types.ts | 0 .../main/services/oauth/openai-codex-flow.ts | 0 .../src => src}/main/services/oauth/pkce.ts | 0 .../main/services/onboarding-service.ts | 0 .../main/services/operations-service.ts | 0 .../main/services/org-governance-service.ts | 0 .../main/services/organization-seed.ts | 0 .../main/services/organization-service.ts | 0 .../main/services/policy-service.ts | 0 .../services/provider-adapter-contract.ts | 0 .../main/services/provider-adapters.ts | 0 .../main/services/provider-auth-lifecycle.ts | 0 .../main/services/provider-auth-profiles.ts | 0 .../services/provider-background-service.ts | 0 .../main/services/provider-background.ts | 0 .../main/services/provider-http.ts | 0 .../main/services/provider-internal.ts | 0 .../main/services/provider-models-fetch.ts | 0 .../main/services/provider-oauth-service.ts | 0 .../services/provider-rate-limit-registry.ts | 0 .../main/services/provider-request-store.ts | 0 .../services/provider-response-observer.ts | 0 .../main/services/provider-response-runner.ts | 0 .../main/services/provider-response-utils.ts | 0 .../main/services/provider-service.ts | 0 .../main/services/provider-sign-in-window.ts | 0 .../main/services/provider-streaming.ts | 0 .../main/services/provider-tool-turn.ts | 0 .../provider-tool-turns/anthropic-format.ts | 0 .../services/provider-tool-turns/aws-sigv4.ts | 0 .../provider-tool-turns/bedrock-format.ts | 0 .../provider-tool-turns/chat-format.ts | 0 .../credential-resolver.ts | 0 .../services/provider-tool-turns/gcp-auth.ts | 0 .../provider-tool-turns/gemini-format.ts | 0 .../provider-tool-turns/responses-format.ts | 0 .../services/provider-tool-turns/router.ts | 0 .../services/provider-tool-turns/turns.ts | 0 .../main/services/rollback-service.ts | 0 .../src => src}/main/services/sdlc-service.ts | 0 .../main/services/search-service.ts | 0 .../src => src}/main/services/secret-vault.ts | 0 .../main/services/skill-artifacts.ts | 0 .../main/services/skill-manifest.ts | 0 .../main/services/skill-service.ts | 0 .../main/services/snapshot-service.ts | 0 .../main/services/social-audit-service.ts | 0 .../services/social-browser-policy-service.ts | 0 .../main/services/social-login-window.ts | 0 .../main/services/social-service.ts | 0 .../main/services/sprint-service.ts | 0 .../main/services/task-execution-service.ts | 0 .../src => src}/main/services/task-prompts.ts | 0 src/main/session-management-service.ts | 215 - src/main/skill-format.ts | 222 - src/main/skill-github.ts | 233 - src/main/skill-keys.ts | 174 - src/main/skill-service.ts | 1 - src/main/skill-types.ts | 30 - src/main/skills/auto-assign-on-hire.ts | 90 - src/main/skills/crud.ts | 133 - src/main/skills/discovery.ts | 161 - src/main/skills/import-github.ts | 159 - src/main/skills/import-local.ts | 219 - src/main/skills/import-url.ts | 89 - src/main/skills/import.ts | 132 - src/main/skills/index.ts | 63 - src/main/skills/materialize.ts | 147 - src/main/skills/read-response-with-limit.ts | 72 - src/main/skills/runtime.ts | 191 - src/main/skills/url-validation.ts | 199 - src/main/task-quality-gates.ts | 300 - src/main/task-rubrics.ts | 100 - src/main/task-workspace-binding.ts | 103 - src/main/thread-integration/index.ts | 385 -- src/main/thread-integration/thread-helpers.ts | 189 - src/main/updater-service.ts | 159 - src/main/vault.ts | 120 - src/main/window-state.ts | 93 - src/main/worker-service.ts | 271 - src/main/worker/entry/crash-recovery.ts | 143 - src/main/worker/entry/index.ts | 183 - src/main/worker/entry/message-handler.ts | 136 - src/main/worker/entry/rpc.ts | 54 - src/main/worker/entry/types.ts | 128 - .../handlers/context-compaction-handler.ts | 30 - src/main/worker/handlers/handler-context.ts | 29 - .../worker/handlers/run-finished-handler.ts | 54 - .../worker/handlers/run-finished-helpers.ts | 453 -- src/main/worker/handlers/run-log-handler.ts | 54 - .../worker/handlers/run-status-handler.ts | 50 - .../observability/failure-escalation.ts | 142 - src/main/worker/observability/log-redactor.ts | 27 - .../observability/run-event-recorder.ts | 33 - .../worker/observability/run-log-filter.ts | 58 - .../runtime/credential-concurrency-gate.ts | 132 - src/main/worker/runtime/helpers.ts | 114 - src/main/worker/runtime/index.ts | 288 - .../internal-tools/file-approval-tool.ts | 139 - .../runtime/internal-tools/hire-agent-tool.ts | 147 - .../internal-tools/internal-tool-rpc.ts | 43 - src/main/worker/runtime/pi-agent-factory.ts | 94 - src/main/worker/runtime/pi-hook-contract.ts | 103 - src/main/worker/runtime/pi-safe-stream.ts | 184 - .../worker/runtime/provider-rate-limits.ts | 31 - src/main/worker/runtime/run-tools.ts | 35 - src/preload/index.ts | 135 +- src/renderer/App.tsx | 249 - src/renderer/components/TitleBar.tsx | 62 - src/renderer/components/Toast.tsx | 75 - src/renderer/components/TwoPaneLayout.tsx | 59 - .../components/automation/AutomationPanel.tsx | 312 - .../components/automation/RuleCard.tsx | 35 - .../components/automation/RuleEditor.tsx | 45 - .../components/automation/WorkflowEditor.tsx | 42 - .../components/automation/WorkflowList.tsx | 58 - .../automation/automation-config.ts | 69 - .../communication/ChannelHeader.tsx | 80 - .../communication/ChannelSidebar.tsx | 252 - .../communication/CommunicationHub.tsx | 327 - .../communication/MessageComposer.tsx | 161 - .../components/communication/MessageItem.tsx | 208 - .../components/communication/MessageList.tsx | 194 - .../communication/SearchResults.tsx | 191 - .../components/communication/ThreadPanel.tsx | 181 - .../communication/WaitStateIndicator.tsx | 63 - .../components/communication/channel-utils.ts | 123 - .../composer-shell/ComposerShell.tsx | 96 - .../composer/ComposerAttachments.tsx | 160 - .../composer/ComposerMentionDropdown.tsx | 89 - .../composer/ComposerReplyBanner.tsx | 42 - .../composer/ComposerSubjectRow.tsx | 34 - .../composer/NoChannelComposer.tsx | 14 - .../composer/TaskDiscussionComposer.tsx | 56 - .../composer/useCaretMeasurement.ts | 79 - .../communication/composer/useMentionState.ts | 76 - .../communication/composer/useMessageSend.ts | 99 - .../communication/message-filters.ts | 36 - .../company-onboarding/CompanyStep.tsx | 165 - .../company-onboarding/ExecutionModeStep.tsx | 127 - .../company-onboarding/LaunchStep.tsx | 87 - .../company-onboarding/MissionStep.tsx | 97 - .../company-onboarding/ModelPoolStep.tsx | 126 - .../company-onboarding/NodeCheckStep.tsx | 125 - .../company-onboarding/OnboardingContext.tsx | 106 - .../company-onboarding/OnboardingHero.tsx | 163 - .../company-onboarding/OnboardingStep.tsx | 36 - .../OnboardingStepPanel.tsx | 221 - .../company-onboarding/OnboardingWizard.tsx | 336 - .../company-onboarding/ProvidersStep.tsx | 158 - .../company-onboarding/WelcomeStep.tsx | 73 - .../provider-cards/ProviderCard.tsx | 38 - .../provider-cards/api-key-card.tsx | 134 - .../provider-cards/cloud-card.tsx | 66 - .../provider-cards/local-card.tsx | 153 - .../provider-cards/oauth-card.tsx | 96 - .../provider-cards/shared.tsx | 101 - .../useConnectorCallbacks.ts | 67 - .../useConnectorModelSelection.ts | 310 - .../company-operations/DocumentCenter.tsx | 183 - .../KnowledgeBaseManager.tsx | 94 - .../company-operations/MeetingsManager.tsx | 108 - .../company-operations/SectionHeader.tsx | 22 - .../company-operations/SprintManager.tsx | 100 - .../components/company-operations/helpers.ts | 82 - src/renderer/components/connectors.tsx | 103 - .../components/dashboard/ActivityFeed.tsx | 77 - .../dashboard/BudgetAlertBanner.tsx | 111 - .../components/dashboard/ChartSection.tsx | 97 - .../components/dashboard/Dashboard.tsx | 232 - .../components/dashboard/KanbanBoard.tsx | 105 - .../components/dashboard/MetricsGrid.tsx | 33 - .../components/dashboard/RecoveryBanner.tsx | 82 - .../dashboard/charts/AgentWorkloadChart.tsx | 52 - .../dashboard/charts/BudgetUtilization.tsx | 131 - .../components/dashboard/charts/ChartCard.tsx | 58 - .../dashboard/charts/ChartTooltip.tsx | 95 - .../dashboard/charts/CostTrendChart.tsx | 57 - .../dashboard/charts/RunActivityChart.tsx | 57 - .../dashboard/charts/SuccessRateChart.tsx | 66 - .../dashboard/charts/chart-utils.ts | 142 - .../components/execution/ActivityList.tsx | 106 - .../components/execution/ApprovalList.tsx | 72 - .../components/execution/BudgetSummary.tsx | 105 - .../components/execution/CostList.tsx | 113 - .../components/execution/IncidentList.tsx | 135 - .../execution/ModelManagementShared.tsx | 146 - .../execution/PendingReviewList.tsx | 130 - .../components/execution/PolicyFormModal.tsx | 164 - .../components/execution/PolicyList.tsx | 160 - .../components/execution/SettingsShell.tsx | 120 - .../execution/SocialDraftPreview.tsx | 129 - .../components/execution/TaskComments.tsx | 63 - .../components/execution/TaskCreator.tsx | 61 - .../components/execution/TaskInspector.tsx | 257 - .../execution/TaskInspectorActivity.tsx | 166 - .../execution/TaskInspectorEditForm.tsx | 87 - .../execution/TaskInspectorGovernance.tsx | 72 - .../execution/TaskInspectorOverview.tsx | 79 - .../execution/TaskInspectorSubtasks.tsx | 47 - .../components/execution/TaskQueue.tsx | 77 - .../components/execution/WorkspaceCreator.tsx | 28 - .../execution/WorkspaceInspector.tsx | 105 - .../components/execution/WorkspaceList.tsx | 55 - .../ApprovalDocumentsPanel.tsx | 301 - .../approval-inspector/ApprovalInspector.tsx | 188 - .../approval-inspector/ApprovalSummary.tsx | 54 - .../approval-inspector/DecisionForm.tsx | 79 - .../DeliverableReviewPanel.tsx | 116 - .../approval-inspector/ProposedHireCard.tsx | 96 - .../approval-inspector/SchedulePicker.tsx | 79 - .../approval-inspector/TypeBadge.tsx | 16 - .../execution/approval-inspector/index.ts | 1 - .../approval-inspector/useApprovalPayload.ts | 23 - .../components/execution/execution-utils.tsx | 76 - .../settings-sections/DataSection.tsx | 133 - .../ExecutionModeSection.tsx | 105 - .../settings-sections/GeneralSection.tsx | 89 - .../settings-sections/SecretsSection.tsx | 102 - .../settings-sections/ShortcutsSection.tsx | 40 - .../components/hiring/HiringPipeline.tsx | 175 - .../components/hiring/hiring-helpers.ts | 36 - src/renderer/components/inbox/Inbox.tsx | 151 - .../components/inbox/PerformanceView.tsx | 127 - src/renderer/components/inbox/StandupView.tsx | 145 - .../components/inbox/inbox-helpers.tsx | 66 - .../components/organization/AgentCreator.tsx | 27 - .../components/organization/AgentEditor.tsx | 36 - .../components/organization/AgentRoster.tsx | 113 - .../components/organization/GoalCreator.tsx | 16 - .../components/organization/GoalEditor.tsx | 30 - .../components/organization/GoalList.tsx | 54 - .../components/organization/OrgChart.tsx | 164 - .../organization/ProjectCreator.tsx | 16 - .../components/organization/ProjectEditor.tsx | 30 - .../components/organization/ProjectList.tsx | 65 - .../organization/TeamHeaderSummary.tsx | 81 - .../organization/agent-form/AgentForm.tsx | 114 - .../agent-form-fields/CreateFormBody.tsx | 254 - .../agent-form-fields/EditFormBody.tsx | 244 - .../edit-sections/ConstraintsSection.tsx | 58 - .../edit-sections/EditActionBar.tsx | 87 - .../edit-sections/IdentitySection.tsx | 77 - .../edit-sections/RuntimeSection.tsx | 116 - .../organization/agent-form/index.ts | 3 - .../organization/agent-form/useAgentForm.ts | 221 - .../organization/goal-form/GoalForm.tsx | 185 - .../organization/goal-form/index.ts | 2 - .../components/organization/helpers.tsx | 104 - .../components/organization/orgTreeLayout.ts | 96 - .../organization/project-form/ProjectForm.tsx | 162 - .../organization/project-form/index.ts | 2 - src/renderer/components/runs/RunCenter.tsx | 116 - src/renderer/components/runs/RunDetail.tsx | 126 - src/renderer/components/runs/RunQueue.tsx | 101 - src/renderer/components/runs/run-helpers.tsx | 28 - .../settings/dialogs/OAuthPromptDialog.tsx | 131 - .../settings/dialogs/oauth-prompt-events.ts | 52 - .../components/settings/forms/ApiKeyForm.tsx | 92 - .../components/settings/forms/AwsForm.tsx | 169 - .../components/settings/forms/AzureForm.tsx | 135 - .../components/settings/forms/LocalForm.tsx | 78 - .../components/settings/forms/VertexForm.tsx | 91 - .../settings/providers/ProviderRow.tsx | 213 - .../settings/providers/ProvidersPanel.tsx | 175 - .../components/settings/providers/index.ts | 2 - .../components/skills/SkillAgentToggles.tsx | 114 - .../components/skills/SkillDetail.tsx | 366 -- .../components/skills/SkillFileTree.tsx | 136 - .../components/skills/SkillImportModal.tsx | 178 - src/renderer/components/skills/SkillList.tsx | 135 - .../components/skills/SkillsSection.tsx | 156 - src/renderer/components/skills/index.ts | 2 - .../components/social/AccountCard.tsx | 100 - .../components/social/ActionHistory.tsx | 122 - .../components/social/AddAccountDialog.tsx | 79 - .../components/social/SocialPanel.tsx | 153 - .../components/social/social-config.ts | 63 - src/renderer/components/ui/ActionButton.tsx | 55 - src/renderer/components/ui/AttentionRow.tsx | 135 - src/renderer/components/ui/Badge.tsx | 13 - src/renderer/components/ui/BudgetBar.tsx | 19 - src/renderer/components/ui/Card.tsx | 30 - src/renderer/components/ui/Eyebrow.tsx | 27 - src/renderer/components/ui/Field.tsx | 10 - src/renderer/components/ui/Input.tsx | 49 - src/renderer/components/ui/MarkdownBody.tsx | 85 - src/renderer/components/ui/Panel.tsx | 33 - src/renderer/components/ui/SectionButton.tsx | 59 - src/renderer/components/ui/Select.tsx | 66 - src/renderer/components/ui/Spinner.tsx | 14 - src/renderer/components/ui/TextArea.tsx | 44 - src/renderer/components/ui/feedback.tsx | 188 - src/renderer/components/ui/hooks.tsx | 113 - src/renderer/components/ui/icons.ts | 125 - src/renderer/components/ui/index.ts | 7 - src/renderer/components/ui/layout.tsx | 145 - src/renderer/components/ui/primitives.tsx | 11 - src/renderer/env.d.ts | 5 +- src/renderer/hooks/useAppActions.ts | 18 - .../hooks/useCommandPaletteHotkeys.ts | 64 - src/renderer/hooks/useCompanyController.ts | 205 - src/renderer/hooks/useCompanyData.ts | 155 - src/renderer/hooks/useDataLoader.ts | 87 - src/renderer/hooks/useDesktopEvents.ts | 159 - src/renderer/hooks/useRunLogs.ts | 139 - src/renderer/hooks/useSectionContext.ts | 24 - src/renderer/hooks/useUIController.ts | 218 - src/renderer/i18n/en.ts | 1458 ---- src/renderer/i18n/index.ts | 34 - src/renderer/i18n/zh.ts | 1458 ---- src/renderer/index.html | 14 +- src/renderer/lib/budget-alerts.ts | 70 - src/renderer/lib/budget-policy-input.ts | 61 - src/renderer/lib/constants.ts | 2 - src/renderer/lib/desktop.ts | 182 - src/renderer/lib/formatters.ts | 92 - src/renderer/lib/keyboard.ts | 85 - src/renderer/lib/platform.ts | 7 - src/renderer/lib/safe-json.ts | 8 - src/renderer/lib/snapshot-events.ts | 120 - src/renderer/main.tsx | 10 - src/renderer/navigation.ts | 90 - .../src => src}/renderer/src/app/App.tsx | 0 .../renderer/src/app/Onboarding.tsx | 0 .../src/app/OnboardingProviderStep.tsx | 0 .../renderer/src/app/useSnapshot.ts | 0 .../renderer/src/fonts/Geist-Variable.woff2 | Bin .../src/fonts/GeistMono-Variable.woff2 | Bin .../src => src}/renderer/src/main.tsx | 0 .../src => src}/renderer/src/overlays.css | 0 .../renderer/src/pages/ApprovalsPage.tsx | 0 .../renderer/src/pages/ChatPage.tsx | 0 .../renderer/src/pages/ConnectorsPage.tsx | 0 .../renderer/src/pages/DocumentsPage.tsx | 0 .../renderer/src/pages/FilesPage.tsx | 0 .../renderer/src/pages/HomePage.tsx | 0 .../renderer/src/pages/NewTaskDialog.tsx | 0 .../renderer/src/pages/OfficePage.tsx | 0 .../renderer/src/pages/RunsPage.tsx | 0 .../renderer/src/pages/SettingsPage.tsx | 0 .../renderer/src/pages/TeamPage.tsx | 0 .../renderer/src/pages/WorkPage.tsx | 0 .../renderer/src/pages/chat/ChatComposer.tsx | 0 .../src/pages/chat/ChatConversation.tsx | 0 .../src/pages/chat/ChatMessageRow.tsx | 0 .../renderer/src/pages/chat/ChatSidebar.tsx | 0 .../src/pages/chat/ChatThreadPanel.tsx | 0 .../renderer/src/pages/chat/ChatTimeline.tsx | 0 .../src/pages/chat/MentionTextarea.tsx | 0 .../renderer/src/pages/chat/chat-helpers.ts | 0 .../src/pages/connectors/ConnectedList.tsx | 0 .../src/pages/connectors/ToolkitCatalog.tsx | 0 .../renderer/src/pages/files/FileVisuals.tsx | 0 .../renderer/src/pages/files/FilesGrid.tsx | 0 .../renderer/src/pages/files/FilesTable.tsx | 0 .../renderer/src/pages/files/FilesTree.tsx | 0 .../renderer/src/pages/files/file-helpers.ts | 0 .../src/pages/home/DashboardCharts.tsx | 0 .../src/pages/office/AgentDetailCard.tsx | 0 .../renderer/src/pages/office/floor-plan.ts | 0 .../src/pages/office/office-renderer.ts | 0 .../renderer/src/pages/office/office-types.ts | 0 .../src/pages/office/scene-renderer.ts | 0 .../renderer/src/pages/office/simulation.ts | 0 .../renderer/src/pages/office/sky.ts | 0 .../renderer/src/pages/office/sprites.ts | 0 .../src/pages/settings/AdvancedPanel.tsx | 0 .../src/pages/settings/BillingPanel.tsx | 0 .../src/pages/settings/ComposioPanel.tsx | 0 .../src/pages/settings/MigrationPanel.tsx | 0 .../settings/ProviderConnectionDialog.tsx | 0 .../src/pages/settings/ProviderLogo.tsx | 0 .../pages/settings/ProviderRequestPanel.tsx | 0 .../src/pages/settings/ProvidersPanel.tsx | 0 .../src/pages/settings/SkillsPanel.tsx | 0 .../src/pages/settings/WorkspacePanel.tsx | 0 .../src/pages/settings/provider-secret.ts | 0 .../src/pages/social/PlatformIcon.tsx | 0 .../src/pages/social/SocialActivity.tsx | 0 .../src/pages/social/SocialCalendar.tsx | 0 .../src/pages/social/platform-tokens.ts | 0 .../src/pages/team/HiringPipeline.tsx | 0 .../renderer/src/pages/team/OrgChartTree.tsx | 0 .../src => src}/renderer/src/pages/types.ts | 0 .../renderer/src/pages/work/GoalDialog.tsx | 0 .../renderer/src/pages/work/ProjectDialog.tsx | 0 .../src/pages/work/ProjectOverview.tsx | 0 .../src/pages/work/TaskDetailDialog.tsx | 0 .../renderer/src/pages/work/task-helpers.ts | 0 .../renderer/src/shared/CascadeMenu.tsx | 0 .../renderer/src/shared/Dialog.tsx | 0 .../src => src}/renderer/src/shared/Icon.tsx | 0 .../renderer/src/shared/NavIcon.tsx | 0 .../renderer/src/shared/OrgSwitcher.tsx | 0 .../renderer/src/shared/Popover.tsx | 0 .../src/shared/ProviderOAuthConnect.tsx | 0 .../renderer/src/shared/SearchDialog.tsx | 0 .../src => src}/renderer/src/shared/Shell.tsx | 0 .../renderer/src/shared/TopbarActions.tsx | 0 .../renderer/src/shared/topbar-context.ts | 0 .../src => src}/renderer/src/shared/ui.tsx | 0 .../src => src}/renderer/src/styles.css | 0 .../renderer/src/styles/components.css | 0 .../src => src}/renderer/src/styles/fonts.css | 0 src/renderer/state/slices/communication.ts | 68 - src/renderer/state/slices/company.ts | 200 - src/renderer/state/slices/navigation.ts | 111 - src/renderer/state/slices/selection.ts | 103 - src/renderer/state/slices/skill.ts | 42 - src/renderer/state/slices/social.ts | 28 - src/renderer/state/slices/ui.ts | 88 - src/renderer/state/snapshot-sections.ts | 116 - src/renderer/state/store.ts | 45 - src/renderer/styles.css | 839 --- src/renderer/views/CommandPaletteView.tsx | 273 - src/renderer/views/SectionContentView.tsx | 62 - src/renderer/views/SidebarView.tsx | 183 - .../views/sections/ExecutionSections.tsx | 324 - .../views/sections/OperationsSections.tsx | 305 - .../views/sections/OrganizationSections.tsx | 173 - src/shared/approval-documents.ts | 140 - .../src => src}/shared/audit-domain.ts | 0 .../src => src}/shared/board-domain.ts | 0 .../src => src}/shared/chat-domain.ts | 0 .../src => src}/shared/commands/chat.ts | 0 .../shared/commands/collaboration.ts | 0 .../src => src}/shared/commands/composio.ts | 0 .../src => src}/shared/commands/files.ts | 0 .../src => src}/shared/commands/governance.ts | 0 .../src => src}/shared/commands/index.ts | 0 .../src => src}/shared/commands/onboarding.ts | 0 .../shared/commands/organization.ts | 0 .../src => src}/shared/commands/provider.ts | 0 .../src => src}/shared/commands/skills.ts | 0 .../src => src}/shared/commands/social.ts | 0 .../src => src}/shared/compliance-domain.ts | 0 src/shared/connector-catalog.ts | 312 - src/shared/connector-models.ts | 37 - src/shared/connector-policy.ts | 21 - src/shared/constants.ts | 36 - src/shared/contracts.ts | 13 - src/shared/contracts/channels.ts | 111 - src/shared/contracts/desktop-api.ts | 52 - src/shared/contracts/desktop-api/agents.ts | 15 - src/shared/contracts/desktop-api/approvals.ts | 12 - .../contracts/desktop-api/automation.ts | 23 - src/shared/contracts/desktop-api/budget.ts | 13 - src/shared/contracts/desktop-api/common.ts | 29 - .../contracts/desktop-api/communication.ts | 20 - src/shared/contracts/desktop-api/companies.ts | 28 - .../contracts/desktop-api/credentials.ts | 26 - src/shared/contracts/desktop-api/runs.ts | 15 - src/shared/contracts/desktop-api/skills.ts | 15 - src/shared/contracts/desktop-api/tasks.ts | 20 - src/shared/contracts/desktop-api/threads.ts | 11 - src/shared/contracts/desktop-api/window.ts | 10 - src/shared/contracts/helpers.ts | 31 - src/shared/contracts/json-fields.ts | 80 - src/shared/contracts/preload-forwarders.ts | 312 - src/shared/contracts/schemas-agent-event.ts | 19 - src/shared/contracts/schemas-agents.ts | 53 - src/shared/contracts/schemas-approvals.ts | 85 - src/shared/contracts/schemas-automation.ts | 28 - src/shared/contracts/schemas-badges.ts | 23 - src/shared/contracts/schemas-budget.ts | 39 - src/shared/contracts/schemas-company.ts | 143 - src/shared/contracts/schemas-credentials.ts | 200 - src/shared/contracts/schemas-execution.ts | 135 - src/shared/contracts/schemas-messages.ts | 140 - src/shared/contracts/schemas-misc.ts | 6 - src/shared/contracts/schemas-oauth.ts | 31 - src/shared/contracts/schemas-tasks.ts | 56 - src/shared/contracts/schemas-threads.ts | 23 - src/shared/contracts/schemas-work-products.ts | 45 - .../src => src}/shared/desktop-api.ts | 0 src/shared/document-categories.ts | 20 - .../src => src}/shared/domain.ts | 0 .../src => src}/shared/identity-domain.ts | 0 {AgentCompany-New/src => src}/shared/ids.ts | 0 src/shared/inbox-items.ts | 167 - {AgentCompany-New/src => src}/shared/ipc.ts | 0 src/shared/locale.ts | 4 - src/shared/markdown-text.ts | 12 - .../src => src}/shared/mention-handles.ts | 0 .../src => src}/shared/operations-domain.ts | 0 .../shared/org-governance-domain.ts | 0 .../shared/provider-auth-domain.ts | 0 .../src => src}/shared/provider-catalog.ts | 0 .../src => src}/shared/provider-models.ts | 0 .../shared/provider-policy-domain.ts | 0 .../shared/provider-request-domain.ts | 0 .../shared/provider-runtime-domain.ts | 0 .../src => src}/shared/result.ts | 0 .../src => src}/shared/rollback-domain.ts | 0 .../src => src}/shared/sdlc-domain.ts | 0 .../src => src}/shared/search-domain.ts | 0 src/shared/sidebar-badges.ts | 102 - .../src => src}/shared/snapshot-domain.ts | 0 .../src => src}/shared/social-domain.ts | 0 src/shared/types.ts | 4 - src/shared/types/enums.ts | 300 - src/shared/types/events.ts | 191 - src/shared/types/records-core.ts | 397 -- src/shared/types/records-extended.ts | 359 - src/shared/types/records.ts | 2 - src/shared/types/snapshot.ts | 101 - .../contract/desktop-release-contract.test.ts | 0 .../contract/provider-contracts.test.ts | 0 tests/e2e/desktop.smoke.spec.ts | 212 - .../tests => tests}/e2e/desktop.spec.ts | 0 tests/e2e/e2e-global-setup.ts | 16 - tests/e2e/launch.ts | 46 - .../tests => tests}/e2e/office.spec.ts | 0 tests/e2e/onboarding-fixture.ts | 66 - tests/e2e/playwright.config.ts | 15 +- .../tests => tests}/e2e/screenshots.spec.ts | 0 tests/eval/README.md | 268 - tests/eval/approval-api-docs-contract.test.ts | 23 - tests/eval/assertion-judge.ts | 213 - tests/eval/eval-runner.ts | 64 - tests/eval/fixture-loader.ts | 157 - tests/eval/fixtures/.gitkeep | 0 tests/eval/fixtures/README.md | 44 - .../fixtures/ceo-board-message-reply.jsonl | 4 - tests/eval/fixtures/ceo-bootstrap-empty.jsonl | 4 - tests/eval/fixtures/ic-task-execute.jsonl | 4 - .../eval/fixtures/manager-task-handoff.jsonl | 4 - tests/eval/fixtures/non-ceo-dm-reply.jsonl | 4 - tests/eval/harness.test.ts | 344 - tests/eval/record-fixture.ts | 295 - tests/eval/replay-client.ts | 106 - .../tests => tests}/eval/replay-eval.test.ts | 0 tests/eval/scenario-contract.ts | 277 - .../ceo-board-message-reply/system.txt | 18 - .../ceo-board-message-reply/user.txt | 7 - .../scenarios/ceo-bootstrap-empty/system.txt | 32 - .../scenarios/ceo-bootstrap-empty/user.txt | 1 - .../eval/scenarios/ic-task-execute/system.txt | 16 - tests/eval/scenarios/ic-task-execute/user.txt | 3 - .../scenarios/manager-task-handoff/system.txt | 17 - .../scenarios/manager-task-handoff/user.txt | 9 - .../scenarios/non-ceo-dm-reply/system.txt | 16 - .../eval/scenarios/non-ceo-dm-reply/user.txt | 7 - tests/eval/semantic-rubric-judge.test.ts | 56 - tests/eval/semantic-rubric-judge.ts | 76 - tests/eval/task-api-docs-contract.test.ts | 15 - tests/eval/task-level-prompt-cases.ts | 345 - tests/eval/task-level-prompt-eval.test.ts | 116 - tests/eval/task-level-prompt-eval.ts | 140 - tests/eval/tool-loop-replay.ts | 258 - tests/eval/types.ts | 199 - .../integration/agent-model-switching.spec.ts | 172 - .../integration/agent-reply.test.ts | 0 tests/integration/api-meetings.spec.ts | 144 - .../api-recursive-org-execution.spec.ts | 307 - tests/integration/api-run-events.spec.ts | 165 - .../artifact-projection-ack.spec.ts | 187 - .../approval-decisions.spec.ts | 76 - .../automation-messages.spec.ts | 343 - .../ceo-phased-prompts.spec.ts | 192 - .../autonomous-chain/crash-recovery.spec.ts | 91 - .../autonomous-chain/e2e-flows.spec.ts | 336 - .../autonomous-chain/role-detection.spec.ts | 65 - .../autonomous-chain/run-failure.spec.ts | 64 - .../autonomous-chain/shared-setup.ts | 135 - .../autonomous-chain/task-propagation.spec.ts | 63 - .../autonomous-chain/wake-reason.spec.ts | 119 - .../autonomous-chain/wakeup-queue.spec.ts | 55 - .../integration/autonomous-run.test.ts | 0 .../integration/collaboration-flow.test.ts | 0 .../connector-model-enforcement.spec.ts | 289 - tests/integration/cross-subsystem.spec.ts | 506 -- tests/integration/database.spec.ts | 257 - .../document-run-provenance.spec.ts | 319 - .../integration/onboarding-model-pool.spec.ts | 327 - .../onboarding-transaction.spec.ts | 121 - .../integration/org-deletion.test.ts | 0 tests/integration/pi-mono-migrations.spec.ts | 123 - tests/integration/pi-runtime-contract.spec.ts | 142 - tests/integration/process-recovery.spec.ts | 584 -- .../skill-aware-assignment.spec.ts | 224 - .../thread-participant-wake.test.ts | 0 .../integration/thread-wait-heartbeat.spec.ts | 444 -- .../work-product-primary-invariant.spec.ts | 251 - .../work-product-url-policy.spec.ts | 377 -- .../work-products-lifecycle.spec.ts | 482 -- tests/support/api-server-callbacks.ts | 24 - tests/support/pi-runtime-contract.ts | 69 - tests/unit/active-run-projection.test.ts | 117 - tests/unit/agent-auth.test.ts | 78 - tests/unit/agent-budget-policy-sync.test.ts | 112 - .../unit/agent-direct-messages.test.ts | 0 tests/unit/agent-hierarchy-cycle.test.ts | 79 - tests/unit/agent-hire-routing.test.ts | 98 - tests/unit/agent-hooks.test.ts | 37 - .../unit/agent-messaging.test.ts | 0 .../agent-permissions-ceo-strategy.test.ts | 159 - tests/unit/agent-permissions.test.ts | 249 - .../unit/agent-run-loop.test.ts | 0 tests/unit/agent-schema-validation.test.ts | 59 - tests/unit/api-body-encoding.test.ts | 20 - tests/unit/api-server-callbacks.test.ts | 30 - tests/unit/app-error-fatal-route.test.ts | 30 - tests/unit/approval-hire-routing.test.ts | 131 - ...approval-review-feedback-writeback.test.ts | 262 - tests/unit/artifact-projector-errors.test.ts | 66 - tests/unit/atomic-checkout.test.ts | 595 -- .../unit/audit-service.test.ts | 0 tests/unit/automation-action-registry.test.ts | 48 - tests/unit/browser-action-queue.test.ts | 133 - tests/unit/browser-action-runtime.test.ts | 92 - tests/unit/browser-manager-timeout.test.ts | 134 - tests/unit/budget-alert.test.ts | 113 - tests/unit/budget-enforcement.test.ts | 376 -- tests/unit/budget-incidents.test.ts | 339 - tests/unit/budget-policy-input.test.ts | 41 - tests/unit/capability-registry.test.ts | 44 - .../unit/cascade-safe-triangle.test.ts | 0 tests/unit/channel-utils.test.ts | 79 - tests/unit/chart-tooltip.test.ts | 74 - .../unit/chat-governance.test.ts | 0 .../tests => tests}/unit/coalesce.test.ts | 0 tests/unit/cofounder-approval-gate.test.ts | 180 - tests/unit/company-mode-switch.test.ts | 179 - tests/unit/company-operation-handlers.test.ts | 36 - tests/unit/company-slice-patches.test.ts | 256 - .../unit/compliance-service.test.ts | 0 tests/unit/connector-catalog.test.ts | 82 - .../unit/connector-grants.test.ts | 0 tests/unit/connector-matching.test.ts | 92 - tests/unit/connector-model-policy.test.ts | 92 - tests/unit/connector-models.test.ts | 38 - tests/unit/connector-provider-guard.test.ts | 68 - tests/unit/connectors.spec.ts | 39 - tests/unit/context-compaction-worker.test.ts | 66 - .../context-compactor-tool-results.test.ts | 119 - tests/unit/contracts.test.ts | 122 - tests/unit/crash-recovery.test.ts | 185 - .../unit/credential-concurrency-gate.test.ts | 106 - tests/unit/credential-resolver.test.ts | 210 - tests/unit/credential-store.test.ts | 152 - tests/unit/credentials-schemas.test.ts | 219 - tests/unit/d1-migrations.test.ts | 136 - tests/unit/dashboard-charts.test.ts | 267 - tests/unit/database-module-groups.test.ts | 78 - tests/unit/database-transaction.test.ts | 62 - tests/unit/database.test.ts | 764 --- tests/unit/deprecation-counter.test.ts | 43 - tests/unit/desktop-error-notice.test.ts | 108 - .../unit/domain-services.test.ts | 0 tests/unit/edge-case-budget.test.ts | 449 -- tests/unit/edge-case-concurrent.test.ts | 344 - tests/unit/edge-case-session.test.ts | 336 - tests/unit/error-boundary.test.ts | 19 - tests/unit/error-taxonomy.test.ts | 42 - .../unit/execution-modes.test.ts | 0 tests/unit/external-url-policy.test.ts | 23 - .../tests => tests}/unit/external-url.test.ts | 0 tests/unit/failure-escalation.test.ts | 241 - .../tests => tests}/unit/file-helpers.test.ts | 0 .../unit/identity-access-service.test.ts | 0 .../unit/inbound-correlation-registry.test.ts | 50 - tests/unit/internal-tool-selector.test.ts | 137 - .../ipc-agent-coordination-handlers.test.ts | 115 - tests/unit/ipc-agent-graph-handlers.test.ts | 107 - tests/unit/ipc-core-admin-handlers.test.ts | 70 - tests/unit/ipc-core-read-handlers.test.ts | 100 - tests/unit/ipc-credentials-handlers.test.ts | 256 - .../ipc-open-work-product-url-policy.test.ts | 135 - tests/unit/ipc-support-error-code.test.ts | 89 - tests/unit/keyboard.test.ts | 152 - tests/unit/knowledge-provenance.test.ts | 59 - tests/unit/landing-platform-support.test.ts | 83 - tests/unit/landing-product-narrative.test.ts | 71 - tests/unit/legacy-baseline-migration.test.ts | 406 -- tests/unit/log-redactor.test.ts | 61 - .../main-warning-suppression-rules.test.ts | 44 - tests/unit/markdown-text.test.ts | 12 - .../unit/mention-resolution.test.ts | 0 tests/unit/message-dispatch.test.ts | 461 -- tests/unit/message-filters.test.ts | 93 - tests/unit/message-search.test.ts | 207 - .../unit/migration-service.test.ts | 0 tests/unit/model-capability-seed.test.ts | 101 - tests/unit/model-dispatch.test.ts | 354 - tests/unit/navigation-model.test.ts | 46 - tests/unit/notification-service.test.ts | 270 - tests/unit/oauth-login-service.test.ts | 64 - tests/unit/oauth-prompt-events.test.ts | 64 - .../unit/office-floor-plan.test.ts | 0 .../unit/office-simulation.test.ts | 0 .../tests => tests}/unit/office-sky.test.ts | 0 .../unit/office-sprites.test.ts | 0 tests/unit/operation-json-fields.test.ts | 74 - .../unit/operations-service.test.ts | 0 .../unit/org-governance-service.test.ts | 0 tests/unit/pi-agent-factory.test.ts | 54 - .../pi-runtime-dependency-contract.test.ts | 51 - tests/unit/pi-safe-stream.test.ts | 266 - tests/unit/preload-bundling-contract.test.ts | 15 - tests/unit/preload-forwarders.test.ts | 180 - .../prompt-manager-classification.test.ts | 273 - .../provider-auth-broker-migration.test.ts | 0 .../unit/provider-background-service.test.ts | 0 .../unit/provider-http.test.ts | 0 .../unit/provider-models-fetch.test.ts | 0 .../unit/provider-oauth.test.ts | 0 .../unit/provider-rate-limit-registry.test.ts | 0 tests/unit/provider-rate-limits.test.ts | 19 - .../unit/provider-service-streaming.test.ts | 0 .../unit/provider-service.test.ts | 0 .../unit/provider-streaming.test.ts | 0 .../unit/provider-tool-turns.test.ts | 0 tests/unit/queued-run-recovery.test.ts | 185 - .../requires-filesystem-migration.test.ts | 190 - tests/unit/resolve-ceo-mode.test.ts | 281 - tests/unit/resolve-workspace.test.ts | 332 - .../unit/rollback-service.test.ts | 0 tests/unit/run-attempt-policy.test.ts | 141 - tests/unit/run-context-input-failures.test.ts | 184 - tests/unit/run-log-atomicity.test.ts | 155 - tests/unit/run-tools-env.test.ts | 48 - tests/unit/run-usage-status.test.ts | 92 - tests/unit/runtime-constants.test.ts | 26 - .../runtime-orchestration-service.test.ts | 65 - tests/unit/runtime-thread-projector.test.ts | 172 - tests/unit/scheduler-heartbeat.test.ts | 427 -- .../tests => tests}/unit/sdlc-service.test.ts | 0 .../unit/search-service.test.ts | 0 tests/unit/selective-ipc.test.ts | 215 - tests/unit/session-management.test.ts | 748 --- tests/unit/skill-format.test.ts | 179 - .../skill-github-import-materialize.test.ts | 92 - tests/unit/skill-injection.test.ts | 51 - tests/unit/skill-keys.test.ts | 180 - .../skill-local-import-materialize.test.ts | 98 - tests/unit/skill-materialize.test.ts | 84 - tests/unit/skill-response-limit.test.ts | 76 - tests/unit/skill-types.test.ts | 115 - tests/unit/skill-url-import.test.ts | 108 - tests/unit/skill-url-validation.test.ts | 171 - tests/unit/snapshot-entity-guard.test.ts | 345 - tests/unit/social-draft.test.ts | 203 - .../unit/social-service.test.ts | 0 tests/unit/sqlite-session-store.test.ts | 198 - .../unit/startup-recovery.test.ts | 0 tests/unit/store.test.ts | 238 - tests/unit/task-completion.test.ts | 183 - .../unit/task-execution-service.test.ts | 0 tests/unit/task-input-schema.test.ts | 23 - tests/unit/task-quality-gates-sweep.test.ts | 247 - tests/unit/task-quality-gates.test.ts | 203 - .../unit/task-queue-worker.test.ts | 0 tests/unit/task-update-transaction.test.ts | 178 - tests/unit/task-workspace-binding.test.ts | 108 - tests/unit/wakeup-lifecycle.test.ts | 143 - tests/unit/worker-completion-boundary.test.ts | 662 -- tests/unit/worker-crash-recovery.test.ts | 201 - tests/unit/worker-message-schema.test.ts | 43 - tests/unit/worker-runner-persistence.test.ts | 154 - tests/unit/worker-service-shutdown.test.ts | 219 - tests/unit/worker-utils.spec.ts | 128 - .../unit/workspace-path.test.ts | 0 tsconfig.base.json | 18 - tsconfig.check.json | 5 - tsconfig.json | 40 +- vitest.config.ts | 13 +- 1904 files changed, 1133 insertions(+), 282075 deletions(-) delete mode 100644 .env.example delete mode 100644 .env.release.example delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/remote-boss-platforms.yml delete mode 100644 .github/workflows/remote-release-platforms.yml delete mode 100644 AgentCompany-New/.gitignore delete mode 100644 AgentCompany-New/electron-builder.yml delete mode 100644 AgentCompany-New/electron.vite.config.ts delete mode 100644 AgentCompany-New/eslint.config.mjs delete mode 100644 AgentCompany-New/package.json delete mode 100644 AgentCompany-New/pnpm-lock.yaml delete mode 100644 AgentCompany-New/src/main/database/schema.ts delete mode 100644 AgentCompany-New/src/main/index.ts delete mode 100644 AgentCompany-New/src/preload/index.ts delete mode 100644 AgentCompany-New/src/renderer/env.d.ts delete mode 100644 AgentCompany-New/src/renderer/index.html delete mode 100644 AgentCompany-New/tests/e2e/playwright.config.ts delete mode 100644 AgentCompany-New/tsconfig.json delete mode 100644 AgentCompany-New/vitest.config.ts delete mode 100644 CONTRIBUTING.md delete mode 100644 README.md delete mode 100644 assets/entitlements.mac.plist delete mode 100644 assets/icon-app.svg delete mode 100644 assets/icon.icns delete mode 100644 assets/icon.ico delete mode 100644 assets/icon.png delete mode 100644 assets/icon.svg delete mode 100644 assets/tray-icon.png delete mode 100644 assets/tray-icon@2x.png delete mode 100644 assets/tray-iconTemplate.png delete mode 100644 assets/tray-iconTemplate@2x.png delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/SKILL.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/3d.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/animations.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/assets.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/assets/charts-bar-chart.tsx delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-typewriter.tsx delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/audio-visualization.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/audio.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/calculate-metadata.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/can-decode.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/charts.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/compositions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/display-captions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/extract-frames.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/ffmpeg.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/fonts.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/get-audio-duration.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/get-video-dimensions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/get-video-duration.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/gifs.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/images.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/import-srt-captions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/light-leaks.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/lottie.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/maps.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/measuring-dom-nodes.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/measuring-text.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/parameters.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/sequencing.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/sfx.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/subtitles.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/tailwind.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/text-animations.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/timing.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/transcribe-captions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/transitions.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/transparent-videos.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/trimming.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/videos.md delete mode 100644 builtin-skills/Video-maker/remotion-best-practices/rules/voiceover.md delete mode 100644 builtin-skills/basic-for-all/deep-research/SKILL.md delete mode 100644 builtin-skills/basic-for-all/my-writing-style/README.md delete mode 100644 builtin-skills/basic-for-all/my-writing-style/SKILL.md delete mode 100644 builtin-skills/basic-for-all/my-writing-style/scripts/improve.py delete mode 100644 builtin-skills/basic-for-all/my-writing-style/scripts/observe.py delete mode 100644 builtin-skills/basic-for-all/nopua/SKILL.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/CREATION-LOG.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/SKILL.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/condition-based-waiting-example.ts delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/condition-based-waiting.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/defense-in-depth.md delete mode 100755 builtin-skills/basic-for-all/systematic-debugging/find-polluter.sh delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/root-cause-tracing.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/test-academic.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/test-pressure-1.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/test-pressure-2.md delete mode 100644 builtin-skills/basic-for-all/systematic-debugging/test-pressure-3.md delete mode 100644 builtin-skills/document-process/docx/LICENSE.txt delete mode 100644 builtin-skills/document-process/docx/SKILL.md delete mode 100755 builtin-skills/document-process/docx/scripts/__init__.py delete mode 100755 builtin-skills/document-process/docx/scripts/accept_changes.py delete mode 100755 builtin-skills/document-process/docx/scripts/comment.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/helpers/__init__.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/helpers/merge_runs.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/helpers/simplify_redlines.py delete mode 100755 builtin-skills/document-process/docx/scripts/office/pack.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/mce/mc.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-2010.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-2012.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-2018.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd delete mode 100644 builtin-skills/document-process/docx/scripts/office/soffice.py delete mode 100755 builtin-skills/document-process/docx/scripts/office/unpack.py delete mode 100755 builtin-skills/document-process/docx/scripts/office/validate.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/validators/__init__.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/validators/base.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/validators/docx.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/validators/pptx.py delete mode 100644 builtin-skills/document-process/docx/scripts/office/validators/redlining.py delete mode 100644 builtin-skills/document-process/docx/scripts/templates/comments.xml delete mode 100644 builtin-skills/document-process/docx/scripts/templates/commentsExtended.xml delete mode 100644 builtin-skills/document-process/docx/scripts/templates/commentsExtensible.xml delete mode 100644 builtin-skills/document-process/docx/scripts/templates/commentsIds.xml delete mode 100644 builtin-skills/document-process/docx/scripts/templates/people.xml delete mode 100644 builtin-skills/document-process/minimax-docx/.gitignore delete mode 100644 builtin-skills/document-process/minimax-docx/.setup.log delete mode 100644 builtin-skills/document-process/minimax-docx/LICENSE delete mode 100644 builtin-skills/document-process/minimax-docx/SKILL.md delete mode 100644 builtin-skills/document-process/minimax-docx/assets/styles/academic_styles.xml delete mode 100644 builtin-skills/document-process/minimax-docx/assets/styles/corporate_styles.xml delete mode 100644 builtin-skills/document-process/minimax-docx/assets/styles/default_styles.xml delete mode 100644 builtin-skills/document-process/minimax-docx/assets/xsd/aesthetic-rules.xsd delete mode 100644 builtin-skills/document-process/minimax-docx/assets/xsd/business-rules.xsd delete mode 100644 builtin-skills/document-process/minimax-docx/assets/xsd/common-types.xsd delete mode 100644 builtin-skills/document-process/minimax-docx/assets/xsd/wml-subset.xsd delete mode 100644 builtin-skills/document-process/minimax-docx/references/cjk_typography.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/cjk_university_template_guide.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/comments_guide.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/design_good_bad_examples.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/design_principles.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_element_order.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_encyclopedia_part1.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_encyclopedia_part2.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_encyclopedia_part3.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_namespaces.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/openxml_units.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/scenario_a_create.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/scenario_b_edit_content.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/scenario_c_apply_template.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/track_changes_guide.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/troubleshooting.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/typography_guide.md delete mode 100644 builtin-skills/document-process/minimax-docx/references/xsd_validation_guide.md delete mode 100755 builtin-skills/document-process/minimax-docx/scripts/doc_to_docx.sh delete mode 100755 builtin-skills/document-process/minimax-docx/scripts/docx_preview.sh delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx delete mode 100755 builtin-skills/document-process/minimax-docx/scripts/env_check.sh delete mode 100644 builtin-skills/document-process/minimax-docx/scripts/setup.ps1 delete mode 100755 builtin-skills/document-process/minimax-docx/scripts/setup.sh delete mode 100644 builtin-skills/document-process/minimax-pdf/README.md delete mode 100644 builtin-skills/document-process/minimax-pdf/SKILL.md delete mode 100644 builtin-skills/document-process/minimax-pdf/design/design.md delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/cover.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/fill_inspect.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/fill_write.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/make.sh delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/merge.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/palette.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/reformat_parse.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/render_body.py delete mode 100644 builtin-skills/document-process/minimax-pdf/scripts/render_cover.js delete mode 100644 builtin-skills/document-process/minimax-xlsx/SKILL.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/create.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/edit.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/fix.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/format.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/ooxml-cheatsheet.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/read-analyze.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/references/validate.md delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/formula_check.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/libreoffice_recalc.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/shared_strings_builder.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/style_audit.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_add_column.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_insert_row.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_pack.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_reader.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_shift_rows.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/scripts/xlsx_unpack.py delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/_rels/.rels delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml delete mode 100644 builtin-skills/document-process/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml delete mode 100644 builtin-skills/document-process/my-writing-style/README.md delete mode 100644 builtin-skills/document-process/my-writing-style/SKILL.md delete mode 100644 builtin-skills/document-process/my-writing-style/scripts/improve.py delete mode 100644 builtin-skills/document-process/my-writing-style/scripts/observe.py delete mode 100644 builtin-skills/document-process/pptx-generator/SKILL.md delete mode 100644 builtin-skills/document-process/pptx-generator/references/design-system.md delete mode 100644 builtin-skills/document-process/pptx-generator/references/editing.md delete mode 100644 builtin-skills/document-process/pptx-generator/references/pitfalls.md delete mode 100644 builtin-skills/document-process/pptx-generator/references/pptxgenjs.md delete mode 100644 builtin-skills/document-process/pptx-generator/references/slide-types.md delete mode 100644 builtin-skills/document-process/wechat-article-writer/SKILL.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/README.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/SKILL.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/elements-of-style/01-introductory.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/elements-of-style/02-elementary-rules-of-usage.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/elements-of-style/03-elementary-principles-of-composition.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/elements-of-style/04-a-few-matters-of-form.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/elements-of-style/05-words-and-expressions-commonly-misused.md delete mode 100644 builtin-skills/document-process/writing-clearly-and-concisely/signs-of-ai-writing.md delete mode 100644 builtin-skills/document-process/xlsx/LICENSE.txt delete mode 100644 builtin-skills/document-process/xlsx/SKILL.md delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/helpers/__init__.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/helpers/merge_runs.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/helpers/simplify_redlines.py delete mode 100755 builtin-skills/document-process/xlsx/scripts/office/pack.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/mce/mc.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/soffice.py delete mode 100755 builtin-skills/document-process/xlsx/scripts/office/unpack.py delete mode 100755 builtin-skills/document-process/xlsx/scripts/office/validate.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/validators/__init__.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/validators/base.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/validators/docx.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/validators/pptx.py delete mode 100644 builtin-skills/document-process/xlsx/scripts/office/validators/redlining.py delete mode 100755 builtin-skills/document-process/xlsx/scripts/recalc.py delete mode 100644 builtin-skills/frontend-design/canvas-design/LICENSE.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/SKILL.md delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/ArsenalSC-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BigShoulders-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BigShoulders-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BigShoulders-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Boldonse-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Boldonse-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/CrimsonPro-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/DMMono-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/DMMono-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/EricaOne-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/EricaOne-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/GeistMono-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/GeistMono-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/GeistMono-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Gloock-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Gloock-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSans-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Italiana-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Italiana-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Jura-Light.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Jura-Medium.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Jura-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Lora-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Lora-BoldItalic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Lora-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Lora-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Lora-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/NationalPark-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/NationalPark-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/NationalPark-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Outfit-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Outfit-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Outfit-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/PixelifySans-Medium.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/PixelifySans-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/PoiretOne-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/PoiretOne-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/RedHatMono-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/RedHatMono-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/RedHatMono-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Silkscreen-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Silkscreen-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/SmoochSans-Medium.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/SmoochSans-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Tektur-Medium.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Tektur-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/Tektur-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/WorkSans-Bold.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/WorkSans-Italic.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/WorkSans-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/WorkSans-Regular.ttf delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/YoungSerif-OFL.txt delete mode 100644 builtin-skills/frontend-design/canvas-design/canvas-fonts/YoungSerif-Regular.ttf delete mode 100644 builtin-skills/frontend-design/design-dna/LICENSE delete mode 100644 builtin-skills/frontend-design/design-dna/README.md delete mode 100644 builtin-skills/frontend-design/design-dna/README.zh-CN.md delete mode 100644 builtin-skills/frontend-design/design-dna/SKILL.md delete mode 100644 builtin-skills/frontend-design/design-dna/docs/example-style-transfer.png delete mode 100644 builtin-skills/frontend-design/design-dna/references/generation-guide.md delete mode 100644 builtin-skills/frontend-design/design-dna/references/schema.md delete mode 100644 builtin-skills/frontend-design/design-taste-frontend/SKILL.md delete mode 100644 builtin-skills/frontend-design/frontend-design/SKILL.md delete mode 100644 builtin-skills/frontend-design/high-end-visual-design/SKILL.md delete mode 100644 builtin-skills/frontend-design/senior-frontend/SKILL.md delete mode 100644 builtin-skills/frontend-design/senior-frontend/references/frontend_best_practices.md delete mode 100644 builtin-skills/frontend-design/senior-frontend/references/nextjs_optimization_guide.md delete mode 100644 builtin-skills/frontend-design/senior-frontend/references/react_patterns.md delete mode 100755 builtin-skills/frontend-design/senior-frontend/scripts/bundle_analyzer.py delete mode 100755 builtin-skills/frontend-design/senior-frontend/scripts/component_generator.py delete mode 100755 builtin-skills/frontend-design/senior-frontend/scripts/frontend_scaffolder.py delete mode 100644 builtin-skills/frontend-design/stitch-design-taste/DESIGN.md delete mode 100644 builtin-skills/frontend-design/stitch-design-taste/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/app-icon-generator/.skillfish.json delete mode 100644 builtin-skills/iOS-Dev/app-icon-generator/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/app-store-screenshots/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/app-store-screenshots/mockup.png delete mode 100644 builtin-skills/iOS-Dev/icon-generator/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/icon-generator/references/icon-sizes.md delete mode 100644 builtin-skills/iOS-Dev/icon-generator/references/unreal-engine.md delete mode 100644 builtin-skills/iOS-Dev/icon-generator/references/web-ui-ux.md delete mode 100644 builtin-skills/iOS-Dev/icon-generator/scripts/generate_icons.py delete mode 100644 builtin-skills/iOS-Dev/ios-swift-development/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/ios-swift-development/references/mvvm-architecture-setup.md delete mode 100644 builtin-skills/iOS-Dev/ios-swift-development/references/network-service-with-urlsession.md delete mode 100644 builtin-skills/iOS-Dev/ios-swift-development/references/swiftui-views.md delete mode 100755 builtin-skills/iOS-Dev/ios-swift-development/scripts/validate-api.sh delete mode 100644 builtin-skills/iOS-Dev/ios-swift-development/templates/api-scaffold.yaml delete mode 100644 builtin-skills/iOS-Dev/mobile-development/SKILL.md delete mode 100644 builtin-skills/iOS-Dev/mobile-development/assets/mobile_config.yaml delete mode 100644 builtin-skills/iOS-Dev/mobile-development/references/MOBILE_GUIDE.md delete mode 100644 builtin-skills/iOS-Dev/mobile-development/scripts/pwa_validator.py delete mode 100644 builtin-skills/marketing/clean-general/SKILL.md delete mode 100644 builtin-skills/marketing/my-writing-style/README.md delete mode 100644 builtin-skills/marketing/my-writing-style/SKILL.md delete mode 100644 builtin-skills/marketing/my-writing-style/scripts/improve.py delete mode 100644 builtin-skills/marketing/my-writing-style/scripts/observe.py delete mode 100644 builtin-skills/marketing/wechat-article-writer/SKILL.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/README.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/SKILL.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/01-introductory.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/02-elementary-rules-of-usage.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/03-elementary-principles-of-composition.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/04-a-few-matters-of-form.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/05-words-and-expressions-commonly-misused.md delete mode 100644 builtin-skills/marketing/writing-clearly-and-concisely/signs-of-ai-writing.md delete mode 100644 builtin-skills/my-writing-style/README.md delete mode 100644 builtin-skills/my-writing-style/SKILL.md delete mode 100644 builtin-skills/my-writing-style/scripts/improve.py delete mode 100644 builtin-skills/my-writing-style/scripts/observe.py delete mode 100644 builtin-skills/software-engineer/ai-coding-discipline/SKILL.md delete mode 100644 builtin-skills/software-engineer/api-design-principles/SKILL.md delete mode 100644 builtin-skills/software-engineer/api-design-principles/assets/api-design-checklist.md delete mode 100644 builtin-skills/software-engineer/api-design-principles/assets/rest-api-template.py delete mode 100644 builtin-skills/software-engineer/api-design-principles/references/graphql-schema-design.md delete mode 100644 builtin-skills/software-engineer/api-design-principles/references/rest-best-practices.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/assets/templates/_template.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/metadata.json delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/_sections.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/adapt-anti-corruption-layer.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/adapt-controller-thin.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/adapt-gateway-abstraction.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/adapt-mapper-translation.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/adapt-presenter-formats.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-boundary-cost-awareness.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-defer-decisions.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-humble-object.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-main-component.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-partial-boundaries.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/bound-service-internal-architecture.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/comp-common-closure.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/comp-common-reuse.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/comp-reuse-release-equivalence.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/comp-screaming-architecture.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/comp-stable-dependencies.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-acyclic-dependencies.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-data-crossing-boundaries.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-interface-ownership.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-inward-only.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-no-framework-imports.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/dep-stable-abstractions.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/entity-encapsulate-invariants.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/entity-no-persistence-awareness.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/entity-pure-business-rules.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/entity-rich-not-anemic.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/entity-value-objects.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/frame-di-container-edge.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/frame-domain-purity.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/frame-logging-abstraction.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/frame-orm-in-infrastructure.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/frame-web-in-infrastructure.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/test-boundary-verification.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/test-layer-isolation.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/test-testable-design.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/test-tests-are-architecture.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-explicit-dependencies.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-input-output-ports.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-no-presentation-logic.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-orchestrates-not-implements.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-single-responsibility.md delete mode 100644 builtin-skills/software-engineer/clean-architecture/references/usecase-transaction-boundary.md delete mode 100644 builtin-skills/software-engineer/clean-code/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-code/assets/templates/_template.md delete mode 100644 builtin-skills/software-engineer/clean-code/metadata.json delete mode 100644 builtin-skills/software-engineer/clean-code/references/_sections.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/bound-learning-tests.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/bound-wrap-third-party.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/class-cohesion.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/class-isolate-from-change.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/class-organize-for-change.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/class-separate-concerns.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/class-small.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/cmt-avoid-commented-out-code.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/cmt-avoid-redundant.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/cmt-explain-intent.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/cmt-express-in-code.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/cmt-warning-consequences.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/emerge-expressiveness.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/emerge-simple-design.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/err-avoid-null.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/err-define-by-caller-needs.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/err-provide-context.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/err-use-exceptions.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/err-write-try-catch-first.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/fmt-horizontal-alignment.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/fmt-indentation.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/fmt-team-rules.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/fmt-vertical-formatting.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-abstraction-level.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-command-query-separation.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-dry.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-minimize-arguments.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-no-side-effects.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-one-thing.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/func-small.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-avoid-disinformation.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-avoid-encodings.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-class-noun.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-intention-revealing.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-meaningful-distinctions.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-method-verb.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-pronounceable.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/name-searchable.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/obj-avoid-hybrids.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/obj-data-abstraction.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/obj-data-object-asymmetry.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/obj-dto.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/obj-law-of-demeter.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/test-build-operate-check.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/test-first-law.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/test-first-principles.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/test-keep-clean.md delete mode 100644 builtin-skills/software-engineer/clean-code/references/test-one-assert.md delete mode 100644 builtin-skills/software-engineer/clean-comments/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-functions/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-general/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-names/SKILL.md delete mode 100644 builtin-skills/software-engineer/clean-tests/SKILL.md delete mode 100644 builtin-skills/software-engineer/coding-guidelines/SKILL.md delete mode 100644 builtin-skills/software-engineer/coding-guidelines/clippy-lints/_index.md delete mode 100644 builtin-skills/software-engineer/coding-guidelines/index/rules-index.md delete mode 100644 builtin-skills/software-engineer/ddia-principles/SKILL.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/SKILL.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/deployment-strategies.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/docker-patterns.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/github-actions.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/incident-response.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/kubernetes.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/platform-engineering.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/release-automation.md delete mode 100644 builtin-skills/software-engineer/devops-engineer/references/terraform-iac.md delete mode 100644 builtin-skills/software-engineer/e2e-testing-patterns/SKILL.md delete mode 100644 builtin-skills/software-engineer/mobile-development/SKILL.md delete mode 100644 builtin-skills/software-engineer/mobile-development/assets/mobile_config.yaml delete mode 100644 builtin-skills/software-engineer/mobile-development/references/MOBILE_GUIDE.md delete mode 100644 builtin-skills/software-engineer/mobile-development/scripts/pwa_validator.py delete mode 100644 builtin-skills/software-engineer/openapi-spec-generation/.skillfish.json delete mode 100644 builtin-skills/software-engineer/openapi-spec-generation/SKILL.md delete mode 100644 builtin-skills/software-engineer/optimize-cicd-pipeline/SKILL.md delete mode 100644 builtin-skills/software-engineer/senior-architect/SKILL.md delete mode 100644 builtin-skills/software-engineer/senior-architect/references/architecture_patterns.md delete mode 100644 builtin-skills/software-engineer/senior-architect/references/system_design_workflows.md delete mode 100644 builtin-skills/software-engineer/senior-architect/references/tech_decision_guide.md delete mode 100755 builtin-skills/software-engineer/senior-architect/scripts/architecture_diagram_generator.py delete mode 100755 builtin-skills/software-engineer/senior-architect/scripts/dependency_analyzer.py delete mode 100755 builtin-skills/software-engineer/senior-architect/scripts/project_architect.py delete mode 100644 docs/agents/domain.md delete mode 100644 docs/agents/issue-tracker.md delete mode 100644 docs/agents/triage-labels.md delete mode 100644 docs/architecture/workspace-concurrency.md delete mode 100644 docs/proposals/B1.1-pi-version-upgrade-trace.md delete mode 100644 docs/proposals/B2-tasks-state-machine.md delete mode 100644 docs/proposals/B4-single-writer-actor.md delete mode 100644 docs/proposals/B5.1-llm-as-judge-followup.md delete mode 100644 docs/proposals/C1-appdatabase-passthrough-removal.md delete mode 100644 docs/proposals/C2-service-graph-runtime-bus.md delete mode 100644 docs/proposals/C3-real-tokenizer-followup.md delete mode 100644 docs/proposals/C4-followup.md delete mode 100644 docs/proposals/C4-initial-user-turn-semantic-cue.md delete mode 100644 docs/proposals/C6.2-error-taxonomy-phase2.md delete mode 100644 docs/proposals/C7-prompt-builder-conditional-assembly.md delete mode 100644 docs/proposals/M10-agent-runtime-hooks-aggregation.md delete mode 100644 docs/proposals/M11-credential-manager-unification.md delete mode 100644 docs/proposals/M12-renderer-state-audit.md delete mode 100644 docs/proposals/M2-ipc-contracts.md delete mode 100644 docs/proposals/M5-monorepo-split.md delete mode 100644 docs/proposals/M7-ceo-mode-state-machine.md delete mode 100644 docs/proposals/M8-worker-module-consolidation.md delete mode 100644 docs/proposals/M9-browser-automation-utility-process.md delete mode 100644 docs/proposals/_BLOCKED-BY-CONSTRAINT.md delete mode 100644 docs/rebuild/05-design-system-and-flows.md delete mode 100644 docs/screenshots/AI-Internal-Realtime-Message.jpeg delete mode 100644 docs/screenshots/Approval-by-Human.jpeg delete mode 100644 docs/screenshots/Auto-OrgChart-Team.jpeg delete mode 100644 docs/screenshots/Auto-Task.jpeg delete mode 100644 docs/screenshots/Dashboard.jpeg delete mode 100644 docs/screenshots/Document-Center.jpeg delete mode 100644 docs/screenshots/Onboarding.jpeg delete mode 100644 landing/.gitignore delete mode 100644 landing/README.md delete mode 100644 landing/_headers delete mode 100644 landing/app/globals.css delete mode 100644 landing/app/layout.tsx delete mode 100644 landing/app/page.tsx delete mode 100644 landing/components/ascii-background.tsx delete mode 100644 landing/components/download-section.tsx delete mode 100644 landing/components/faq.tsx delete mode 100644 landing/components/features.tsx delete mode 100644 landing/components/footer.tsx delete mode 100644 landing/components/hero.tsx delete mode 100644 landing/components/how-it-works.tsx delete mode 100644 landing/components/icon-mark.tsx delete mode 100644 landing/components/navbar.tsx delete mode 100644 landing/components/release-links.generated.ts delete mode 100644 landing/components/runtimes-bar.tsx delete mode 100644 landing/components/site-constants.ts delete mode 100644 landing/components/theme-provider.tsx delete mode 100644 landing/components/theme-toggle.tsx delete mode 100644 landing/functions/api/download-stats.ts delete mode 100644 landing/functions/api/download.ts delete mode 100644 landing/functions/types.ts delete mode 100644 landing/lib/downloads.ts delete mode 100644 landing/lib/platform-support.ts delete mode 100644 landing/lib/product-narrative.ts delete mode 100644 landing/migrations/0001_download_counter.sql delete mode 100644 landing/next-env.d.ts delete mode 100644 landing/next.config.ts delete mode 100644 landing/package-lock.json delete mode 100644 landing/package.json delete mode 100644 landing/postcss.config.mjs delete mode 100644 landing/preview-dark.html delete mode 100644 landing/preview.html delete mode 100644 landing/public/_headers delete mode 100644 landing/public/assets/icon.svg delete mode 100644 landing/public/favicon.ico delete mode 100644 landing/public/icon.png delete mode 100644 landing/public/screenshots/AI-Internal-Realtime-Message.jpeg delete mode 100644 landing/public/screenshots/Approval-by-Human.jpeg delete mode 100644 landing/public/screenshots/Auto-OrgChart-Team.jpeg delete mode 100644 landing/public/screenshots/Auto-Task.jpeg delete mode 100644 landing/public/screenshots/Dashboard.jpeg delete mode 100644 landing/public/screenshots/Document-Center.jpeg delete mode 100644 landing/public/screenshots/Onboarding.jpeg delete mode 100644 landing/tsconfig.json delete mode 100644 landing/wrangler.toml rename AgentCompany-New/pnpm-workspace.yaml => pnpm-workspace.yaml (100%) delete mode 100644 promo-video/agentcompany-promo.mp4 delete mode 100644 promo-video/assets/AI-Internal-Realtime-Message.jpeg delete mode 100644 promo-video/assets/Approval-by-Human.jpeg delete mode 100644 promo-video/assets/Auto-OrgChart-Team.jpeg delete mode 100644 promo-video/assets/Auto-Task.jpeg delete mode 100644 promo-video/assets/Dashboard.jpeg delete mode 100644 promo-video/assets/Document-Center.jpeg delete mode 100644 promo-video/assets/Onboarding.jpeg delete mode 100644 promo-video/assets/icon.png delete mode 100644 promo-video/assets/icon.svg delete mode 100644 promo-video/index.html delete mode 100644 promo-video/snapshots/frame-00-at-0.5s.png delete mode 100644 promo-video/snapshots/frame-01-at-5.0s.png delete mode 100644 promo-video/snapshots/frame-02-at-7.0s.png delete mode 100644 promo-video/snapshots/frame-03-at-11.5s.png delete mode 100644 promo-video/snapshots/frame-04-at-17.0s.png delete mode 100644 promo-video/snapshots/frame-05-at-22.5s.png delete mode 100644 promo-video/snapshots/frame-06-at-28.5s.png rename {AgentCompany-New/resources => resources}/entitlements.mac.plist (100%) rename {AgentCompany-New/resources => resources}/icon.png (100%) delete mode 100644 scripts/README.md delete mode 100644 scripts/build-all-platforms.mjs delete mode 100644 scripts/build-desktop.mjs delete mode 100644 scripts/build/emit-builder-config.mjs delete mode 100644 scripts/build/prepare-env.mjs delete mode 100644 scripts/build/run-electron-builder.mjs delete mode 100644 scripts/codemod/README.md delete mode 100644 scripts/codemod/remove-appdatabase-passthrough.mjs delete mode 100644 scripts/electron-builder-mac-sign.mjs rename {AgentCompany-New/scripts => scripts}/ensure-electron.cjs (100%) delete mode 100644 scripts/generate-landing-release-links.mjs delete mode 100644 scripts/icons/generate-icons.py delete mode 100755 scripts/patch-electron-name.sh delete mode 100644 scripts/postinstall.mjs delete mode 100644 scripts/release-boss.mjs delete mode 100644 scripts/release-local-mac.mjs delete mode 100644 scripts/release-local-winlinux.mjs delete mode 100644 scripts/release-local.mjs delete mode 100644 scripts/release-local/r2.mjs delete mode 100644 scripts/release-public-cloudflare.mjs delete mode 100644 scripts/release-website.mjs delete mode 100644 scripts/release/lib/d1-migrations.mjs delete mode 100644 scripts/release/lib/dotenv.mjs delete mode 100644 scripts/release/lib/process.mjs delete mode 100644 scripts/release/lib/snapshot.mjs delete mode 100644 scripts/release/lib/workflow.mjs delete mode 100644 scripts/resume-release-public.mjs delete mode 100644 src/main/agent-auth.ts delete mode 100644 src/main/agent-permissions.ts delete mode 100644 src/main/agent-role-helpers.ts delete mode 100644 src/main/agent-runtime/agent-event-projection.ts delete mode 100644 src/main/agent-runtime/agent-hooks.ts delete mode 100644 src/main/agent-runtime/agent-message-schema.ts delete mode 100644 src/main/agent-runtime/artifact-baseline.ts delete mode 100644 src/main/agent-runtime/artifact-change-detector.ts delete mode 100644 src/main/agent-runtime/artifact-git.ts delete mode 100644 src/main/agent-runtime/artifact-logging.ts delete mode 100644 src/main/agent-runtime/artifact-path-filter.ts delete mode 100644 src/main/agent-runtime/artifact-projection-events.ts delete mode 100644 src/main/agent-runtime/artifact-projector.ts delete mode 100644 src/main/agent-runtime/artifact-types.ts delete mode 100644 src/main/agent-runtime/artifact-work-products.ts delete mode 100644 src/main/agent-runtime/context-compactor.ts delete mode 100644 src/main/agent-runtime/cost-writer.ts delete mode 100644 src/main/agent-runtime/hook-handlers.ts delete mode 100644 src/main/agent-runtime/hook-rpc.ts delete mode 100644 src/main/agent-runtime/inbound-correlation-registry.ts delete mode 100644 src/main/agent-runtime/inbox-projection.ts delete mode 100644 src/main/agent-runtime/index.ts delete mode 100644 src/main/agent-runtime/internal-tools/file-approval-handler.ts delete mode 100644 src/main/agent-runtime/internal-tools/hire-agent-handler.ts delete mode 100644 src/main/agent-runtime/internal-tools/router.ts delete mode 100644 src/main/agent-runtime/runtime-artifact-reconciler.ts delete mode 100644 src/main/agent-runtime/runtime-bridge.ts delete mode 100644 src/main/agent-runtime/runtime-message-injector.ts delete mode 100644 src/main/agent-runtime/runtime-thread-projector.ts delete mode 100644 src/main/agent-runtime/sqlite-session-store.ts delete mode 100644 src/main/api-server.ts delete mode 100644 src/main/api-server/deprecation-counter.ts delete mode 100644 src/main/api-server/index.ts delete mode 100644 src/main/api-server/routes-agent-control.ts delete mode 100644 src/main/api-server/routes-agents-standup.ts delete mode 100644 src/main/api-server/routes-agents.ts delete mode 100644 src/main/api-server/routes-approvals.ts delete mode 100644 src/main/api-server/routes-files.ts delete mode 100644 src/main/api-server/routes-meetings.ts delete mode 100644 src/main/api-server/routes-messages.ts delete mode 100644 src/main/api-server/routes-misc.ts delete mode 100644 src/main/api-server/routes-runs.ts delete mode 100644 src/main/api-server/routes-tasks.ts delete mode 100644 src/main/api-server/routes-work-graph.ts delete mode 100644 src/main/api-server/server-core.ts delete mode 100644 src/main/app-lifecycle-service.ts rename {AgentCompany-New/src => src}/main/app/coalesce.ts (100%) rename {AgentCompany-New/src => src}/main/app/create-window.ts (100%) rename {AgentCompany-New/src => src}/main/app/external-url.ts (100%) rename {AgentCompany-New/src => src}/main/app/ipc-handlers.ts (100%) rename {AgentCompany-New/src => src}/main/app/provider-background-worker.ts (100%) rename {AgentCompany-New/src => src}/main/app/startup-recovery.ts (100%) rename {AgentCompany-New/src => src}/main/app/task-queue-worker.ts (100%) rename {AgentCompany-New/src => src}/main/app/window-security.ts (100%) delete mode 100644 src/main/approval-policy-definitions.ts delete mode 100644 src/main/approval-policy.ts delete mode 100644 src/main/automation-service.ts delete mode 100644 src/main/automation/automation-action-handlers.ts delete mode 100644 src/main/automation/automation-action-runtime.ts delete mode 100644 src/main/automation/automation-action-schemas.ts delete mode 100644 src/main/automation/automation-actions.ts delete mode 100644 src/main/automation/automation-approval-handler.ts delete mode 100644 src/main/automation/automation-conditions.ts delete mode 100644 src/main/automation/automation-handlers.ts delete mode 100644 src/main/automation/automation-run-completion.ts delete mode 100644 src/main/automation/automation-workflow.ts delete mode 100644 src/main/automation/index.ts delete mode 100644 src/main/automation/types.ts delete mode 100644 src/main/bootstrap-application.ts delete mode 100644 src/main/bootstrap/backfill-workspace-artifacts.ts delete mode 100644 src/main/bootstrap/prepare-database.ts delete mode 100644 src/main/bootstrap/prepare-logger.ts delete mode 100644 src/main/bootstrap/prepare-services.ts delete mode 100644 src/main/bootstrap/recover-interrupted-tasks.ts delete mode 100644 src/main/bootstrap/recover-scheduled-posts.ts delete mode 100644 src/main/bootstrap/run-startup-health-checks.ts delete mode 100644 src/main/bootstrap/wire-api-server.ts delete mode 100644 src/main/boss-seed.ts delete mode 100644 src/main/browser-action-service.ts delete mode 100644 src/main/browser-manager.ts delete mode 100644 src/main/browser/browser-action-auth.ts delete mode 100644 src/main/browser/browser-action-cdp.ts delete mode 100644 src/main/browser/browser-action-errors.ts delete mode 100644 src/main/browser/browser-action-executor.ts delete mode 100644 src/main/browser/browser-screenshot-policy.ts delete mode 100644 src/main/browser/browser-types.ts delete mode 100644 src/main/browser/browser-url-helpers.ts delete mode 100644 src/main/browser/platform-selectors.ts delete mode 100644 src/main/budget-enforcement-service.ts delete mode 100644 src/main/checkpoint-engine.ts delete mode 100644 src/main/connector-auth-service.ts delete mode 100644 src/main/connector-definitions-docs.ts delete mode 100644 src/main/connector-definitions-lookup.ts delete mode 100644 src/main/connector-definitions.ts delete mode 100644 src/main/connector-definitions/apikey.ts delete mode 100644 src/main/connector-definitions/cloud.ts delete mode 100644 src/main/connector-definitions/index.ts delete mode 100644 src/main/connector-definitions/local.ts delete mode 100644 src/main/connector-definitions/oauth.ts delete mode 100644 src/main/connector-health-service.ts delete mode 100644 src/main/connector-matching.ts delete mode 100644 src/main/connector-model-policy.ts delete mode 100644 src/main/connectors.ts delete mode 100644 src/main/constants.ts delete mode 100644 src/main/credentials/credential-resolver.ts delete mode 100644 src/main/credentials/credential-store.ts delete mode 100644 src/main/credentials/index.ts delete mode 100644 src/main/credentials/oauth-login-service.ts delete mode 100644 src/main/credentials/types.ts delete mode 100644 src/main/database-base.ts delete mode 100644 src/main/database.ts delete mode 100644 src/main/database/activity.ts delete mode 100644 src/main/database/agent-permissions.ts delete mode 100644 src/main/database/agents-crud.ts delete mode 100644 src/main/database/agents-hierarchy.ts delete mode 100644 src/main/database/agents.ts delete mode 100644 src/main/database/approvals.ts delete mode 100644 src/main/database/automation.ts delete mode 100644 src/main/database/backup.ts delete mode 100644 src/main/database/budget.ts delete mode 100644 src/main/database/company-crud.ts delete mode 100644 src/main/database/company-metrics.ts delete mode 100644 src/main/database/company-settings.ts delete mode 100644 src/main/database/company.ts delete mode 100644 src/main/database/config-revisions.ts rename {AgentCompany-New/src => src}/main/database/connection.ts (100%) delete mode 100644 src/main/database/connectors-crud.ts delete mode 100644 src/main/database/cost-entries.ts delete mode 100644 src/main/database/crash-recovery-helpers.ts delete mode 100644 src/main/database/credentials.ts delete mode 100644 src/main/database/document-lifecycle-events.ts delete mode 100644 src/main/database/documents-work-products.ts delete mode 100644 src/main/database/documents.ts delete mode 100644 src/main/database/entity-crud.ts delete mode 100644 src/main/database/helpers.ts delete mode 100644 src/main/database/inbox-projections.ts delete mode 100644 src/main/database/index.ts delete mode 100644 src/main/database/knowledge.ts delete mode 100644 src/main/database/messages.ts rename {AgentCompany-New/src => src}/main/database/migrations/001-initial.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/002-collaboration.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/003-onboarding.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/004-files-posts.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/005-chat-read-state.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/006-app-state.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/007-skill-hardening.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/008-provider-health.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/009-social-governance.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/010-file-handoff-security.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/011-board-interventions.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/012-compliance-controls.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/013-search-documents.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/014-provider-policy-usage.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/015-identity-access.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/016-org-governance.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/017-operations-controls.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/018-sdlc-controls.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/019-audit-replay.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/020-rollback-snapshots.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/021-provider-auth-broker.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/022-provider-rate-limit-observations.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/023-provider-request-runtime.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/024-task-run-provider-request.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/025-chat-message-delivery.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/026-browser-platform-governance.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/027-social-audit-records.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/028-migration-cutover-journal.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/029-file-handoff-records.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/030-approval-source-refs.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/031-provider-request-workspace.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/032-browser-action-metadata.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/033-audit-event-immutability.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/034-provider-auth-sessions.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/035-task-run-isolation.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/036-additional-connectors.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/037-custom-providers.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/038-provider-auth-profile-cascade.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/039-audit-immutability-org-teardown.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/040-documents-knowledge-automation.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/041-task-subtasks-delete.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/042-approval-notes-meetings-sprints.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/043-composio-integration.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/044-mention-wake-state.ts (100%) rename {AgentCompany-New/src => src}/main/database/migrations/045-connector-grants.ts (100%) delete mode 100644 src/main/database/migrations/baseline-v56.ts delete mode 100644 src/main/database/migrations/legacy-to-v56.ts delete mode 100644 src/main/database/migrations/types.ts delete mode 100644 src/main/database/migrations/v57-task-leases.ts delete mode 100644 src/main/database/migrations/v58-approval-policies.ts delete mode 100644 src/main/database/migrations/v59-social-company-scope.ts delete mode 100644 src/main/database/migrations/v60-filesystem-task-workspaces.ts delete mode 100644 src/main/database/model-capabilities-crud.ts delete mode 100644 src/main/database/run-events.ts delete mode 100644 src/main/database/run-logs.ts delete mode 100644 src/main/database/runs.ts delete mode 100644 src/main/database/session-entries.ts delete mode 100644 src/main/database/settings.ts delete mode 100644 src/main/database/skills.ts delete mode 100644 src/main/database/snapshot.ts delete mode 100644 src/main/database/social.ts delete mode 100644 src/main/database/task-assignment.ts delete mode 100644 src/main/database/task-checkout.ts delete mode 100644 src/main/database/task-queries.ts delete mode 100644 src/main/database/task-review-guard.ts delete mode 100644 src/main/database/task-sessions-crud.ts delete mode 100644 src/main/database/task-status-rules.ts delete mode 100644 src/main/database/tasks-crud.ts delete mode 100644 src/main/database/tasks-status.ts delete mode 100644 src/main/database/tasks-update.ts delete mode 100644 src/main/database/tasks.ts delete mode 100644 src/main/database/threads.ts delete mode 100644 src/main/database/wakeup.ts delete mode 100644 src/main/database/workspaces.ts delete mode 100644 src/main/default-automation-rules.ts delete mode 100644 src/main/desktop-shell-menu.ts delete mode 100644 src/main/desktop-shell-service.ts delete mode 100644 src/main/desktop-shell-window.ts delete mode 100644 src/main/document-lifecycle-handlers.ts delete mode 100644 src/main/document-lifecycle-processor.ts delete mode 100644 src/main/document-lifecycle.ts delete mode 100644 src/main/errors/handlers.ts delete mode 100644 src/main/errors/index.ts delete mode 100644 src/main/errors/taxonomy.ts delete mode 100644 src/main/execution-mode-reconciler.ts delete mode 100644 src/main/execution-policy.ts delete mode 100644 src/main/external-url-policy.ts delete mode 100644 src/main/hire-hook.ts delete mode 100644 src/main/host-environment-service.ts delete mode 100644 src/main/install-main-warning-suppressions.ts delete mode 100644 src/main/ipc-agent-coordination-handlers.ts delete mode 100644 src/main/ipc-automation-operations-handlers.ts delete mode 100644 src/main/ipc-browser-handlers.ts delete mode 100644 src/main/ipc-budget-handlers.ts delete mode 100644 src/main/ipc-company-operations/document-handlers.ts delete mode 100644 src/main/ipc-company-operations/index.ts delete mode 100644 src/main/ipc-company-operations/knowledge-entry-handlers.ts delete mode 100644 src/main/ipc-company-operations/meeting-handlers.ts delete mode 100644 src/main/ipc-company-operations/reference-tables.ts delete mode 100644 src/main/ipc-company-operations/sprint-handlers.ts delete mode 100644 src/main/ipc-company-operations/types.ts delete mode 100644 src/main/ipc-core-admin-handlers.ts delete mode 100644 src/main/ipc-core-agent-graph-handlers.ts delete mode 100644 src/main/ipc-core-common.ts delete mode 100644 src/main/ipc-core-handlers.ts delete mode 100644 src/main/ipc-core-operations-handlers.ts delete mode 100644 src/main/ipc-core-read-handlers.ts delete mode 100644 src/main/ipc-core-task-graph-handlers.ts delete mode 100644 src/main/ipc-core-work-graph-handlers.ts delete mode 100644 src/main/ipc-credentials-handlers.ts delete mode 100644 src/main/ipc-domain-common.ts delete mode 100644 src/main/ipc-domain-handlers.ts delete mode 100644 src/main/ipc-oauth-handlers.ts delete mode 100644 src/main/ipc-onboarding-handlers.ts delete mode 100644 src/main/ipc-recovery-handlers.ts delete mode 100644 src/main/ipc-skill-handlers.ts delete mode 100644 src/main/ipc-support.ts delete mode 100644 src/main/ipc-thread-handlers.ts delete mode 100644 src/main/main-process-setup.ts delete mode 100644 src/main/main-runtime-support.ts delete mode 100644 src/main/main-runtime.ts delete mode 100644 src/main/main-warning-suppression-rules.ts delete mode 100644 src/main/messaging/dispatch.ts delete mode 100644 src/main/messaging/index.ts delete mode 100644 src/main/messaging/normalize.ts delete mode 100644 src/main/model-capability-seed.ts delete mode 100644 src/main/model-dispatch.ts delete mode 100644 src/main/model-resolver.ts delete mode 100644 src/main/notification-service.ts delete mode 100644 src/main/onboarding-service.ts delete mode 100644 src/main/orchestration-service.ts delete mode 100644 src/main/orchestration/heartbeat.ts delete mode 100644 src/main/orchestration/index.ts delete mode 100644 src/main/orchestration/initial-user-turn.ts delete mode 100644 src/main/orchestration/internal-tool-selector.ts delete mode 100644 src/main/orchestration/resolve-workspace.ts delete mode 100644 src/main/orchestration/run-dispatch.ts delete mode 100644 src/main/orchestration/scheduler.ts delete mode 100644 src/main/orchestration/task-runner.ts delete mode 100644 src/main/orchestration/turn-context.ts delete mode 100644 src/main/orchestration/types.ts delete mode 100644 src/main/prompt-builder/api-docs/agent-control.en.md delete mode 100644 src/main/prompt-builder/api-docs/agents.en.md delete mode 100644 src/main/prompt-builder/api-docs/approvals.en.md delete mode 100644 src/main/prompt-builder/api-docs/files.en.md delete mode 100644 src/main/prompt-builder/api-docs/goals-projects.en.md delete mode 100644 src/main/prompt-builder/api-docs/header.en.md delete mode 100644 src/main/prompt-builder/api-docs/knowledge.en.md delete mode 100644 src/main/prompt-builder/api-docs/meetings.en.md delete mode 100644 src/main/prompt-builder/api-docs/messages.en.md delete mode 100644 src/main/prompt-builder/api-docs/sprints.en.md delete mode 100644 src/main/prompt-builder/api-docs/tasks.en.md delete mode 100644 src/main/prompt-builder/api-endpoints.ts delete mode 100644 src/main/prompt-builder/api-section.ts delete mode 100644 src/main/prompt-builder/assets.d.ts delete mode 100644 src/main/prompt-builder/capability-registry.ts delete mode 100644 src/main/prompt-builder/ceo-modes/awaiting-hire.en.md delete mode 100644 src/main/prompt-builder/ceo-modes/awaiting-org.en.md delete mode 100644 src/main/prompt-builder/ceo-modes/operating.en.md delete mode 100644 src/main/prompt-builder/ceo-modes/proactive-footer.en.md delete mode 100644 src/main/prompt-builder/ceo-modes/resolve-mode.ts delete mode 100644 src/main/prompt-builder/ceo-modes/team-building.en.md delete mode 100644 src/main/prompt-builder/context-injection.ts delete mode 100644 src/main/prompt-builder/department-guidelines/customer_support.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/engineering.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/finance.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/hr.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/marketing.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/operations.en.md delete mode 100644 src/main/prompt-builder/department-guidelines/sales.en.md delete mode 100644 src/main/prompt-builder/index.ts delete mode 100644 src/main/prompt-builder/messages/index.ts delete mode 100644 src/main/prompt-builder/messages/operating-en.ts delete mode 100644 src/main/prompt-builder/messages/system-en.ts delete mode 100644 src/main/prompt-builder/operating-instructions-ceo.ts delete mode 100644 src/main/prompt-builder/operating-instructions.ts delete mode 100644 src/main/prompt-builder/skill-injection.ts delete mode 100644 src/main/prompt-builder/sop-section.ts delete mode 100644 src/main/prompt-builder/sops/sop-001-standup.en.md delete mode 100644 src/main/prompt-builder/sops/sop-002-task-lifecycle.en.md delete mode 100644 src/main/prompt-builder/sops/sop-003-delegation.en.md delete mode 100644 src/main/prompt-builder/sops/sop-004-code-review.en.md delete mode 100644 src/main/prompt-builder/sops/sop-005-hiring.en.md delete mode 100644 src/main/prompt-builder/sops/sop-006-escalation.en.md delete mode 100644 src/main/prompt-builder/sops/sop-007-communication.en.md delete mode 100644 src/main/prompt-builder/sops/sop-008-cross-department.en.md delete mode 100644 src/main/prompt-builder/sops/sop-009-documents.en.md delete mode 100644 src/main/prompt-builder/sops/sop-010-budget.en.md delete mode 100644 src/main/prompt-builder/sops/sop-011-quality.en.md delete mode 100644 src/main/prompt-builder/sops/sop-012-cadence.en.md delete mode 100644 src/main/prompt-builder/sops/sop-013-incident.en.md delete mode 100644 src/main/prompt-builder/sops/sop-014-hiring-pipeline.en.md delete mode 100644 src/main/prompt-builder/sops/sop-015-knowledge.en.md delete mode 100644 src/main/prompt-builder/system-prompt.ts delete mode 100644 src/main/prompt-builder/wake-reasons/en.ts delete mode 100644 src/main/prompt-builder/wake-reasons/index.ts delete mode 100644 src/main/run-attempt-policy.ts delete mode 100644 src/main/run-housekeeping.ts delete mode 100644 src/main/run-usage-status.ts delete mode 100644 src/main/service-graph-pi-runtime.ts delete mode 100644 src/main/service-graph.ts delete mode 100644 src/main/service-graph/create-background-services.ts delete mode 100644 src/main/service-graph/create-desktop-shell.ts delete mode 100644 src/main/service-graph/create-leaf-services.ts delete mode 100644 src/main/service-graph/create-lifecycle.ts delete mode 100644 src/main/service-graph/create-runtime-orchestration-service.ts rename {AgentCompany-New/src => src}/main/services/agent-connector-tools.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-deliverable-tools.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-message-presence.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-read-messages.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-run-loop.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-tool-args.ts (100%) rename {AgentCompany-New/src => src}/main/services/agent-tools.ts (100%) rename {AgentCompany-New/src => src}/main/services/approval-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/audit-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/auth-broker-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/automation-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/board-intervention-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-agent-wake-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-mentions.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-message-mutation-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-message-structure.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-service-internal.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/chat-slash-router.ts (100%) rename {AgentCompany-New/src => src}/main/services/compliance-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/composio/composio-client.ts (100%) rename {AgentCompany-New/src => src}/main/services/composio/composio-connection-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/composio/composio-credentials.ts (100%) rename {AgentCompany-New/src => src}/main/services/composio/composio-tool-bridge.ts (100%) rename {AgentCompany-New/src => src}/main/services/composio/connector-grants.ts (100%) rename {AgentCompany-New/src => src}/main/services/deliverable-writer.ts (100%) rename {AgentCompany-New/src => src}/main/services/document-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/file-handoff-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/file-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/files/file-object-store.ts (100%) rename {AgentCompany-New/src => src}/main/services/files/workspace-path.ts (100%) rename {AgentCompany-New/src => src}/main/services/goal-kickoff.ts (100%) rename {AgentCompany-New/src => src}/main/services/identity-access-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/knowledge-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/meeting-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/migration-cutover-journal-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/migration-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/migration-validation-summary.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/anthropic-claude-flow.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/github-copilot-flow.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/google-antigravity-flow.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/oauth-callback-server.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/oauth-flows.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/oauth-page.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/oauth-types.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/openai-codex-flow.ts (100%) rename {AgentCompany-New/src => src}/main/services/oauth/pkce.ts (100%) rename {AgentCompany-New/src => src}/main/services/onboarding-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/operations-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/org-governance-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/organization-seed.ts (100%) rename {AgentCompany-New/src => src}/main/services/organization-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/policy-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-adapter-contract.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-adapters.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-auth-lifecycle.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-auth-profiles.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-background-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-background.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-http.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-internal.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-models-fetch.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-oauth-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-rate-limit-registry.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-request-store.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-response-observer.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-response-runner.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-response-utils.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-sign-in-window.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-streaming.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turn.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/anthropic-format.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/aws-sigv4.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/bedrock-format.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/chat-format.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/credential-resolver.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/gcp-auth.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/gemini-format.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/responses-format.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/router.ts (100%) rename {AgentCompany-New/src => src}/main/services/provider-tool-turns/turns.ts (100%) rename {AgentCompany-New/src => src}/main/services/rollback-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/sdlc-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/search-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/secret-vault.ts (100%) rename {AgentCompany-New/src => src}/main/services/skill-artifacts.ts (100%) rename {AgentCompany-New/src => src}/main/services/skill-manifest.ts (100%) rename {AgentCompany-New/src => src}/main/services/skill-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/snapshot-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/social-audit-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/social-browser-policy-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/social-login-window.ts (100%) rename {AgentCompany-New/src => src}/main/services/social-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/sprint-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/task-execution-service.ts (100%) rename {AgentCompany-New/src => src}/main/services/task-prompts.ts (100%) delete mode 100644 src/main/session-management-service.ts delete mode 100644 src/main/skill-format.ts delete mode 100644 src/main/skill-github.ts delete mode 100644 src/main/skill-keys.ts delete mode 100644 src/main/skill-service.ts delete mode 100644 src/main/skill-types.ts delete mode 100644 src/main/skills/auto-assign-on-hire.ts delete mode 100644 src/main/skills/crud.ts delete mode 100644 src/main/skills/discovery.ts delete mode 100644 src/main/skills/import-github.ts delete mode 100644 src/main/skills/import-local.ts delete mode 100644 src/main/skills/import-url.ts delete mode 100644 src/main/skills/import.ts delete mode 100644 src/main/skills/index.ts delete mode 100644 src/main/skills/materialize.ts delete mode 100644 src/main/skills/read-response-with-limit.ts delete mode 100644 src/main/skills/runtime.ts delete mode 100644 src/main/skills/url-validation.ts delete mode 100644 src/main/task-quality-gates.ts delete mode 100644 src/main/task-rubrics.ts delete mode 100644 src/main/task-workspace-binding.ts delete mode 100644 src/main/thread-integration/index.ts delete mode 100644 src/main/thread-integration/thread-helpers.ts delete mode 100644 src/main/updater-service.ts delete mode 100644 src/main/vault.ts delete mode 100644 src/main/window-state.ts delete mode 100644 src/main/worker-service.ts delete mode 100644 src/main/worker/entry/crash-recovery.ts delete mode 100644 src/main/worker/entry/index.ts delete mode 100644 src/main/worker/entry/message-handler.ts delete mode 100644 src/main/worker/entry/rpc.ts delete mode 100644 src/main/worker/entry/types.ts delete mode 100644 src/main/worker/handlers/context-compaction-handler.ts delete mode 100644 src/main/worker/handlers/handler-context.ts delete mode 100644 src/main/worker/handlers/run-finished-handler.ts delete mode 100644 src/main/worker/handlers/run-finished-helpers.ts delete mode 100644 src/main/worker/handlers/run-log-handler.ts delete mode 100644 src/main/worker/handlers/run-status-handler.ts delete mode 100644 src/main/worker/observability/failure-escalation.ts delete mode 100644 src/main/worker/observability/log-redactor.ts delete mode 100644 src/main/worker/observability/run-event-recorder.ts delete mode 100644 src/main/worker/observability/run-log-filter.ts delete mode 100644 src/main/worker/runtime/credential-concurrency-gate.ts delete mode 100644 src/main/worker/runtime/helpers.ts delete mode 100644 src/main/worker/runtime/index.ts delete mode 100644 src/main/worker/runtime/internal-tools/file-approval-tool.ts delete mode 100644 src/main/worker/runtime/internal-tools/hire-agent-tool.ts delete mode 100644 src/main/worker/runtime/internal-tools/internal-tool-rpc.ts delete mode 100644 src/main/worker/runtime/pi-agent-factory.ts delete mode 100644 src/main/worker/runtime/pi-hook-contract.ts delete mode 100644 src/main/worker/runtime/pi-safe-stream.ts delete mode 100644 src/main/worker/runtime/provider-rate-limits.ts delete mode 100644 src/main/worker/runtime/run-tools.ts delete mode 100644 src/renderer/App.tsx delete mode 100644 src/renderer/components/TitleBar.tsx delete mode 100644 src/renderer/components/Toast.tsx delete mode 100644 src/renderer/components/TwoPaneLayout.tsx delete mode 100644 src/renderer/components/automation/AutomationPanel.tsx delete mode 100644 src/renderer/components/automation/RuleCard.tsx delete mode 100644 src/renderer/components/automation/RuleEditor.tsx delete mode 100644 src/renderer/components/automation/WorkflowEditor.tsx delete mode 100644 src/renderer/components/automation/WorkflowList.tsx delete mode 100644 src/renderer/components/automation/automation-config.ts delete mode 100644 src/renderer/components/communication/ChannelHeader.tsx delete mode 100644 src/renderer/components/communication/ChannelSidebar.tsx delete mode 100644 src/renderer/components/communication/CommunicationHub.tsx delete mode 100644 src/renderer/components/communication/MessageComposer.tsx delete mode 100644 src/renderer/components/communication/MessageItem.tsx delete mode 100644 src/renderer/components/communication/MessageList.tsx delete mode 100644 src/renderer/components/communication/SearchResults.tsx delete mode 100644 src/renderer/components/communication/ThreadPanel.tsx delete mode 100644 src/renderer/components/communication/WaitStateIndicator.tsx delete mode 100644 src/renderer/components/communication/channel-utils.ts delete mode 100644 src/renderer/components/communication/composer-shell/ComposerShell.tsx delete mode 100644 src/renderer/components/communication/composer/ComposerAttachments.tsx delete mode 100644 src/renderer/components/communication/composer/ComposerMentionDropdown.tsx delete mode 100644 src/renderer/components/communication/composer/ComposerReplyBanner.tsx delete mode 100644 src/renderer/components/communication/composer/ComposerSubjectRow.tsx delete mode 100644 src/renderer/components/communication/composer/NoChannelComposer.tsx delete mode 100644 src/renderer/components/communication/composer/TaskDiscussionComposer.tsx delete mode 100644 src/renderer/components/communication/composer/useCaretMeasurement.ts delete mode 100644 src/renderer/components/communication/composer/useMentionState.ts delete mode 100644 src/renderer/components/communication/composer/useMessageSend.ts delete mode 100644 src/renderer/components/communication/message-filters.ts delete mode 100644 src/renderer/components/company-onboarding/CompanyStep.tsx delete mode 100644 src/renderer/components/company-onboarding/ExecutionModeStep.tsx delete mode 100644 src/renderer/components/company-onboarding/LaunchStep.tsx delete mode 100644 src/renderer/components/company-onboarding/MissionStep.tsx delete mode 100644 src/renderer/components/company-onboarding/ModelPoolStep.tsx delete mode 100644 src/renderer/components/company-onboarding/NodeCheckStep.tsx delete mode 100644 src/renderer/components/company-onboarding/OnboardingContext.tsx delete mode 100644 src/renderer/components/company-onboarding/OnboardingHero.tsx delete mode 100644 src/renderer/components/company-onboarding/OnboardingStep.tsx delete mode 100644 src/renderer/components/company-onboarding/OnboardingStepPanel.tsx delete mode 100644 src/renderer/components/company-onboarding/OnboardingWizard.tsx delete mode 100644 src/renderer/components/company-onboarding/ProvidersStep.tsx delete mode 100644 src/renderer/components/company-onboarding/WelcomeStep.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/ProviderCard.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/api-key-card.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/cloud-card.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/local-card.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/oauth-card.tsx delete mode 100644 src/renderer/components/company-onboarding/provider-cards/shared.tsx delete mode 100644 src/renderer/components/company-onboarding/useConnectorCallbacks.ts delete mode 100644 src/renderer/components/company-onboarding/useConnectorModelSelection.ts delete mode 100644 src/renderer/components/company-operations/DocumentCenter.tsx delete mode 100644 src/renderer/components/company-operations/KnowledgeBaseManager.tsx delete mode 100644 src/renderer/components/company-operations/MeetingsManager.tsx delete mode 100644 src/renderer/components/company-operations/SectionHeader.tsx delete mode 100644 src/renderer/components/company-operations/SprintManager.tsx delete mode 100644 src/renderer/components/company-operations/helpers.ts delete mode 100644 src/renderer/components/connectors.tsx delete mode 100644 src/renderer/components/dashboard/ActivityFeed.tsx delete mode 100644 src/renderer/components/dashboard/BudgetAlertBanner.tsx delete mode 100644 src/renderer/components/dashboard/ChartSection.tsx delete mode 100644 src/renderer/components/dashboard/Dashboard.tsx delete mode 100644 src/renderer/components/dashboard/KanbanBoard.tsx delete mode 100644 src/renderer/components/dashboard/MetricsGrid.tsx delete mode 100644 src/renderer/components/dashboard/RecoveryBanner.tsx delete mode 100644 src/renderer/components/dashboard/charts/AgentWorkloadChart.tsx delete mode 100644 src/renderer/components/dashboard/charts/BudgetUtilization.tsx delete mode 100644 src/renderer/components/dashboard/charts/ChartCard.tsx delete mode 100644 src/renderer/components/dashboard/charts/ChartTooltip.tsx delete mode 100644 src/renderer/components/dashboard/charts/CostTrendChart.tsx delete mode 100644 src/renderer/components/dashboard/charts/RunActivityChart.tsx delete mode 100644 src/renderer/components/dashboard/charts/SuccessRateChart.tsx delete mode 100644 src/renderer/components/dashboard/charts/chart-utils.ts delete mode 100644 src/renderer/components/execution/ActivityList.tsx delete mode 100644 src/renderer/components/execution/ApprovalList.tsx delete mode 100644 src/renderer/components/execution/BudgetSummary.tsx delete mode 100644 src/renderer/components/execution/CostList.tsx delete mode 100644 src/renderer/components/execution/IncidentList.tsx delete mode 100644 src/renderer/components/execution/ModelManagementShared.tsx delete mode 100644 src/renderer/components/execution/PendingReviewList.tsx delete mode 100644 src/renderer/components/execution/PolicyFormModal.tsx delete mode 100644 src/renderer/components/execution/PolicyList.tsx delete mode 100644 src/renderer/components/execution/SettingsShell.tsx delete mode 100644 src/renderer/components/execution/SocialDraftPreview.tsx delete mode 100644 src/renderer/components/execution/TaskComments.tsx delete mode 100644 src/renderer/components/execution/TaskCreator.tsx delete mode 100644 src/renderer/components/execution/TaskInspector.tsx delete mode 100644 src/renderer/components/execution/TaskInspectorActivity.tsx delete mode 100644 src/renderer/components/execution/TaskInspectorEditForm.tsx delete mode 100644 src/renderer/components/execution/TaskInspectorGovernance.tsx delete mode 100644 src/renderer/components/execution/TaskInspectorOverview.tsx delete mode 100644 src/renderer/components/execution/TaskInspectorSubtasks.tsx delete mode 100644 src/renderer/components/execution/TaskQueue.tsx delete mode 100644 src/renderer/components/execution/WorkspaceCreator.tsx delete mode 100644 src/renderer/components/execution/WorkspaceInspector.tsx delete mode 100644 src/renderer/components/execution/WorkspaceList.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/ApprovalDocumentsPanel.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/ApprovalInspector.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/ApprovalSummary.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/DecisionForm.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/DeliverableReviewPanel.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/ProposedHireCard.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/SchedulePicker.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/TypeBadge.tsx delete mode 100644 src/renderer/components/execution/approval-inspector/index.ts delete mode 100644 src/renderer/components/execution/approval-inspector/useApprovalPayload.ts delete mode 100644 src/renderer/components/execution/execution-utils.tsx delete mode 100644 src/renderer/components/execution/settings-sections/DataSection.tsx delete mode 100644 src/renderer/components/execution/settings-sections/ExecutionModeSection.tsx delete mode 100644 src/renderer/components/execution/settings-sections/GeneralSection.tsx delete mode 100644 src/renderer/components/execution/settings-sections/SecretsSection.tsx delete mode 100644 src/renderer/components/execution/settings-sections/ShortcutsSection.tsx delete mode 100644 src/renderer/components/hiring/HiringPipeline.tsx delete mode 100644 src/renderer/components/hiring/hiring-helpers.ts delete mode 100644 src/renderer/components/inbox/Inbox.tsx delete mode 100644 src/renderer/components/inbox/PerformanceView.tsx delete mode 100644 src/renderer/components/inbox/StandupView.tsx delete mode 100644 src/renderer/components/inbox/inbox-helpers.tsx delete mode 100644 src/renderer/components/organization/AgentCreator.tsx delete mode 100644 src/renderer/components/organization/AgentEditor.tsx delete mode 100644 src/renderer/components/organization/AgentRoster.tsx delete mode 100644 src/renderer/components/organization/GoalCreator.tsx delete mode 100644 src/renderer/components/organization/GoalEditor.tsx delete mode 100644 src/renderer/components/organization/GoalList.tsx delete mode 100644 src/renderer/components/organization/OrgChart.tsx delete mode 100644 src/renderer/components/organization/ProjectCreator.tsx delete mode 100644 src/renderer/components/organization/ProjectEditor.tsx delete mode 100644 src/renderer/components/organization/ProjectList.tsx delete mode 100644 src/renderer/components/organization/TeamHeaderSummary.tsx delete mode 100644 src/renderer/components/organization/agent-form/AgentForm.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/CreateFormBody.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/EditFormBody.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/edit-sections/ConstraintsSection.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/edit-sections/EditActionBar.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/edit-sections/IdentitySection.tsx delete mode 100644 src/renderer/components/organization/agent-form/agent-form-fields/edit-sections/RuntimeSection.tsx delete mode 100644 src/renderer/components/organization/agent-form/index.ts delete mode 100644 src/renderer/components/organization/agent-form/useAgentForm.ts delete mode 100644 src/renderer/components/organization/goal-form/GoalForm.tsx delete mode 100644 src/renderer/components/organization/goal-form/index.ts delete mode 100644 src/renderer/components/organization/helpers.tsx delete mode 100644 src/renderer/components/organization/orgTreeLayout.ts delete mode 100644 src/renderer/components/organization/project-form/ProjectForm.tsx delete mode 100644 src/renderer/components/organization/project-form/index.ts delete mode 100644 src/renderer/components/runs/RunCenter.tsx delete mode 100644 src/renderer/components/runs/RunDetail.tsx delete mode 100644 src/renderer/components/runs/RunQueue.tsx delete mode 100644 src/renderer/components/runs/run-helpers.tsx delete mode 100644 src/renderer/components/settings/dialogs/OAuthPromptDialog.tsx delete mode 100644 src/renderer/components/settings/dialogs/oauth-prompt-events.ts delete mode 100644 src/renderer/components/settings/forms/ApiKeyForm.tsx delete mode 100644 src/renderer/components/settings/forms/AwsForm.tsx delete mode 100644 src/renderer/components/settings/forms/AzureForm.tsx delete mode 100644 src/renderer/components/settings/forms/LocalForm.tsx delete mode 100644 src/renderer/components/settings/forms/VertexForm.tsx delete mode 100644 src/renderer/components/settings/providers/ProviderRow.tsx delete mode 100644 src/renderer/components/settings/providers/ProvidersPanel.tsx delete mode 100644 src/renderer/components/settings/providers/index.ts delete mode 100644 src/renderer/components/skills/SkillAgentToggles.tsx delete mode 100644 src/renderer/components/skills/SkillDetail.tsx delete mode 100644 src/renderer/components/skills/SkillFileTree.tsx delete mode 100644 src/renderer/components/skills/SkillImportModal.tsx delete mode 100644 src/renderer/components/skills/SkillList.tsx delete mode 100644 src/renderer/components/skills/SkillsSection.tsx delete mode 100644 src/renderer/components/skills/index.ts delete mode 100644 src/renderer/components/social/AccountCard.tsx delete mode 100644 src/renderer/components/social/ActionHistory.tsx delete mode 100644 src/renderer/components/social/AddAccountDialog.tsx delete mode 100644 src/renderer/components/social/SocialPanel.tsx delete mode 100644 src/renderer/components/social/social-config.ts delete mode 100644 src/renderer/components/ui/ActionButton.tsx delete mode 100644 src/renderer/components/ui/AttentionRow.tsx delete mode 100644 src/renderer/components/ui/Badge.tsx delete mode 100644 src/renderer/components/ui/BudgetBar.tsx delete mode 100644 src/renderer/components/ui/Card.tsx delete mode 100644 src/renderer/components/ui/Eyebrow.tsx delete mode 100644 src/renderer/components/ui/Field.tsx delete mode 100644 src/renderer/components/ui/Input.tsx delete mode 100644 src/renderer/components/ui/MarkdownBody.tsx delete mode 100644 src/renderer/components/ui/Panel.tsx delete mode 100644 src/renderer/components/ui/SectionButton.tsx delete mode 100644 src/renderer/components/ui/Select.tsx delete mode 100644 src/renderer/components/ui/Spinner.tsx delete mode 100644 src/renderer/components/ui/TextArea.tsx delete mode 100644 src/renderer/components/ui/feedback.tsx delete mode 100644 src/renderer/components/ui/hooks.tsx delete mode 100644 src/renderer/components/ui/icons.ts delete mode 100644 src/renderer/components/ui/index.ts delete mode 100644 src/renderer/components/ui/layout.tsx delete mode 100644 src/renderer/components/ui/primitives.tsx delete mode 100644 src/renderer/hooks/useAppActions.ts delete mode 100644 src/renderer/hooks/useCommandPaletteHotkeys.ts delete mode 100644 src/renderer/hooks/useCompanyController.ts delete mode 100644 src/renderer/hooks/useCompanyData.ts delete mode 100644 src/renderer/hooks/useDataLoader.ts delete mode 100644 src/renderer/hooks/useDesktopEvents.ts delete mode 100644 src/renderer/hooks/useRunLogs.ts delete mode 100644 src/renderer/hooks/useSectionContext.ts delete mode 100644 src/renderer/hooks/useUIController.ts delete mode 100644 src/renderer/i18n/en.ts delete mode 100644 src/renderer/i18n/index.ts delete mode 100644 src/renderer/i18n/zh.ts delete mode 100644 src/renderer/lib/budget-alerts.ts delete mode 100644 src/renderer/lib/budget-policy-input.ts delete mode 100644 src/renderer/lib/constants.ts delete mode 100644 src/renderer/lib/desktop.ts delete mode 100644 src/renderer/lib/formatters.ts delete mode 100644 src/renderer/lib/keyboard.ts delete mode 100644 src/renderer/lib/platform.ts delete mode 100644 src/renderer/lib/safe-json.ts delete mode 100644 src/renderer/lib/snapshot-events.ts delete mode 100644 src/renderer/main.tsx delete mode 100644 src/renderer/navigation.ts rename {AgentCompany-New/src => src}/renderer/src/app/App.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/app/Onboarding.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/app/OnboardingProviderStep.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/app/useSnapshot.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/fonts/Geist-Variable.woff2 (100%) rename {AgentCompany-New/src => src}/renderer/src/fonts/GeistMono-Variable.woff2 (100%) rename {AgentCompany-New/src => src}/renderer/src/main.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/overlays.css (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/ApprovalsPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/ChatPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/ConnectorsPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/DocumentsPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/FilesPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/HomePage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/NewTaskDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/OfficePage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/RunsPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/SettingsPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/TeamPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/WorkPage.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatComposer.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatConversation.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatMessageRow.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatSidebar.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatThreadPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/ChatTimeline.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/MentionTextarea.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/chat/chat-helpers.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/connectors/ConnectedList.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/connectors/ToolkitCatalog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/files/FileVisuals.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/files/FilesGrid.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/files/FilesTable.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/files/FilesTree.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/files/file-helpers.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/home/DashboardCharts.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/AgentDetailCard.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/floor-plan.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/office-renderer.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/office-types.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/scene-renderer.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/simulation.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/sky.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/office/sprites.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/AdvancedPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/BillingPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/ComposioPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/MigrationPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/ProviderConnectionDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/ProviderLogo.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/ProviderRequestPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/ProvidersPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/SkillsPanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/WorkspacePanel.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/settings/provider-secret.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/social/PlatformIcon.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/social/SocialActivity.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/social/SocialCalendar.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/social/platform-tokens.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/team/HiringPipeline.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/team/OrgChartTree.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/types.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/work/GoalDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/work/ProjectDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/work/ProjectOverview.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/work/TaskDetailDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/pages/work/task-helpers.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/CascadeMenu.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/Dialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/Icon.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/NavIcon.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/OrgSwitcher.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/Popover.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/ProviderOAuthConnect.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/SearchDialog.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/Shell.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/TopbarActions.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/topbar-context.ts (100%) rename {AgentCompany-New/src => src}/renderer/src/shared/ui.tsx (100%) rename {AgentCompany-New/src => src}/renderer/src/styles.css (100%) rename {AgentCompany-New/src => src}/renderer/src/styles/components.css (100%) rename {AgentCompany-New/src => src}/renderer/src/styles/fonts.css (100%) delete mode 100644 src/renderer/state/slices/communication.ts delete mode 100644 src/renderer/state/slices/company.ts delete mode 100644 src/renderer/state/slices/navigation.ts delete mode 100644 src/renderer/state/slices/selection.ts delete mode 100644 src/renderer/state/slices/skill.ts delete mode 100644 src/renderer/state/slices/social.ts delete mode 100644 src/renderer/state/slices/ui.ts delete mode 100644 src/renderer/state/snapshot-sections.ts delete mode 100644 src/renderer/state/store.ts delete mode 100644 src/renderer/styles.css delete mode 100644 src/renderer/views/CommandPaletteView.tsx delete mode 100644 src/renderer/views/SectionContentView.tsx delete mode 100644 src/renderer/views/SidebarView.tsx delete mode 100644 src/renderer/views/sections/ExecutionSections.tsx delete mode 100644 src/renderer/views/sections/OperationsSections.tsx delete mode 100644 src/renderer/views/sections/OrganizationSections.tsx delete mode 100644 src/shared/approval-documents.ts rename {AgentCompany-New/src => src}/shared/audit-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/board-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/chat-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/chat.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/collaboration.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/composio.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/files.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/governance.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/index.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/onboarding.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/organization.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/provider.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/skills.ts (100%) rename {AgentCompany-New/src => src}/shared/commands/social.ts (100%) rename {AgentCompany-New/src => src}/shared/compliance-domain.ts (100%) delete mode 100644 src/shared/connector-catalog.ts delete mode 100644 src/shared/connector-models.ts delete mode 100644 src/shared/connector-policy.ts delete mode 100644 src/shared/constants.ts delete mode 100644 src/shared/contracts.ts delete mode 100644 src/shared/contracts/channels.ts delete mode 100644 src/shared/contracts/desktop-api.ts delete mode 100644 src/shared/contracts/desktop-api/agents.ts delete mode 100644 src/shared/contracts/desktop-api/approvals.ts delete mode 100644 src/shared/contracts/desktop-api/automation.ts delete mode 100644 src/shared/contracts/desktop-api/budget.ts delete mode 100644 src/shared/contracts/desktop-api/common.ts delete mode 100644 src/shared/contracts/desktop-api/communication.ts delete mode 100644 src/shared/contracts/desktop-api/companies.ts delete mode 100644 src/shared/contracts/desktop-api/credentials.ts delete mode 100644 src/shared/contracts/desktop-api/runs.ts delete mode 100644 src/shared/contracts/desktop-api/skills.ts delete mode 100644 src/shared/contracts/desktop-api/tasks.ts delete mode 100644 src/shared/contracts/desktop-api/threads.ts delete mode 100644 src/shared/contracts/desktop-api/window.ts delete mode 100644 src/shared/contracts/helpers.ts delete mode 100644 src/shared/contracts/json-fields.ts delete mode 100644 src/shared/contracts/preload-forwarders.ts delete mode 100644 src/shared/contracts/schemas-agent-event.ts delete mode 100644 src/shared/contracts/schemas-agents.ts delete mode 100644 src/shared/contracts/schemas-approvals.ts delete mode 100644 src/shared/contracts/schemas-automation.ts delete mode 100644 src/shared/contracts/schemas-badges.ts delete mode 100644 src/shared/contracts/schemas-budget.ts delete mode 100644 src/shared/contracts/schemas-company.ts delete mode 100644 src/shared/contracts/schemas-credentials.ts delete mode 100644 src/shared/contracts/schemas-execution.ts delete mode 100644 src/shared/contracts/schemas-messages.ts delete mode 100644 src/shared/contracts/schemas-misc.ts delete mode 100644 src/shared/contracts/schemas-oauth.ts delete mode 100644 src/shared/contracts/schemas-tasks.ts delete mode 100644 src/shared/contracts/schemas-threads.ts delete mode 100644 src/shared/contracts/schemas-work-products.ts rename {AgentCompany-New/src => src}/shared/desktop-api.ts (100%) delete mode 100644 src/shared/document-categories.ts rename {AgentCompany-New/src => src}/shared/domain.ts (100%) rename {AgentCompany-New/src => src}/shared/identity-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/ids.ts (100%) delete mode 100644 src/shared/inbox-items.ts rename {AgentCompany-New/src => src}/shared/ipc.ts (100%) delete mode 100644 src/shared/locale.ts delete mode 100644 src/shared/markdown-text.ts rename {AgentCompany-New/src => src}/shared/mention-handles.ts (100%) rename {AgentCompany-New/src => src}/shared/operations-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/org-governance-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-auth-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-catalog.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-models.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-policy-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-request-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/provider-runtime-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/result.ts (100%) rename {AgentCompany-New/src => src}/shared/rollback-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/sdlc-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/search-domain.ts (100%) delete mode 100644 src/shared/sidebar-badges.ts rename {AgentCompany-New/src => src}/shared/snapshot-domain.ts (100%) rename {AgentCompany-New/src => src}/shared/social-domain.ts (100%) delete mode 100644 src/shared/types.ts delete mode 100644 src/shared/types/enums.ts delete mode 100644 src/shared/types/events.ts delete mode 100644 src/shared/types/records-core.ts delete mode 100644 src/shared/types/records-extended.ts delete mode 100644 src/shared/types/records.ts delete mode 100644 src/shared/types/snapshot.ts rename {AgentCompany-New/tests => tests}/contract/desktop-release-contract.test.ts (100%) rename {AgentCompany-New/tests => tests}/contract/provider-contracts.test.ts (100%) delete mode 100644 tests/e2e/desktop.smoke.spec.ts rename {AgentCompany-New/tests => tests}/e2e/desktop.spec.ts (100%) delete mode 100644 tests/e2e/e2e-global-setup.ts delete mode 100644 tests/e2e/launch.ts rename {AgentCompany-New/tests => tests}/e2e/office.spec.ts (100%) delete mode 100644 tests/e2e/onboarding-fixture.ts rename {AgentCompany-New/tests => tests}/e2e/screenshots.spec.ts (100%) delete mode 100644 tests/eval/README.md delete mode 100644 tests/eval/approval-api-docs-contract.test.ts delete mode 100644 tests/eval/assertion-judge.ts delete mode 100644 tests/eval/eval-runner.ts delete mode 100644 tests/eval/fixture-loader.ts delete mode 100644 tests/eval/fixtures/.gitkeep delete mode 100644 tests/eval/fixtures/README.md delete mode 100644 tests/eval/fixtures/ceo-board-message-reply.jsonl delete mode 100644 tests/eval/fixtures/ceo-bootstrap-empty.jsonl delete mode 100644 tests/eval/fixtures/ic-task-execute.jsonl delete mode 100644 tests/eval/fixtures/manager-task-handoff.jsonl delete mode 100644 tests/eval/fixtures/non-ceo-dm-reply.jsonl delete mode 100644 tests/eval/harness.test.ts delete mode 100644 tests/eval/record-fixture.ts delete mode 100644 tests/eval/replay-client.ts rename {AgentCompany-New/tests => tests}/eval/replay-eval.test.ts (100%) delete mode 100644 tests/eval/scenario-contract.ts delete mode 100644 tests/eval/scenarios/ceo-board-message-reply/system.txt delete mode 100644 tests/eval/scenarios/ceo-board-message-reply/user.txt delete mode 100644 tests/eval/scenarios/ceo-bootstrap-empty/system.txt delete mode 100644 tests/eval/scenarios/ceo-bootstrap-empty/user.txt delete mode 100644 tests/eval/scenarios/ic-task-execute/system.txt delete mode 100644 tests/eval/scenarios/ic-task-execute/user.txt delete mode 100644 tests/eval/scenarios/manager-task-handoff/system.txt delete mode 100644 tests/eval/scenarios/manager-task-handoff/user.txt delete mode 100644 tests/eval/scenarios/non-ceo-dm-reply/system.txt delete mode 100644 tests/eval/scenarios/non-ceo-dm-reply/user.txt delete mode 100644 tests/eval/semantic-rubric-judge.test.ts delete mode 100644 tests/eval/semantic-rubric-judge.ts delete mode 100644 tests/eval/task-api-docs-contract.test.ts delete mode 100644 tests/eval/task-level-prompt-cases.ts delete mode 100644 tests/eval/task-level-prompt-eval.test.ts delete mode 100644 tests/eval/task-level-prompt-eval.ts delete mode 100644 tests/eval/tool-loop-replay.ts delete mode 100644 tests/eval/types.ts delete mode 100644 tests/integration/agent-model-switching.spec.ts rename {AgentCompany-New/tests => tests}/integration/agent-reply.test.ts (100%) delete mode 100644 tests/integration/api-meetings.spec.ts delete mode 100644 tests/integration/api-recursive-org-execution.spec.ts delete mode 100644 tests/integration/api-run-events.spec.ts delete mode 100644 tests/integration/artifact-projection-ack.spec.ts delete mode 100644 tests/integration/autonomous-chain/approval-decisions.spec.ts delete mode 100644 tests/integration/autonomous-chain/automation-messages.spec.ts delete mode 100644 tests/integration/autonomous-chain/ceo-phased-prompts.spec.ts delete mode 100644 tests/integration/autonomous-chain/crash-recovery.spec.ts delete mode 100644 tests/integration/autonomous-chain/e2e-flows.spec.ts delete mode 100644 tests/integration/autonomous-chain/role-detection.spec.ts delete mode 100644 tests/integration/autonomous-chain/run-failure.spec.ts delete mode 100644 tests/integration/autonomous-chain/shared-setup.ts delete mode 100644 tests/integration/autonomous-chain/task-propagation.spec.ts delete mode 100644 tests/integration/autonomous-chain/wake-reason.spec.ts delete mode 100644 tests/integration/autonomous-chain/wakeup-queue.spec.ts rename {AgentCompany-New/tests => tests}/integration/autonomous-run.test.ts (100%) rename {AgentCompany-New/tests => tests}/integration/collaboration-flow.test.ts (100%) delete mode 100644 tests/integration/connector-model-enforcement.spec.ts delete mode 100644 tests/integration/cross-subsystem.spec.ts delete mode 100644 tests/integration/database.spec.ts delete mode 100644 tests/integration/document-run-provenance.spec.ts delete mode 100644 tests/integration/onboarding-model-pool.spec.ts delete mode 100644 tests/integration/onboarding-transaction.spec.ts rename {AgentCompany-New/tests => tests}/integration/org-deletion.test.ts (100%) delete mode 100644 tests/integration/pi-mono-migrations.spec.ts delete mode 100644 tests/integration/pi-runtime-contract.spec.ts delete mode 100644 tests/integration/process-recovery.spec.ts delete mode 100644 tests/integration/skill-aware-assignment.spec.ts rename {AgentCompany-New/tests => tests}/integration/thread-participant-wake.test.ts (100%) delete mode 100644 tests/integration/thread-wait-heartbeat.spec.ts delete mode 100644 tests/integration/work-product-primary-invariant.spec.ts delete mode 100644 tests/integration/work-product-url-policy.spec.ts delete mode 100644 tests/integration/work-products-lifecycle.spec.ts delete mode 100644 tests/support/api-server-callbacks.ts delete mode 100644 tests/support/pi-runtime-contract.ts delete mode 100644 tests/unit/active-run-projection.test.ts delete mode 100644 tests/unit/agent-auth.test.ts delete mode 100644 tests/unit/agent-budget-policy-sync.test.ts rename {AgentCompany-New/tests => tests}/unit/agent-direct-messages.test.ts (100%) delete mode 100644 tests/unit/agent-hierarchy-cycle.test.ts delete mode 100644 tests/unit/agent-hire-routing.test.ts delete mode 100644 tests/unit/agent-hooks.test.ts rename {AgentCompany-New/tests => tests}/unit/agent-messaging.test.ts (100%) delete mode 100644 tests/unit/agent-permissions-ceo-strategy.test.ts delete mode 100644 tests/unit/agent-permissions.test.ts rename {AgentCompany-New/tests => tests}/unit/agent-run-loop.test.ts (100%) delete mode 100644 tests/unit/agent-schema-validation.test.ts delete mode 100644 tests/unit/api-body-encoding.test.ts delete mode 100644 tests/unit/api-server-callbacks.test.ts delete mode 100644 tests/unit/app-error-fatal-route.test.ts delete mode 100644 tests/unit/approval-hire-routing.test.ts delete mode 100644 tests/unit/approval-review-feedback-writeback.test.ts delete mode 100644 tests/unit/artifact-projector-errors.test.ts delete mode 100644 tests/unit/atomic-checkout.test.ts rename {AgentCompany-New/tests => tests}/unit/audit-service.test.ts (100%) delete mode 100644 tests/unit/automation-action-registry.test.ts delete mode 100644 tests/unit/browser-action-queue.test.ts delete mode 100644 tests/unit/browser-action-runtime.test.ts delete mode 100644 tests/unit/browser-manager-timeout.test.ts delete mode 100644 tests/unit/budget-alert.test.ts delete mode 100644 tests/unit/budget-enforcement.test.ts delete mode 100644 tests/unit/budget-incidents.test.ts delete mode 100644 tests/unit/budget-policy-input.test.ts delete mode 100644 tests/unit/capability-registry.test.ts rename {AgentCompany-New/tests => tests}/unit/cascade-safe-triangle.test.ts (100%) delete mode 100644 tests/unit/channel-utils.test.ts delete mode 100644 tests/unit/chart-tooltip.test.ts rename {AgentCompany-New/tests => tests}/unit/chat-governance.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/coalesce.test.ts (100%) delete mode 100644 tests/unit/cofounder-approval-gate.test.ts delete mode 100644 tests/unit/company-mode-switch.test.ts delete mode 100644 tests/unit/company-operation-handlers.test.ts delete mode 100644 tests/unit/company-slice-patches.test.ts rename {AgentCompany-New/tests => tests}/unit/compliance-service.test.ts (100%) delete mode 100644 tests/unit/connector-catalog.test.ts rename {AgentCompany-New/tests => tests}/unit/connector-grants.test.ts (100%) delete mode 100644 tests/unit/connector-matching.test.ts delete mode 100644 tests/unit/connector-model-policy.test.ts delete mode 100644 tests/unit/connector-models.test.ts delete mode 100644 tests/unit/connector-provider-guard.test.ts delete mode 100644 tests/unit/connectors.spec.ts delete mode 100644 tests/unit/context-compaction-worker.test.ts delete mode 100644 tests/unit/context-compactor-tool-results.test.ts delete mode 100644 tests/unit/contracts.test.ts delete mode 100644 tests/unit/crash-recovery.test.ts delete mode 100644 tests/unit/credential-concurrency-gate.test.ts delete mode 100644 tests/unit/credential-resolver.test.ts delete mode 100644 tests/unit/credential-store.test.ts delete mode 100644 tests/unit/credentials-schemas.test.ts delete mode 100644 tests/unit/d1-migrations.test.ts delete mode 100644 tests/unit/dashboard-charts.test.ts delete mode 100644 tests/unit/database-module-groups.test.ts delete mode 100644 tests/unit/database-transaction.test.ts delete mode 100644 tests/unit/database.test.ts delete mode 100644 tests/unit/deprecation-counter.test.ts delete mode 100644 tests/unit/desktop-error-notice.test.ts rename {AgentCompany-New/tests => tests}/unit/domain-services.test.ts (100%) delete mode 100644 tests/unit/edge-case-budget.test.ts delete mode 100644 tests/unit/edge-case-concurrent.test.ts delete mode 100644 tests/unit/edge-case-session.test.ts delete mode 100644 tests/unit/error-boundary.test.ts delete mode 100644 tests/unit/error-taxonomy.test.ts rename {AgentCompany-New/tests => tests}/unit/execution-modes.test.ts (100%) delete mode 100644 tests/unit/external-url-policy.test.ts rename {AgentCompany-New/tests => tests}/unit/external-url.test.ts (100%) delete mode 100644 tests/unit/failure-escalation.test.ts rename {AgentCompany-New/tests => tests}/unit/file-helpers.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/identity-access-service.test.ts (100%) delete mode 100644 tests/unit/inbound-correlation-registry.test.ts delete mode 100644 tests/unit/internal-tool-selector.test.ts delete mode 100644 tests/unit/ipc-agent-coordination-handlers.test.ts delete mode 100644 tests/unit/ipc-agent-graph-handlers.test.ts delete mode 100644 tests/unit/ipc-core-admin-handlers.test.ts delete mode 100644 tests/unit/ipc-core-read-handlers.test.ts delete mode 100644 tests/unit/ipc-credentials-handlers.test.ts delete mode 100644 tests/unit/ipc-open-work-product-url-policy.test.ts delete mode 100644 tests/unit/ipc-support-error-code.test.ts delete mode 100644 tests/unit/keyboard.test.ts delete mode 100644 tests/unit/knowledge-provenance.test.ts delete mode 100644 tests/unit/landing-platform-support.test.ts delete mode 100644 tests/unit/landing-product-narrative.test.ts delete mode 100644 tests/unit/legacy-baseline-migration.test.ts delete mode 100644 tests/unit/log-redactor.test.ts delete mode 100644 tests/unit/main-warning-suppression-rules.test.ts delete mode 100644 tests/unit/markdown-text.test.ts rename {AgentCompany-New/tests => tests}/unit/mention-resolution.test.ts (100%) delete mode 100644 tests/unit/message-dispatch.test.ts delete mode 100644 tests/unit/message-filters.test.ts delete mode 100644 tests/unit/message-search.test.ts rename {AgentCompany-New/tests => tests}/unit/migration-service.test.ts (100%) delete mode 100644 tests/unit/model-capability-seed.test.ts delete mode 100644 tests/unit/model-dispatch.test.ts delete mode 100644 tests/unit/navigation-model.test.ts delete mode 100644 tests/unit/notification-service.test.ts delete mode 100644 tests/unit/oauth-login-service.test.ts delete mode 100644 tests/unit/oauth-prompt-events.test.ts rename {AgentCompany-New/tests => tests}/unit/office-floor-plan.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/office-simulation.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/office-sky.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/office-sprites.test.ts (100%) delete mode 100644 tests/unit/operation-json-fields.test.ts rename {AgentCompany-New/tests => tests}/unit/operations-service.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/org-governance-service.test.ts (100%) delete mode 100644 tests/unit/pi-agent-factory.test.ts delete mode 100644 tests/unit/pi-runtime-dependency-contract.test.ts delete mode 100644 tests/unit/pi-safe-stream.test.ts delete mode 100644 tests/unit/preload-bundling-contract.test.ts delete mode 100644 tests/unit/preload-forwarders.test.ts delete mode 100644 tests/unit/prompt-manager-classification.test.ts rename {AgentCompany-New/tests => tests}/unit/provider-auth-broker-migration.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-background-service.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-http.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-models-fetch.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-oauth.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-rate-limit-registry.test.ts (100%) delete mode 100644 tests/unit/provider-rate-limits.test.ts rename {AgentCompany-New/tests => tests}/unit/provider-service-streaming.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-service.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-streaming.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/provider-tool-turns.test.ts (100%) delete mode 100644 tests/unit/queued-run-recovery.test.ts delete mode 100644 tests/unit/requires-filesystem-migration.test.ts delete mode 100644 tests/unit/resolve-ceo-mode.test.ts delete mode 100644 tests/unit/resolve-workspace.test.ts rename {AgentCompany-New/tests => tests}/unit/rollback-service.test.ts (100%) delete mode 100644 tests/unit/run-attempt-policy.test.ts delete mode 100644 tests/unit/run-context-input-failures.test.ts delete mode 100644 tests/unit/run-log-atomicity.test.ts delete mode 100644 tests/unit/run-tools-env.test.ts delete mode 100644 tests/unit/run-usage-status.test.ts delete mode 100644 tests/unit/runtime-constants.test.ts delete mode 100644 tests/unit/runtime-orchestration-service.test.ts delete mode 100644 tests/unit/runtime-thread-projector.test.ts delete mode 100644 tests/unit/scheduler-heartbeat.test.ts rename {AgentCompany-New/tests => tests}/unit/sdlc-service.test.ts (100%) rename {AgentCompany-New/tests => tests}/unit/search-service.test.ts (100%) delete mode 100644 tests/unit/selective-ipc.test.ts delete mode 100644 tests/unit/session-management.test.ts delete mode 100644 tests/unit/skill-format.test.ts delete mode 100644 tests/unit/skill-github-import-materialize.test.ts delete mode 100644 tests/unit/skill-injection.test.ts delete mode 100644 tests/unit/skill-keys.test.ts delete mode 100644 tests/unit/skill-local-import-materialize.test.ts delete mode 100644 tests/unit/skill-materialize.test.ts delete mode 100644 tests/unit/skill-response-limit.test.ts delete mode 100644 tests/unit/skill-types.test.ts delete mode 100644 tests/unit/skill-url-import.test.ts delete mode 100644 tests/unit/skill-url-validation.test.ts delete mode 100644 tests/unit/snapshot-entity-guard.test.ts delete mode 100644 tests/unit/social-draft.test.ts rename {AgentCompany-New/tests => tests}/unit/social-service.test.ts (100%) delete mode 100644 tests/unit/sqlite-session-store.test.ts rename {AgentCompany-New/tests => tests}/unit/startup-recovery.test.ts (100%) delete mode 100644 tests/unit/store.test.ts delete mode 100644 tests/unit/task-completion.test.ts rename {AgentCompany-New/tests => tests}/unit/task-execution-service.test.ts (100%) delete mode 100644 tests/unit/task-input-schema.test.ts delete mode 100644 tests/unit/task-quality-gates-sweep.test.ts delete mode 100644 tests/unit/task-quality-gates.test.ts rename {AgentCompany-New/tests => tests}/unit/task-queue-worker.test.ts (100%) delete mode 100644 tests/unit/task-update-transaction.test.ts delete mode 100644 tests/unit/task-workspace-binding.test.ts delete mode 100644 tests/unit/wakeup-lifecycle.test.ts delete mode 100644 tests/unit/worker-completion-boundary.test.ts delete mode 100644 tests/unit/worker-crash-recovery.test.ts delete mode 100644 tests/unit/worker-message-schema.test.ts delete mode 100644 tests/unit/worker-runner-persistence.test.ts delete mode 100644 tests/unit/worker-service-shutdown.test.ts delete mode 100644 tests/unit/worker-utils.spec.ts rename {AgentCompany-New/tests => tests}/unit/workspace-path.test.ts (100%) delete mode 100644 tsconfig.base.json delete mode 100644 tsconfig.check.json diff --git a/.env.example b/.env.example deleted file mode 100644 index eddadb61..00000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -AGENTCOMPANY_UPDATE_URL= -AGENTCOMPANY_DISABLE_UPDATES=true -CSC_LINK= -CSC_KEY_PASSWORD= -WIN_CSC_LINK= -WIN_CSC_KEY_PASSWORD= diff --git a/.env.release.example b/.env.release.example deleted file mode 100644 index 023478ae..00000000 --- a/.env.release.example +++ /dev/null @@ -1,35 +0,0 @@ -# Cloudflare R2 release hosting (Wrangler OAuth is used for bucket/bootstrap/upload) -# If left empty, release-local will discover/fill what it can via `npx wrangler`. -R2_ACCOUNT_ID= -R2_BUCKET=agentcompany-updates -R2_PUBLIC_BASE_URL= -AGENTCOMPANY_RELEASE_PREFIX=AC - -# Optional override. When left empty, release-local derives: -# ${R2_PUBLIC_BASE_URL}/${AGENTCOMPANY_RELEASE_PREFIX} -AGENTCOMPANY_UPDATE_URL= - -# Public-release macOS signing / notarization -# Supply either: -# - CSC_LINK= -# - CSC_KEY_PASSWORD= -# or, if you already imported the cert+private-key into Keychain: -# - CSC_NAME=" ()" -CSC_LINK= -CSC_KEY_PASSWORD= -CSC_NAME= - -# Choose one notarization method: -# 1) Apple ID + app-specific password -APPLE_ID= -APPLE_APP_SPECIFIC_PASSWORD= -APPLE_TEAM_ID= - -# 2) App Store Connect API key -APPLE_API_KEY= -APPLE_API_KEY_ID= -APPLE_API_ISSUER= - -# Optional Windows signing -WIN_CSC_LINK= -WIN_CSC_KEY_PASSWORD= diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 60f4d658..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,291 +0,0 @@ -name: Build & Release - -on: - push: - tags: - - 'v*' - pull_request: - branches: [main] - workflow_dispatch: - inputs: - publish: - description: 'Publish to GitHub Releases' - required: false - type: boolean - default: false - -concurrency: - group: build-${{ github.ref }} - cancel-in-progress: true - -env: - PNPM_VERSION: '10.24.0' - NODE_VERSION: '22' - CI_RELEASE_TAG: ci-build-${{ github.run_id }} - -jobs: - # ───────────────────────────────────────────── - # Stage 1: Lint & Typecheck (fast feedback) - # ───────────────────────────────────────────── - check: - name: Lint & Typecheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm audit:deps - - run: pnpm typecheck - - run: pnpm lint - - # ───────────────────────────────────────────── - # Stage 2: Unit Tests - # ───────────────────────────────────────────── - test: - name: Unit Tests - runs-on: ubuntu-latest - needs: check - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm test:unit - - run: pnpm test:integration - - # ───────────────────────────────────────────── - # Stage 3: Build matrix (parallel per platform) - # ───────────────────────────────────────────── - - build-macos: - name: macOS (${{ matrix.arch }}) - runs-on: ${{ matrix.runner }} - needs: test - permissions: - contents: write - strategy: - fail-fast: false - matrix: - include: - - arch: arm64 - runner: macos-14 - builder_args: --mac --arm64 - - arch: x64 - runner: macos-15 - builder_args: --mac --x64 - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Decode signing certificate - if: env.CERT_B64 != '' - env: - CERT_B64: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 }} - run: echo "$CERT_B64" | base64 --decode > /tmp/cert.p12 - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package & sign - run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never - env: - CSC_LINK: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 != '' && '/tmp/cert.p12' || '' }} - CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }} - CSC_IDENTITY_AUTO_DISCOVERY: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 != '' && 'true' || 'false' }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - - name: Upload to CI release (Cloudflare transport) - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release view "$CI_RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$CI_RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "CI Build $GITHUB_RUN_ID" \ - --notes "Temporary build artifact transport for Cloudflare publication." \ - --target "$GITHUB_SHA" - gh release upload "$CI_RELEASE_TAG" \ - build/release/*.dmg \ - build/release/*.zip \ - build/release/*.blockmap \ - build/release/latest-mac.yml \ - --clobber - - name: Upload artifacts for release job - uses: actions/upload-artifact@v4 - with: - name: macos-${{ matrix.arch }} - path: | - build/release/*.dmg - build/release/*.zip - build/release/*.blockmap - build/release/latest-mac.yml - - build-windows: - name: Windows (${{ matrix.arch }}) - runs-on: windows-latest - needs: test - permissions: - contents: write - strategy: - fail-fast: false - matrix: - include: - - arch: x64 - builder_args: --win --x64 - - arch: arm64 - builder_args: --win --arm64 - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package - run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never - env: - CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }} - CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }} - - name: Upload to CI release (Cloudflare transport) - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release view "$CI_RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$CI_RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "CI Build $GITHUB_RUN_ID" \ - --notes "Temporary build artifact transport for Cloudflare publication." \ - --target "$GITHUB_SHA" - gh release upload "$CI_RELEASE_TAG" \ - build/release/*.exe \ - build/release/*.blockmap \ - build/release/latest.yml \ - --clobber - - name: Upload artifacts for release job - uses: actions/upload-artifact@v4 - with: - name: windows-${{ matrix.arch }} - path: | - build/release/*.exe - build/release/*.blockmap - build/release/latest.yml - - build-linux: - name: Linux (${{ matrix.arch }}) - runs-on: ubuntu-latest - needs: test - permissions: - contents: write - strategy: - fail-fast: false - matrix: - include: - - arch: x64 - builder_args: --linux --x64 - - arch: arm64 - builder_args: --linux --arm64 - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package - run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never - - name: Upload release files - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release view "$CI_RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$CI_RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "CI Build $GITHUB_RUN_ID" \ - --notes "Temporary build artifact transport for Cloudflare publication." \ - --target "$GITHUB_SHA" - gh release upload "$CI_RELEASE_TAG" \ - build/release/*.AppImage \ - build/release/*.deb \ - build/release/*.rpm \ - build/release/*.blockmap \ - build/release/latest-linux.yml \ - --clobber - - name: Upload artifacts for release job - uses: actions/upload-artifact@v4 - with: - name: linux-${{ matrix.arch }} - path: | - build/release/*.AppImage - build/release/*.deb - build/release/*.rpm - build/release/*.blockmap - build/release/latest-linux.yml - - # ───────────────────────────────────────────── - # Stage 4: Publish to GitHub Releases - # ───────────────────────────────────────────── - release: - name: Publish Release - runs-on: ubuntu-latest - needs: [build-macos, build-windows, build-linux] - if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.publish == 'true' - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - merge-multiple: false - - - name: Collect release files - run: | - mkdir -p release-files - find artifacts -type f \( \ - -name "*.dmg" -o -name "*.zip" -o -name "*.exe" \ - -o -name "*.AppImage" -o -name "*.deb" -o -name "*.rpm" \ - -o -name "*.snap" -o -name "*.blockmap" \ - -o -name "latest*.yml" \ - \) -exec cp {} release-files/ \; - ls -lh release-files/ - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - draft: true - generate_release_notes: true - files: release-files/* - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/remote-boss-platforms.yml b/.github/workflows/remote-boss-platforms.yml deleted file mode 100644 index e4f7872d..00000000 --- a/.github/workflows/remote-boss-platforms.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Remote Boss Platforms - -on: - workflow_dispatch: - inputs: - version: - description: Boss build version - required: true - type: string - release_tag: - description: Draft GitHub release tag used as the Boss transport bucket - required: true - type: string - release_title: - description: Human-readable title for the draft release - required: false - type: string - -concurrency: - group: remote-boss-${{ github.ref }}-${{ inputs.release_tag }} - cancel-in-progress: false - -env: - PNPM_VERSION: "10.24.0" - NODE_VERSION: "22" - -jobs: - build-windows: - name: Boss Windows Installer - runs-on: windows-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm audit:deps - - name: Build Boss edition - run: node boss-build/build-boss-edition.mjs --platform=win --version=${{ inputs.version }} - shell: bash - env: - CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }} - CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }} - - name: Upload release files - shell: bash - env: - GH_TOKEN: ${{ github.token }} - RELEASE_TAG: ${{ inputs.release_tag }} - RELEASE_TITLE: ${{ inputs.release_title }} - run: | - set -euo pipefail - gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "${RELEASE_TITLE:-Boss Release $GITHUB_RUN_ID}" \ - --notes "Temporary Boss transport generated by remote-boss-platforms.yml." \ - --target "$GITHUB_SHA" - - shopt -s nullglob - files=( - boss-build/build/out/*.exe - boss-build/build/out/*.blockmap - ) - if [ ${#files[@]} -eq 0 ]; then - echo "No Boss Windows release files found." - exit 1 - fi - - gh release upload "$RELEASE_TAG" "${files[@]}" --clobber diff --git a/.github/workflows/remote-release-platforms.yml b/.github/workflows/remote-release-platforms.yml deleted file mode 100644 index ec4be51a..00000000 --- a/.github/workflows/remote-release-platforms.yml +++ /dev/null @@ -1,173 +0,0 @@ -name: Remote Release Platforms - -on: - workflow_dispatch: - inputs: - release_tag: - description: Draft GitHub release tag used as the transport bucket - required: true - type: string - release_title: - description: Human-readable title for the draft release - required: false - type: string - -concurrency: - group: remote-release-${{ github.ref }}-${{ inputs.release_tag }} - cancel-in-progress: false - -env: - PNPM_VERSION: "10.24.0" - NODE_VERSION: "22" - -jobs: - build-windows: - name: Windows Universal Installer - runs-on: windows-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package - run: pnpm exec electron-builder --win --x64 --arm64 --config electron-builder.yml --publish never - env: - CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }} - CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }} - - name: Upload release files - shell: bash - env: - GH_TOKEN: ${{ github.token }} - RELEASE_TAG: ${{ inputs.release_tag }} - RELEASE_TITLE: ${{ inputs.release_title }} - run: | - set -euo pipefail - gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "${RELEASE_TITLE:-Remote Release $GITHUB_RUN_ID}" \ - --notes "Temporary release transport generated by remote-release-platforms.yml." \ - --target "$GITHUB_SHA" - - shopt -s nullglob - files=( - build/release/*.exe - build/release/*.blockmap - build/release/latest.yml - ) - if [ ${#files[@]} -eq 0 ]; then - echo "No Windows release files found." - exit 1 - fi - - gh release upload "$RELEASE_TAG" "${files[@]}" --clobber - - build-linux-x64: - name: Linux x64 - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package - run: pnpm exec electron-builder --linux --x64 --config electron-builder.yml --publish never - - name: Upload release files - env: - GH_TOKEN: ${{ github.token }} - RELEASE_TAG: ${{ inputs.release_tag }} - RELEASE_TITLE: ${{ inputs.release_title }} - run: | - set -euo pipefail - gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "${RELEASE_TITLE:-Remote Release $GITHUB_RUN_ID}" \ - --notes "Temporary release transport generated by remote-release-platforms.yml." \ - --target "$GITHUB_SHA" - - shopt -s nullglob - files=() - for file in build/release/AgentCompany-*.AppImage; do - if [[ "$file" != *arm64* ]]; then - files+=("$file") - fi - done - files+=( - build/release/agent-company_*_amd64.deb - build/release/agent-company-*.x86_64.rpm - build/release/latest-linux.yml - ) - if [ ${#files[@]} -eq 0 ]; then - echo "No Linux x64 release files found." - exit 1 - fi - - gh release upload "$RELEASE_TAG" "${files[@]}" --clobber - - build-linux-arm64: - name: Linux arm64 - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: pnpm - - run: pnpm install --frozen-lockfile - - name: Build electron-vite - run: pnpm exec electron-vite build - - name: Package - run: pnpm exec electron-builder --linux --arm64 --config electron-builder.yml --publish never - - name: Upload release files - env: - GH_TOKEN: ${{ github.token }} - RELEASE_TAG: ${{ inputs.release_tag }} - RELEASE_TITLE: ${{ inputs.release_title }} - run: | - set -euo pipefail - gh release view "$RELEASE_TAG" >/dev/null 2>&1 || \ - gh release create "$RELEASE_TAG" \ - --draft \ - --prerelease \ - --title "${RELEASE_TITLE:-Remote Release $GITHUB_RUN_ID}" \ - --notes "Temporary release transport generated by remote-release-platforms.yml." \ - --target "$GITHUB_SHA" - - shopt -s nullglob - files=( - build/release/*arm64*.AppImage - build/release/*arm64*.deb - build/release/*aarch64*.rpm - ) - if [ ${#files[@]} -eq 0 ]; then - echo "No Linux arm64 release files found." - exit 1 - fi - - gh release upload "$RELEASE_TAG" "${files[@]}" --clobber diff --git a/.gitignore b/.gitignore index 9ad0aefc..1ee471ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,100 +1,9 @@ -# Dependencies node_modules/ - -# Build outputs out/ -mac-arm64/ -dist/ -coverage/ -*.tsbuildinfo -win-unpacked -.blockmap -.claude -/build -.omc -.omx -.planning/* -!.planning/**/ -paperclip-reference -Reference -.pnpm-store -# Test artifacts +release/ test-results/ playwright-report/ - -# Signing certificates (NEVER commit these) -*.p12 -*.cer -*.pem -*.key -*.p8 -*.csr -*.certSigningRequest -*.provisionprofile -*.mobileprovision - -# Environment files -.env -.env.* -.env.local -.env.*.local -!.env.example -!.env.release.example -!.env.release.local - -# Editor and OS files -.DS_Store -Thumbs.db -.idea/ -.vscode/ - -# Local reference material -oldreference/ - -# Markdown docs -*.md -!/README.md -!/docs/*.md -!/docs/proposals/*.md -!/docs/architecture/*.md -!/CLAUDE.md -!/AGENTS.md -!/CONTEXT.md -!/docs/agents/*.md -!/问题.md -!/.planning/**/*.md -!/src/main/prompt-builder/**/*.md -!/scripts/README.md -!/scripts/codemod/README.md -!/CONTRIBUTING.md -!/build-guide.md -!/AgentCompany-New/NewPRD.md -!/AgentCompany-New/agentcompanydesign.zip -# Bundled Agent Skills ship their SKILL.md / README.md as source of truth. -# The Pi skills loader rejects entries whose frontmatter `name` diverges from -# the parent directory; losing SKILL.md to the blanket *.md ignore meant a -# fresh checkout silently dropped every skill from the catalogue. -!/builtin-skills/**/*.md -!/tests/eval/**/*.md -*.zip -*.blockmap -*.exe - -# Local design scratch files -homepagedesign.html - -# Landing page is part of the repo and should be versioned - -# Boss edition build (contains credentials — never commit) -boss-build/ - -# Package manager logs -npm-debug.log* -pnpm-debug.log* -yarn-debug.log* -yarn-error.log* -local-release/ -.omx/ - -# Runtime state (written by app at runtime) -/state/ +coverage/ +*.tsbuildinfo +design-source/ +cred.txt diff --git a/AgentCompany-New/.gitignore b/AgentCompany-New/.gitignore deleted file mode 100644 index 1ee471ea..00000000 --- a/AgentCompany-New/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules/ -out/ -release/ -test-results/ -playwright-report/ -coverage/ -*.tsbuildinfo -design-source/ -cred.txt diff --git a/AgentCompany-New/electron-builder.yml b/AgentCompany-New/electron-builder.yml deleted file mode 100644 index 38b05265..00000000 --- a/AgentCompany-New/electron-builder.yml +++ /dev/null @@ -1,41 +0,0 @@ -appId: ai.agentcompany.desktop -productName: AgentCompany -icon: resources/icon.png -directories: - output: release - buildResources: resources -files: - - out/**/* - - package.json -asar: true -mac: - category: public.app-category.business - hardenedRuntime: true - gatekeeperAssess: false - entitlements: resources/entitlements.mac.plist - entitlementsInherit: resources/entitlements.mac.plist - target: - - target: dmg - arch: - - x64 - - arm64 - - target: zip - arch: - - x64 - - arm64 -win: - target: - - target: nsis - arch: - - x64 - artifactName: ${productName}-${version}-${arch}.${ext} -linux: - category: Office - target: - - target: AppImage - arch: - - x64 - - target: deb - arch: - - x64 -publish: null diff --git a/AgentCompany-New/electron.vite.config.ts b/AgentCompany-New/electron.vite.config.ts deleted file mode 100644 index d90ddbd8..00000000 --- a/AgentCompany-New/electron.vite.config.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { fileURLToPath } from "node:url"; -import { dirname, resolve } from "node:path"; -import { defineConfig, externalizeDepsPlugin } from "electron-vite"; -import react from "@vitejs/plugin-react"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export default defineConfig({ - main: { - plugins: [externalizeDepsPlugin()], - resolve: { - alias: { - "@shared": resolve(__dirname, "src/shared"), - "@main": resolve(__dirname, "src/main"), - }, - }, - build: { - rollupOptions: { - input: resolve(__dirname, "src/main/index.ts"), - }, - }, - }, - preload: { - plugins: [externalizeDepsPlugin()], - resolve: { - alias: { - "@shared": resolve(__dirname, "src/shared"), - "@preload": resolve(__dirname, "src/preload"), - }, - }, - build: { - rollupOptions: { - input: resolve(__dirname, "src/preload/index.ts"), - output: { - format: "cjs", - entryFileNames: "index.js", - }, - }, - }, - }, - renderer: { - root: resolve(__dirname, "src/renderer"), - resolve: { - alias: { - "@shared": resolve(__dirname, "src/shared"), - "@renderer": resolve(__dirname, "src/renderer"), - }, - }, - plugins: [react()], - }, -}); diff --git a/AgentCompany-New/eslint.config.mjs b/AgentCompany-New/eslint.config.mjs deleted file mode 100644 index d353b11d..00000000 --- a/AgentCompany-New/eslint.config.mjs +++ /dev/null @@ -1,33 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { ignores: ["out", "release", "node_modules", "design-source"] }, - js.configs.recommended, - ...tseslint.configs.recommended, - { - languageOptions: { - ecmaVersion: 2022, - globals: { ...globals.browser, ...globals.node }, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], - }, - }, - { - files: ["scripts/**/*.cjs"], - rules: { - "@typescript-eslint/no-require-imports": "off", - }, - }, -); diff --git a/AgentCompany-New/package.json b/AgentCompany-New/package.json deleted file mode 100644 index 6a1c4906..00000000 --- a/AgentCompany-New/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "agentcompany-new", - "version": "1.0.0", - "private": true, - "type": "module", - "description": "Enterprise Electron control plane for AI agent companies.", - "author": { - "name": "AgentCompany", - "email": "dev@agentcompany.ai" - }, - "main": "out/main/index.js", - "scripts": { - "dev": "electron-vite dev", - "build": "electron-vite build", - "typecheck": "tsc --noEmit", - "lint": "eslint .", - "test:unit": "vitest run tests/unit", - "test:contract": "vitest run tests/contract", - "test:integration": "vitest run tests/integration", - "test:replay-eval": "vitest run tests/eval", - "test": "pnpm test:unit && pnpm test:contract && pnpm test:integration && pnpm test:replay-eval", - "test:e2e": "pnpm build && playwright test -c tests/e2e/playwright.config.ts", - "verify": "pnpm verify:ci", - "verify:ci": "pnpm typecheck && pnpm lint && pnpm test:unit && pnpm test:contract && pnpm test:integration && pnpm test:replay-eval && pnpm test:e2e", - "package:dir": "pnpm build && electron-builder --dir --publish never", - "package:win": "pnpm build && electron-builder --win --x64 --publish never", - "package:mac:arm": "pnpm build && electron-builder --mac --arm64 --publish never", - "package:mac:x64": "pnpm build && electron-builder --mac --x64 --publish never", - "package:mac": "pnpm build && electron-builder --mac --x64 --arm64 --publish never", - "package:linux": "pnpm build && electron-builder --linux --x64 --publish never", - "postinstall": "node scripts/ensure-electron.cjs" - }, - "dependencies": { - "lucide-react": "0.468.0", - "react": "19.2.4", - "react-dom": "19.2.4", - "reicon-react": "^1.1.2", - "zod": "4.3.6" - }, - "devDependencies": { - "@eslint/js": "9.38.0", - "@playwright/test": "1.58.2", - "@types/node": "25.2.3", - "@types/react": "19.2.2", - "@types/react-dom": "19.2.2", - "@vitejs/plugin-react": "5.0.0", - "electron": "39.8.5", - "electron-builder": "26.15.0", - "electron-builder-squirrel-windows": "26.15.0", - "electron-vite": "5.0.0", - "eslint": "9.38.0", - "eslint-plugin-react-hooks": "7.0.0", - "eslint-plugin-react-refresh": "0.4.24", - "globals": "16.4.0", - "typescript": "5.9.3", - "typescript-eslint": "8.46.1", - "vite": "7.3.2", - "vitest": "4.1.0" - }, - "engines": { - "node": ">=22.0.0", - "pnpm": ">=10.0.0" - }, - "packageManager": "pnpm@11.9.0" -} diff --git a/AgentCompany-New/pnpm-lock.yaml b/AgentCompany-New/pnpm-lock.yaml deleted file mode 100644 index 27daa3e9..00000000 --- a/AgentCompany-New/pnpm-lock.yaml +++ /dev/null @@ -1,5269 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -overrides: - app-builder-lib: 26.15.0 - dmg-builder: 26.15.0 - electron-builder-squirrel-windows: 26.15.0 - tmp: 0.2.6 - -importers: - - .: - dependencies: - lucide-react: - specifier: 0.468.0 - version: 0.468.0(react@19.2.4) - react: - specifier: 19.2.4 - version: 19.2.4 - react-dom: - specifier: 19.2.4 - version: 19.2.4(react@19.2.4) - reicon-react: - specifier: ^1.1.2 - version: 1.1.2(react@19.2.4) - zod: - specifier: 4.3.6 - version: 4.3.6 - devDependencies: - '@eslint/js': - specifier: 9.38.0 - version: 9.38.0 - '@playwright/test': - specifier: 1.58.2 - version: 1.58.2 - '@types/node': - specifier: 25.2.3 - version: 25.2.3 - '@types/react': - specifier: 19.2.2 - version: 19.2.2 - '@types/react-dom': - specifier: 19.2.2 - version: 19.2.2(@types/react@19.2.2) - '@vitejs/plugin-react': - specifier: 5.0.0 - version: 5.0.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)) - electron: - specifier: 39.8.5 - version: 39.8.5 - electron-builder: - specifier: 26.15.0 - version: 26.15.0(electron-builder-squirrel-windows@26.15.0) - electron-builder-squirrel-windows: - specifier: 26.15.0 - version: 26.15.0(dmg-builder@26.15.0) - electron-vite: - specifier: 5.0.0 - version: 5.0.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)) - eslint: - specifier: 9.38.0 - version: 9.38.0(jiti@2.7.0) - eslint-plugin-react-hooks: - specifier: 7.0.0 - version: 7.0.0(eslint@9.38.0(jiti@2.7.0)) - eslint-plugin-react-refresh: - specifier: 0.4.24 - version: 0.4.24(eslint@9.38.0(jiti@2.7.0)) - globals: - specifier: 16.4.0 - version: 16.4.0 - typescript: - specifier: 5.9.3 - version: 5.9.3 - typescript-eslint: - specifier: 8.46.1 - version: 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - vite: - specifier: 7.3.2 - version: 7.3.2(@types/node@25.2.3)(jiti@2.7.0) - vitest: - specifier: 4.1.0 - version: 4.1.0(@types/node@25.2.3)(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)) - -packages: - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@electron/asar@3.4.1': - resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/fuses@1.8.0': - resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} - hasBin: true - - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - - '@electron/get@3.1.0': - resolution: {integrity: sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==} - engines: {node: '>=14'} - - '@electron/notarize@2.5.0': - resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} - engines: {node: '>= 10.0.0'} - - '@electron/osx-sign@1.3.3': - resolution: {integrity: sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==} - engines: {node: '>=12.0.0'} - hasBin: true - - '@electron/rebuild@4.0.3': - resolution: {integrity: sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA==} - engines: {node: '>=22.12.0'} - hasBin: true - - '@electron/universal@2.0.3': - resolution: {integrity: sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==} - engines: {node: '>=16.4'} - - '@electron/windows-sign@1.2.2': - resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==} - engines: {node: '>=14.14'} - hasBin: true - - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.16.0': - resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.38.0': - resolution: {integrity: sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@malept/cross-spawn-promise@2.0.0': - resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} - engines: {node: '>= 12.13.0'} - - '@malept/flatpak-bundler@0.4.0': - resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} - engines: {node: '>= 10.0.0'} - - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@2.2.0': - resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} - engines: {node: '>= 20.19.0'} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@npmcli/agent@3.0.0': - resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} - engines: {node: ^18.17.0 || >=20.5.0} - - '@npmcli/fs@4.0.0': - resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} - engines: {node: ^18.17.0 || >=20.5.0} - - '@peculiar/asn1-schema@2.7.0': - resolution: {integrity: sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==} - - '@peculiar/json-schema@1.1.12': - resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} - engines: {node: '>=8.0.0'} - - '@peculiar/utils@2.0.3': - resolution: {integrity: sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==} - - '@peculiar/webcrypto@1.7.1': - resolution: {integrity: sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ==} - engines: {node: '>=14.18.0'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@playwright/test@1.58.2': - resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==} - engines: {node: '>=18'} - hasBin: true - - '@rolldown/pluginutils@1.0.0-beta.30': - resolution: {integrity: sha512-whXaSoNUFiyDAjkUF8OBpOm77Szdbk5lGNqFe6CbVbJFrhCCPinCbRA3NjawwlNHla1No7xvXXh+CpSxnPfUEw==} - - '@rollup/rollup-android-arm-eabi@4.60.4': - resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.60.4': - resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.60.4': - resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.60.4': - resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.60.4': - resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.60.4': - resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.60.4': - resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.60.4': - resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.60.4': - resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.60.4': - resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.60.4': - resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.60.4': - resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.60.4': - resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.4': - resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} - cpu: [x64] - os: [win32] - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@szmarczak/http-timer@4.0.6': - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/debug@4.1.13': - resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - - '@types/http-cache-semantics@4.2.0': - resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/keyv@3.1.4': - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@22.19.19': - resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - - '@types/node@25.2.3': - resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} - - '@types/react-dom@19.2.2': - resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.2': - resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} - - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@typescript-eslint/eslint-plugin@8.46.1': - resolution: {integrity: sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.46.1 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.46.1': - resolution: {integrity: sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.46.1': - resolution: {integrity: sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.46.1': - resolution: {integrity: sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.46.1': - resolution: {integrity: sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.46.1': - resolution: {integrity: sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.46.1': - resolution: {integrity: sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.46.1': - resolution: {integrity: sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.46.1': - resolution: {integrity: sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.46.1': - resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@vitejs/plugin-react@5.0.0': - resolution: {integrity: sha512-Jx9JfsTa05bYkS9xo0hkofp2dCmp1blrKjw9JONs5BTHOvJCgLbaPSuZLGSVJW6u2qe0tc4eevY0+gSNNi0YCw==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/expect@4.1.0': - resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} - - '@vitest/mocker@4.1.0': - resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.1.0': - resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} - - '@vitest/runner@4.1.0': - resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} - - '@vitest/snapshot@4.1.0': - resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} - - '@vitest/spy@4.1.0': - resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} - - '@vitest/utils@4.1.0': - resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} - - '@xmldom/xmldom@0.8.13': - resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} - engines: {node: '>=10.0.0'} - - '@xmldom/xmldom@0.9.10': - resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} - engines: {node: '>=14.6'} - - abbrev@3.0.1: - resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} - engines: {node: ^18.17.0 || >=20.5.0} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - app-builder-lib@26.15.0: - resolution: {integrity: sha512-j2+P6Lh+l/VuWfXZWSs7u+OAPqYJQGnZZO30M833XQQaRuyohm4RZk7Gw4nQXfeyQH9GqXaTwR16Y0LaVTlS+g==} - engines: {node: '>=14.0.0'} - peerDependencies: - dmg-builder: 26.15.0 - electron-builder-squirrel-windows: 26.15.0 - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - asn1js@3.0.10: - resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==} - engines: {node: '>=12.0.0'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - async-exit-hook@2.0.1: - resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} - engines: {node: '>=0.12.0'} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - - aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - baseline-browser-mapping@2.10.31: - resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} - engines: {node: '>=6.0.0'} - hasBin: true - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - - boolean@3.2.0: - resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - builder-util-runtime@9.7.0: - resolution: {integrity: sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw==} - engines: {node: '>=12.0.0'} - - builder-util@26.15.0: - resolution: {integrity: sha512-dUx+HxVbiNsNQ4mGe1PyoC/tBmsHwBNDLdBuqWCj+rhHFE9lHgrXiGYKAM1uNlznhAaUSyMlms84VeSSr3gOBA==} - engines: {node: '>=14.0.0'} - - bytestreamjs@2.0.1: - resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} - engines: {node: '>=6.0.0'} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - cacache@19.0.1: - resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - - cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001793: - resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chownr@3.0.0: - resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} - engines: {node: '>=18'} - - chromium-pickle-js@0.2.0: - resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} - - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} - engines: {node: '>=8'} - - ci-info@4.4.0: - resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} - engines: {node: '>=8'} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - compare-version@0.1.2: - resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} - engines: {node: '>=0.10.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - - cross-dirname@0.1.0: - resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - - dir-compare@4.2.0: - resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} - - dmg-builder@26.15.0: - resolution: {integrity: sha512-oS8MWttbpIUF/2v8LOEY+f4ayL84ipMOarZvdRMl/pxlhLxAYjYMklTXHEXIl37Ig+qJv/bVF7HgyIoOoZyMWA==} - - dotenv-expand@11.0.7: - resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} - engines: {node: '>=12'} - - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - duplexer2@0.1.4: - resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true - - electron-builder-squirrel-windows@26.15.0: - resolution: {integrity: sha512-WyiGTdAHOk8oncyg/Ik0+NsrPI6y7ftG/eB7uxr9iGjmF9RNuIdeW/BRpI7iLEe718WkBQCbspUAq/4Vi31wXg==} - - electron-builder@26.15.0: - resolution: {integrity: sha512-zd4cfvjHmtyGqMaDudg5rAjNUkwIJDz8ICaCsz77hFKcjMQHcZNNNCs/C4phwN9+gEVwmhvpKMzNFum6fs/n6A==} - engines: {node: '>=14.0.0'} - hasBin: true - - electron-publish@26.15.0: - resolution: {integrity: sha512-pt6K3ol/a+o3HbqmYkL2NYlVH5pd34tL4FPRcgX8E88xQAqQyIsseXe4vWy7Pq2BaYy+iFGJrtInZe11FFAQwQ==} - - electron-to-chromium@1.5.360: - resolution: {integrity: sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==} - - electron-vite@5.0.0: - resolution: {integrity: sha512-OHp/vjdlubNlhNkPkL/+3JD34ii5ov7M0GpuXEVdQeqdQ3ulvVR7Dg/rNBLfS5XPIFwgoBLDf9sjjrL+CuDyRQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@swc/core': ^1.0.0 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - '@swc/core': - optional: true - - electron-winstaller@5.4.0: - resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} - engines: {node: '>=8.0.0'} - - electron@39.8.5: - resolution: {integrity: sha512-q6+LiQIcTadSyvtPgLDQkCtVA9jQJXQVMrQcctfOJILh6OFMN+UJJLRkuUTy8CZDYeCIBn1ZycqsL1dAXugxZA==} - engines: {node: '>= 12.20.55'} - hasBin: true - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-plugin-react-hooks@7.0.0: - resolution: {integrity: sha512-fNXaOwvKwq2+pXiRpXc825Vd63+KM4DLL40Rtlycb8m7fYpp6efrTp1sa6ZbP/Ap58K2bEKFXRmhURE+CJAQWw==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - - eslint-plugin-react-refresh@0.4.24: - resolution: {integrity: sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==} - peerDependencies: - eslint: '>=8.40' - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint@9.38.0: - resolution: {integrity: sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - exponential-backoff@3.1.3: - resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - filelist@1.0.6: - resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - - fs-extra@11.3.5: - resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} - engines: {node: '>=14.14'} - - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - - fs-minipass@3.0.3: - resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - global-agent@3.0.0: - resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} - engines: {node: '>=10.0'} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@16.4.0: - resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} - engines: {node: '>=18'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} - engines: {node: '>= 12'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} - - isbinaryfile@5.0.7: - resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==} - engines: {node: '>= 18.0.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isexe@3.1.5: - resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} - engines: {node: '>=18'} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jake@10.9.4: - resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} - engines: {node: '>=10'} - hasBin: true - - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - jsonfile@6.2.1: - resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - lazy-val@1.0.5: - resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash@4.18.1: - resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - lucide-react@0.468.0: - resolution: {integrity: sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - make-fetch-happen@14.0.3: - resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - matcher@3.0.0: - resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} - engines: {node: '>=10'} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@5.1.9: - resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} - engines: {node: '>=10'} - - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass-collect@2.0.1: - resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} - engines: {node: '>=16 || 14 >=14.17'} - - minipass-fetch@4.0.1: - resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - minipass-flush@1.0.7: - resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - minizlib@3.1.0: - resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} - engines: {node: '>= 18'} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - node-abi@4.31.0: - resolution: {integrity: sha512-Erq5w/t3syw3s4sDsUaX4QttIdBPsGKTT1DTRsCkTonGggczhlDKm/wDX3o+HPJpQ41EjXCbcmXf0tgr5YZJXw==} - engines: {node: '>=22.12.0'} - - node-api-version@0.2.1: - resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} - - node-gyp@11.5.0: - resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - - node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - - node-releases@2.0.44: - resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} - - nopt@8.1.0: - resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - - normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-map@7.0.4: - resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} - engines: {node: '>=18'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pe-library@0.4.1: - resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} - engines: {node: '>=12', npm: '>=6'} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pkijs@3.4.0: - resolution: {integrity: sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==} - engines: {node: '>=16.0.0'} - - playwright-core@1.58.2: - resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} - engines: {node: '>=18'} - hasBin: true - - playwright@1.58.2: - resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} - engines: {node: '>=18'} - hasBin: true - - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.0'} - - plist@3.1.1: - resolution: {integrity: sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==} - engines: {node: '>=10.4.0'} - - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} - - postject@1.0.0-alpha.6: - resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} - engines: {node: '>=14.0.0'} - hasBin: true - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - proc-log@5.0.0: - resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - - proper-lockfile@4.1.2: - resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - - pump@3.0.4: - resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - pvtsutils@1.3.6: - resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} - - pvutils@1.1.5: - resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} - engines: {node: '>=16.0.0'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - - read-binary-file-arch@1.0.6: - resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} - hasBin: true - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - reicon-react@1.1.2: - resolution: {integrity: sha512-dbp1CPEPKFjWfG41lGRMWi74YKfKJlb2JcB/TRBAUQF6jalZYW1dRZisRPCpze5TfQwRBD30p40qnoY+oYi7MQ==} - peerDependencies: - react: '>=16.8.0' - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - resedit@1.7.2: - resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} - engines: {node: '>=12', npm: '>=6'} - - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - roarr@2.15.4: - resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} - engines: {node: '>=8.0'} - - rollup@4.60.4: - resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sanitize-filename@1.6.4: - resolution: {integrity: sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==} - - sax@1.6.0: - resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} - engines: {node: '>=11.0.0'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} - engines: {node: '>=10'} - hasBin: true - - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - - socks@2.8.9: - resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - ssri@12.0.0: - resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - stat-mode@1.0.0: - resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} - engines: {node: '>= 6'} - - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - sumchecker@3.0.1: - resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} - engines: {node: '>= 8.0'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - tar@7.5.15: - resolution: {integrity: sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==} - engines: {node: '>=18'} - - temp-file@3.4.0: - resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} - - temp@0.9.4: - resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} - engines: {node: '>=6.0.0'} - - tiny-async-pool@1.3.0: - resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} - engines: {node: '>=18'} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} - engines: {node: '>=14.0.0'} - - tmp-promise@3.0.3: - resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} - - tmp@0.2.6: - resolution: {integrity: sha512-5sJPdPjfI5Kx+qbrDesxkglRBxW//g7hCsqspEjwkewGvBMGIKMOTKzLt1hFVJzyadba3lDUN20O9qhvbQUSTA==} - engines: {node: '>=14.14'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - typescript-eslint@8.46.1: - resolution: {integrity: sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unique-filename@4.0.0: - resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} - engines: {node: ^18.17.0 || >=20.5.0} - - unique-slug@5.0.0: - resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} - engines: {node: ^18.17.0 || >=20.5.0} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unzipper@0.12.3: - resolution: {integrity: sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vite@7.3.2: - resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@4.1.0: - resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.0 - '@vitest/browser-preview': 4.1.0 - '@vitest/browser-webdriverio': 4.1.0 - '@vitest/ui': 4.1.0 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - webcrypto-core@1.9.2: - resolution: {integrity: sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@5.0.0: - resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yallist@5.0.0: - resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} - engines: {node: '>=18'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - -snapshots: - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.3': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@electron/asar@3.4.1': - dependencies: - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.5 - - '@electron/fuses@1.8.0': - dependencies: - chalk: 4.1.2 - fs-extra: 9.1.0 - minimist: 1.2.8 - - '@electron/get@2.0.3': - dependencies: - debug: 4.4.3 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/get@3.1.0': - dependencies: - debug: 4.4.3 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/notarize@2.5.0': - dependencies: - debug: 4.4.3 - fs-extra: 9.1.0 - promise-retry: 2.0.1 - transitivePeerDependencies: - - supports-color - - '@electron/osx-sign@1.3.3': - dependencies: - compare-version: 0.1.2 - debug: 4.4.3 - fs-extra: 10.1.0 - isbinaryfile: 4.0.10 - minimist: 1.2.8 - plist: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@electron/rebuild@4.0.3': - dependencies: - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 - detect-libc: 2.1.2 - got: 11.8.6 - graceful-fs: 4.2.11 - node-abi: 4.31.0 - node-api-version: 0.2.1 - node-gyp: 11.5.0 - ora: 5.4.1 - read-binary-file-arch: 1.0.6 - semver: 7.8.0 - tar: 7.5.15 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - '@electron/universal@2.0.3': - dependencies: - '@electron/asar': 3.4.1 - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.3 - dir-compare: 4.2.0 - fs-extra: 11.3.5 - minimatch: 9.0.9 - plist: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@electron/windows-sign@1.2.2': - dependencies: - cross-dirname: 0.1.0 - debug: 4.4.3 - fs-extra: 11.3.5 - minimist: 1.2.8 - postject: 1.0.0-alpha.6 - transitivePeerDependencies: - - supports-color - optional: true - - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/aix-ppc64@0.27.7': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.27.7': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-arm@0.27.7': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/android-x64@0.27.7': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.27.7': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.27.7': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.27.7': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.27.7': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.27.7': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-arm@0.27.7': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.27.7': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.27.7': - optional: true - - '@esbuild/linux-mips64el@0.25.12': - optional: true - - '@esbuild/linux-mips64el@0.27.7': - optional: true - - '@esbuild/linux-ppc64@0.25.12': - optional: true - - '@esbuild/linux-ppc64@0.27.7': - optional: true - - '@esbuild/linux-riscv64@0.25.12': - optional: true - - '@esbuild/linux-riscv64@0.27.7': - optional: true - - '@esbuild/linux-s390x@0.25.12': - optional: true - - '@esbuild/linux-s390x@0.27.7': - optional: true - - '@esbuild/linux-x64@0.25.12': - optional: true - - '@esbuild/linux-x64@0.27.7': - optional: true - - '@esbuild/netbsd-arm64@0.25.12': - optional: true - - '@esbuild/netbsd-arm64@0.27.7': - optional: true - - '@esbuild/netbsd-x64@0.25.12': - optional: true - - '@esbuild/netbsd-x64@0.27.7': - optional: true - - '@esbuild/openbsd-arm64@0.25.12': - optional: true - - '@esbuild/openbsd-arm64@0.27.7': - optional: true - - '@esbuild/openbsd-x64@0.25.12': - optional: true - - '@esbuild/openbsd-x64@0.27.7': - optional: true - - '@esbuild/openharmony-arm64@0.25.12': - optional: true - - '@esbuild/openharmony-arm64@0.27.7': - optional: true - - '@esbuild/sunos-x64@0.25.12': - optional: true - - '@esbuild/sunos-x64@0.27.7': - optional: true - - '@esbuild/win32-arm64@0.25.12': - optional: true - - '@esbuild/win32-arm64@0.27.7': - optional: true - - '@esbuild/win32-ia32@0.25.12': - optional: true - - '@esbuild/win32-ia32@0.27.7': - optional: true - - '@esbuild/win32-x64@0.25.12': - optional: true - - '@esbuild/win32-x64@0.27.7': - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0(jiti@2.7.0))': - dependencies: - eslint: 9.38.0(jiti@2.7.0) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.16.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.38.0': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@isaacs/fs-minipass@4.0.1': - dependencies: - minipass: 7.1.3 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@malept/cross-spawn-promise@2.0.0': - dependencies: - cross-spawn: 7.0.6 - - '@malept/flatpak-bundler@0.4.0': - dependencies: - debug: 4.4.3 - fs-extra: 9.1.0 - lodash: 4.18.1 - tmp-promise: 3.0.3 - transitivePeerDependencies: - - supports-color - - '@noble/hashes@1.4.0': {} - - '@noble/hashes@2.2.0': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@npmcli/agent@3.0.0': - dependencies: - agent-base: 7.1.4 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 10.4.3 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - '@npmcli/fs@4.0.0': - dependencies: - semver: 7.8.0 - - '@peculiar/asn1-schema@2.7.0': - dependencies: - '@peculiar/utils': 2.0.3 - asn1js: 3.0.10 - tslib: 2.8.1 - - '@peculiar/json-schema@1.1.12': - dependencies: - tslib: 2.8.1 - - '@peculiar/utils@2.0.3': - dependencies: - tslib: 2.8.1 - - '@peculiar/webcrypto@1.7.1': - dependencies: - '@peculiar/asn1-schema': 2.7.0 - '@peculiar/json-schema': 1.1.12 - '@peculiar/utils': 2.0.3 - tslib: 2.8.1 - webcrypto-core: 1.9.2 - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@playwright/test@1.58.2': - dependencies: - playwright: 1.58.2 - - '@rolldown/pluginutils@1.0.0-beta.30': {} - - '@rollup/rollup-android-arm-eabi@4.60.4': - optional: true - - '@rollup/rollup-android-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-x64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-arm64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-x64@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-musl@4.60.4': - optional: true - - '@rollup/rollup-openbsd-x64@4.60.4': - optional: true - - '@rollup/rollup-openharmony-arm64@4.60.4': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.60.4': - optional: true - - '@sindresorhus/is@4.6.0': {} - - '@standard-schema/spec@1.1.0': {} - - '@szmarczak/http-timer@4.0.6': - dependencies: - defer-to-connect: 2.0.1 - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.2.0 - '@types/keyv': 3.1.4 - '@types/node': 25.2.3 - '@types/responselike': 1.0.3 - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/debug@4.1.13': - dependencies: - '@types/ms': 2.1.0 - - '@types/deep-eql@4.0.2': {} - - '@types/estree@1.0.8': {} - - '@types/estree@1.0.9': {} - - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 25.2.3 - - '@types/http-cache-semantics@4.2.0': {} - - '@types/json-schema@7.0.15': {} - - '@types/keyv@3.1.4': - dependencies: - '@types/node': 25.2.3 - - '@types/ms@2.1.0': {} - - '@types/node@22.19.19': - dependencies: - undici-types: 6.21.0 - - '@types/node@25.2.3': - dependencies: - undici-types: 7.16.0 - - '@types/react-dom@19.2.2(@types/react@19.2.2)': - dependencies: - '@types/react': 19.2.2 - - '@types/react@19.2.2': - dependencies: - csstype: 3.2.3 - - '@types/responselike@1.0.3': - dependencies: - '@types/node': 25.2.3 - - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 25.2.3 - optional: true - - '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/type-utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.1 - eslint: 9.38.0(jiti@2.7.0) - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.46.1 - debug: 4.4.3 - eslint: 9.38.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.46.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) - '@typescript-eslint/types': 8.46.1 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.46.1': - dependencies: - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/visitor-keys': 8.46.1 - - '@typescript-eslint/tsconfig-utils@8.46.1(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.38.0(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.46.1': {} - - '@typescript-eslint/typescript-estree@8.46.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.46.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/visitor-keys': 8.46.1 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.9 - semver: 7.8.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/types': 8.46.1 - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - eslint: 9.38.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.46.1': - dependencies: - '@typescript-eslint/types': 8.46.1 - eslint-visitor-keys: 4.2.1 - - '@vitejs/plugin-react@5.0.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.30 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.3.2(@types/node@25.2.3)(jiti@2.7.0) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@4.1.0': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.0 - '@vitest/utils': 4.1.0 - chai: 6.2.2 - tinyrainbow: 3.1.0 - - '@vitest/mocker@4.1.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0))': - dependencies: - '@vitest/spy': 4.1.0 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.2(@types/node@25.2.3)(jiti@2.7.0) - - '@vitest/pretty-format@4.1.0': - dependencies: - tinyrainbow: 3.1.0 - - '@vitest/runner@4.1.0': - dependencies: - '@vitest/utils': 4.1.0 - pathe: 2.0.3 - - '@vitest/snapshot@4.1.0': - dependencies: - '@vitest/pretty-format': 4.1.0 - '@vitest/utils': 4.1.0 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.1.0': {} - - '@vitest/utils@4.1.0': - dependencies: - '@vitest/pretty-format': 4.1.0 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - - '@xmldom/xmldom@0.8.13': {} - - '@xmldom/xmldom@0.9.10': {} - - abbrev@3.0.1: {} - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - agent-base@7.1.4: {} - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - app-builder-lib@26.15.0(dmg-builder@26.15.0)(electron-builder-squirrel-windows@26.15.0): - dependencies: - '@electron/asar': 3.4.1 - '@electron/fuses': 1.8.0 - '@electron/get': 3.1.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.3 - '@electron/rebuild': 4.0.3 - '@electron/universal': 2.0.3 - '@malept/flatpak-bundler': 0.4.0 - '@noble/hashes': 2.2.0 - '@peculiar/webcrypto': 1.7.1 - '@types/fs-extra': 9.0.13 - ajv: 8.20.0 - asn1js: 3.0.10 - async-exit-hook: 2.0.1 - builder-util: 26.15.0 - builder-util-runtime: 9.7.0 - chromium-pickle-js: 0.2.0 - ci-info: 4.3.1 - debug: 4.4.3 - dmg-builder: 26.15.0(electron-builder-squirrel-windows@26.15.0) - dotenv: 16.6.1 - dotenv-expand: 11.0.7 - ejs: 3.1.10 - electron-builder-squirrel-windows: 26.15.0(dmg-builder@26.15.0) - electron-publish: 26.15.0 - fs-extra: 10.1.0 - hosted-git-info: 4.1.0 - isbinaryfile: 5.0.7 - jiti: 2.7.0 - js-yaml: 4.1.1 - json5: 2.2.3 - lazy-val: 1.0.5 - minimatch: 10.2.5 - pkijs: 3.4.0 - plist: 3.1.0 - proper-lockfile: 4.1.2 - resedit: 1.7.2 - semver: 7.7.4 - tar: 7.5.15 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - unzipper: 0.12.3 - which: 5.0.0 - transitivePeerDependencies: - - supports-color - - argparse@2.0.1: {} - - asn1js@3.0.10: - dependencies: - pvtsutils: 1.3.6 - pvutils: 1.1.5 - tslib: 2.8.1 - - assertion-error@2.0.1: {} - - async-exit-hook@2.0.1: {} - - async@3.2.6: {} - - asynckit@0.4.0: {} - - at-least-node@1.0.0: {} - - aws4@1.13.2: {} - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - base64-js@1.5.1: {} - - baseline-browser-mapping@2.10.31: {} - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - bluebird@3.7.2: {} - - boolean@3.2.0: - optional: true - - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.1.0: - dependencies: - balanced-match: 1.0.2 - - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.4 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.31 - caniuse-lite: 1.0.30001793 - electron-to-chromium: 1.5.360 - node-releases: 2.0.44 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - - buffer-crc32@0.2.13: {} - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - builder-util-runtime@9.7.0: - dependencies: - debug: 4.4.3 - sax: 1.6.0 - transitivePeerDependencies: - - supports-color - - builder-util@26.15.0: - dependencies: - '@types/debug': 4.1.13 - builder-util-runtime: 9.7.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - js-yaml: 4.1.1 - sanitize-filename: 1.6.4 - source-map-support: 0.5.21 - stat-mode: 1.0.0 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - transitivePeerDependencies: - - supports-color - - bytestreamjs@2.0.1: {} - - cac@6.7.14: {} - - cacache@19.0.1: - dependencies: - '@npmcli/fs': 4.0.0 - fs-minipass: 3.0.3 - glob: 10.5.0 - lru-cache: 10.4.3 - minipass: 7.1.3 - minipass-collect: 2.0.1 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - p-map: 7.0.4 - ssri: 12.0.0 - tar: 7.5.15 - unique-filename: 4.0.0 - - cacheable-lookup@5.0.4: {} - - cacheable-request@7.0.4: - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.2.0 - keyv: 4.5.4 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - callsites@3.1.0: {} - - caniuse-lite@1.0.30001793: {} - - chai@6.2.2: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chownr@3.0.0: {} - - chromium-pickle-js@0.2.0: {} - - ci-info@4.3.1: {} - - ci-info@4.4.0: {} - - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-spinners@2.9.2: {} - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone-response@1.0.3: - dependencies: - mimic-response: 1.0.1 - - clone@1.0.4: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@5.1.0: {} - - commander@9.5.0: - optional: true - - compare-version@0.1.2: {} - - concat-map@0.0.1: {} - - convert-source-map@2.0.0: {} - - core-util-is@1.0.2: {} - - cross-dirname@0.1.0: - optional: true - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.2.3: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - deep-is@0.1.4: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - defer-to-connect@2.0.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - optional: true - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - optional: true - - delayed-stream@1.0.0: {} - - detect-libc@2.1.2: {} - - detect-node@2.1.0: - optional: true - - dir-compare@4.2.0: - dependencies: - minimatch: 3.1.5 - p-limit: 3.1.0 - - dmg-builder@26.15.0(electron-builder-squirrel-windows@26.15.0): - dependencies: - app-builder-lib: 26.15.0(dmg-builder@26.15.0)(electron-builder-squirrel-windows@26.15.0) - builder-util: 26.15.0 - fs-extra: 10.1.0 - js-yaml: 4.1.1 - transitivePeerDependencies: - - electron-builder-squirrel-windows - - supports-color - - dotenv-expand@11.0.7: - dependencies: - dotenv: 16.6.1 - - dotenv@16.6.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - duplexer2@0.1.4: - dependencies: - readable-stream: 2.3.8 - - eastasianwidth@0.2.0: {} - - ejs@3.1.10: - dependencies: - jake: 10.9.4 - - electron-builder-squirrel-windows@26.15.0(dmg-builder@26.15.0): - dependencies: - app-builder-lib: 26.15.0(dmg-builder@26.15.0)(electron-builder-squirrel-windows@26.15.0) - builder-util: 26.15.0 - electron-winstaller: 5.4.0 - transitivePeerDependencies: - - dmg-builder - - supports-color - - electron-builder@26.15.0(electron-builder-squirrel-windows@26.15.0): - dependencies: - app-builder-lib: 26.15.0(dmg-builder@26.15.0)(electron-builder-squirrel-windows@26.15.0) - builder-util: 26.15.0 - builder-util-runtime: 9.7.0 - chalk: 4.1.2 - ci-info: 4.4.0 - dmg-builder: 26.15.0(electron-builder-squirrel-windows@26.15.0) - fs-extra: 10.1.0 - lazy-val: 1.0.5 - simple-update-notifier: 2.0.0 - yargs: 17.7.2 - transitivePeerDependencies: - - electron-builder-squirrel-windows - - supports-color - - electron-publish@26.15.0: - dependencies: - '@types/fs-extra': 9.0.13 - aws4: 1.13.2 - builder-util: 26.15.0 - builder-util-runtime: 9.7.0 - chalk: 4.1.2 - form-data: 4.0.5 - fs-extra: 10.1.0 - lazy-val: 1.0.5 - mime: 2.6.0 - transitivePeerDependencies: - - supports-color - - electron-to-chromium@1.5.360: {} - - electron-vite@5.0.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)): - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) - cac: 6.7.14 - esbuild: 0.25.12 - magic-string: 0.30.21 - picocolors: 1.1.1 - vite: 7.3.2(@types/node@25.2.3)(jiti@2.7.0) - transitivePeerDependencies: - - supports-color - - electron-winstaller@5.4.0: - dependencies: - '@electron/asar': 3.4.1 - debug: 4.4.3 - fs-extra: 7.0.1 - lodash: 4.18.1 - temp: 0.9.4 - optionalDependencies: - '@electron/windows-sign': 1.2.2 - transitivePeerDependencies: - - supports-color - - electron@39.8.5: - dependencies: - '@electron/get': 2.0.3 - '@types/node': 22.19.19 - extract-zip: 2.0.1 - transitivePeerDependencies: - - supports-color - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - - env-paths@2.2.1: {} - - err-code@2.0.3: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@2.1.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - - es6-error@4.1.1: - optional: true - - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - - esbuild@0.27.7: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-plugin-react-hooks@7.0.0(eslint@9.38.0(jiti@2.7.0)): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - eslint: 9.38.0(jiti@2.7.0) - hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.4.24(eslint@9.38.0(jiti@2.7.0)): - dependencies: - eslint: 9.38.0(jiti@2.7.0) - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint@9.38.0(jiti@2.7.0): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.16.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.38.0 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.7.0 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.9 - - esutils@2.0.3: {} - - expect-type@1.3.0: {} - - exponential-backoff@3.1.3: {} - - extract-zip@2.0.1: - dependencies: - debug: 4.4.3 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.1.2: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - filelist@1.0.6: - dependencies: - minimatch: 5.1.9 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.3 - mime-types: 2.1.35 - - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - - fs-extra@11.3.5: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@9.1.0: - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - - fs-minipass@3.0.3: - dependencies: - minipass: 7.1.3 - - fs.realpath@1.0.0: {} - - fsevents@2.3.2: - optional: true - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.3 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@5.2.0: - dependencies: - pump: 3.0.4 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - - global-agent@3.0.0: - dependencies: - boolean: 3.2.0 - es6-error: 4.1.1 - matcher: 3.0.0 - roarr: 2.15.4 - semver: 7.7.4 - serialize-error: 7.0.1 - optional: true - - globals@14.0.0: {} - - globals@16.4.0: {} - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - optional: true - - gopd@1.2.0: {} - - got@11.8.6: - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - optional: true - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.3: - dependencies: - function-bind: 1.1.2 - - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - - http-cache-semantics@4.2.0: {} - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - http2-wrapper@1.0.3: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - optional: true - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ip-address@10.2.0: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-interactive@1.0.0: {} - - is-number@7.0.0: {} - - is-unicode-supported@0.1.0: {} - - isarray@1.0.0: {} - - isbinaryfile@4.0.10: {} - - isbinaryfile@5.0.7: {} - - isexe@2.0.0: {} - - isexe@3.1.5: {} - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - jake@10.9.4: - dependencies: - async: 3.2.6 - filelist: 1.0.6 - picocolors: 1.1.1 - - jiti@2.7.0: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json-stringify-safe@5.0.1: - optional: true - - json5@2.2.3: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsonfile@6.2.1: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - lazy-val@1.0.5: {} - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - lodash@4.18.1: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - lowercase-keys@2.0.0: {} - - lru-cache@10.4.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lucide-react@0.468.0(react@19.2.4): - dependencies: - react: 19.2.4 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - make-fetch-happen@14.0.3: - dependencies: - '@npmcli/agent': 3.0.0 - cacache: 19.0.1 - http-cache-semantics: 4.2.0 - minipass: 7.1.3 - minipass-fetch: 4.0.1 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - negotiator: 1.0.0 - proc-log: 5.0.0 - promise-retry: 2.0.1 - ssri: 12.0.0 - transitivePeerDependencies: - - supports-color - - matcher@3.0.0: - dependencies: - escape-string-regexp: 4.0.0 - optional: true - - math-intrinsics@1.1.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@2.6.0: {} - - mimic-fn@2.1.0: {} - - mimic-response@1.0.1: {} - - mimic-response@3.1.0: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.6 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 - - minimatch@5.1.9: - dependencies: - brace-expansion: 2.1.0 - - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.0 - - minimist@1.2.8: {} - - minipass-collect@2.0.1: - dependencies: - minipass: 7.1.3 - - minipass-fetch@4.0.1: - dependencies: - minipass: 7.1.3 - minipass-sized: 1.0.3 - minizlib: 3.1.0 - optionalDependencies: - encoding: 0.1.13 - - minipass-flush@1.0.7: - dependencies: - minipass: 3.3.6 - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@7.1.3: {} - - minizlib@3.1.0: - dependencies: - minipass: 7.1.3 - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - - ms@2.1.3: {} - - nanoid@3.3.12: {} - - natural-compare@1.4.0: {} - - negotiator@1.0.0: {} - - node-abi@4.31.0: - dependencies: - semver: 7.8.0 - - node-api-version@0.2.1: - dependencies: - semver: 7.8.0 - - node-gyp@11.5.0: - dependencies: - env-paths: 2.2.1 - exponential-backoff: 3.1.3 - graceful-fs: 4.2.11 - make-fetch-happen: 14.0.3 - nopt: 8.1.0 - proc-log: 5.0.0 - semver: 7.8.0 - tar: 7.5.15 - tinyglobby: 0.2.16 - which: 5.0.0 - transitivePeerDependencies: - - supports-color - - node-int64@0.4.0: {} - - node-releases@2.0.44: {} - - nopt@8.1.0: - dependencies: - abbrev: 3.0.1 - - normalize-url@6.1.0: {} - - object-keys@1.1.1: - optional: true - - obug@2.1.1: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - - p-cancelable@2.1.1: {} - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-map@7.0.4: {} - - package-json-from-dist@1.0.1: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - - pathe@2.0.3: {} - - pe-library@0.4.1: {} - - pend@1.2.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - pkijs@3.4.0: - dependencies: - '@noble/hashes': 1.4.0 - asn1js: 3.0.10 - bytestreamjs: 2.0.1 - pvtsutils: 1.3.6 - pvutils: 1.1.5 - tslib: 2.8.1 - - playwright-core@1.58.2: {} - - playwright@1.58.2: - dependencies: - playwright-core: 1.58.2 - optionalDependencies: - fsevents: 2.3.2 - - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.13 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - plist@3.1.1: - dependencies: - '@xmldom/xmldom': 0.9.10 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - postcss@8.5.15: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postject@1.0.0-alpha.6: - dependencies: - commander: 9.5.0 - optional: true - - prelude-ls@1.2.1: {} - - proc-log@5.0.0: {} - - process-nextick-args@2.0.1: {} - - progress@2.0.3: {} - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - - proper-lockfile@4.1.2: - dependencies: - graceful-fs: 4.2.11 - retry: 0.12.0 - signal-exit: 3.0.7 - - pump@3.0.4: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - - punycode@2.3.1: {} - - pvtsutils@1.3.6: - dependencies: - tslib: 2.8.1 - - pvutils@1.1.5: {} - - queue-microtask@1.2.3: {} - - quick-lru@5.1.1: {} - - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - - react-refresh@0.17.0: {} - - react@19.2.4: {} - - read-binary-file-arch@1.0.6: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.2 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - reicon-react@1.1.2(react@19.2.4): - dependencies: - react: 19.2.4 - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - - resedit@1.7.2: - dependencies: - pe-library: 0.4.1 - - resolve-alpn@1.2.1: {} - - resolve-from@4.0.0: {} - - responselike@2.0.1: - dependencies: - lowercase-keys: 2.0.0 - - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - retry@0.12.0: {} - - reusify@1.1.0: {} - - rimraf@2.6.3: - dependencies: - glob: 7.2.3 - - roarr@2.15.4: - dependencies: - boolean: 3.2.0 - detect-node: 2.1.0 - globalthis: 1.0.4 - json-stringify-safe: 5.0.1 - semver-compare: 1.0.0 - sprintf-js: 1.1.3 - optional: true - - rollup@4.60.4: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.4 - '@rollup/rollup-android-arm64': 4.60.4 - '@rollup/rollup-darwin-arm64': 4.60.4 - '@rollup/rollup-darwin-x64': 4.60.4 - '@rollup/rollup-freebsd-arm64': 4.60.4 - '@rollup/rollup-freebsd-x64': 4.60.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 - '@rollup/rollup-linux-arm-musleabihf': 4.60.4 - '@rollup/rollup-linux-arm64-gnu': 4.60.4 - '@rollup/rollup-linux-arm64-musl': 4.60.4 - '@rollup/rollup-linux-loong64-gnu': 4.60.4 - '@rollup/rollup-linux-loong64-musl': 4.60.4 - '@rollup/rollup-linux-ppc64-gnu': 4.60.4 - '@rollup/rollup-linux-ppc64-musl': 4.60.4 - '@rollup/rollup-linux-riscv64-gnu': 4.60.4 - '@rollup/rollup-linux-riscv64-musl': 4.60.4 - '@rollup/rollup-linux-s390x-gnu': 4.60.4 - '@rollup/rollup-linux-x64-gnu': 4.60.4 - '@rollup/rollup-linux-x64-musl': 4.60.4 - '@rollup/rollup-openbsd-x64': 4.60.4 - '@rollup/rollup-openharmony-arm64': 4.60.4 - '@rollup/rollup-win32-arm64-msvc': 4.60.4 - '@rollup/rollup-win32-ia32-msvc': 4.60.4 - '@rollup/rollup-win32-x64-gnu': 4.60.4 - '@rollup/rollup-win32-x64-msvc': 4.60.4 - fsevents: 2.3.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.1.2: {} - - safer-buffer@2.1.2: - optional: true - - sanitize-filename@1.6.4: - dependencies: - truncate-utf8-bytes: 1.0.2 - - sax@1.6.0: {} - - scheduler@0.27.0: {} - - semver-compare@1.0.0: - optional: true - - semver@5.7.2: {} - - semver@6.3.1: {} - - semver@7.7.4: {} - - semver@7.8.0: {} - - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - optional: true - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - siginfo@2.0.0: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-update-notifier@2.0.0: - dependencies: - semver: 7.8.0 - - smart-buffer@4.2.0: {} - - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - socks: 2.8.9 - transitivePeerDependencies: - - supports-color - - socks@2.8.9: - dependencies: - ip-address: 10.2.0 - smart-buffer: 4.2.0 - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - sprintf-js@1.1.3: - optional: true - - ssri@12.0.0: - dependencies: - minipass: 7.1.3 - - stackback@0.0.2: {} - - stat-mode@1.0.0: {} - - std-env@4.1.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-json-comments@3.1.1: {} - - sumchecker@3.0.1: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - tar@7.5.15: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.3 - minizlib: 3.1.0 - yallist: 5.0.0 - - temp-file@3.4.0: - dependencies: - async-exit-hook: 2.0.1 - fs-extra: 10.1.0 - - temp@0.9.4: - dependencies: - mkdirp: 0.5.6 - rimraf: 2.6.3 - - tiny-async-pool@1.3.0: - dependencies: - semver: 5.7.2 - - tinybench@2.9.0: {} - - tinyexec@1.1.2: {} - - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinyrainbow@3.1.0: {} - - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.6 - - tmp@0.2.6: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - truncate-utf8-bytes@1.0.2: - dependencies: - utf8-byte-length: 1.0.5 - - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - tslib@2.8.1: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@0.13.1: - optional: true - - typescript-eslint@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.38.0(jiti@2.7.0) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - undici-types@6.21.0: {} - - undici-types@7.16.0: {} - - unique-filename@4.0.0: - dependencies: - unique-slug: 5.0.0 - - unique-slug@5.0.0: - dependencies: - imurmurhash: 0.1.4 - - universalify@0.1.2: {} - - universalify@2.0.1: {} - - unzipper@0.12.3: - dependencies: - bluebird: 3.7.2 - duplexer2: 0.1.4 - fs-extra: 11.3.5 - graceful-fs: 4.2.11 - node-int64: 0.4.0 - - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - utf8-byte-length@1.0.5: {} - - util-deprecate@1.0.2: {} - - vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0): - dependencies: - esbuild: 0.27.7 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.15 - rollup: 4.60.4 - tinyglobby: 0.2.16 - optionalDependencies: - '@types/node': 25.2.3 - fsevents: 2.3.3 - jiti: 2.7.0 - - vitest@4.1.0(@types/node@25.2.3)(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)): - dependencies: - '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(vite@7.3.2(@types/node@25.2.3)(jiti@2.7.0)) - '@vitest/pretty-format': 4.1.0 - '@vitest/runner': 4.1.0 - '@vitest/snapshot': 4.1.0 - '@vitest/spy': 4.1.0 - '@vitest/utils': 4.1.0 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 - tinyrainbow: 3.1.0 - vite: 7.3.2(@types/node@25.2.3)(jiti@2.7.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.2.3 - transitivePeerDependencies: - - msw - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - webcrypto-core@1.9.2: - dependencies: - '@peculiar/asn1-schema': 2.7.0 - '@peculiar/json-schema': 1.1.12 - '@peculiar/utils': 2.0.3 - asn1js: 3.0.10 - tslib: 2.8.1 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - which@5.0.0: - dependencies: - isexe: 3.1.5 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - - wrappy@1.0.2: {} - - xmlbuilder@15.1.1: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yallist@4.0.0: {} - - yallist@5.0.0: {} - - yargs-parser@21.1.1: {} - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - - yocto-queue@0.1.0: {} - - zod-validation-error@4.0.2(zod@4.3.6): - dependencies: - zod: 4.3.6 - - zod@4.3.6: {} diff --git a/AgentCompany-New/src/main/database/schema.ts b/AgentCompany-New/src/main/database/schema.ts deleted file mode 100644 index ff507503..00000000 --- a/AgentCompany-New/src/main/database/schema.ts +++ /dev/null @@ -1,149 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { initialEnterpriseSchema } from "./migrations/001-initial"; -import { collaborationProviderPolicySchema } from "./migrations/002-collaboration"; -import { onboardingExecutionSchema } from "./migrations/003-onboarding"; -import { filesPinnedAndScheduledPosts } from "./migrations/004-files-posts"; -import { chatReadState } from "./migrations/005-chat-read-state"; -import { appStateSchema } from "./migrations/006-app-state"; -import { skillHardeningSchema } from "./migrations/007-skill-hardening"; -import { providerHealthSchema } from "./migrations/008-provider-health"; -import { socialGovernanceSchema } from "./migrations/009-social-governance"; -import { fileHandoffSecuritySchema } from "./migrations/010-file-handoff-security"; -import { boardInterventionSchema } from "./migrations/011-board-interventions"; -import { complianceControlsSchema } from "./migrations/012-compliance-controls"; -import { searchDocumentsSchema } from "./migrations/013-search-documents"; -import { providerPolicyUsageSchema } from "./migrations/014-provider-policy-usage"; -import { identityAccessSchema } from "./migrations/015-identity-access"; -import { orgGovernanceSchema } from "./migrations/016-org-governance"; -import { operationsControlsSchema } from "./migrations/017-operations-controls"; -import { sdlcControlsSchema } from "./migrations/018-sdlc-controls"; -import { auditReplaySchema } from "./migrations/019-audit-replay"; -import { rollbackSnapshotsSchema } from "./migrations/020-rollback-snapshots"; -import { providerAuthBrokerSchema } from "./migrations/021-provider-auth-broker"; -import { providerRateLimitObservationSchema } from "./migrations/022-provider-rate-limit-observations"; -import { providerRequestRuntimeSchema } from "./migrations/023-provider-request-runtime"; -import { taskRunProviderRequestSchema } from "./migrations/024-task-run-provider-request"; -import { chatMessageDeliverySchema } from "./migrations/025-chat-message-delivery"; -import { browserPlatformGovernanceSchema } from "./migrations/026-browser-platform-governance"; -import { socialAuditRecordsSchema } from "./migrations/027-social-audit-records"; -import { migrationCutoverJournalSchema } from "./migrations/028-migration-cutover-journal"; -import { fileHandoffRecordsSchema } from "./migrations/029-file-handoff-records"; -import { approvalSourceRefsSchema } from "./migrations/030-approval-source-refs"; -import { providerRequestWorkspaceSchema } from "./migrations/031-provider-request-workspace"; -import { browserActionMetadataSchema } from "./migrations/032-browser-action-metadata"; -import { auditEventImmutabilitySchema } from "./migrations/033-audit-event-immutability"; -import { providerAuthSessionsSchema } from "./migrations/034-provider-auth-sessions"; -import { taskRunIsolationSchema } from "./migrations/035-task-run-isolation"; -import { additionalConnectorsSchema } from "./migrations/036-additional-connectors"; -import { customProvidersSchema } from "./migrations/037-custom-providers"; -import { providerAuthProfileCascadeSchema } from "./migrations/038-provider-auth-profile-cascade"; -import { auditImmutabilityOrgTeardownSchema } from "./migrations/039-audit-immutability-org-teardown"; -import { documentsKnowledgeAutomationSchema } from "./migrations/040-documents-knowledge-automation"; -import { taskSubtasksDeleteSchema } from "./migrations/041-task-subtasks-delete"; -import { approvalNotesMeetingsSprintsSchema } from "./migrations/042-approval-notes-meetings-sprints"; -import { composioIntegrationSchema } from "./migrations/043-composio-integration"; -import { mentionWakeStateSchema } from "./migrations/044-mention-wake-state"; -import { connectorGrantsSchema } from "./migrations/045-connector-grants"; - -interface Migration { - version: number; - name: string; - sql: string; -} - -const MIGRATIONS: Migration[] = [ - { version: 1, name: "initial_enterprise_schema", sql: initialEnterpriseSchema }, - { version: 2, name: "collaboration_provider_policy_schema", sql: collaborationProviderPolicySchema }, - { version: 3, name: "onboarding_execution_schema", sql: onboardingExecutionSchema }, - { version: 4, name: "files_pinned_and_scheduled_posts", sql: filesPinnedAndScheduledPosts }, - { version: 5, name: "chat_read_state", sql: chatReadState }, - { version: 6, name: "app_state", sql: appStateSchema }, - { version: 7, name: "skill_hardening", sql: skillHardeningSchema }, - { version: 8, name: "provider_health", sql: providerHealthSchema }, - { version: 9, name: "social_governance", sql: socialGovernanceSchema }, - { version: 10, name: "file_handoff_security", sql: fileHandoffSecuritySchema }, - { version: 11, name: "board_interventions", sql: boardInterventionSchema }, - { version: 12, name: "compliance_controls", sql: complianceControlsSchema }, - { version: 13, name: "search_documents", sql: searchDocumentsSchema }, - { version: 14, name: "provider_policy_usage", sql: providerPolicyUsageSchema }, - { version: 15, name: "identity_access", sql: identityAccessSchema }, - { version: 16, name: "org_governance", sql: orgGovernanceSchema }, - { version: 17, name: "operations_controls", sql: operationsControlsSchema }, - { version: 18, name: "sdlc_controls", sql: sdlcControlsSchema }, - { version: 19, name: "audit_replay", sql: auditReplaySchema }, - { version: 20, name: "rollback_snapshots", sql: rollbackSnapshotsSchema }, - { version: 21, name: "provider_auth_broker", sql: providerAuthBrokerSchema }, - { version: 22, name: "provider_rate_limit_observations", sql: providerRateLimitObservationSchema }, - { version: 23, name: "provider_request_runtime", sql: providerRequestRuntimeSchema }, - { version: 24, name: "task_run_provider_request", sql: taskRunProviderRequestSchema }, - { version: 25, name: "chat_message_delivery", sql: chatMessageDeliverySchema }, - { version: 26, name: "browser_platform_governance", sql: browserPlatformGovernanceSchema }, - { version: 27, name: "social_audit_records", sql: socialAuditRecordsSchema }, - { version: 28, name: "migration_cutover_journal", sql: migrationCutoverJournalSchema }, - { version: 29, name: "file_handoff_records", sql: fileHandoffRecordsSchema }, - { version: 30, name: "approval_source_refs", sql: approvalSourceRefsSchema }, - { version: 31, name: "provider_request_workspace", sql: providerRequestWorkspaceSchema }, - { version: 32, name: "browser_action_metadata", sql: browserActionMetadataSchema }, - { version: 33, name: "audit_event_immutability", sql: auditEventImmutabilitySchema }, - { version: 34, name: "provider_auth_sessions", sql: providerAuthSessionsSchema }, - { version: 35, name: "task_run_isolation", sql: taskRunIsolationSchema }, - { version: 36, name: "additional_connectors", sql: additionalConnectorsSchema }, - { version: 37, name: "custom_providers", sql: customProvidersSchema }, - { version: 38, name: "provider_auth_profile_cascade", sql: providerAuthProfileCascadeSchema }, - { version: 39, name: "audit_immutability_org_teardown", sql: auditImmutabilityOrgTeardownSchema }, - { version: 40, name: "documents_knowledge_automation", sql: documentsKnowledgeAutomationSchema }, - { version: 41, name: "task_subtasks_delete", sql: taskSubtasksDeleteSchema }, - { version: 42, name: "approval_notes_meetings_sprints", sql: approvalNotesMeetingsSprintsSchema }, - { version: 43, name: "composio_integration", sql: composioIntegrationSchema }, - { version: 44, name: "mention_wake_state", sql: mentionWakeStateSchema }, - { version: 45, name: "connector_grants", sql: connectorGrantsSchema }, -]; - -const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version; - -export function installSchema(db: DatabaseSync): void { - db.exec(` - create table if not exists schema_migrations ( - version integer primary key, - name text not null, - applied_at text not null - ); - `); - - const row = db.prepare("select coalesce(max(version), 0) as version from schema_migrations").get() as { version: number }; - let currentVersion = row.version; - if (currentVersion > SCHEMA_VERSION) { - throw new Error(`Database schema ${currentVersion} is newer than supported schema ${SCHEMA_VERSION}.`); - } - backfillMigrationLedger(db, currentVersion); - - for (const migration of MIGRATIONS) { - if (currentVersion >= migration.version) continue; - applyMigration(db, migration); - currentVersion = migration.version; - } -} - -function applyMigration(db: DatabaseSync, migration: Migration): void { - db.exec("begin immediate"); - try { - db.exec(migration.sql); - recordMigration(db, migration); - db.exec("commit"); - } catch (error) { - db.exec("rollback"); - throw error; - } -} - -function backfillMigrationLedger(db: DatabaseSync, currentVersion: number): void { - for (const migration of MIGRATIONS) { - if (migration.version > currentVersion) return; - recordMigration(db, migration); - } -} - -function recordMigration(db: DatabaseSync, migration: Migration): void { - db.prepare("insert or ignore into schema_migrations(version, name, applied_at) values (?, ?, datetime('now'))") - .run(migration.version, migration.name); -} diff --git a/AgentCompany-New/src/main/index.ts b/AgentCompany-New/src/main/index.ts deleted file mode 100644 index 40a97167..00000000 --- a/AgentCompany-New/src/main/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { app } from "electron"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { DatabaseConnection } from "./database/connection"; -import { createMainWindow } from "./app/create-window"; -import { registerIpcHandlers } from "./app/ipc-handlers"; -import { startProviderBackgroundWorker } from "./app/provider-background-worker"; -import { recoverInterruptedWork } from "./app/startup-recovery"; -import { startTaskQueueWorker } from "./app/task-queue-worker"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -// A losing second instance must never touch the database: quit is -// asynchronous, so all startup work stays behind the lock check. -if (!app.requestSingleInstanceLock()) { - app.quit(); -} else { - app.whenReady().then(() => { - const profileDir = process.env.AGENTCOMPANY_NEW_PROFILE_DIR ?? join(app.getPath("userData"), "profile"); - const connection = new DatabaseConnection(join(profileDir, "agentcompany.db")); - connection.transaction(() => recoverInterruptedWork(connection.db)); - const win = createMainWindow({ - preloadPath: join(__dirname, "../preload/index.js"), - rendererDist: join(__dirname, "../renderer"), - devServerUrl: process.env.ELECTRON_RENDERER_URL, - }); - - registerIpcHandlers({ - connection, - mainWindow: win, - artifactRoot: join(profileDir, "artifacts"), - }); - const stopProviderBackgroundWorker = startProviderBackgroundWorker({ - db: connection.db, - mainWindow: win, - }); - const autonomousExecution = process.env.AGENTCOMPANY_NEW_AUTORUN !== "0"; - const stopTaskQueueWorker = autonomousExecution - ? startTaskQueueWorker({ connection, mainWindow: win }) - : () => {}; - - app.on("second-instance", () => { - if (win.isMinimized()) win.restore(); - win.focus(); - }); - - app.on("before-quit", () => { - stopProviderBackgroundWorker(); - stopTaskQueueWorker(); - connection.close(); - }); - }); - - app.on("window-all-closed", () => { - if (process.platform !== "darwin") app.quit(); - }); -} diff --git a/AgentCompany-New/src/preload/index.ts b/AgentCompany-New/src/preload/index.ts deleted file mode 100644 index b2617bd1..00000000 --- a/AgentCompany-New/src/preload/index.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { contextBridge, ipcRenderer } from "electron"; -import { IPC_CHANNELS } from "../shared/ipc"; -import type { DesktopApi, RendererEvent } from "../shared/desktop-api"; - -function invoke(channel: string, payload?: unknown): Promise { - return ipcRenderer.invoke(channel, payload) as Promise; -} - -const api: DesktopApi = { - loadSnapshot: () => invoke(IPC_CHANNELS.loadSnapshot), - bootstrapOnboarding: (input) => invoke(IPC_CHANNELS.bootstrapOnboarding, input), - createOrganization: (input) => invoke(IPC_CHANNELS.createOrganization, input), - setActiveOrganization: (input) => invoke(IPC_CHANNELS.setActiveOrganization, input), - deleteOrganization: (input) => invoke(IPC_CHANNELS.deleteOrganization, input), - createAgent: (input) => invoke(IPC_CHANNELS.createAgent, input), - updateAgent: (input) => invoke(IPC_CHANNELS.updateAgent, input), - createTask: (input) => invoke(IPC_CHANNELS.createTask, input), - updateTask: (input) => invoke(IPC_CHANNELS.updateTask, input), - deleteTask: (input) => invoke(IPC_CHANNELS.deleteTask, input), - updateTaskStatus: (input) => invoke(IPC_CHANNELS.updateTaskStatus, input), - runTask: (input) => invoke(IPC_CHANNELS.runTask, input), - createGoal: (input) => invoke(IPC_CHANNELS.createGoal, input), - createProject: (input) => invoke(IPC_CHANNELS.createProject, input), - createWorkspace: (input) => invoke(IPC_CHANNELS.createWorkspace, input), - createDocument: (input) => invoke(IPC_CHANNELS.createDocument, input), - updateDocument: (input) => invoke(IPC_CHANNELS.updateDocument, input), - deleteDocument: (input) => invoke(IPC_CHANNELS.deleteDocument, input), - createKnowledgeEntry: (input) => invoke(IPC_CHANNELS.createKnowledgeEntry, input), - deleteKnowledgeEntry: (input) => invoke(IPC_CHANNELS.deleteKnowledgeEntry, input), - createAutomationRule: (input) => invoke(IPC_CHANNELS.createAutomationRule, input), - updateAutomationRule: (input) => invoke(IPC_CHANNELS.updateAutomationRule, input), - deleteAutomationRule: (input) => invoke(IPC_CHANNELS.deleteAutomationRule, input), - createMeeting: (input) => invoke(IPC_CHANNELS.createMeeting, input), - deleteMeeting: (input) => invoke(IPC_CHANNELS.deleteMeeting, input), - createSprint: (input) => invoke(IPC_CHANNELS.createSprint, input), - deleteSprint: (input) => invoke(IPC_CHANNELS.deleteSprint, input), - createApproval: (input) => invoke(IPC_CHANNELS.createApproval, input), - decideApproval: (input) => invoke(IPC_CHANNELS.decideApproval, input), - syncEmployeeIdentity: (input) => invoke(IPC_CHANNELS.syncEmployeeIdentity, input), - grantRole: (input) => invoke(IPC_CHANNELS.grantRole, input), - createChatSpace: (input) => invoke(IPC_CHANNELS.createChatSpace, input), - sendMessage: (input) => invoke(IPC_CHANNELS.sendMessage, input), - editMessage: (input) => invoke(IPC_CHANNELS.editMessage, input), - deleteMessage: (input) => invoke(IPC_CHANNELS.deleteMessage, input), - markChatSpaceRead: (input) => invoke(IPC_CHANNELS.markChatSpaceRead, input), - saveProviderCredential: (input) => invoke(IPC_CHANNELS.saveProviderCredential, input), - revokeProviderCredential: (input) => invoke(IPC_CHANNELS.revokeProviderCredential, input), - launchProviderSignIn: (input) => invoke(IPC_CHANNELS.launchProviderSignIn, input), - startProviderOAuth: (input) => invoke(IPC_CHANNELS.startProviderOAuth, input), - cancelProviderOAuth: (input) => invoke(IPC_CHANNELS.cancelProviderOAuth, input), - checkProviderHealth: (input) => invoke(IPC_CHANNELS.checkProviderHealth, input), - listProviderModels: (input) => invoke(IPC_CHANNELS.listProviderModels, input), - updateProviderPolicy: (input) => invoke(IPC_CHANNELS.updateProviderPolicy, input), - openExternalUrl: (url) => invoke(IPC_CHANNELS.openExternalUrl, url), - createProviderResponse: (input) => invoke(IPC_CHANNELS.createProviderResponse, input), - streamProviderResponse: (input) => invoke(IPC_CHANNELS.streamProviderResponse, input), - cancelProviderResponse: (input) => invoke(IPC_CHANNELS.cancelProviderResponse, input), - importSkillDirectory: (input) => invoke(IPC_CHANNELS.importSkillDirectory, input), - bindSkill: (input) => invoke(IPC_CHANNELS.bindSkill, input), - resolveAgentSkills: (input) => invoke(IPC_CHANNELS.resolveAgentSkills, input), - runSkillTests: (input) => invoke(IPC_CHANNELS.runSkillTests, input), - createSocialAccount: (input) => invoke(IPC_CHANNELS.createSocialAccount, input), - launchSocialLogin: (input) => invoke(IPC_CHANNELS.launchSocialLogin, input), - createScheduledPost: (input) => invoke(IPC_CHANNELS.createScheduledPost, input), - setScheduledPostState: (input) => invoke(IPC_CHANNELS.setScheduledPostState, input), - importFile: (input) => invoke(IPC_CHANNELS.importFile, input), - openFile: (input) => invoke(IPC_CHANNELS.openFile, input), - pickDirectory: () => invoke(IPC_CHANNELS.pickDirectory), - setFilePinned: (input) => invoke(IPC_CHANNELS.setFilePinned, input), - createMigrationReport: (input) => invoke(IPC_CHANNELS.createMigrationReport, input), - createRollbackSnapshot: (input) => invoke(IPC_CHANNELS.createRollbackSnapshot, input), - setRollbackSnapshotActive: (input) => invoke(IPC_CHANNELS.setRollbackSnapshotActive, input), - resolveMigrationReconciliation: (input) => invoke(IPC_CHANNELS.resolveMigrationReconciliation, input), - setFeatureFlag: (input) => invoke(IPC_CHANNELS.setFeatureFlag, input), - runChaosDrill: (input) => invoke(IPC_CHANNELS.runChaosDrill, input), - runSdlcReview: (input) => invoke(IPC_CHANNELS.runSdlcReview, input), - runEvalSuite: (input) => invoke(IPC_CHANNELS.runEvalSuite, input), - setPrBotGate: (input) => invoke(IPC_CHANNELS.setPrBotGate, input), - createComplianceExport: (input) => invoke(IPC_CHANNELS.createComplianceExport, input), - createAuditReplay: (input) => invoke(IPC_CHANNELS.createAuditReplay, input), - createLegalHold: (input) => invoke(IPC_CHANNELS.createLegalHold, input), - setLegalHoldState: (input) => invoke(IPC_CHANNELS.setLegalHoldState, input), - createRetentionFreeze: (input) => invoke(IPC_CHANNELS.createRetentionFreeze, input), - setRetentionFreezeState: (input) => invoke(IPC_CHANNELS.setRetentionFreezeState, input), - saveComposioSettings: (input) => invoke(IPC_CHANNELS.saveComposioSettings, input), - listComposioToolkits: (input) => invoke(IPC_CHANNELS.listComposioToolkits, input), - connectComposioToolkit: (input) => invoke(IPC_CHANNELS.connectComposioToolkit, input), - refreshComposioAccounts: (input) => invoke(IPC_CHANNELS.refreshComposioAccounts, input), - grantConnector: (input) => invoke(IPC_CHANNELS.grantConnector, input), - revokeConnector: (input) => invoke(IPC_CHANNELS.revokeConnector, input), - search: (input) => invoke(IPC_CHANNELS.search, input), - subscribe: (callback) => { - const listener = (_event: Electron.IpcRendererEvent, payload: RendererEvent) => callback(payload); - ipcRenderer.on(IPC_CHANNELS.rendererEvent, listener); - return () => ipcRenderer.removeListener(IPC_CHANNELS.rendererEvent, listener); - }, - platform: process.platform as DesktopApi["platform"], - windowMinimize: () => invoke(IPC_CHANNELS.windowMinimize), - windowMaximize: () => invoke(IPC_CHANNELS.windowMaximize), - windowClose: () => invoke(IPC_CHANNELS.windowClose), -}; - -contextBridge.exposeInMainWorld("agentCompany", api); diff --git a/AgentCompany-New/src/renderer/env.d.ts b/AgentCompany-New/src/renderer/env.d.ts deleted file mode 100644 index 31acb172..00000000 --- a/AgentCompany-New/src/renderer/env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { DesktopApi } from "../shared/desktop-api"; - -declare global { - interface Window { - agentCompany: DesktopApi; - } -} diff --git a/AgentCompany-New/src/renderer/index.html b/AgentCompany-New/src/renderer/index.html deleted file mode 100644 index e6056b45..00000000 --- a/AgentCompany-New/src/renderer/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - AgentCompany - - -
- - - diff --git a/AgentCompany-New/tests/e2e/playwright.config.ts b/AgentCompany-New/tests/e2e/playwright.config.ts deleted file mode 100644 index d06eeac5..00000000 --- a/AgentCompany-New/tests/e2e/playwright.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "@playwright/test"; - -export default defineConfig({ - testDir: ".", - timeout: 60_000, - retries: 0, - workers: 1, - reporter: "list", -}); diff --git a/AgentCompany-New/tsconfig.json b/AgentCompany-New/tsconfig.json deleted file mode 100644 index 5a11490f..00000000 --- a/AgentCompany-New/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "allowJs": false, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "types": ["node", "electron", "vitest/globals"], - "baseUrl": ".", - "paths": { - "@main/*": ["src/main/*"], - "@preload/*": ["src/preload/*"], - "@renderer/*": ["src/renderer/*"], - "@shared/*": ["src/shared/*"] - } - }, - "include": ["src", "tests", "electron.vite.config.ts", "vitest.config.ts", "eslint.config.mjs"], - "references": [] -} diff --git a/AgentCompany-New/vitest.config.ts b/AgentCompany-New/vitest.config.ts deleted file mode 100644 index 4e9e2444..00000000 --- a/AgentCompany-New/vitest.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - environment: "node", - include: ["tests/{unit,contract,integration,eval}/**/*.test.ts"], - }, -}); diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index ff027b66..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,111 +0,0 @@ -# Contributing - -This file documents the rules that are load-bearing for day-to-day work -in this repo. If you are using an AI agent, it must follow this file -too. - -## Database access - -All database calls go through domain modules: - -```ts -db.tasks.saveTask(...) -db.agents.getAgent(...) -db.documentsMod.saveDocument(...) -``` - -**Adding a new pass-through on `AppDatabase` is not allowed.** The -pass-through layer existed historically, was removed in C1 (commits -`e352a69` → C1 part 2/3 → `ee1734e`), and is now guarded by an ESLint -rule that blocks regressions. Route every new call directly through -the owning sub-module. - -If the ESLint rule fires on your change: - -1. Read the sub-module list in `src/main/database/` to find the right - owner for your method. -2. Either add the method to that sub-module (if it is new), or change - the call site to use `db..(...)` (if the method - already exists there). -3. Do not silence the rule with an inline disable. If you think the - rule is wrong for your case, open an issue — the rule has caught - real regressions. - -## C1 codemod - -If a large surface of call sites ever needs to flip shape again (e.g. -a sub-module gets renamed, or a method moves between sub-modules), use -the codemod at `scripts/codemod/remove-appdatabase-passthrough.mjs` as -a starting point. - -Usage: - -```bash -# Dry run first: -node scripts/codemod/remove-appdatabase-passthrough.mjs --dry-run - -# Then apply: -node scripts/codemod/remove-appdatabase-passthrough.mjs - -# Scope to specific modules: -node scripts/codemod/remove-appdatabase-passthrough.mjs --modules=tasks,agents -``` - -The script's `METHOD_TO_MODULE` map and completeness evidence are -documented in `scripts/codemod/README.md`. The codemod stays in the -repo for future similar migrations; removing it would mean the next -person has to re-derive it from scratch. - -## Reverting C1 - -C1 landed as three commits, and `ee1734e` bundled the final pass-through -removal with a vault-binding simplification. This means a clean revert -must be **sequential**, not independent: - -``` -git revert ee1734e # revert 3/3 first (re-adds pass-throughs + vault back) -git revert -git revert e352a69 # revert 1/3 last -``` - -Reverting out of order (e.g. only `e352a69`) leaves the ESLint guard -still active and the build will fail on the re-introduced pass-throughs. -If you only want to undo the vault changes without re-introducing -pass-throughs, do a hunk-scoped revert: - -``` -git revert -n ee1734e -git checkout --patch HEAD -- -git commit -``` - -## File-size ceiling - -Files in `src/main/**` should stay under 500 LOC where practical. Two -files currently exceed the ceiling and carry TODO markers with a hard -review date (`M-followup by 2026-05-20`): - -- `src/main/agent-runtime/artifact-projector.ts` (637 LOC) -- `src/main/agent-runtime/runtime-bridge.ts` (648 LOC) - -If `2026-05-20` passes and these have not been decomposed, a follow-up -session MUST revisit them — either decompose, or justify the exception -in writing and update the TODO date. - -## Error taxonomy (C6) - -The error taxonomy migration is waved in `docs/proposals/C6.2-error-taxonomy-phase2.md`. -Each wave has a hard cap of 30 catch sites — C6 does not expand into an -unbounded sweep. If your change touches a catch block in `src/main/` -that has no `classifyUnknownError` call, add one using the existing -module pattern; do not leave bare `} catch {}` in new code. - -## Before opening a PR - -- `pnpm typecheck` clean -- `pnpm test:unit` green -- `pnpm lint` clean (this is where the pass-through guard lives) -- Keep the diff scoped — do not roll unrelated fixes into a single PR - -If you use an agent, confirm it has read this file and `AGENTS.md` -before letting it commit. diff --git a/README.md b/README.md deleted file mode 100644 index e9df1bed..00000000 --- a/README.md +++ /dev/null @@ -1,255 +0,0 @@ -

- AgentCompany logo -

- -

AgentCompany

- -

Run an AI company from your desktop.

- -

- Latest Release - License - Platform - Electron -

- -

- Download  |  Website -

- ---- - -

- AgentCompany dashboard -

- -## What it does - -Type a company name and a goal. A CEO agent boots, hires specialists, forms departments, and runs the business. You approve or steer from the desktop. - -Local, SQLite-backed, no external services. Inspired by [Paperclip](https://github.com/paperclipai/paperclip). - ---- - -## 26 providers, no CLI - -The runtime links [pi-mono](https://github.com/mariozechner/pi) directly. - -**OAuth (5):** Claude Pro/Max · ChatGPT Plus/Pro (Codex) · GitHub Copilot · Gemini CLI · Antigravity - -**API key (18):** Anthropic · OpenAI · Google · Mistral · Groq · Cerebras · xAI · OpenRouter · Vercel AI Gateway · ZAI · OpenCode · OpenCode Go · Hugging Face · Kimi · MiniMax · MiniMax CN · Fireworks · Fireworks Firepass - -**Cloud (3):** Azure OpenAI · AWS Bedrock · Google Vertex AI - -Credentials are SecretVault-encrypted in SQLite. - ---- - -## Two execution modes - -- **AI CEO** — autonomous. Hiring, tasks, deliverables run without you. -- **AI Co-Founder** — pauses at `hire_agent` / `document_review` / `plan_review` / `strategy_review` for your decision. - -Switch at Settings → Execution mode. - ---- - -## Features - -### Self-organizing teams -CEO builds the org chart from one goal. - -

- Org chart -

- -### Agent messaging -Threads and DMs between agents. Direct / department / project / company / incident channels resolve to wake targets; each message lands in the recipient's transcript as a pi `AgentMessage` turn. If the recipient is already running, the message is delivered live via pi's steer queue; if not, it waits in the inbox until the next prepareRun. - -

- Agent messaging -

- -### Tasks -Goals break into tasks. Agents pick them up, report progress, escalate blockers. - -

- Task queue -

- -### Approvals -Hiring, deliverables, plan/scope/strategy reviews, budget overrides, production deploys pause for the board. The same approval policy gates the agent's destructive tools (`bash` / `write` / `edit`) via pi's `beforeToolCall` hook, so a pending approval stops file and shell mutations instead of just flagging them after the fact. - -

- Approvals -

- -### Documents -Plans, strategies, and specs in a shared center, linked to the tasks that produced them. - -

- Document center -

- -### Launch in a minute -Name, mission, goal, provider, mode. - -

- Onboarding -

- ---- - -## Quick Start - -[Download the latest release](https://github.com/ZacharyZhang-NY/AgentCompany/releases) — macOS (Apple Silicon & Intel), Windows, Linux. - -### Build from source - -```sh -# Node.js 22+, pnpm 10+ -pnpm install -pnpm dev -``` - -### First run - -1. Requirements. Welcome screen, then a Node.js check. CLI runtimes call the local API through `node -e`. -2. Providers. Connect at least one runtime. -3. Company. Enter name, description, and workspace. -4. Team Models. Enable the models available to the CEO and workers. -5. Mode. Default is `ai_ceo`; `ai_cofounder` keeps key decisions human-reviewed. -6. Mission. Capture the first goal and acceptance description. -7. Launch. AgentCompany creates the company, CEO agent, workspace, kickoff task, and initial run handoff. - ---- - -## Verification - -```sh -pnpm typecheck -pnpm lint -pnpm test:unit -pnpm test:integration -pnpm test:e2e -pnpm build:verify -``` - -## Packaging - -```sh -pnpm build # Package for current platform → /build/release -pnpm build:dir # Unpackaged directory -pnpm build:current # Current host platform -pnpm release:local # Signed release pipeline — see docs/release/local-r2.md -``` - -Targets: macOS `.dmg`, Windows `.exe` (NSIS), Linux `.AppImage`. Built with `electron-builder`. Local builds use ad-hoc signing (`CSC_IDENTITY_AUTO_DISCOVERY=false`). Defaults to `--publish never`. - ---- - -## Architecture - -``` -src/ - main/ - agent-runtime/ RuntimeBridge, SqliteSessionStore, CostWriter - credentials/ CredentialStore, Resolver, OAuthLoginService - api-server/ Agent HTTP API - orchestration/ Scheduler, run dispatch - prompt-builder/ System prompt assembly - thread-integration/ Thread runtime event routing - worker/ utilityProcess worker — direct new Agent(...) - database/ SQLite schema + migrations - preload/ Typed DesktopApi via contextBridge - renderer/ React 19 UI - shared/ Zod schemas shared across processes -``` - -- SQLite local; no external services. -- `contextIsolation: true`, `nodeIntegration: false`, Zod-validated IPC. -- Worker constructs `new Agent({...})` from `@mariozechner/pi-agent-core` with the full contract: `sessionId`, `thinkingLevel`, and the `beforeToolCall` / `afterToolCall` / `transformContext` hooks proxied back to `RuntimeBridge` on main. -- Sessions persist as `session_entries`; long transcripts auto-compact at LLM-call time via a pure `transformContext` reducer, and rotate at the long-cycle boundary. -- `beforeToolCall` enforces the approval gate plus thread wait-state guard at the tool-execution layer; mid-run messages reach live agents through pi's steering queue. -- Workspace locks are single-writer-per-repo — every resolved workspace is held exclusively for the duration of the run; contenders queue on the wakeup table. -- Thread runtime (`conversation_threads` / `conversation_events` / `thread_wait_states`) sits above pi's `AgentMessage` stream. -- Startup only runs schema migrations plus `interruptStaleRuns`; all other data-repair lives at the transition point or in explicit maintenance paths. - ---- - -## Top-level directories - -| Path | Purpose | -|------|---------| -| `src/` | TypeScript source for main / preload / renderer / shared. | -| `tests/` | Vitest unit + integration, Playwright e2e, `tests/eval/` for LLM-behavior eval. | -| `assets/` | App icons, tray icons, and macOS entitlements. Referenced by `electron-builder.yml` and `src/main/index.ts` — must stay at repo root. | -| `builtin-skills/` | Agent skill bundles shipped with the app. Loaded at runtime from `process.cwd()` or `process.resourcesPath` (see `src/main/skills/runtime.ts`) and packaged by `electron-builder.yml`. Must stay at repo root. | -| `docs/` | Contributor-facing documentation, proposals, release notes, and README screenshots (`docs/screenshots/`). | -| `scripts/` | Build, release, and packaging Node scripts. | -| `landing/` | Marketing site (Next.js). Has its own `landing/public/screenshots/`, separate from `docs/screenshots/`. | -| `AgentCompany-Rust/` | Exploratory Rust port; see section below. | - -Agent runtime source of truth is the pinned `@mariozechner/*` npm dependency set in root `package.json` and `pnpm-lock.yaml`. Third-party reference snapshots live outside this repository. - ---- - -## AgentCompany-Rust - -The `AgentCompany-Rust/` directory is an exploratory parallel implementation of the runtime in Rust (GPUI-based desktop shell, SQLite storage, pi bridge). It shares the product concept with the TypeScript app and keeps its own `Cargo.toml` workspace, PRD, and progress notes under `AgentCompany-Rust/`. - -Current status: - -- TypeScript Electron app is the shipping product and the only target of the release pipeline (`pnpm build`, `pnpm release:*`). -- Rust workspace is experimental, not wired into CI, not packaged, not distributed. -- Schemas and runtime contracts are maintained independently; no cross-language codegen yet. - -Detailed design lives in `AgentCompany-Rust/PRD.md`. Positioning beyond "exploratory parallel implementation" is left to the Rust owner to document. - ---- - -## Scripts - -`package.json` scripts follow a `:` convention. Common entry points: - -| Script | Purpose | -|--------|---------| -| `pnpm dev` | Run the Electron app in dev mode (electron-vite). | -| `pnpm typecheck` | `tsc --noEmit` using the root `tsconfig.json`. | -| `pnpm lint` / `pnpm lint:fix` | ESLint across the repo; `:fix` auto-fixes. | -| `pnpm test` | Vitest unit + integration in one pass. | -| `pnpm test:unit` / `pnpm test:integration` / `pnpm test:e2e` | Individual test tiers. | -| `pnpm test:run` | Sequential unit → integration → e2e. | -| `pnpm build:verify` | `electron-vite build` only — no packaging. | -| `pnpm build` / `pnpm build:dir` / `pnpm build:current` | Full packaged build / unpackaged dir / current host platform. | -| `pnpm release:local` | Signed release pipeline — see `docs/release/local-r2.md`. | -| `pnpm release:cloudflare` / `pnpm release:boss` | Distribution pipelines. | -| `pnpm verify` | `typecheck && lint && test:unit && test:integration && test:e2e`. | -| `pnpm verify:release` | `verify && build:dir` — the full gate before a release. | - -Rules for adding scripts: - -- Use `group:subgroup` (`test:unit`, `build:dir`, `release:local`); avoid flat verbs like `checktypes`. -- `group` alone should do the useful-by-default thing for that group. -- `verify` is the CI-side aggregate; keep it in sync when adding a new tier. - ---- - -## Tech Stack - -| Layer | Tech | -|-------|------| -| Framework | Electron 39.8.0 | -| Language | TypeScript 5.9 | -| UI | React 19, Tailwind CSS 4, Framer Motion, Zustand | -| Build | electron-vite, Vite 7, electron-builder | -| Database | SQLite via `node:sqlite` (WAL) | -| Validation | Zod 4 | -| Agent runtime | `@mariozechner/pi-ai`, `@mariozechner/pi-agent-core`, `@mariozechner/pi-coding-agent` | -| Testing | Vitest, Playwright | - ---- - -## License - -[MIT](LICENSE) diff --git a/assets/entitlements.mac.plist b/assets/entitlements.mac.plist deleted file mode 100644 index ea3e9d2c..00000000 --- a/assets/entitlements.mac.plist +++ /dev/null @@ -1,18 +0,0 @@ - - - - - com.apple.security.cs.allow-jit - - com.apple.security.cs.allow-unsigned-executable-memory - - com.apple.security.cs.allow-dyld-environment-variables - - com.apple.security.network.client - - com.apple.security.network.server - - com.apple.security.files.user-selected.read-write - - - diff --git a/assets/icon-app.svg b/assets/icon-app.svg deleted file mode 100644 index 9bbff777..00000000 --- a/assets/icon-app.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/assets/icon.icns b/assets/icon.icns deleted file mode 100644 index 7c689cac555672300d632910022cf1a466b4bf17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151372 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

hBi{fhhWlvd2T8TtL=~GqX|ZD=S3z zc~%X87@4m5AE|t(@ux7H*U-Lxfn$meHX-`+N9%oeH3baWS=2jW;a@{>M_!Pkzc|78%QLA;G~k_Um0T+)D`)d(fRuL-~VRcRTVoI@RLy*Tgylv8u?_k;70{ z-Hy!CQdy8{F4@N6Y(=G>wvwTrND4A}^YGYOXKrRG4>XU17No5mHMrFf;lXL+&ipXI zesv|Qp-q@1Pt@FwRWlJ`!CLOl1x-)(B%lA5OU{+2S=Nx8c-P10@(OALt0up-q`jhBpOUb`b3Lq@FxPo!|q@G(pOTe~m?LLvjh>thj zeI54+G@&XxTx!MEB$U^=8)cMbMU&X}&_V$h`I36f@0Fl<=*Bg{^lT&PaL`x=yVJuJ z@$Pu;SQsi{)XhzDj&f~BTln?SVXONIiQh9LmgKqoJ&n=ATxhkLd7PwdV8gAOn@xG8 zUU(5$lz-{>!UBKP0Ns?8nBB<}crC1zIE?fohHp<(|aCn_A|_gY$^7P_r) z@&Y_NH)lTh&FzWo-TYDx4wQgUk_lc3hJ@sEa5x4Z9_}oBNRIo;tMRzrf0l0N~OfiNzE?(sm^r8C)E2%Jz6;?3d(P_WNW)@ z;_8amy`F#-EG|xq#nkI$3lCcuxqjpa(T|UhFM_Z@q0qYyqXuzMKS$!<(?>N~z*^<5 zcnMRG4NE9SS?ChGK$uV{5|A>zrJ7DY=@Puv*_F$5a#dhHQ*IJ_v1(a86_PzIO}XK& zg1WcA^UlYo@-yM3*{5(DzZwI@JgTxUUii1Xt03`wwx*+3muppof@w$7CnEm-yQV!_Z zwCtBz#kc`BaVB^x1O*Ol=;RQ$wGCKHQK>u?b}))X15GqTz;fK+@e@>-8(;LUg&=wU z@>utA`E~8bYolyxdisNK4>kHVJR(UyNQ(S_pIa2_fr738br@gDdR-fi_h=M>M{Uxy zCPtnnLQQs<**GDvRAcYLP1FTEFlu~X@khrPlYg2getRk-#RIM1BE!RS+pY%FAuZ^2 z6VGr{qJebN@gz>Tf+Brq;UvMVW2S$~HF9jkl(T@zW zyfnnYK}T(&k`m*M`6UgmXnAMJilyaw&58QW_D*}Md`N2x{lBvCe|dYqowCB4xI{!t zBt$URWk{0OYjxgQuGgpR~VWprYPxP6*p4P@_mzYk-PwZebH%HFHlSS!&v(4`M{q8 z^J!+-FOeyXYJkUqkEi>2dnCzr(I8@Palt)YCWes9X72qr&F?Vl<8X-kb?7K;Y$|~X zl}rmC!bN;;a8VGVhH?MQRh#@;kgH?Eop(cq54N@W(o&QJW&TdV?V3yLgJ?*W zLXkE0($X3f8bdhcmMc&9tEm*xcU=Y?#5&dz|MQTiBI}(6%7Lr5_>E}~if5jjk_&C} zH;`!8S-sD#D4q;;l6GW?i_ew7l)W3a)Zt(C4*$p+ZYR{h%|}g_6-cse@OZX( zT|Ce4|D*$+N}0PQCm}s#e*3ns>ExACJm0Q-SzbZ{dC?Y80mX4+yd$dkP(_y{U%=E_k;v6!IK%7h%KY_+ zce9nCjbdxAD!}RK4%xJh=zFS!8T5k|+aDdc%+jb*>y`auV4Is0=^BR>??fnr)R{t$ zcJ0}m5%*hLa4Pki)2GZvN6gX8W%lmsa93KUqV~L$y=>n#HrmwH%dUI)&%NjJdDhI7 zioh`Y);7gWKBmZJwmZYBcXjNS)sX{3He6Ux5Lh}?)!8ILpQ7M=K4}7ML%2z;{i+@c zO0-5J2cSf)x*w{2k;4Rhz>W@s0_-NJyuDoqO`>@ zhX+&^0_fW8u>Khueto>snj$wk1Z`z7&Nm#qK6;g&Y4DjF7q}LX zjb$>KucmaqIo1^v9H&*#T;EnwjBfS3zzJygC7!s%@@-8B!@9e>%fpnU#zVtV$1|8O zsjW?BeT5sBehzP);|k0| zERl&fih+*&f12CsS#R$dhn*s&X`W9Fwzd8Q9ME;vu#V6x9A;Ep`Mq`zp;A8#wO22n zH7Tj;m+w)%oZW1Qx1n{NLEG%dq2U3X=x%6mX#ahL&q1#+e_06yKkg&e|38>vap1oA ze`XkB?X(60p(y?zGn{>pqBTn#k?%6z*_?53YC;r=k~Bzep&?GJ#cSDvzSxI>@#`}| zoPQAuv&s%-Bqwt*wiXIDKAJ?X#`_^Kb*TXq7C%b66a`%Y`7@$Tn*+PYM8vWSXNmSy z*1;*AGh}z!b^TWOxvTruW6fny*D@FXoX4ns4(5+{E~5Go=u4+6T)7*l(WngOk6@r) z%?#)ZxpwTsWuYU^8=xp>3zLLi)zxY zO?H-m3*x;m1#<ihtg)9XwY5(hUrPDNQk!(u4PCu6pS9 zxcrn+r46e@Yj&&v0z{vgr9ZQ0D~Nc!(V7e;BWrJL)L+E$VZbo)(8+~`k=@^XxOZQZ9aMQN%9+y{@T=9 z=z)9pbSVmgLd)P_$CT=$B5UNE(`TMD3PI&}Sp&DvknAD|=wCZKR`y0c7BiMx3kacD zR&Aw-BqFCZc7U3#5 zI1%9Qu}GmqAvp*m&-^n>;Pdac;QLF$4Z*P58y@nC)V&N$TUvq`>d+o;m1^DEKzgMQ z9G2tSnWef;J_cSO$qjytTyi@mw(uiw&%A_EMj!~^&Go=Y0@^pc!QdSzzz-%|<_ee2iwaZ&y$1&x~5ni#ShvPKZYdUY^dD z{+o1{UWC2(tOReiu-?FmGb`|ZwK$mmn#pnDYugSEw5Rhrn~3n-3?uw$J`FE{^<|(m zjxL#)Y&eRSIkczF?%j2q?Mf}h%r6~jv^TIlm%fLGhx^C;7C!w_38s%X&4a~+&0 zz}NPdr4{yFAC8=@do3YcX!oEL5t*2JoJin|J=Y>)30Bjw6sr4Z`!QjxACW5Oh9FbW z;vL@_$K*6!cIoDVjJxn(E7yI%-C{LZ==)|zb}){C~32= zecmK*sn)iS*=T#)Mp0I5#?@r^>H)%%{ItwlESFH)=tdiKMz!;upvmu%7B2>YTZJ}* ztJV3&_Cu8(To5@i9dp03Zlg28PxE)#Xq_)ZU!PujV7NtyErRyaKeo9tr!W{w7pgM_ zG=&2gy6r5G&aOY&aT1!b&I7r*se zY)!Mhal@;do1!D{s{l2TXEZi8wqIF3=*NARjo9vTwG4k{)y zJrK4?(nfUX&@OsJi;BB{i{Nz?F|4Y?}MNWUj(vU6E~#*{8Zp?0jqDemSB=c&-a zXr;$M?h!{liq<3X%!|?Fr0~1q6n#3U-MS#cT0`-BI4HZi&iz(%Mz?62{_)qR`D(_I zn_E+&O;&L}oQ7t*zIxkWDyo#9=PNGVnVd{D9%-$N0Tw0uZL_>ucf5E2D9tfN4Vi zjI*@!obxX$b#~KPNdV5pxBFk2CI6&5aLo=0@XTV zDR`*Q`HwD!gks<#ABlOkI{#T(fy=P$Ndc z+!1%69+LXebtBR_d$ax--OiW_;8p(L=4%3h+kyYNp#7pIV;~Sd%KvdebFEWTXLE-F z&NOY#T;EKx7O}!6X^V%|D$NAiqRY>)c226~Y!Bq{XAz5i=FH-{H2J)xAQ@>J6d0P- z0z!!-LQn`MD#npE{X@i;DAQKamhO>@>ClO=a7|E!4S}qCkAKJXQ+1oIx)r@`eSKVc zeKsz%oXBJFY9TN!B~6t3oWvM7_W$kArZ+4Qvs$j)Pn^F2bLaG+JD)2aquTk7>+R^%Cetxi+F=f6-|>QAF5F-%V9lD_kc;H ztUbHh&=_V=23t)p&P`HM=uaQ?i8GVI__eHtTA}D@3uYc$91Ff^il}+T8C5Brb!ZaG zq!_A@!ocOUrGp$MDWB{^5#!@;4Vz3iwMOxIvA!hLtsPq?$}F3qXxrp>_AF62GC0eA z*DYkDbf!0$s^Ca4C@^1&U0AMW&2Lf*K?4s*qOkYsK)b`~FJ14aNqmXI3Ow=T%98ay zgv*1OTLLZma3;NCLv3x}7uYXf2(V%Xv1B}iNj#oL;kgaVYHK4)OA(dd%VE7$=$zd| z$~snQZLR$BtZS7WKCIsp`0}iwb&V3X4{=0*Ic^OA!q(V)4s7kHZ#=#%ETf#R z{rEO8I#?ih*VTg7R&0%{Py2>qZD*`)!Z6Yr-#R;UlV~HjD%wa?VrYIIoUEyh=lw9~ zJ^C}G+=mYzIcUnwUD>zCF8yA6_;$2jS(xCTHSdF7xAhU6PQ%yQt~0?QURhogk)Vm3 z^52q%2Ql6AUkoX{Jj^#E-}!mbGR;#f;B4NwAEwW0>bb*3<9Ng#tIUXFNmKY7BQGs4 zC(+#tHuG}r*MF$BdqfP8z@QYApBP=U$_~y929;XVC{T>&J%>i6luj)zMYE3GGgD;% z4cggJe<65VpmX+>ZF%10inJ}B$xFA}pZ2W#6-G3F0zVhi@FNTet$({U<)4C&P27-~vf5C8hU&9fohco_(J#))(t7NCyXH_S^giec&Yky3u7u#qVIM zSSY&4l^MrX0Cu72?4QIRRU=#58T(v0eC&=&5LFa;IGOM{?+qyQa-*%PvNL3Hs2#%w z!2`@y39vh<Porzqowh`6n=eppVFmVSl-$h&<_mdO(Er{%6< z*|=|Cc9q9&+=!~YO|Kl5o|J}1jFaj5Hr+o|mjk4D5wJkIEsp*)4z)Jr;u*B!tOR9s zCitSpLB%IF*$hTC`Imd5pU2XTHMF!cov+?ROIlc{eW?5xUO3FDlDj*Ljz{3`8&F*| zhSk&LhlD{UuJT*bRm6REs@v^|_vNPf_WbdgSuQ|dpOl9OwfuM%Q#-DhMZ=zyHyQ#V zZfJCi`&jVbt2(STCEprgXHD{&cKz9_2q)^SFFyb|D$V%MDl<&X%qDK{{b>A-r?Y~1 z*i;OMn2&Mbq?HB23Dy<+|za@2_h-{?6$;V1wbwRzo2JIda{@O5Zxu&`Ei5!SI^ZIF&@bN=h!c zjyne?QhZqSm~6k}katE-X2mn80@>zO;;zZ-{n#U_kL2s~8S_^L^VM<+3JT0lyXh1{ zC8-%yvPW_~;?Fi{tCzWCSe$#tBE}A-y78Z>S>W?5hL}n z5NR*-XW0%Thb=sHxdqYSjSX5WNc4oUycradGeI%Fn$DP*dXz59+N%02YB--HB7s5X z8E!UgR9ahGE48;I+6P1xnViKaDk>+m^2wov!@3<-*l>twR3ve`m7J+F@QHL$O`!(s zNs`s<5lqoU;X`e1N91yqC$!u=bI@yqsfItI!T7F2%*<7v?*HobZQkS<;_Pz6fRy{c zm9!#DI5zpY84g3y|F+Xc2)N$K$Sw2XL^&T-!2yyZp+^aW!}6)T(m+Gb!s2wPUqA_@ zfrs4O?DBX549YCL*r30p^U3XKPRRa1FFW`edjBxmrV*2 z!ftv(5*|b~0#MAm_#1jsGu)%2qc}}9KMeHsyF}ejpN!Z1ZdV)hy8v$A^th#6J#C+G zX(fpcStX9cOcvj4D3*b2oZN?>PcKV+`X<-#cY%I)@`q{>3d}mINH+au0sDuAk2BMu zRPwKr8XOf(;sB%Ty`?Cu7HAVRKH6A)AnzR5>2v${;b{0hfiI3sk|Y1GOwML5zlT+; zFWK7~{Vgm4bPAI5rmP=p1ACj-6zOn&BAYQ;f&r*x&P}w@z~Mv#)F~i~A3E=3L?DAL zqha->5|AMN>P?lIo})`Z=p0w9dPIc^)U^zTM$_D+X%1r4%~74hLA-j^H1ip@>$GG7 zf7_+I*3-@!eM7+^Nb93d2$xfhfTWu2dv=6%xLz@}dz?t#zzh1$?bIHdgtfKldEcI@ z2%q{A@#rVw!ruuy+le>?0a{%MIj~)i+@ZxwD}<2y!2{VoI(EYG{E|9rbg_q9fb0Cz zAW>w8>2bF9)hB~>H0pRWhg#fnd#TG zO8skRglA!~OH?)AKYv~LCbamZ0>ZM|=2l#1Qc?^+98Fv4Ih68sAo|oTx2T8)gIw^} zS->p~g@ZRf2uAr$1rye}rCUi-B}30%l8xa!whX(F`|)-^rkJbn!OR@NR-V8QVh%?u zMao_dG;_5?9b>;R0A5r}<4}VGA=biwM~2LobAWCjB%3#!&`e&tFCT_sbyfZi%V6}z z4%66txrTzCNLfS@y`Ku}d}d_@{P_!IFG&?_gt4&mpr-1)TXanHLh~!JYK|v*0$*pV z`3`9`a*6`gtR^>U;w=1rtO4A9TM*sj;*UM%HGZ#Y&UrCB6i&B8^PyPc2#Bnv>=kdX zYVHGSk>?Hq4v_UBK&f-;{|qmoc=Wh@bDsKrhKSFetWe#3sef_42wsqOp4VJga(>Hp zY#)BIMcOAInWQ$xW_%Gu6=s!=t1$ z@tF+s3ffaF5|5Nkn3Ck_bn`^@6Vu@LD**t+ZujpmHLp!S6p1dXZTk+h2vz&qX5ry| zw$_QW+(E8gP+JgqlJJrplb<(u!M}9>&%{rTWCT zTZ}Rw4GsxIkVI_CDz#85g2Q2Lr9m|K**{RDSdK=4e9vo!8_2kJJl`xo?eZm1D|R&~ zNgkmENuEs8U$q}FnAZIXvMo(?gRkB3K3=F(J_$8I4IU`{t&fAm^PW@;aH-SYWV~1Z zc(_k%@bX;x-FZIOLsNH=%c8B>gy`6d-9!q2UJU0e+dST!EJs*0D$P8Ab$kPahvHU!IDbG`rcB5?gM))% zU#<>q0L~Rt7vq~Yj7BO4dfdYU{)(fN3=P%sHeBn_2n#ITj`s-G?!?!O57lhY;r^Qw zA%4Gy2D2_>8yixKtC&69*&cSX@f3D^76h8G$QQV^)8GCe<_ zo4-7H>86R~X#X1~ous(sC#o|tzF0Te8rOrS3&0@HAoqG=q9h`YvKzJX8Zc(amPT(kO-Zd*^y z;ZZR;f0!~LxciCTEeWZXTr!LDWnb*>K#gKI%kt*$sn8h^yu65WQq)}f^){tg8oo;n!Z#ApEqBQ0m0TW{M4l2;3*Ft7Ru|trq4nLz^;hZ(D^ktqRbkR_ zWNqyqo+sB(JpPpnOSeQ>COpK-t)!BYlB=@-R6taVzt`oB8u_Vj9T*5k>HgSrJYJv# z>Nxh#MVh9Ce*|FC%EhVp2pi73`MyXRdA?9x60)iu=o&bf$HA6E6urCz(68TcqN7v) zmP!?o$P+ndt?Bs7h=MBU9*tgsQ7i4`#mB(IS;B*j<87IMCsB874B>(OQuleE8bSXP{!G zpY0i`_}ljr8@3tOIfsQm2f&JxtISj?QA;O%;*d|ESQYSlKwG~X;zMq1r1?qCwymVP zW)O}+o?MR+Sbc;?Nch9%mST z@uy$W4d*XBVaa?BFgwos3R96pY7l3*f#ivd2Gg52&^SKTdYjv~bc^}#Jk+)EQBah0 zTTNTdipp4(LM2W7AAaN;yQRphre7dX2VFjPS!8tK=Wdl)VE)CY9Tz zoC*{?veej3Me#a30R@5|)-mDhKcYR#2Q$l2d5w*?(`9P;sZn{^rSCO0f0-qS^nPVb zfL@oZv&?DX2NWcRhiea*=ASVwWyHnef-2qWwUd-w$wb_<=al3UYJsULDgy2+odV!S z(kVn1?cc$I5m7y#uc5x)o4CSx@kYV9`(9?ZMy$G;(99K+GvlY*SK(NyZ#C3b8JW8E zp4iWiw-Z)TS+O|ccvXrk9&1iWDP_uT4Sp&!icNpq($4(PsJT_tig92G*_)hCR|J4! zCFHQaj7~|N4j{o8Ic%0A=oW1@{1Qo3YDBOUm4|*k9+lTt{a#ORbUgQU71yuHrBAtIu?gG~u%qq=^=kbyi@3!Ce3BQXFvl`Fa2A;N=8m zQBl##6ixgf;AC)QFuyOI?0k&7^XuAHt+&oxIP&V}z=o&JauT+h6n7Q5PI@ae<;K&lyR*LFree!8mRAf;b(CO6$FART3v< zkC7-k(PaL*=q;G@8ZGiq5}?b&k84#OM`(hN>=I3K&jvDfeSknR?j+^nPg zsuJs%dl+GLNuYbqntgUQS$5-?H&NCQ&S6-_gHB#M8r+ByO)XR(^ zTPyd8@>g0#vBW+|?@N{4V*w($SYMa8{Z{z*{AoL;M)HNHAF~jzuIXnt5qkPTVrI@1 zY=AHU!nk7N?ymro{1cy0P>;NZ{&)%J=4^dzYw&iO0t0$kl2?460;(&roE9Fh3^;Zfvw>Oc}MR#!Hdw-9&r#H%fYvJ8toZW!+~LE&znW=1DuA-or!z7Ru}J zpcAM>GH6C+u6|?@$CG($WV`e7*e%ih6$$%`&_ouO<^5$8E`S)+7!*%z4&BeZ{@r54 zcqOFx?rswhVh`vgp+WO{U1d{x{>%1WM@qTqmbALc3=jr`j@O>?d~Q$87HUnDv+uNJ z<46?NyZpfLa3l5ko3!BqBv1>(aK79 z&t1}+U*KlAYaV6rh;FkOGyg7hdKKNOk zB1?n^~0~J&u2gK&mQy6?$4hR-h0Qn+k3_Aq_%oiw{v~MQOE_J&q!8$=h4h%8TCD?R?2cWD^ z%y&=U%E}5f>_qOTD=j1myYY!AJgA6?iH%uSMTMu$;|xP1bp+E9iw=YlW}!P^>J&>R zKo%B;x`AnK^7}9iC=S{9_@Kv+;644{eJH0^Y6f*?7Mw~N7K%1C*16P&)c7vpqFgE% zM=G>_swDYO01?W>ya>|9r;bLBrQpIqMJ1#n!$=|Az>)`%f&Z&FVPersI2Cyi$H4^= zfzY~Mu2rz$gPIV?VUYv-KM{#1({1nW7D4LCvKc~5K01=2D#V&BH4tYCS@QO6g8AdS zC=M`0Od@*g$$+Y;e>9myNQ8vqP;aTSn6`Frt?<7FKM^6~p~?pUU4}y-=l8zlRaN1o z-zOb?#uA|XBbsO~d%uSptlwirNs|l)$*b)j2!erPiAk)X4lfr@|0ijA(_^I>Um1;_ zOMBlFn?`lKuy-)l7|4MsliZGEF>P&Fpz6ha_F<>Q9scyUy3tP1A!?GiX;!MZLdK(i z1^WCrz1u%iI4p0-Ml_GB_5JGUdQUEj+aP2>)(ZZAPXQaj`lh_k$^LQI=eB3OngYE++>6ak-R3(;-W|`P=qR7 z+(4gMJ^9`ZJ*Nf>1$b0WmIXz#3)0MFePb{3UtM@CDgd$H1P0)0x5YKwI{jp z#gCf*n(Ky-oeY;J(I(=_EMX{f$%CfxL~fP?5m0wcju()B5Bci{ClQeG+7fYVKaQ@# z71>C@CYD-dBgRA3bx2`*GOO=wV($P>9BJ6eRg&X36^y(Tuq|{ry??&H=dhVO_5oT@ zw719b%qyGTv_?c0Co$D}tg5O)9BwaU+O2pb;sP}f!$|<|@d16uF4wIm{Yx3+37Dw) ziFu#R;NS#uOC>xrsB3E@=CgwpaM=9vI5!w^F0?{34SHOIf!TAIc84IMOHYMgtEYWK zFYc}e=~Nqqv5wJ!{_D?4=te)(UZ9goL1B!&vTpbF4yyKDQk_H+Hj#k?4Ne1Z>W3w! z$W4V}RrK@PkqgYmvGI7Yh3-3;88o2pATwRy995-WBhE9@wiI5~use@R2o*R|=ICO) z-4ZZ6z^MN{C-DIf9+tTL`}g2dW)9rPPF#Q*a<=dA*+m=A7sG5`Rza8g@3}zemEJ2V z;rQ_W6qG8;NuT9zpIs>A`4N+bBH?{|Eq5q975XGMy6}X4{PWsh0pjoxIrsBX}K@$YF~z#K@^(_WOXmqZN1fRI!{1kV92B_nAA0E(#=k;&t-T@DPH>A~KAYBFr3e;*N?^vprVPk;H+a{~UNw_yN7$CA;&Li=36@NL-t z#B(#Y@im71v_A^hfrb`~m0q>6BWPK1Uw5ll41U^ z34nsI?~x4QfJug51kcXSa=$FH4DAPedR2PZ&&TFyyxHT&Xttk)cKcnDe*D-1y1q6M z6r21B%vEyV<`w)|IY0bh=JNu<;|~Ao{p)N^fTcIDNdxr}kT>bNX%y7bvifdC+h+k)K8E=k;}F2(SN_UNp28>=C{HIT zIT=;RI3qJ@)~yjsE<_MRz+TUGGv-8wr`y2&02j#m28-~cBR$!9{@f*^?q!&ud=H%PPZsz!STObMq-=A{KCy(BQ=B|l`IYau3ke! z1E?*Qg`HF=ESpBy;3r73LL*gDN=#c_O<$-1rUxBK(s9}z0ggTf6mtrg36>HM(TxQ| z`O6`Z$;mWVXX}(dzlmsA^cl&61O>d0btKO^jDToXWzheG_?btgw7&e)=xSdzm=wA zBqJ+3d9_a&C(CKSLd2@qK=hYYc-(l48de#ARvJk}8gtRy5v}C29)Gb5c3vm0L z$Vf=~J~nt_qsYdF)9LZe;K>Ay?eqgAI#5DQ4Ii>A8_=IgmYko^cr>@tpJ`rT&GN;j zV)OETKS!MLUkk+$k`;RxH@CKSdpTWEKiJ+ak8U4ul=O5%fn$#7^Lk4iysoYXAA>-A z7~K$u{gd=B0CLdLxl#9(6G5(;|KTw}J#ujXr~C9xyCD!s$9u=!)tQB62eDuYm+@{B z<=vf~!pcfK2uo1saO1%q{zqE~Y7n%%^P^=jd_hW4`w_|E7pYIWKBnE-r9meAPcOY} z;E4VW6%>?VCo6D7o&74w)qxOJawfAU*NkKD>fdo;L+o2Qzq7D-uEi}aVKow; zNduFRMDq~QGF+@|w?|ZY-^(Ek(00*BeD**B{C$2gX$m?}V~C9sp75oP^LxI4{HKHZ z5+ac=cqMQ`$XD=!#Nq9tuKQS(y6q&<=yk^0vs5h|cgJUY7XvA3v{r@FH4unn`|5(0 z4tjyx&^NlM^ZVfPN)|a`do^ONK9YY8csCla8czKB6~-E!UN#0P4YWWwUbyFYYuE;# zF=jCuITQC2{P}lI5D?inFJ*4?V?dJs*&`s4Nd?rUu^|W&;RLDzT)jMl%+={CsRgOh z)k4kSTVOGJ>06whm*|Bb_U++eVP=ZO`uF4HY>p&9ee9YY`ewvU7iBLXqM@f5D<8Vm zOOB2#&e+HQq5a=-pK@UpS^0%(;UTc@4ME#Ipv4KI!NX8ak%yz9ZGKi()=<_gE(YT8 zuu{eH@`cDe5g*A0lW?g_003~Qft9Y;+pAtjEgtls^Tl0m7PDoJ8m@mhrqeP+&RE9O z<+W6ue82*e0I^=0gJoX>cx8*75V<}rU3R>ZX7iJ9kf>Xjp6 z({N|s2_mu^IqePrf2gUmS3XoiMrh=jO-EDc69lvfzTa@(tQ*2sXPie!#bCBj@78V& z#k4Y2PEVuZ;zCLu^oD00lf;1%34CECc+2`tN|GE5Oc*#qDBXt*9BRb{GDKl?dYCW! zJ6#?8j-SL-a|PqXdmOy4)EH9sXUZ@~6_pAg$!zQu)Us}F)aM=I7aJJ=v!{gG95B-qEjVS;j!x-1QNUh|7R|oRhypX zmlW(|Z!IgFhH~kO8>P8!(^J+%%(u;3O#8aj_W5RdTEN5M496g~j^Xs$+Z%Hxiy>t1 zYpFBCj+3<}m>i#6Jr)0$F2S1K^L)FWFk7J`rGe8F`|>sevus^3sz1V**YF%}QqC%2 zI2Uqblfdc4_|NM_22O&&{`_|T03Rx_Z|_0HItHAwDe9=i>-}Y)D1D^DO@s*QH@)1o zOUGCtD*Ofz2By>7%uPfo9*-iB5ZKc*&1{4OZPsDkif4^(RIJgvxePy}V#)X8AStM}YYj>;RK=)TIL3365A>oLE zbbpKhlmHDqcppp;5_!LZmrc7_kNN=0AxKT^S!l(+`9Mmn&XcS^d^JJ4;)7&T6=@2a z#2Iw~m6l;tWo0EVA-N==7;uxTZV7g$-ZN5S?G*lhwhAc;>OP|F?2sm5A0sM!$vGKf*vrIf*hYl@4`Qv5@)KJ_Hn*+>50PH7N17pC6x0txLwcRyq|YOT8O)g<=KU%kN%aC9JYX+y&iUXR>80eMq0{pOQEs?3R5(ya!Q zXTht(Sq}athH{tyY*L=;m@QUoH|9ev;)p;JDH1=)r*x4@IGFxsr zm+Y&>SUOF>h@-q|hm@ulaAq*w^kZ!S7A~V|0R^lb+UlZvpW{60ztwx==J9N_>Z%v) zzds!Fo^gGkqJ}~NA>dcsOB?5bj2$W9@B@`Aj;$Sl=ONKRO|Gy)juYrE=`jy2FRz_2 zCsTdOCJ3cbf(CVJlcog0V5p!(&yN)hCVG|QCGO@4At4J?lwN;#mzxU|0 ztm$fMIf|=W&rR3}4^tJB6$u7PqfAd%yzD3*?U;cHYRjai;{n8?zdS=#8Z~V;u>Itd ztJh@9E7wB{XKAROhu_Pv!FO!44;j+Ph3Y);8HDvK0w}JB^J(G}Mt&L%CglHMq8Wh> zWcSO?!w>my1m41b!(?<93sV!l|D##;`jIt0coX4ctEmjj&9YY)j<@hf0Gbe-o!cbp z3*~4oWCSN>RDrXDVe?0goHwZ8VAMJ*5eolpjhXLa;)H>o!r`OQabR=vM*ZXF5~A4< zq&>n~=4kM!<`rf*p*u>v zN3U^xWra*jN0*O*M+I&e83=XxefL4|8Lh=59#Vv=1a4oyu%_`db^&faY2lfL(mx@= z5(c(v2;6CLuO{4!J+HB#yhm)A52>U=)${Uqn2l zpP-$-m+dJPJiWAs?{XKO8(+yo2dwHk)-+TsG%hFVgUia~^D=zS>?Me?j#Y>dXl5(&tS-DzTb$2ZgWPQ3r5zRt?JvGYnG zULOR}j_7NHxA&36%#|OXY=c}lj4dpHdkL}r+g34PM+Av+&*p(2u>bRIP)pyBLyRMy z-ZqA|Q)eS+G|GGu3aBkS&fYbdneL?OC9=Kt5Zw@a@V=6#iw&$RpNS*kc#kKwL^Ml z7rCVG-~ErtnWc&P;t4wg@;Lm#8ajJW4CMP!C}u&m5N6=+kHOdbasy!0<4R3Kx9oCQ zdAUOC{=uEQOw&r)wL|s_uyu0VpYDuNHa_PMl2Xht^h4*dGf3rvf zsj?LY{Lws)%8|(VDiylj>&C8x5g|A)YkKniyKU*e-NAy8<|?*(FYkbd39eOKW#=Rp zX_$?(ZmcovYLV%FKVy>1Pr%?+zVG*&4bu{R43m736jLN|p5biTk|iscm|q6u0dnhv zXJ_rIFeo5nL0LFOiQ8d)hKBj-EOW5l=t0fk0Wrs*(S^pIaQmBV>f}YiKO5uOPY*n| zdjE%_x-`qUq|IJllLzAk^!b2oGW58AbVDH!Mgxz1~-?(RCfyiO{ z@@3e>BAz}windcMaVtby=`_kvFZEDvB;+|WRkA9P_oidJ*8~~BTRNb@vAJN4YF!Q2 z#TAm1H7H!b)Z(@K+13_bB*v+xaK=~gS^azB&{o%7PJo^Gfj!{~)u-26=@;7Z z)jT!m#cF}o;!**$k9{wgG8j8%eP#djm!R}RlYTmU4PZ?Dz1IeGM?erED5qGk0-+2u z@lsDORRY;cWo~69mT8y@`ONv%mKz*f!iYFJ)OYCog}^5Z;M7T~APk^|Y+ELfwZ%9L zbCoYNJoz_PLfhN#JApv3ZR;*v5mz0nTX5=eW?`qzSR%k+^BBVDC+%f<#)hXMl52ph-p`PQi~;X>!i{@iph z4&NJgtCW>-oQI9OSE9bYrTFvbu~et^2djT&_8>;BCh*k)*W#)3j^>v#*cLva{}RV5 z@SMt`zL|>aIs<<(xT_;N5iW*-&32_a*5Ks!1%a!RRr{|AVrsoKz0rFUhjxw^FWSm; zt))b$U~h}ccSwh0HJ5|iuIm)zWNd@2DLF{hsLJpD$gq2QsU9a2%>K{)4HJXK4#Le2sPS(U`SP_nN6^(ZQIvc%bOxZoGS+IgV6**Q6i; zk!-RzFQyA>CNLj#Wq^^a_BZnoOcEqTf5?>aNPNpne@tYOEQ~k{2NZ$qmub(QXf~k` zzU|W!Z#Afw8HQaADyW6ok+p7hjl-)#H0P{HsbOZUO~aE%hj?zy;IhlNzY>adzUX%`Mf~paQ?S6ypYQ#ogR*Jgw z%+h6yti_Sgt53T{&8W!)&=FKEWNf{qot z`1YX+KqhnIIxatpVoIOw@$KRlu*Ud*-i>xLEeCODMFR=NnYwL{=+sU8Qn8M?&D3;> zGqR@Or@f=1a4{A&G#zNmA4c4vgl^B5km=c(>5Rg56Eh+J8P6U+ZK(@SV$RmB<~8Ol0ZUSIf~*hJVVds~@0!##1D|HRAr_(Sx*8 zciY!gu~5OiUSy(l@>PPix(2h+o%^k8xJMS3!36^&n-ge~X-$3$bYSnzKjL#ib=v zrQsHM69Ftj=+0Ba-Lv>8EI)jkMR2=o$$&@p*`HJMGRJ)jZ!nNQ;(BK&fj=U>OB-Sd zBOYMzm}nE27jG<^aI8~zY@u=b67YB8}`<=-N9){agYSvr~$M14;6Q`zp z7-*>(;))gh=8aB|u^O1~7SC!65RA~!0}h6p3P^|A&(g4`dlnY&vsvk=LYO`iiFB$5 zKe%Dc?u2VV`shTIS5-`SEc_#^%0N)~_yzFryQ&Xl zle{N`A3r@9f6Q!};>K55*|mKnuAsmJI0ob*2ApgwzFVrM z6=ha7pg{agqs1I@xE`Yw=hzosPY%$N7s=*RmV;n5=TLA~LJArUogK|KMz`Hhh)FQ&d)B0b#s}#%83furLKm`cjq$ zh13EUdv-}kgg3xvJESn=ZVB0=ykmx!|EUbxHYizZj(T6F1!#Gbn|)xhR4u@swK@Ii zxt#bQRYfq3aq)P=!cwm1uBy)V{1wSTvj6NMs)G`A>32BT9NShwhU3(S>Si17gDx`V zlXJG}k^{oK($79gQgs$I-la{F_np7G4ZQuso4V<{&z8Nw^fw-0r0&AKGwz;0 zuFeF|oU>d~)DcTB5M~b6F}WT(BQuIej^XrPl?BTKd_%H<69?v|EQH~3dmmxS-qs{? z{%u(b(2JWdB~s|X8@L&?aJ;J^8ZXQ6>LdbPRE|gTJbhXz(!ZQx(kBfkHRc|lc3ows zB?ZwQ$P3+Ae_DxWJ1$gg3V|_dUTiCmji30+Zawl?c`G5me@<89#HP%_m!EoPE^Y-u znNmWuo@5M`_ceH}$)N=Ah*_YzPo?qu3Hb|W{FTY z%3m8wG}`HhlCBk*uXi1Jsmdv2qRm!tL7Y$OKbv`RMMa0lyU7txiNA}B%7NShyt4wp zz#H-E>~MP9mV31{fAde1iLGs7v94qAqEF<4J46+?F!ANt@vO$NI%PM4BA>boQ=Exs zl$<% zlwvCWx{q2DqSGqRA0snxbKSfrHv{>Xjst+>A_*4^SVMXi%_fce{gpq78`3tI@d~a3 z0Xw90YFgDzT%Rii;e&SHg6LLHQLlli<18e@pf+IMIMwx(Xr-ZRx~l`>H@^bx5FM~w zpRE$Ped8au$=l;@Zz=%YbCqWHv}U&RkB|yzHQpgCHP}RLSGs8AT1nVH!g5^SUI)4i zm*aNu+Yt%C5gB2f^(jzW(3_eclMlo=FoQ*p!-a%lhB@wp!-&(;$w)bjgF=z$Casl5LDVR~Tqc3-0HwVO9FOrb}j zSFscPzYq(gKWm9#|JgmWlACH`cPtk&<$2O1)gnE9huneMr2mvr5%6t)!6{|=v5Q_f zCk88UnyT>Y5o%!|jKtEFb*D`H40Iw`8&ZnI%m58o- zxBlJlRW&x@CsC6_XKV7MqBX%9dXGjO)4tbJJM0tyMR#&eAnYVPhK)kBlD2K62KN3a ztbmtv(!}E|sC(nD&GM=_Jt`Q$GEq(^+}UPXrFVkz0-MQW?O{^sH*KTX)Q_d=8$KD4 zvWuSbUu5FZ#C@FHdnfd8=&9<33*BBSoHG4#)KL&10bjdS({d~G|ZLbi&Q&gQ06b@Hx>~W0Imt6d^QhOZBx8|Gk*VMry-v# z$i#CKQ>aCn+jH$)V!h3+=l$(h=dmw4^q>N8-?V$Jc56c$h%@2Gy?x<9ZyyMD$MFCcT2#sv!tfhqCY?KZ^YdZ{ zgi+kclUyJ%58Vc}3%@abWMXa(@{td7lusn>wjfh^sNcWvGoOB;e00sqjIhAt%>MR+ zl=sMcz3qr;p<3x^K$(M4*m-!}BJthmt@K~%W{0F{066geq}_~;9L)J69LQ~fXi#=> zA`kstcm!40-mT6{IPER!!9u~mh)0}o| zoL-u*3u&^WR!pMlXM~_`{f#nKr_e?y5|tgs8hEfXNE*N)-Ph59_@G+``F((<7aI!; z+772p;Ff79xn!#AGIdqU^#vySxiIDO{_?GdLRn9m?9WjFIfjA5B)5=kZ z=#Du+YVKk+@&NlEfdR`~0GD|hu0b0WS5)pD^g<3F#X2ikjI87!-g!W#IDi^CR zV&9S%r*_1g1XX*Y)H{~xH{hu$el%NV?7J~_$gAG5!&hzB7SF_^j*Vf;U)WpfFR!VI zlh9|Ur2^ZM$H&JZD9cH26`|45GkskRMw{9(x45vib(zuLYf7QEN^owMoEqyTw3FEBb{CKCWX{(U$N4IM|Z0G~kn2P&AdJF)R0xSQEMv# zoBgw?tu(ulZW(fW{ zgc;6{|9DK3Il(Z;mT9W3+TwEc+xtT<{(pjh^d4C>WrXIsMaMp0{;)@0xHRPREw^)j$3^ZEsv=z4ujG{EEayKV7ffT6=zS${>86VZ0_sOk@AS%=Y2q{bQ6o z@4x1JG(-GvUIzOghBH){_m2c-Fz+9e&3XUL7$m^^hY{!h2Km1|`9C@Nzq`ZypDJMf zPd)NXM#iDCXv2-lFbyX~$Z~Xer$4IuTXKEPk!IM9vFc(XnG$o ze|&u%Et$0IrI+J4h8eC%mUCuQRM5(<-gK>Vqn^Qr8DBZ$0O6 zb3@3Ig}d5sOHJZqIP1*uV}_%<$E6OpC(%8r<_Yz8J@A&25WO{7TPIG=*f`j!E9pV? zhmBpon9$f@D)-UNbOqawLu}vO z-+S^L!>Eccz;EVvL=psJb!LX(zoY5tTpgeP{%VEi z=bRWeChdBB@$&f_b`^z*+@zTcvNPXR`&6&hWw~OH)8v!lOO`AVSc|QjLK~m3uE`*F zXUVe>7M)w0D^vW=PRKspV26#$wZyL(v)w&(jeIJ5Usk^uQ}7mZnAyg@rFMc}+Baaa zWQieMEL;noWLt%7y5vW5I|Ods1{IyQKiT0_c?9XrG)wrez`V7V#mqRp>wI;e872$R|RVE3fg69uS~WTn;_}s^VP1)ZDs4<^EbM%v}^XXH2E#^o95lScTd;jz3b0J@x>{cWoAMQ zW5QlW{@rg9j_us}LeI7NuUQYtEjxL#$Z>DOj%gnYd=oxw0} ztUP+2J%8S>JI&;^r@#Nsyuz^PO1$vo0=p$I!d7g)ve@o!=qx^uv+Ui+W_0sDhqE5v zB4lTM=FGa%n|Br-`MsW$K#Mi|y`A4K7nj`GtkLY1e%WlwCfD&8u0xjOQDFSY&XfsH zqV~SKztFWrjoz8bz7lchhpFS==6}fwPb_(&R4IZB!EW-J7vVF?bhwfB?;mO%?ix-n z#pGZx4qs)8on&3kh1Z4Ln9is|QAtP}t5x`icbvy<-ED1B&f)tPwK05KiUNL{LWe0^ zkzg@6FZXg(=zjg@&xclyz-QR?2Fc8wd-2&bwPvsAE6Z(fB=3H!r;Hcu=s0V3w6?bT zhWN#X>Pq4W^o%aYheCu?=v*A`Ej_SH8@o^`;uILV!VnwGer-JawMi2uh)Fy@RVh*- zzBKj8i(tR&^kM+};+_4LIqPz~rzI=I8Ea}@f0muS+Zq>o8ts(H+=*>=k|sgrv0L*x z_FJ+ej%G(Ji?816_-^mf6ot5L_HoMgCc_zyCOh7&2h;!cn&FQ6|89O~M?+0whq`(6 z@9%}qFKn8zO+ID2+~Z+y#(7XoK}d@2g@$0^@E{$PLC z>TM3m{q|NNMd9fU-3ZTxwjW*C&CkS(ob&aK4O)*6|4LSPI!Dqv%o%FC+?+;~7(afz zI3!M4ET-#E`u2y;%{OStlh`SqrM;@lzJRx6C6C0>TL$b~L(@#-hjg#46dAW*Z{?QO zPB%J#VfOrmF3Y=LO}4AhQ5Ks$MbTb-ji*2f&C-P=hpResQ%vYs-O`&IUhDM#QOTsY z=Ye+hlcUKBvv)u3*ss3gJsy?ZLDQ?%(jHtnVw_>RyRVnlj5{>7Vs>f?qo-AF`GO1ZPS2f}8`RO^((HA6ii*WmT4*-={bRH}(DTY-Up+^Q?0Ns0k5NsgV68^=K;tg0 z2z9{}g&VR97U=Q|aJQ2Him?JHZyIlS?tEK{LYdd}fVfZ`z$JFpmr3_La&At>55fyf z$UOJG01M=N{4N%y{WEzHotsw{zQQ>nFlCWyS9_|y@|yS8Rt-*uQk7=~YxH=5j+6Txh^mg=;hMSJfc_{u9p@HI^1Sq$FA6zW2>|wz!0Z z@u!ysC4~-;6|8kwIboMRTO3Olm#nD33tzwPUg}tXo9?5!IbNMP$Zci##L1tqEgx#L zG$L=_RA+Aw`*}Wvn;QcH=Wn%Pe>|N+LeHMC#V07lu~Nl_@=vd?p%t7QMGLf8;#lwS zr93v;*>l|QZ*L>$zAd2pHay8ZBRpH2=6@~JJA^RRn z2+5h2k;-MiRK?MaP}d5Q4NXz-N^)v)W`!yXFJ%bUeD>J6=l#PCbntbw^A4ehe?45w zKU(x!sKr&w9Pfe|y&b`<4z<9qHOo$|7X9aQQs_aN_~ONjS?x(`htu@xp_5&(l0}-c z=cTZB$;Ja}&0!kZs|zss@`Z1ctQ%4)9*WQvpfZN7G8Z@DWZP3Gr+LnMX&-p zCdCFEJO7Z7`I?%V__4CP>L;t?NL6#}#tI2Z4()Ws56cdHzq-8l>G=UY&asn+Z=mP&#;k}T^VCYm zb^Ao;&l8m+vJdYs&`yK~Vih{+;tc&{+fwyx9}<_C02xE}whX1CkDEPl-njS*{5=v% zId5X?JTUgQA>)_WiUFEEG)BX#>Fy6~t%bi-r5;G!nYWOg=`-3GGvkDrk)h`FF-_OCr&ynd zY*fuu`-flVh~R^euEMKJ#kBJSSs|KFyY^((#Cex43%jpSfBN-x6Zbb<<+Wjx=Wi|B zt$|mEY`C&0u=$;7z~NtCZEp!Twtp#IxTiykUYxl9%wUG2B9mKGm*sIX#w68qOfSPo z)zQYNQPg{X-w}QIFOi`;uHxzyyt4S>Sf8ugJQ40}HYvX|x!AqVmKn1O0%Pm5R2XJ- z2L755R?!r|NneMJ2?&t1>O9Bpnkvb}#SwKmnyl^jN_Km$wbZ@)BrS3*%?3)XTt{Bd zszKBE-i`qJbB6-{kMo**GK8HGkcz~pg8FA?wP?q9o_qAE)v%82p&P`R#6tL(CnOQ( zv2Y^_KI?wLxz648aJ^30@~Hp$anmcg1q-_83Ot|-{`IvTiFAfp?e;NDhSr@s8+Lwr zK`(Aib~$@>nbTIf2;JnEastkc92IH$_%M{<(!=eSW40d&r-^b&*K?fu{iLjQe`L4L zyS4E^JC1_&;fy3@?7SE4E`z00nl$OOQr8%`HFULNKK?o!70Fe_UY(yDlm`XDPQ{AE zF9z=G5Zj8lP-oBm`2{jN|8@Okf1Jer`0eRsRtTK!ZLV2EUHUhJZ5<$tvv2HZOa8tx|(w4x2IdpUl7Wg)U` z-uA+<715#amcE|BQW*6RMY;21ddDS1?vb9+BPX_Gi2*b!N1JYga6!{AEnSN+Y>W5w z6?2*@RIY{A8l`tPgjP9>XKL1U!9luFL)wym0Q( zNM~e5sxvX1yn$4Gg^qmTJbuj2*dfoe$qDg;ws0VFISKO ziQIGN>ayp>z1m-1U4I;T%V+GkOFjSg1wA?XS4xPFY1vEHN9@#b(PM(FcwJfCgfZviFi1P zPgb=5lGvbU>_cV2x>f$A;Y) z|B9lV_LRlDUGh8(<4srO6%|~tr}?n^rv9%>Gib&5^Gy%jI<>re%sg@JZ#+$t=?T7Z zW02h4T4%ez$f$&)2UM@m_4zCJtn%c~b9so@zIs*>jhZ z)Quz8XwoDbYhml>=ky&vszo__TAo_nv+Q50`8A_7(|sqgi`<3mqc?Se#bdYLFT>zp zN^e;;%#Hh(es$Iw{=Aope_~3*5xK{D%}`wO6aWtkJ!A|&rh3--_(~zk>%!c&Niv86qIs@#f?b#L<0F53aqd2Z zT^Z6U9Uj|ZH=?&aJ{&5#)NzY)*1hAa(p{E^+4UTWigJq|#I)1JHHqE!Aa3EFH)ERx zBCakypdKi@Ee_)Qvb1DpcKe-*Uxze&w1Nsll~1K2N`7d8H@I7EZCf6CKl|8L9{b2_ z^o*4^@ci@Vr{FxtHT^gY7|1bwB*Pg$a51^lX|$&Dp!mO8!cUsIJAW=bX!FqDaEr|? zB|RKkTlVh?#4nu>)3Z;F655&j>XM#mVXrqIQ~aDRXhqxK^HA!$#w>3cJEJFlCger% zXot`^0$!dT@0JHB*=sP>bZVQ3l^t*TGiY(aS<@R`AxbrzN0D!K) zUJFI(7X&JHr_7bvn13xZtG+&OvxU@P;6qAKJT+QNm;UUaFR7$m8q;eizxQi>f*ZaB zQ3-tUVkz)9hAEpwD$0p#riwiTfrc%bMbI2ahTUBqO-+QIy1RGp-dTJ@ z0&+QdB>(I-C!u*#4GRJp&TaOg{M<`f1k%DPxON3wH~4sTugAa-otoyZIX&9@O~v$u zJ2$C40buDtQFzVVOUuUFMORjCHBP>b2a7)yjal0+b<|c$m>|3iMbiBy5x@x-y0oZ5 z64F{ePVW5oqn9)p1s>9VlIrb?XYcpGV6xTCz@K?VkM82bJ4bocnQwkvKenWwRefU72EiHQp%+O}@KwcgiY{x)@j^L~>y;|?lX zKPJ8U{n2>m;}H#?b^#@D++teL_)~NL{#9E{M=|DdbOY)nBrAe&3|RBqC;v9MHpM=` zuG3?yR+(-wJMbYbRd=c=!#LBJN~Wf!-fW;Fpa0|gr^;TL;02afa1^ue#v3CvtgnA@ z{;S;}=G#-6>>^<3Yu8?#GEL{l<3CT*db*Y%^!*t$QTnm{J$P%;X-k+4H#$&_5R4MJ zn4DSvNA5Yry)v2`XUuy4=+I`@X0kq&$-2lp3CJQoS-MgLn7^U*tx?)k{Q`=O%_>X!*TZ1{r<4Y z{?45{#ZWB-hee*9kgTAlwzDRKujIkL8E{`X7Nl~$Cyv}dWYN_pU0-EfzkY$~Cz*RDFXm{}j6lJBmrKnggJCF!!gpJo*fvS ze0S&>!bGG#d*^H@loLEt(exTmaz$xN#;N-__FOVjTzcepOpHm&R_qBI>Ir;~2S^Gt z5pd5^oj^zvs6q@J6~)&)B%9i-`w-Zj5= z`BBK};?kn!GVrT`KO`SNzFbpFtE7-CyL|p&#zBk(ZTFNVduAT^^nwiV4w!0PgxK{B zpKPqFF2d#1+PYPNrZ|e7A`l7f9XoC~doD0_u{ht|^T*>AM)mSCE{QST3_x}~V$V+3 zREmUz=;q(1^R2qN2PaVV$OeWr0-1@{pozBDC)Ywy?BpyN<}=CJ?aK<*_nUm4EzA4e zyf0t*M_P1ftxa9F_kvIShk+NZ+qKJ+gvN>{tlQY?5*bOzkkp^5N9&X`TUXCYcV2DO z`EPBUoBu3Ebqr2)=GXPh#y1V|=*Y@xtF!}RF4{a0U7geqDUY>65{I29eO@ipR%1uX zd#8#OdfT?qr++pMOPMfx$A92`kU2dTa8_f-;-jt4gW9S-HDb(Ig8uEl2{(J4`TXH= zh`{van-CDxjE8JC)T1ZO`J5&0WA6Rf z_;r4BE~IRp9e4Mx7R=%NzrTM}=s*z)L*AJivsL7R#`IcHOt!My>^XeH*p3#t*#yre z$eYn}9mwFHQ3~;Xrk+JE+^ZT3)}?%Y56PnXhM*+{8x-G1hK^r+OD8n&*a^?JqkIf^ z9_}8ac69?*Vgc8>|>eb5DFI)@kP2aK__NVG1RF0#NeW{aVr z-7Td+c=SPLl`o3FYb!x%3WzRR4{SOPVVVO&M|*OT#*Qqz;*U{o9qH!)>$lYQF61s6 z#I$UnjY?=e{8&%V1n7wue53*~pXGOfG*^B5o{uP+D?W^wIh!7n|F~|C%Y3p7p~|;# zDS!}PTzS+UK=LB{{1Hrt89Nq&lQJFoY!W?QkR~VGVkgNR3`PMGRDj! zeTzX@8LkcHyN*r48QN4odF&;!LJJ3Z&5QPYawdfVth5yb#pB_$&Zt%1yUk9NlyDG2 zs*0p9=3^9N)|~#maCh0dW&z9P(A#>Zy4NwuzBnyK!6eEo{ayY2cU^?XOeE>F7sjUC z0+>5l&iE!4{Cw@H@iS(`ht@8;KK9Rgh6!o47i1jPP}Tu?aNt07Z#NX>#ch9tC~-d0 z0*OhDyREq;+nELe6o0hFSp?et;Bmv!lDMumfla`hxb0|eh&P37s znP)|L>^rL*?>`vuWq+s~{W4f#8=D)2_nv_#x%NojIEpXv`o2Bc2>SKr`Y>^5I&6Ci zm#dUl@Uoc3G^a6z;wxmHuk8fr(NXUg+Sb+d4kP=7yg8+@YE>AJZ?fGtXiFWolZ^f+ zczgegnqT$jF!`7>6t-nJ^_^(giX-*d0J@q|!mo7XwRkyWteYc6=EWq5Lb=!nzhS$w zKS~tTe|!$G)4M#yP6*M)WjI@X8EDD_su6jk=E~5)Ca0&#o*pyf(&-r=ZsQCxubHtJ z|9>F@cu)BG8 zHs7*puKb0k4NXj>R)%j>&N8an#>afi#B^^b0ifQQ?PZJIGJ5cR<(-)2cOWmnnj|$5 z1H(o}-SWAJ!)Avi2WFEsu73C^A=%uv28uA{`g0}1F9B%FZ=zJ>nL(taLV=ZwBVqzX zdvAZ8WuGMC`{&M$Ojd}Ix6EE-`}PK*hBKd%>T_DSZ#qOV3Zj@FD2oh4n(byu?dZVy zDGD()1DbuT1xZ)*xeFHpKJLKs3T`$oDQFD$fRwwqd)#wAuJ7phX+awwrL7gq9R zuo_6Ucg%-~8kZP2%`TNC}tk(%$Hs7uy zjt;SpJd>=@B1nmSJw5UUhl|mw9yo|ENh^;}H`BR#8_Hq12O`@+vKAlG=Gm6rzD|O% zo({2k;nB*8wy%*1^c;s&&CZ7W*AV8Qu$8M30No5droC?cdVf%&=nl$T;03qy)n+j` z%$(^SdcS8VAxL$(Zmz1#XSm5^ixhYU?1Scbu>1L$aaoaUoSbd+#4QR2(&@*C4g6!K z-wr({V^g_Ef7gr4H)+0vEoPX3;Dii;OJ{>&L!FNb!lg7etlBi}r}haltLlt{vb*nK zMoldeM~jORAz_8EOEli8shrT!W`VL*r$;wiZRvu3MmC2O1{hVxheolvUayusNoA{d z_Z6Y9ip=z+uwRuTw=t_^MUL3?u~_^UTkx5wz2VnWCaJo z0qhyx3?D8EGh)cO=Z!z1wQDmnPqeiwgkWenIXMlmRq*_U0t*TXE`ij7B*xX{u3FO%+ngX#=MjJ) z9m}3Qd$umajL=-J4(4LM08#YNp)_}dNd+*Cm~sGui{C zRC2@h0EXY9ub-D65Djg!ul@ExzVYEn_aUS?&XAC zY&$m+c;G1VeTJXl0emF*CM0+XTVP_pz&VCM!R4^he2b(;PSg8GK?1_B;67UXkM`#h z?aus;IY;bXErsZ9IV$dCCPn`#YD*c-25A5W+CdOaSiH9~ z`4UnHw$?MfI(j!V4m0TEo5-ch6rSPUacNI=&rR&v(815yY~(TdI_nV(mlC8#H%Vmn zKLsDea-Q+i;@;@m!}|~HHyg${2+<(xGt8b{dL#e#@2`rsZ#RLbi^hX`#GdNdS=VR& zab}nYbg1VSK{$egMd$|K-xJlR6Fz?YC@!a{p*(opqQeIt9{gUViA8K0Mk~FPmL^J8 z1IeSdS8K+=`!iL~o@ZMgbH|x~cJ6?RXTkOaHA;QfH$uEDUtV!?>}t0qT%<2$r#i8Z z3`X{rh4bevuqzk%aP4#+!FVq#op6g45vhDByA$Eee`BVstj@?$AYedklWCgV(no<3 zwyev}i3HLQ6}5Vn{b*}H%u!P(ju=8*GBpVqpLMGuWlZQSza&n=u!ovrACsq(tT1-1 zv~-?t@KP)mpcAc-56de$zs=OQXyso34Xwbsc1xQ>&{JHf+B|TZfS})V zY1L~Ul4D1}>{Mms+eVVY_mkZ4iUf+X+``@wy|q6xht0^}w(oH)q$6rpI*|bcq>K}; zZ6Q<6j|hxp#C$*`gil2D8dluaT@$?64uRxEoVUKGfCzhCC_f`_)bClSzj<^he$Qe1 zB#6qS$@Ofs%kLlH$sIO?Q6djQ_%1^3h1P|LX)XQdZ=d!0H7Urzix+2hc0wyUaB8zo zYZZm9psb4rc@qNqn=a-+d?=x{=S>S(26e2zwa6Cv(9^?*XeCeRe-a!JN!Qe+BtI#; zFAxF@3xF8vnHeeaVZqC+eEW!8ErPUf*ZL!G0WlMaPwbod*s{n-I$e$i(vZg-4! zWGd~5JOGhy3GkA#-z3zIyK`G968o1q^VX5NN1tAX$l&xy|L zkazQ}d+&Zk<;%MV*kjS#;9BP81rw~qCgbGSv$>M&PmN|5i&T0^fLL;pgS>|(0e7T4 z$XD_zp~NtYeBibvu7`g)5K(1h4iIko9!@l0g$Q5xM|$tEw4a5Ku+@fB+O*dT?2~k` z8ujUP$4WkCSdHWYM)*d5C@x@Gb>s&$ZH_kJAP_Dp3OS<=etWa3q*Mcr73UZ2!`SQQ zXIYsM`}Q_TBg~_AEp(C$I8H3ulp(Qt)%T5qm`Zw-p+Fo!2ohkHt-e-z+qXmJY(|V2 z;TsZyoT8A3k^{5xJi}PgfpGdGarvi|GQw3N6VM-G4VJB=#2nI=G;jmBLrcd`RgX4^ zzl0c z-MdVt`T%!7s0Pbdk7p**pxVEh4o&qb8yS(9*g#&}JZDmf_}t%MMwPNRob%#+=%(iaBx5$}gs&t?A*S0%_~qsaKoGTW=}e=A5o@7_ zOhpNfrO)W{a)JB4`uF7~g0zU%Q&>u#G&73G ztzZJv_7cA$Lt>7OupArqBY;8ZFhO+RK)7XojAFQ=0y^0`I$3QNO2~F;PKj-6%?XDf zno8xqd^>gp6q>KUKPgFd(g;Gr^4HQ?D1}UJkgcSWX+_-jozKo#REi|5>&J=vA0EDc zn)4gCt}inhUK^T`Z)*NZ4%$a~a3F}lAXOVc`+Ggdu%jzLx))izI}+#)Vv!&y8$wFM z0_T9{^tzC9sxsMrzTX@jG60q|->jE%f?DeZRN}H~TWZDHo=w! zx3(lg;}CpLmXWAbR+SpelNt8HS8OOA=My5>g zYOOszBk$e5bfWfE9Te2@_fzl*(Ho>H%mIs3%BK;QXk$ z=g*8aCE1nFj%MD{>?|`+3Pt%SP-9j|dGH3KcFwn@mGJB#W zYnq0z+oms*1s^o%b$?(D*`b{sW-PBF4i1LR=+l0Z8}mE`$ukP8HhWgAuVgC!xpCek z#0Vd(265Ib+IwX#xU$4Z1D!@2{1AvvUr|D(NQS;sbLFX|2(Ys0Qq1a>c+R3N7AMaO z$>p=u4pBKp#SrC~ti>*RLzyZiQX(7@4&nfNE(kl^W&HMmM|$76O63AZ`|2eb$z)t$ zcmJ}o;(6$soF!rp`oc1abfU;X$Di z8%0OQZhvIj^ZiGUsj0`&5a)CH{{z}pkVdznG#!#f^gt zUlkAXPS0?UG_eYbiCM}MQpQ07yRm7}!O!NYou9(UC(*laf=no+Hg+I6X;_*1bMuHH z+6_-njjHZy#J=j!P29YC_3`>oyGZa@(=nTzK-i%^d$GVN?2!(wCD}n=ASR9cft{86w z9*k_~4?E;)VW)ND61UOSUwYsn1d&SwE2$Cu|9GLFL+#U{#vaxGU?3X*2x)?S>+Bg# z?)v0;-74Ut#mV%f0v(cSm=rX9_*fA*m`D&BOlIPSsx0PHT}3$Z%Dv|xAVenPc~Lf$ zr7$QLZ5F8LEDG;l50YHnU61eBmPEJCe5r}G9x466FCP>46o)!eOY0o`Go0ylWEcZm zGn?-Ar{S{nr@!sEjGWcYLJxOPd*obw7&RSR=|8%B9J@@st80L?DQl}NyykB+4di*( z#RxSbXR5#l)OYXwtCBm$qa(he{Sf#~5?B++2(teJNP-Ip>F{r;f8oc*m6r3i-#39T zwyW@}tgS70lqPkru4n1#jei&yq9to~&o@L@-IzQ)WYWzc&r)rjZfxa%g;%JuNS;$|(LfzqH7CZjru~Yx>CY8rO)`i#m61zJkoabH2zVF@gt%!a`dWur z5!S_F5j#NV&ow;Z-n4!Dd>KPRx6(j|VTstHKaz@828F-xEI8xVy!YLQi_?@poX@Su zj%qzRhB3^BK#eO;Tstawp(~~K*i;AHV#FSx_eim+L5DO#A*;K?(*q7P7OwraIB=fv zY+ z7i50u=t-}r<$8&fMy~z&iFD+Bw*a0uSvdgGdpi>$`OC)dUR_Ob+YY6RDmyR#8gD1l zcUSsHIg=hqk&fiXFkk3mf(W^tZ(skbi0{!D9T=qX&j}S)VswwYnkrem1}8?#r(%RN zoc8u{C2(a(MQtSX#G_C?jTx{2mdk&&Cnfe~ z@R8HjAGK!{e>i&RbXvzp?MjhE8{J@N16yk&F{&8~Er>AUtMPzIRJ}ak#OQ9Q`NZ#G z?oRzdyvE;nvwuF$$IqPkrsAMV2Dn)u8ti_g8xc`wjH9dWg*r0{)+3b9p1Lnhnu0@u z=D?xc_3{d(VB#O&*Jo+Ub#h3A&Sv?*M6k36_ctRo6nCn)X}T%G>t z%^|tBC%oE5(ygE{G(4X*n?@27N1h?>JFs(78FL2oy(OguO{;Eryu9y6{08K;F_{$) zI$hu1t6S0R^}{Hciy(LI`-e^ezy{#(aF*f7hO@v5CFA9@5qz->|EyxfNSc(4MY$BaBnm&QIUf=E-y^blK)IP zpD0ugCxEUD84Mm&_U*fOeR=!~Q~BIKRRIKShq?Y<3KquQJ9jQEv_B}KPfpAIz3*tj zQ?Ov}stAo++B_P0>zlfb`NvKSqjmm%_g9lGZW7&#%!wmRGiuf<0Z%MF_!)rzVoFO+ za!j4f9D&Sa2!8zRfsEi2J(wyj?bP760c2_Z{ZY9Mo(8=8Ag87urG*Lk0|6Sdi43OV zHN*IAJHfG`oBq)05s`pk{mUuzSTUDUrWDxXp4nNKy@hAkfJ;&-QvM&CD*phPw;3!~rZ9DIveRWTtf~80IR!;7%>t^G1~o!-eZ|FGVCGQ-n<* z>?$?&E&lcAg+kG8Ns|X)`s|i8ilXc$v0?ccH4+|^)7{-BEPX^i8z!}$mlX>PSggVF zz-w*5=;j4`T>BYrE!We2mA|VLF{oWB%k0Ub`AY$GZ2Rd5lyCok4%nxDl5^`4mEPk7 zV=32pI!snQ`0IzqBR1L`%-ovfwyn+zk4()TWu!(N0zdmZnIRs4caK1hqe)sQIQAJtVy0?1M zPm62-5y3CS{viRiH|X5sGT$tSh+;FY*)9zM6+0UXH{t;I4xlC8e}GiaVF{zd&tI52 z!>_Fkh`1dK$`>V!${5W~fM_bmbpvJV)-}E!GT5!?^(jroqDLs0i7`zA#cVF&0Vu+w z{U%aUneLAdkLz(g;3C$QZtRs}B_ykOne(@qU%rUJL#vH_@S#{|cr-!$ptmB6HEzZX zxzwf0cTM1QLRnn%X7N^G0&4q-Eo|~6{_8`Rzk8GTIRt62EG?s`+qYH00ERy`^M;Ed zALH~23~3P+d$`66z$=}N+8spb5sN9}x`nvh;S^Ytxjlo2q4?4MZDN39>qmfSb^{Uy zssrixX(x|MuxO6gy~8iJva}P=2ynl(kWoMlS=yhTVW?kh{q^K%+lwS5Okz-o+nO|; ztvsojOVlKm(IubV`LnU%$=~V3H+uF=jf#8W8qQJC{7C-To%Iv32RcAL362~`(q@?H zbiMW$cpwdMVhn}a{L^I!cqG4_LW8Z$MbS| zydP{ze=>@b0x#Sl|i|pC`kwW7IT=Rf-`{ad_S)4 zRD-hswjCIxPj zP*Ca{vhO=G%X6UyN_EbhqtqO$+KjRWataotQG&(^w0)Ahnx7xIU-4)3@S&-lZ&H>y zv|Mvuy@j;u$nW9f^c8lk_haj-n3*vUshaU!zaDL{e-s-JxyYB9Ti+@fMieBZt#gsz zgHSf+){0e*&`omx_m4*`pR#}de!VTv1efw%COlkr*2Is?zBz0K!p*t`VB}34%T^jL z)9|iTVA%YYOU*1?-};7zb-XIolY+Pq-2tcsF2GeJ4FYf`^~V!PpJ=S>)+_77m#kIJ z3hh*@`t)u7CMC6h;}E9fdKP z8x=)ZY=WMAFCI|Dd#A^DTnu==RUW+dW55Bd}1B z*cLr|P&mc|7cJe|i+?n{RIH|BLeZioo8>ooDP-4}@-{yG$%dYm(>_?O-jt8?80I_4 z#cbSIi5fY$CR)f&0@@hG?^;!V;oSN2r8=878{8*%ChPQ=0Pr&asb>gU;GJ>7{dLV* z!oVi|5zr%ev!Tb>$ch_QBorNb?Ni>ZuuGu1*;yM&pi&XSKb3;vwp%&NXSo@~7(GwQ zk3U{|HY>}zRfGYR)t`#Mtc^|;I5XU7kbx#aWDR*0KVF+}=@hV*zt)DFD{w)eDKmdJ zCRKx%*(ZBd+zFg_P(%r)QqP>;)V5~~9@BQLey*1GiSiGRS61zLGK@3)L7kcfxxohh3&N5W;8Gr|=OHRwl;3-}v{D z)>r_OfG&WR8NKm)zAS`v{g*z;Sd6naj{=(`3N`fqf7k>%_LN)E8mhnyto6I!7RaT~ zrKkhqe0}D|OMEp{KpayCbI+AB!;-XvV*OF}3Un29hiv-=;pm}R`DXLBk#je9@UYPr zdG*$+p|rq4Bs-|`58qVUe?yPQq9|7P7L~=>qkz(&LUudWSx5P3fDXGMUlUn@&V){1 z#+Hxkvh)WYEKeMTOdFUmY^xWl6O11pMtWZ#xOvfSfsDl@3RVN=oppD4IhV@$531&& zDFI^Ctv=J=<2n-Ghe}Ri{E$+@p~B%+4TU917zuB&>8xaU;J;y`0SHXFHB4i=HRJXU z+4%bFr4mU1Td?cd81`xWB*Nlx0I^&4f{(}I(jCtsS5 z{;g-3Ek;p*i&$nTCh$zzf-xYc6CGe~fbVTpfV8^AK%8UeAd+z?AYgt4Y#%}t2`aaQ z=u%Ep#($!aCTq|az!j5_d)y9iETRG08|@?D!t;+7z7|@e^j{WUUu%s!7=W;y4#toQ zub|79rG9?0!u16|z_E`V-%p1~(1P7m`qwocp3^*z&F=mnb1)+d#DUWa1XlGq7F3b;J(3$Ipcg>Y;RS^2F463jltYl~L3`8_d7r>ijxe%gv_Iw!$bPhqII&sJw8*mdc9?%E% z`b@lq*G83p5q%`p{@UjRQ{crc`!eg&@9*zr2+)So0B$6p$B4pZ;OxJ0D=M#@w4Ik8 ztPhX58axY|Y2Szls)c^~FX%Qmf+T72?6Fxn9TA*Z@8?pOGj%-7U0eu!c z0#`boB(D_}a4S1%*0?r?9)dMQ3FUt0u}lt(x4D0Ry2w-azZ_CbKNB)T5p54dl&SvK zG9X~TijU3i(uXPQuPCj8Sx`g9n_~f@7UHHvm=9Dq$TU?{gYjttcQFuf#cu1G`1K+A zR;ocsot;AU5K;Jr`A<(pRR!^L#Ax$8iyHl&K6Qg%NKlO9w>SGCp41D11G4wvAo-oS zGi_12o8Z~HIqz2KIoQ#XNAU$f2JP}H|@o3-bPe<&N5VTzt(Yxsms}z%Zs$Fx{{?$?((zP zMnw}b@TV;^f^Ato=UaZ|{k<}lIbP+3s?+G3Rc;41V&72kyPC~FSqR!2j8dJ73tS;H zU$D(3N}fF5UHSifXVju&4agkpNXVxQXW#+;2n^U4o((z6?D`r3tEecomhb8^c!O*4m(ULJzf+ z%>pJTD9CA;$0_In9L%Gs#ps!shP4K%cdkwyh_Eby zCjes$_+)Fl(6Va_0*A>o`K<`}O*BN*fi%FCT}BEM1sIg2R~}q(-L`Z~@DfUJSUzqq zk>MqUjU?{$2Yq5@Pe zz&shj1Lw%Ryu4roT;n)cmxcmEWRNRQw$|~iI+xF_=3!z^xQiB0+W1h50JcUVVkqZ^?ddA6H}H!5r-WDH63vmMt~YP(f)ysS&TI zi7o&AW&+GgUj7xa3sV)r2Q}yWP|P@7KpT?+@J0|EQ33GM1D{AE4HOp495kSXEaz`E znZv?IAEkUSx#SCJ)Hp#&Q39;kMfSl8)NbZStc|Zh+TB;ByVepm_#`zGVE8SuOED)r9K5!D4q z=R%uasV@3+b;EJKl@8lAjlpq5Oh#JAd7BwF*OTs?jitJeFS3^q#i$rB5Yi}t!K=ns z(;Xm5TCQlVFKt7T2!Q#iBxDz;gNX)Il#Qft1Mx~(m_+nKM5gn{^$`Wps9v$cRkAiB zCJfuBOn~8UOSUP#VW2#Sk&OZurmcR$R7gczxJqa6yt?nbhGpnSf(%9ykr9z(o45VZ z!9cKxwWzdf%IwcLda4nUmWzL-vp*8y=i9EX0^ci@YRb>2z<9~2bT@h+6K*byL-S5? zX?@S5+geiO&M!E94k@F}CepFS3SX+C{0@F8Sqs{uIC{|@cnz+CkgUnY%r)xk);^zwMiTr8HEPyT?VX{iyD4B`=W`1t%bCtqdGu2V zhRi}(J_p3fg$}Remmcj(MpN6lvefekzuFu#7H!SoX!n%Pe3g6cHQrM z+~-9b#)GV5PTiTk59Ca%_EYZp4a$^yu>AhJJRqBU62vu4#3M-XJ}F7>ZFbyN{iGyP z)3SM9^n8OltE(>&E9u^^O_%2&!Of6&c6B|JbDKQFFAT2SK8_GE7SXF z9il-=YU3g%avbRFq_Ed*z3yGOJ`u?D=gGvUfk8f%y5Wedbh}Nqx(bdvgjnL;cxQ4E6XD^Vxyb>Y?+5>u|Wi%)q8pW|h;eQ|s z+YAiudyVP!T#6zlw$i#*r8h)CSbj_5fwqP_x56(WIBZ@NLH;SrhO9LrY@6r8LI=T- z=kUQGEAjgTj*JHp+Vxv2O!3%N(63YtvorJfk37z?H4Ty~k2kY=X`WcWH?CB<;*V?z z!YR7^CFtSB&jgWv8Q#}S6EzI}lVl9`Z+SDD>QzvaT=03pgq_aWCa$%o=2vRQ1)=hj zt=p+JA|S{4n+tOPQ=pwzukv(c6v^a@Ikc;!QCk>P>|b=|_fPxxTUpO!yua&P*S6Ct zZZV;CTS<3PGr(FKO3)(o2IN=wWCmkTv`37sDGhPwP54rJ%+Z z1hCP%n>UM5u;C@5yowSq$~jKd6Hi1W3Ccbi;m!9aAxHSsHdBiTmV=xT<&q<)s{bES z66WgcM;uNJwi%Y@c;?WyjVj%S-v#$ySe-eZjWNA{wJQ|m!xaI#dli@Grw+s=bTzX4;uxHR~!WBca?%@ZqZDA+_{Ei4$!c|+KdAU40#PjI3l*K1TF z=XfAB(?IEQYj#N6ha*4itTSrqFm}Bx^nYyT5gYn(N~Sqgzpm)|T*s^KwL|&)>YE!v zf!Jl7g8bYbFz0=k8~0g|*>~TiB0uX9ttW3bxekW4%a$*b2$=PiC?KSK#9(;OINT3*OGPf1kA1EW$!uX!tts>z=YT(vK)M(qgz&Ox!%kdL*6 z0v5JP+`?bNs({yUO!j9(&?E7&SBoz2HJPI!V0YES($JWE}KHlvfW+|#e zQp#4850?E!p4vwD!?!>hcI|^jlqxGzni|+1J$3>j3)it7H25;sV)<&+y)Tk&ZRwS` zt9jW{w61dIH`(*+Yf9VGQQII5ataD3js%%xQiT;;l+p*-vDuiLgiQ43K%W z|LB=;`?ivJdPhS%J{_Mh(~Q^XuL+|i0@y}s@XUn^4T;Mbr)=b8@ACTKs2qMu1yzU< zBSQI3RC)BCXah|hzQNW35@N)BI2ncEDsXTw5Y-Cp&v5I7YPKtJZWF(^4|;i7ls?nU ztu@M-UqEm3<}5*Mzq{?l1wTj5ojW@3#2EWm2(baJ03WC0=W{>6cV>!*=7L)(@8#y*#B)YftW7Klfg& z(6Wf+MX0;Z$fP4TkF~YT@7WN@QRbPKn(Sh`lV9%Wznu-_i1HUaCbmqoD zz`!_AYpijLL5chFHt96V3(I4SCE4~t9EtMkLn<2k;*TG>YBJ55PtB0R6JDLM+7?@> z+o9(E1P)a?HKiz+UqTgjBK4XR(5RD^H2ec^FAtpFI}nP2R6JkCF`DN32lm^o-XzR| zWYRuFQDw&9KuS;m?2PYYT6#wO`~Be1fyt`=17$#cZx7%uSFTJ!OoB?~$(6}pma^9i zRmY3%=73I06oB|AU0TyUjxUhj3fDan0U*5A(OHn~+2nl#J|G7Y#V_?>?SN5#iZa%6 z>1}s$z0rhHy(qfl^^kbM!}ch8PS}&^|v2(_H8c}Pl$krjp+`f=`O*| zjszKpZB}yVkewt`{nQHmmmhD6`%WE6ZiTxdwLIneOvT$nGH{$;+`mpPk5NgH=p>`K z{X|k4_Y~hXS*lyy^$Fy~oWC#kxy)8g_L?3li=LO*QmThmH9FW|sb}G@?9pRZIU?gw zT5r!V9vEea#QsGVVAlBiEvbk{^Ngu!bx|6{Fz6!JV#G~g3v<9NbN^)Q`nUN|GT6ja zcpv-jKALE*9_SzG{in&SS^{wZG~83rs>BgQKoZYEDyk9&+NF5uBHmB$c%oWF&SV!Bi>1oy8*HlNBG13_|ZKM`#m}fZ}Y>B(n`!>q?Qh zOhLW)?_i=k7Ck->Jw+`op%GC=po;d*oT4knw+;dbv zbhsK1D_Z_YlUF!930#5J_URd`afRZ}quZ@H=h3#)RG^zTVdF|Hr_30A2i?&80&5=E z-{>Q*#V@>PJr7a)k1Ecnp|Lin3Ao3yie%3`L^ciKy$u>H2VszjU-P@vF&QZ}VbV@X zNLurHqsXxJo@}jnhSP{s+-N86ysca2P*VeEeutNc4)%gHY}}$}i#)ti0 zW{2HDmr$T1!&Q1(H`asW0~WmCyZaX;`AmGwFE+(B?f&^wE*C9EU~AYa2qL;;(oiLv ztcMPD^u4@>disYQ72qihs z4kgkMYAq}sh=g*goOdEkR1(c3l`Ba}63U9Kme}J^QBE^h9Vn+*Mrk!elT@M;D$~rq zpSPv|_n-T^_+xZkGJVbWzVG)O?)&#lUO&!Z+eG9392bO3IT;Y!1-)t8%mhJP(U-#f z0!55<2(c`12omy{?5;aMzHmmuINHeCU(R3do1kv{yuHdw+y-JJWksc}g<*7-*Xym< zPwZ9|KKL4L_W^=kx>|;myMZ7Q2Tgi?M?1i={0stCIPtT|`t;$|WD9&ljZA!+@CxHJ ztQ0tVEOr&@u!nk-H`Ogtg4+2kVOp1FRk6#(A~Q$P-&`LQbl+vCe1g`)*sTbbeY2je zl#yNWVad6Jibq!NiKk_4E--A}jT9I#xx)!dRArVCf~qZ2&}x!?etw}OREu|C)7${d z&9oLKzTEn2cW@qjY4%V$kmeJbp1z3sh6nEqySVD614yo>fMNR zjOhycfZ9hzwE_3G4@3L$q;Oa!Ousk|pq-L>p^B*b<|>Zu@zG-(YN*d1YmCgG<~-F> zBkGiI6U9d$Wrm*uAfHNN@M9B^H(#=mDeVcU^JXOp;l#Hq)qW>xEo<@QpV{0}N#;!u z|I4P^E@k>K(GEzLlEm`u8$L-ryweQ|>OMCecaSW`NixY)Pm%Sa&L3-oo2(WfnYb}4 zqpyINA3-}S=al@ua9F+Ghzty7FuPt+hJEKx?X%RUzp%1U6rW-#e&w&YvU|~iU(oRz z=CVdin(({*RrV~b;fhEYxMJlsJ1|?aTsZonw%{t5b^xsuEADu0Y`1XXp@1l70=f`| zUd#44Ey1*X%9))U7}JUFx0a^tYC`+jHTUz&il)~x)pb@ovVGLmF&AakM%c&Ma!oaQ*d+^`~d9e2KJ?X2%;4^cKGywrO_kl|I5 zb_J6e5E!r-DR;u^RH7%ws)j2QlqWwqBC`*OBH3HvB|(QNeQ!W7xlR`ees!I(y2fJz z#NP<7mi$9Qf|eGa^d0nDqQq&0`-ZA0Er⩔%XD1-@it0iqMf^X|4YaAg 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 EU!FQjt^fc4 diff --git a/assets/icon.svg b/assets/icon.svg deleted file mode 100644 index dd6927c4..00000000 --- a/assets/icon.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/tray-icon.png b/assets/tray-icon.png deleted file mode 100644 index b0a3876bd5b9be9b4645779c30ca4dea5047f15a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 738 zcmV<80v-K{P)tl@t@3is=$c`=c-69}Jyyb2ED^(vX6BE)ukd=ATWM z4Z&1;sw7E#oo@z)3BGA&Tbc~~<$4%S0u#zPDZG!D!#$sSE*#F4#K*^bIm9I#X7VGz z5n$hdu&^*18ygM}P*rt}o2@O#ikXMzjRX!6L)It_rOrx#Ha$;`|M9>8d50>I^RW48|h@bJNX3JdcO9-vYs zQ&MscfWAH}>+9di&p%6cb{3{)SyahlelcCeq2OdyUQ-xA_9DttQegJg3dO|}(aXM!( znOa#~T=d6AMk)dakV>WK8m<1zuj!{=v3&7mmM?_KNnWYZ^g(AXVt$+Y7 zm6!S3uBFHK_SMxpx7=<@4#zMnD_;Q6>vhOvvcLdLCIbNT^PiZUd=J3F!U7J*Fk4$& zq@|^jn|lV2$3wr>20&bFER~g4_YWv2(2$Xl4nSAeQ@mc^5Ir&Rj$60e7#n{DKy$ON z7ualrtgWs4_KZzPB$E9Bwwuh<)HEY6#}EX8yX|-A?(U?!yOUIP3IL_&wIn4a;c~g@ z=(va1>qV_jL8~p^^L)u(|AN$1HTFR(BO{|cdi(^B$AdkTuXS5`0>%zp<62?;?I#b5RmiU^d-s9odTZWnI%x8ElFV?Z$0zdaQn0safXPms;f Ua%ru9hX4Qo07*qoM6N<$g80!(CIA2c diff --git a/assets/tray-icon@2x.png b/assets/tray-icon@2x.png deleted file mode 100644 index 984016a61fc48f7a27462084acce6abd3f7be5f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1554 zcmV+t2JQKYP)Oz6G$WU=4>&bQ~De*3xi z{?0k~mQyN~19*w0U>$(9f&f?tV67kk)&W>62!M3})(Qe(9e}lh09Xg$IF9M}GY7Ew z<4sH0@Kh=lizsXWtXx@!sHjL5UrkAN06fpbY_6pI zuC6Y*qX1w4ps*kh2}&j5`FuVcaUPXB3IGNGtX4DSIh`%&y>mzIC;(&zpwlgYMw3i< ze!m}%+IqqZ4-c0uldJ&jHY?>hj~s>D?H+3LJdcL@S|}9qM3W7GTCKu@1sR0r_xn*( zQ%iV7h51;xa6Sx+^s?lV4M26ZjoS3IwjD=zx0~<=YeaQ5eYHp-SpXy`l_)I8BfS3p ze(LOJW-df>@+<&AO3K@qH%}{hHdz3e&BM#yL7i;x!1e2Y5#GoeVYAUQhS-uEKxAYD z%F0$yeqG%TqODe|Fn@kJ;pOIJWBT;zQpS@W!0OejsAccPiJdeuCwUqC0)DdlEd^`&BmkN$iTDlyuu`!b510)7uEH0#$z1`hzw0E2$ zJd4Fd)rdh&nluS(*HlQBQ8EA=#|bWb>*{x)zrTN|Jz9-;UMABzgoTBPo)M4`fL^bI zT21cp`}*#}>1-jqii-08+!{}w9F3BacSO$!NC?1YwNT!kANIoQ^$xXpo`=b_j_Bj{ zdU5aGed<`N#e@kHCWxL>5&*Misi`NuPo6x%zI}~^XEYWeJ}!>%KK<--)YUgoV@{hk z4Y@hlqGy!^z=jRmoVdBhk90%Ko8sT!CM`L3X_V51@4<2}^aiv%oi4Gt^sYKq= zT*4a|7{Km5dkIgk*FmL9BD|jt90UM(JP*;>*hG!3)y_p~YKo|NMF(KDR#8)0d&eo< zxN(#4gto@d_t~{;4}3l!)yHn9YfB&!6+m=!l;D)s(6Eze&z`Ljd>i!qZF9S~7cEEI zs6JVSMVL8rh6rh&NmKw873GMCAfM)3zWfKyopTZ1Xj|R%^i-lA7;$m01(0@Fq5&`( zi>Oe4-@c9GKc65xt#&Tl?jHF4ergPjCK+jI@I0P}Xlgnz z>M@TWKSp!&A$+%W8{uae7GcJWHwaJYDj2Qcj#Z)n5GqPFj#|OR%t*Dh9wQ2!(ACu0 zc^a24{Z1WgHdkWe#EIibJS;BIe~ZtV^A_4#orKrZ(}TrJ^6>QO(;+W9Itr;NDF_J( zp~l#<-8c%Lx;Y;yTtc64Tbuff*uw-H`x>2iGg%~!-bgRZVCSejQf?)(AW z0*Q%<#FTdPW;d3Xlo3B30J4{4jp@e&z?wCy5gHmwc+Jg+V7I?Z>?t&wWa@pxSQHQd ztHlJL&xbQ-&f>#On~|N9kE>U&QT=q8x-pL(6Z4ATGk{-yJqcZ=0bhLiHO`(rhu+>h zSY|99SAHPCTOc+z2KVp(Lp@1rw!| zYdDXR$$Rg6xBJwo^X=_?&Uv46XjL86hLL8#vp8x7e2PyL@<3&y2m13s z2c;G~p@>CP^MI?;Y1gEeaf5f18bN#Uh8J{WCN`;IqY-#Lkj=;^zu;$d)q{3Qef>Zm z#sb{NWz3iBfh)0iC-Pq8X_RCBfc7kC0k`SW2x1;F6Qb1>c%}aN16?yVM=rE2k5qSl#f5t(4D`6K~Sx()meCiuFRX>cP SKtGQF0000u}Am3V3UDQ>G{q6)kbCl@SaR|2$(JS9>HGV{ze~jwqTF$Wxr(iF`AAw1NpHNZ<1ly(9ATY7k!dq%cbl>(Qz;4{Y~bvlB;yAQrC3?U&yA|oN6L@UkvwS zR=2yDkw^q<#*A#WjrmW^m!O^Md=sz^SPI+*uIF@$iHV7c36OsQX!l`xUIqIA0000< KMNUMnLSTa2=s_p| diff --git a/builtin-skills/Video-maker/remotion-best-practices/SKILL.md b/builtin-skills/Video-maker/remotion-best-practices/SKILL.md deleted file mode 100644 index 7ddaa0fd..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/SKILL.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -name: remotion-best-practices -description: Best practices for Remotion - Video creation in React -metadata: - tags: remotion, video, react, animation, composition ---- - -## When to use - -Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge. - -## Captions - -When dealing with captions or subtitles, load the [./rules/subtitles.md](./rules/subtitles.md) file for more information. - -## Using FFmpeg - -For some video operations, such as trimming videos or detecting silence, FFmpeg should be used. Load the [./rules/ffmpeg.md](./rules/ffmpeg.md) file for more information. - -## Audio visualization - -When needing to visualize audio (spectrum bars, waveforms, bass-reactive effects), load the [./rules/audio-visualization.md](./rules/audio-visualization.md) file for more information. - -## Sound effects - -When needing to use sound effects, load the [./rules/sound-effects.md](./rules/sound-effects.md) file for more information. - -## How to use - -Read individual rule files for detailed explanations and code examples: - -- [rules/3d.md](rules/3d.md) - 3D content in Remotion using Three.js and React Three Fiber -- [rules/animations.md](rules/animations.md) - Fundamental animation skills for Remotion -- [rules/assets.md](rules/assets.md) - Importing images, videos, audio, and fonts into Remotion -- [rules/audio.md](rules/audio.md) - Using audio and sound in Remotion - importing, trimming, volume, speed, pitch -- [rules/calculate-metadata.md](rules/calculate-metadata.md) - Dynamically set composition duration, dimensions, and props -- [rules/can-decode.md](rules/can-decode.md) - Check if a video can be decoded by the browser using Mediabunny -- [rules/charts.md](rules/charts.md) - Chart and data visualization patterns for Remotion (bar, pie, line, stock charts) -- [rules/compositions.md](rules/compositions.md) - Defining compositions, stills, folders, default props and dynamic metadata -- [rules/extract-frames.md](rules/extract-frames.md) - Extract frames from videos at specific timestamps using Mediabunny -- [rules/fonts.md](rules/fonts.md) - Loading Google Fonts and local fonts in Remotion -- [rules/get-audio-duration.md](rules/get-audio-duration.md) - Getting the duration of an audio file in seconds with Mediabunny -- [rules/get-video-dimensions.md](rules/get-video-dimensions.md) - Getting the width and height of a video file with Mediabunny -- [rules/get-video-duration.md](rules/get-video-duration.md) - Getting the duration of a video file in seconds with Mediabunny -- [rules/gifs.md](rules/gifs.md) - Displaying GIFs synchronized with Remotion's timeline -- [rules/images.md](rules/images.md) - Embedding images in Remotion using the Img component -- [rules/light-leaks.md](rules/light-leaks.md) - Light leak overlay effects using @remotion/light-leaks -- [rules/lottie.md](rules/lottie.md) - Embedding Lottie animations in Remotion -- [rules/measuring-dom-nodes.md](rules/measuring-dom-nodes.md) - Measuring DOM element dimensions in Remotion -- [rules/measuring-text.md](rules/measuring-text.md) - Measuring text dimensions, fitting text to containers, and checking overflow -- [rules/sequencing.md](rules/sequencing.md) - Sequencing patterns for Remotion - delay, trim, limit duration of items -- [rules/tailwind.md](rules/tailwind.md) - Using TailwindCSS in Remotion -- [rules/text-animations.md](rules/text-animations.md) - Typography and text animation patterns for Remotion -- [rules/timing.md](rules/timing.md) - Interpolation curves in Remotion - linear, easing, spring animations -- [rules/transitions.md](rules/transitions.md) - Scene transition patterns for Remotion -- [rules/transparent-videos.md](rules/transparent-videos.md) - Rendering out a video with transparency -- [rules/trimming.md](rules/trimming.md) - Trimming patterns for Remotion - cut the beginning or end of animations -- [rules/videos.md](rules/videos.md) - Embedding videos in Remotion - trimming, volume, speed, looping, pitch -- [rules/parameters.md](rules/parameters.md) - Make a video parametrizable by adding a Zod schema -- [rules/maps.md](rules/maps.md) - Add a map using Mapbox and animate it -- [rules/voiceover.md](rules/voiceover.md) - Adding AI-generated voiceover to Remotion compositions using ElevenLabs TTS diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/3d.md b/builtin-skills/Video-maker/remotion-best-practices/rules/3d.md deleted file mode 100644 index c9d254f1..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/3d.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -name: 3d -description: 3D content in Remotion using Three.js and React Three Fiber. -metadata: - tags: 3d, three, threejs ---- - -# Using Three.js and React Three Fiber in Remotion - -Follow React Three Fiber and Three.js best practices. -Only the following Remotion-specific rules need to be followed: - -## Prerequisites - -First, the `@remotion/three` package needs to be installed. -If it is not, use the following command: - -```bash -npx remotion add @remotion/three # If project uses npm -bunx remotion add @remotion/three # If project uses bun -yarn remotion add @remotion/three # If project uses yarn -pnpm exec remotion add @remotion/three # If project uses pnpm -``` - -## Using ThreeCanvas - -You MUST wrap 3D content in `` and include proper lighting. -`` MUST have a `width` and `height` prop. - -```tsx -import { ThreeCanvas } from "@remotion/three"; -import { useVideoConfig } from "remotion"; - -const { width, height } = useVideoConfig(); - - - - - - - - -; -``` - -## No animations not driven by `useCurrentFrame()` - -Shaders, models etc MUST NOT animate by themselves. -No animations are allowed unless they are driven by `useCurrentFrame()`. -Otherwise, it will cause flickering during rendering. - -Using `useFrame()` from `@react-three/fiber` is forbidden. - -## Animate using `useCurrentFrame()` - -Use `useCurrentFrame()` to perform animations. - -```tsx -const frame = useCurrentFrame(); -const rotationY = frame * 0.02; - - - - -; -``` - -## Using `` inside `` - -The `layout` prop of any `` inside a `` must be set to `none`. - -```tsx -import { Sequence } from "remotion"; -import { ThreeCanvas } from "@remotion/three"; - -const { width, height } = useVideoConfig(); - - - - - - - - -; -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/animations.md b/builtin-skills/Video-maker/remotion-best-practices/rules/animations.md deleted file mode 100644 index 619591e8..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/animations.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: animations -description: Fundamental animation skills for Remotion -metadata: - tags: animations, transitions, frames, useCurrentFrame ---- - -All animations MUST be driven by the `useCurrentFrame()` hook. -Write animations in seconds and multiply them by the `fps` value from `useVideoConfig()`. - -```tsx -import { useCurrentFrame } from "remotion"; - -export const FadeIn = () => { - const frame = useCurrentFrame(); - const { fps } = useVideoConfig(); - - const opacity = interpolate(frame, [0, 2 * fps], [0, 1], { - extrapolateRight: "clamp", - }); - - return

; -}; -``` - -CSS transitions or animations are FORBIDDEN - they will not render correctly. -Tailwind animation class names are FORBIDDEN - they will not render correctly. diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/assets.md b/builtin-skills/Video-maker/remotion-best-practices/rules/assets.md deleted file mode 100644 index a5d40152..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/assets.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -name: assets -description: Importing images, videos, audio, and fonts into Remotion -metadata: - tags: assets, staticFile, images, fonts, public ---- - -# Importing assets in Remotion - -## The public folder - -Place assets in the `public/` folder at your project root. - -## Using staticFile() - -You MUST use `staticFile()` to reference files from the `public/` folder: - -```tsx -import { Img, staticFile } from "remotion"; - -export const MyComposition = () => { - return ; -}; -``` - -The function returns an encoded URL that works correctly when deploying to subdirectories. - -## Using with components - -**Images:** - -```tsx -import { Img, staticFile } from "remotion"; - -; -``` - -**Videos:** - -```tsx -import { Video } from "@remotion/media"; -import { staticFile } from "remotion"; - -
-
-
-); - -const XAxis: React.FC<{ - children: React.ReactNode; - labels: string[]; - height: number; -}> = ({children, labels, height}) => ( -
-
- {children} -
-
- {labels.map((label) => ( -
- {label} -
- ))} -
-
-); - -export const MyAnimation = () => { - const frame = useCurrentFrame(); - const {fps, height} = useVideoConfig(); - - const data = [ - {month: 'Jan', price: 2039}, - {month: 'Mar', price: 2160}, - {month: 'May', price: 2327}, - {month: 'Jul', price: 2426}, - {month: 'Sep', price: 2634}, - {month: 'Nov', price: 2672}, - ]; - - const minPrice = 2000; - const maxPrice = 2800; - const priceRange = maxPrice - minPrice; - const chartHeight = height - 280; - const yAxisSteps = [2000, 2400, 2800]; - - return ( - - Gold Price 2024 - -
- - d.month)}> - {data.map((item, i) => { - const progress = spring({ - frame: frame - i * 5 - 10, - fps, - config: {damping: 18, stiffness: 80}, - }); - - const barHeight = - ((item.price - minPrice) / priceRange) * chartHeight * progress; - - return ( - - ); - })} - -
-
- ); -}; diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-typewriter.tsx b/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-typewriter.tsx deleted file mode 100644 index 89f62ea0..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { - AbsoluteFill, - interpolate, - useCurrentFrame, - useVideoConfig, -} from 'remotion'; - -const COLOR_BG = '#ffffff'; -const COLOR_TEXT = '#000000'; -const FULL_TEXT = 'From prompt to motion graphics. This is Remotion.'; -const PAUSE_AFTER = 'From prompt to motion graphics.'; -const FONT_SIZE = 72; -const FONT_WEIGHT = 700; -const CHAR_FRAMES = 2; -const CURSOR_BLINK_FRAMES = 16; -const PAUSE_SECONDS = 1; - -// Ideal composition size: 1280x720 - -const getTypedText = ({ - frame, - fullText, - pauseAfter, - charFrames, - pauseFrames, -}: { - frame: number; - fullText: string; - pauseAfter: string; - charFrames: number; - pauseFrames: number; -}): string => { - const pauseIndex = fullText.indexOf(pauseAfter); - const preLen = - pauseIndex >= 0 ? pauseIndex + pauseAfter.length : fullText.length; - - let typedChars = 0; - if (frame < preLen * charFrames) { - typedChars = Math.floor(frame / charFrames); - } else if (frame < preLen * charFrames + pauseFrames) { - typedChars = preLen; - } else { - const postPhase = frame - preLen * charFrames - pauseFrames; - typedChars = Math.min( - fullText.length, - preLen + Math.floor(postPhase / charFrames), - ); - } - return fullText.slice(0, typedChars); -}; - -const Cursor: React.FC<{ - frame: number; - blinkFrames: number; - symbol?: string; -}> = ({frame, blinkFrames, symbol = '\u258C'}) => { - const opacity = interpolate( - frame % blinkFrames, - [0, blinkFrames / 2, blinkFrames], - [1, 0, 1], - {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'}, - ); - - return {symbol}; -}; - -export const MyAnimation = () => { - const frame = useCurrentFrame(); - const {fps} = useVideoConfig(); - - const pauseFrames = Math.round(fps * PAUSE_SECONDS); - - const typedText = getTypedText({ - frame, - fullText: FULL_TEXT, - pauseAfter: PAUSE_AFTER, - charFrames: CHAR_FRAMES, - pauseFrames, - }); - - return ( - -
- {typedText} - -
-
- ); -}; diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx b/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx deleted file mode 100644 index 0aae3e29..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import {loadFont} from '@remotion/google-fonts/Inter'; -import React from 'react'; -import {AbsoluteFill, spring, useCurrentFrame, useVideoConfig} from 'remotion'; - -/* - * Highlight a word in a sentence with a spring-animated wipe effect. - */ - -// Ideal composition size: 1280x720 - -const COLOR_BG = '#ffffff'; -const COLOR_TEXT = '#000000'; -const COLOR_HIGHLIGHT = '#A7C7E7'; -const FULL_TEXT = 'This is Remotion.'; -const HIGHLIGHT_WORD = 'Remotion'; -const FONT_SIZE = 72; -const FONT_WEIGHT = 700; -const HIGHLIGHT_START_FRAME = 30; -const HIGHLIGHT_WIPE_DURATION = 18; - -const {fontFamily} = loadFont(); - -const Highlight: React.FC<{ - word: string; - color: string; - delay: number; - durationInFrames: number; -}> = ({word, color, delay, durationInFrames}) => { - const frame = useCurrentFrame(); - const {fps} = useVideoConfig(); - - const highlightProgress = spring({ - fps, - frame, - config: {damping: 200}, - delay, - durationInFrames, - }); - const scaleX = Math.max(0, Math.min(1, highlightProgress)); - - return ( - - - {word} - - ); -}; - -export const MyAnimation = () => { - const highlightIndex = FULL_TEXT.indexOf(HIGHLIGHT_WORD); - const hasHighlight = highlightIndex >= 0; - const preText = hasHighlight ? FULL_TEXT.slice(0, highlightIndex) : FULL_TEXT; - const postText = hasHighlight - ? FULL_TEXT.slice(highlightIndex + HIGHLIGHT_WORD.length) - : ''; - - return ( - -
- {hasHighlight ? ( - <> - {preText} - - {postText} - - ) : ( - {FULL_TEXT} - )} -
-
- ); -}; diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/audio-visualization.md b/builtin-skills/Video-maker/remotion-best-practices/rules/audio-visualization.md deleted file mode 100644 index 733b0d35..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/audio-visualization.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -name: audio-visualization -description: Audio visualization patterns - spectrum bars, waveforms, bass-reactive effects -metadata: - tags: audio, visualization, spectrum, waveform, bass, music, audiogram, frequency ---- - -# Audio Visualization in Remotion - -## Prerequisites - -```bash -npx remotion add @remotion/media-utils -``` - -## Loading Audio Data - -Use `useWindowedAudioData()` (https://www.remotion.dev/docs/use-windowed-audio-data) to load audio data: - -```tsx -import { useWindowedAudioData } from "@remotion/media-utils"; -import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; - -const frame = useCurrentFrame(); -const { fps } = useVideoConfig(); - -const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ - src: staticFile("podcast.wav"), - frame, - fps, - windowInSeconds: 30, -}); -``` - -## Spectrum Bar Visualization - -Use `visualizeAudio()` (https://www.remotion.dev/docs/visualize-audio) to get frequency data for bar charts: - -```tsx -import { useWindowedAudioData, visualizeAudio } from "@remotion/media-utils"; -import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; - -const frame = useCurrentFrame(); -const { fps } = useVideoConfig(); - -const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ - src: staticFile("music.mp3"), - frame, - fps, - windowInSeconds: 30, -}); - -if (!audioData) { - return null; -} - -const frequencies = visualizeAudio({ - fps, - frame, - audioData, - numberOfSamples: 256, - optimizeFor: "speed", - dataOffsetInSeconds, -}); - -return ( -
- {frequencies.map((v, i) => ( -
- ))} -
-); -``` - -- `numberOfSamples` must be power of 2 (32, 64, 128, 256, 512, 1024) -- Values range 0-1; left of array = bass, right = highs -- Use `optimizeFor: "speed"` for Lambda or high sample counts - -**Important:** When passing `audioData` to child components, also pass the `frame` from the parent. Do not call `useCurrentFrame()` in each child - this causes discontinuous visualization when children are inside `` with offsets. - -## Waveform Visualization - -Use `visualizeAudioWaveform()` (https://www.remotion.dev/docs/media-utils/visualize-audio-waveform) with `createSmoothSvgPath()` (https://www.remotion.dev/docs/media-utils/create-smooth-svg-path) for oscilloscope-style displays: - -```tsx -import { - createSmoothSvgPath, - useWindowedAudioData, - visualizeAudioWaveform, -} from "@remotion/media-utils"; -import { staticFile, useCurrentFrame, useVideoConfig } from "remotion"; - -const frame = useCurrentFrame(); -const { width, fps } = useVideoConfig(); -const HEIGHT = 200; - -const { audioData, dataOffsetInSeconds } = useWindowedAudioData({ - src: staticFile("voice.wav"), - frame, - fps, - windowInSeconds: 30, -}); - -if (!audioData) { - return null; -} - -const waveform = visualizeAudioWaveform({ - fps, - frame, - audioData, - numberOfSamples: 256, - windowInSeconds: 0.5, - dataOffsetInSeconds, -}); - -const path = createSmoothSvgPath({ - points: waveform.map((y, i) => ({ - x: (i / (waveform.length - 1)) * width, - y: HEIGHT / 2 + (y * HEIGHT) / 2, - })), -}); - -return ( - - - -); -``` - -## Bass-Reactive Effects - -Extract low frequencies for beat-reactive animations: - -```tsx -const frequencies = visualizeAudio({ - fps, - frame, - audioData, - numberOfSamples: 128, - optimizeFor: "speed", - dataOffsetInSeconds, -}); - -const lowFrequencies = frequencies.slice(0, 32); -const bassIntensity = - lowFrequencies.reduce((sum, v) => sum + v, 0) / lowFrequencies.length; - -const scale = 1 + bassIntensity * 0.5; -const opacity = Math.min(0.6, bassIntensity * 0.8); -``` - -## Volume-Based Waveform - -Use `getWaveformPortion()` (https://www.remotion.dev/docs/get-waveform-portion) when you need simplified volume data instead of frequency spectrum: - -```tsx -import { getWaveformPortion } from "@remotion/media-utils"; -import { useCurrentFrame, useVideoConfig } from "remotion"; - -const frame = useCurrentFrame(); -const { fps } = useVideoConfig(); -const currentTimeInSeconds = frame / fps; - -const waveform = getWaveformPortion({ - audioData, - startTimeInSeconds: currentTimeInSeconds, - durationInSeconds: 5, - numberOfSamples: 50, -}); - -// Returns array of { index, amplitude } objects (amplitude: 0-1) -waveform.map((bar) => ( -
-)); -``` - -## Postprocessing - -Low frequencies naturally dominate. Apply logarithmic scaling for visual balance: - -```tsx -const minDb = -100; -const maxDb = -30; - -const scaled = frequencies.map((value) => { - const db = 20 * Math.log10(value); - return (db - minDb) / (maxDb - minDb); -}); -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/audio.md b/builtin-skills/Video-maker/remotion-best-practices/rules/audio.md deleted file mode 100644 index 1097c70e..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/audio.md +++ /dev/null @@ -1,169 +0,0 @@ ---- -name: audio -description: Using audio and sound in Remotion - importing, trimming, volume, speed, pitch -metadata: - tags: audio, media, trim, volume, speed, loop, pitch, mute, sound, sfx ---- - -# Using audio in Remotion - -## Prerequisites - -First, the @remotion/media package needs to be installed. -If it is not installed, use the following command: - -```bash -npx remotion add @remotion/media -``` - -## Importing Audio - -Use `
; -}); -``` - -## Pie Chart - -Animate segments using stroke-dashoffset, starting from 12 o'clock: - -```tsx -const progress = interpolate(frame, [0, 100], [0, 1]); -const circumference = 2 * Math.PI * radius; -const segmentLength = (value / total) * circumference; -const offset = interpolate(progress, [0, 1], [segmentLength, 0]); - -; -``` - -## Line Chart / Path Animation - -Use `@remotion/paths` for animating SVG paths (line charts, stock graphs, signatures). - -Install: `npx remotion add @remotion/paths` -Docs: https://remotion.dev/docs/paths.md - -### Convert data points to SVG path - -```tsx -type Point = { x: number; y: number }; - -const generateLinePath = (points: Point[]): string => { - if (points.length < 2) return ""; - return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" "); -}; -``` - -### Draw path with animation - -```tsx -import { evolvePath } from "@remotion/paths"; - -const path = "M 100 200 L 200 150 L 300 180 L 400 100"; -const progress = interpolate(frame, [0, 2 * fps], [0, 1], { - extrapolateLeft: "clamp", - extrapolateRight: "clamp", - easing: Easing.out(Easing.quad), -}); - -const { strokeDasharray, strokeDashoffset } = evolvePath(progress, path); - -; -``` - -### Follow path with marker/arrow - -```tsx -import { - getLength, - getPointAtLength, - getTangentAtLength, -} from "@remotion/paths"; - -const pathLength = getLength(path); -const point = getPointAtLength(path, progress * pathLength); -const tangent = getTangentAtLength(path, progress * pathLength); -const angle = Math.atan2(tangent.y, tangent.x); - - - -; -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/compositions.md b/builtin-skills/Video-maker/remotion-best-practices/rules/compositions.md deleted file mode 100644 index 0db5f602..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/compositions.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -name: compositions -description: Defining compositions, stills, folders, default props and dynamic metadata -metadata: - tags: composition, still, folder, props, metadata ---- - -A `` defines the component, width, height, fps and duration of a renderable video. - -It normally is placed in the `src/Root.tsx` file. - -```tsx -import { Composition } from "remotion"; -import { MyComposition } from "./MyComposition"; - -export const RemotionRoot = () => { - return ( - - ); -}; -``` - -## Default Props - -Pass `defaultProps` to provide initial values for your component. -Values must be JSON-serializable (`Date`, `Map`, `Set`, and `staticFile()` are supported). - -```tsx -import { Composition } from "remotion"; -import { MyComposition, MyCompositionProps } from "./MyComposition"; - -export const RemotionRoot = () => { - return ( - - ); -}; -``` - -Use `type` declarations for props rather than `interface` to ensure `defaultProps` type safety. - -## Folders - -Use `` to organize compositions in the sidebar. -Folder names can only contain letters, numbers, and hyphens. - -```tsx -import { Composition, Folder } from "remotion"; - -export const RemotionRoot = () => { - return ( - <> - - - - - - - - - - - ); -}; -``` - -## Stills - -Use `` for single-frame images. It does not require `durationInFrames` or `fps`. - -```tsx -import { Still } from "remotion"; -import { Thumbnail } from "./Thumbnail"; - -export const RemotionRoot = () => { - return ( - - ); -}; -``` - -## Calculate Metadata - -Use `calculateMetadata` to make dimensions, duration, or props dynamic based on data. - -```tsx -import { Composition, CalculateMetadataFunction } from "remotion"; -import { MyComposition, MyCompositionProps } from "./MyComposition"; - -const calculateMetadata: CalculateMetadataFunction< - MyCompositionProps -> = async ({ props, abortSignal }) => { - const data = await fetch(`https://api.example.com/video/${props.videoId}`, { - signal: abortSignal, - }).then((res) => res.json()); - - return { - durationInFrames: Math.ceil(data.duration * 30), - props: { - ...props, - videoUrl: data.url, - }, - }; -}; - -export const RemotionRoot = () => { - return ( - - ); -}; -``` - -The function can return `props`, `durationInFrames`, `width`, `height`, `fps`, and codec-related defaults. It runs once before rendering begins. - -## Nesting compositions within another - -To add a composition within another composition, you can use the `` component with a `width` and `height` prop to specify the size of the composition. - -```tsx - - - - - -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/display-captions.md b/builtin-skills/Video-maker/remotion-best-practices/rules/display-captions.md deleted file mode 100644 index f9cb0f05..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/display-captions.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -name: display-captions -description: Displaying captions in Remotion with TikTok-style pages and word highlighting -metadata: - tags: captions, subtitles, display, tiktok, highlight ---- - -# Displaying captions in Remotion - -This guide explains how to display captions in Remotion, assuming you already have captions in the [`Caption`](https://www.remotion.dev/docs/captions/caption) format. - -## Prerequisites - -Read [Transcribing audio](transcribe-captions.md) for how to generate captions. - -First, the [`@remotion/captions`](https://www.remotion.dev/docs/captions) package needs to be installed. -If it is not installed, use the following command: - -```bash -npx remotion add @remotion/captions -``` - -## Fetching captions - -First, fetch your captions JSON file. Use [`useDelayRender()`](https://www.remotion.dev/docs/use-delay-render) to hold the render until the captions are loaded: - -```tsx -import { useState, useEffect, useCallback } from "react"; -import { AbsoluteFill, staticFile, useDelayRender } from "remotion"; -import type { Caption } from "@remotion/captions"; - -export const MyComponent: React.FC = () => { - const [captions, setCaptions] = useState(null); - const { delayRender, continueRender, cancelRender } = useDelayRender(); - const [handle] = useState(() => delayRender()); - - const fetchCaptions = useCallback(async () => { - try { - // Assuming captions.json is in the public/ folder. - const response = await fetch(staticFile("captions123.json")); - const data = await response.json(); - setCaptions(data); - continueRender(handle); - } catch (e) { - cancelRender(e); - } - }, [continueRender, cancelRender, handle]); - - useEffect(() => { - fetchCaptions(); - }, [fetchCaptions]); - - if (!captions) { - return null; - } - - return {/* Render captions here */}; -}; -``` - -## Creating pages - -Use `createTikTokStyleCaptions()` to group captions into pages. The `combineTokensWithinMilliseconds` option controls how many words appear at once: - -```tsx -import { useMemo } from "react"; -import { createTikTokStyleCaptions } from "@remotion/captions"; -import type { Caption } from "@remotion/captions"; - -// How often captions should switch (in milliseconds) -// Higher values = more words per page -// Lower values = fewer words (more word-by-word) -const SWITCH_CAPTIONS_EVERY_MS = 1200; - -const { pages } = useMemo(() => { - return createTikTokStyleCaptions({ - captions, - combineTokensWithinMilliseconds: SWITCH_CAPTIONS_EVERY_MS, - }); -}, [captions]); -``` - -## Rendering with Sequences - -Map over the pages and render each one in a ``. Calculate the start frame and duration from the page timing: - -```tsx -import { Sequence, useVideoConfig, AbsoluteFill } from "remotion"; -import type { TikTokPage } from "@remotion/captions"; - -const CaptionedContent: React.FC = () => { - const { fps } = useVideoConfig(); - - return ( - - {pages.map((page, index) => { - const nextPage = pages[index + 1] ?? null; - const startFrame = (page.startMs / 1000) * fps; - const endFrame = Math.min( - nextPage ? (nextPage.startMs / 1000) * fps : Infinity, - startFrame + (SWITCH_CAPTIONS_EVERY_MS / 1000) * fps, - ); - const durationInFrames = endFrame - startFrame; - - if (durationInFrames <= 0) { - return null; - } - - return ( - - - - ); - })} - - ); -}; -``` - -## White-space preservation - -The captions are whitespace sensitive. You should include spaces in the `text` field before each word. Use `whiteSpace: "pre"` to preserve the whitespace in the captions. - -## Separate component for captions - -Put captioning logic in a separate component. -Make a new file for it. - -## Word highlighting - -A caption page contains `tokens` which you can use to highlight the currently spoken word: - -```tsx -import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion"; -import type { TikTokPage } from "@remotion/captions"; - -const HIGHLIGHT_COLOR = "#39E508"; - -const CaptionPage: React.FC<{ page: TikTokPage }> = ({ page }) => { - const frame = useCurrentFrame(); - const { fps } = useVideoConfig(); - - // Current time relative to the start of the sequence - const currentTimeMs = (frame / fps) * 1000; - // Convert to absolute time by adding the page start - const absoluteTimeMs = page.startMs + currentTimeMs; - - return ( - -
- {page.tokens.map((token) => { - const isActive = - token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs; - - return ( - - {token.text} - - ); - })} -
-
- ); -}; -``` - -## Display captions alongside video content - -By default, put the captions alongside the video content, so the captions are in sync. -For each video, make a new captions JSON file. - -```tsx - - -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/extract-frames.md b/builtin-skills/Video-maker/remotion-best-practices/rules/extract-frames.md deleted file mode 100644 index 1a8a0c89..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/extract-frames.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -name: extract-frames -description: Extract frames from videos at specific timestamps using Mediabunny -metadata: - tags: frames, extract, video, thumbnail, filmstrip, canvas ---- - -# Extracting frames from videos - -Use Mediabunny to extract frames from videos at specific timestamps. This is useful for generating thumbnails, filmstrips, or processing individual frames. - -## The `extractFrames()` function - -This function can be copy-pasted into any project. - -```tsx -import { - ALL_FORMATS, - Input, - UrlSource, - VideoSample, - VideoSampleSink, -} from "mediabunny"; - -type Options = { - track: { width: number; height: number }; - container: string; - durationInSeconds: number | null; -}; - -export type ExtractFramesTimestampsInSecondsFn = ( - options: Options, -) => Promise | number[]; - -export type ExtractFramesProps = { - src: string; - timestampsInSeconds: number[] | ExtractFramesTimestampsInSecondsFn; - onVideoSample: (sample: VideoSample) => void; - signal?: AbortSignal; -}; - -export async function extractFrames({ - src, - timestampsInSeconds, - onVideoSample, - signal, -}: ExtractFramesProps): Promise { - using input = new Input({ - formats: ALL_FORMATS, - source: new UrlSource(src), - }); - - const [durationInSeconds, format, videoTrack] = await Promise.all([ - input.computeDuration(), - input.getFormat(), - input.getPrimaryVideoTrack(), - ]); - - if (!videoTrack) { - throw new Error("No video track found in the input"); - } - - if (signal?.aborted) { - throw new Error("Aborted"); - } - - const timestamps = - typeof timestampsInSeconds === "function" - ? await timestampsInSeconds({ - track: { - width: videoTrack.displayWidth, - height: videoTrack.displayHeight, - }, - container: format.name, - durationInSeconds, - }) - : timestampsInSeconds; - - if (timestamps.length === 0) { - return; - } - - if (signal?.aborted) { - throw new Error("Aborted"); - } - - const sink = new VideoSampleSink(videoTrack); - - for await (using videoSample of sink.samplesAtTimestamps(timestamps)) { - if (signal?.aborted) { - break; - } - - if (!videoSample) { - continue; - } - - onVideoSample(videoSample); - } -} -``` - -## Basic usage - -Extract frames at specific timestamps: - -```tsx -await extractFrames({ - src: "https://remotion.media/video.mp4", - timestampsInSeconds: [0, 1, 2, 3, 4], - onVideoSample: (sample) => { - const canvas = document.createElement("canvas"); - canvas.width = sample.displayWidth; - canvas.height = sample.displayHeight; - const ctx = canvas.getContext("2d"); - sample.draw(ctx!, 0, 0); - }, -}); -``` - -## Creating a filmstrip - -Use a callback function to dynamically calculate timestamps based on video metadata: - -```tsx -const canvasWidth = 500; -const canvasHeight = 80; -const fromSeconds = 0; -const toSeconds = 10; - -await extractFrames({ - src: "https://remotion.media/video.mp4", - timestampsInSeconds: async ({ track, durationInSeconds }) => { - const aspectRatio = track.width / track.height; - const amountOfFramesFit = Math.ceil( - canvasWidth / (canvasHeight * aspectRatio), - ); - const segmentDuration = toSeconds - fromSeconds; - const timestamps: number[] = []; - - for (let i = 0; i < amountOfFramesFit; i++) { - timestamps.push( - fromSeconds + (segmentDuration / amountOfFramesFit) * (i + 0.5), - ); - } - - return timestamps; - }, - onVideoSample: (sample) => { - console.log(`Frame at ${sample.timestamp}s`); - - const canvas = document.createElement("canvas"); - canvas.width = sample.displayWidth; - canvas.height = sample.displayHeight; - const ctx = canvas.getContext("2d"); - sample.draw(ctx!, 0, 0); - }, -}); -``` - -## Cancellation with AbortSignal - -Cancel frame extraction after a timeout: - -```tsx -const controller = new AbortController(); - -setTimeout(() => controller.abort(), 5000); - -try { - await extractFrames({ - src: "https://remotion.media/video.mp4", - timestampsInSeconds: [0, 1, 2, 3, 4], - onVideoSample: (sample) => { - using frame = sample; - const canvas = document.createElement("canvas"); - canvas.width = frame.displayWidth; - canvas.height = frame.displayHeight; - const ctx = canvas.getContext("2d"); - frame.draw(ctx!, 0, 0); - }, - signal: controller.signal, - }); - - console.log("Frame extraction complete!"); -} catch (error) { - console.error("Frame extraction was aborted or failed:", error); -} -``` - -## Timeout with Promise.race - -```tsx -const controller = new AbortController(); - -const timeoutPromise = new Promise((_, reject) => { - const timeoutId = setTimeout(() => { - controller.abort(); - reject(new Error("Frame extraction timed out after 10 seconds")); - }, 10000); - - controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), { - once: true, - }); -}); - -try { - await Promise.race([ - extractFrames({ - src: "https://remotion.media/video.mp4", - timestampsInSeconds: [0, 1, 2, 3, 4], - onVideoSample: (sample) => { - using frame = sample; - const canvas = document.createElement("canvas"); - canvas.width = frame.displayWidth; - canvas.height = frame.displayHeight; - const ctx = canvas.getContext("2d"); - frame.draw(ctx!, 0, 0); - }, - signal: controller.signal, - }), - timeoutPromise, - ]); - - console.log("Frame extraction complete!"); -} catch (error) { - console.error("Frame extraction was aborted or failed:", error); -} -``` diff --git a/builtin-skills/Video-maker/remotion-best-practices/rules/ffmpeg.md b/builtin-skills/Video-maker/remotion-best-practices/rules/ffmpeg.md deleted file mode 100644 index 57936902..00000000 --- a/builtin-skills/Video-maker/remotion-best-practices/rules/ffmpeg.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: ffmpeg -description: Using FFmpeg and FFprobe in Remotion -metadata: - tags: ffmpeg, ffprobe, video, trimming ---- - -## FFmpeg in Remotion - -`ffmpeg` and `ffprobe` do not need to be installed. They are available via the `bunx remotion ffmpeg` and `bunx remotion ffprobe`: - -```bash -bunx remotion ffmpeg -i input.mp4 output.mp3 -bunx remotion ffprobe input.mp4 -``` - -### Trimming videos - -You have 2 options for trimming videos: - -1. Use the FFmpeg command line. You MUST re-encode the video to avoid frozen frames at the start of the video. - -```bash -# Re-encodes from the exact frame -bunx remotion ffmpeg -ss 00:00:05 -i public/input.mp4 -to 00:00:10 -c:v libx264 -c:a aac public/output.mp4 -``` - -2. Use the `trimBefore` and `trimAfter` props of the `
-
- {/* Front camera dot */} -
- {/* Bezel edge highlight */} -
- {/* Screen area */} -
- {alt} -
-
-
- ); -} -``` - -**iPad layout adjustments vs iPhone:** -- Use `width: "65-70%"` for iPad mockups (vs 82-86% for iPhone) — iPad is wider relative to its height -- Two-iPad layouts work the same as two-phone layouts but with adjusted widths -- Caption font sizes should scale from `canvasW` (which is 2064 for iPad vs 1320 for iPhone) -- Same slide designs/copy can be reused — just swap the Phone component for IPad and adjust positioning - -### Typography (Resolution-Independent) - -All sizing relative to canvas width W: - -| Element | Size | Weight | Line Height | -|---------|------|--------|-------------| -| Category label | `W * 0.028` | 600 (semibold) | default | -| Headline | `W * 0.09` to `W * 0.1` | 700 (bold) | 1.0 | -| Hero headline | `W * 0.1` | 700 (bold) | 0.92 | - -### Phone Placement Patterns - -Vary across slides — NEVER use the same layout twice in a row: - -**Centered phone** (hero, single-feature): -``` -bottom: 0, width: "82-86%", translateX(-50%) translateY(12-14%) -``` - -**Two phones layered** (comparison): -``` -Back: left: "-8%", width: "65%", rotate(-4deg), opacity: 0.55 -Front: right: "-4%", width: "82%", translateY(10%) -``` - -**Phone + floating elements** (only if user provided component PNGs): -``` -Cards should NOT block the phone's main content. -Position at edges, slight rotation (2-5deg), drop shadows. -If distracting, push partially off-screen or make smaller. -``` - -### "More Features" Slide (Optional) - -Dark/contrast background with app icon, headline ("And so much more."), and feature pills. Can include a "Coming Soon" section with dimmer pills. - -## Step 6: Export - -### Why html-to-image, NOT html2canvas - -`html2canvas` breaks on CSS filters, gradients, drop-shadow, backdrop-filter, and complex clipping. `html-to-image` uses native browser SVG serialization — handles all CSS faithfully. - -### Export Implementation - -```typescript -import { toPng } from "html-to-image"; - -// Before capture: move element on-screen -el.style.left = "0px"; -el.style.opacity = "1"; -el.style.zIndex = "-1"; - -const opts = { width: W, height: H, pixelRatio: 1, cacheBust: true }; - -// CRITICAL: Double-call trick — first warms up fonts/images, second produces clean output -await toPng(el, opts); -const dataUrl = await toPng(el, opts); - -// After capture: move back off-screen -el.style.left = "-9999px"; -el.style.opacity = ""; -el.style.zIndex = ""; -``` - -### Export Matrix - -If the project supports multiple locales and themes, add bulk export helpers so the user can export everything in one pass: - -```typescript -const jobs = LOCALES.flatMap(locale => - ACTIVE_THEME_IDS.flatMap(themeId => - ACTIVE_DEVICES.flatMap(device => - getSlidesFor(device).map((slide, index) => ({ - locale, - themeId, - device, - index, - slide, - })), - ), - ), -); -``` - -Name files so they sort cleanly and preserve metadata: - -```text -01-hero-en-clean-light-iphone-1320x2868.png -01-hero-ar-dark-bold-ipad-2064x2752.png -``` - -At minimum, support: - -1. export current slide -2. export all slides for current locale/device/theme -3. export all locales for current theme -4. export full matrix when the user explicitly asks for it - -### Key Rules - -- **Double-call trick**: First `toPng()` loads fonts/images lazily. Second produces clean output. Without this, exports are blank. -- **On-screen for capture**: Temporarily move to `left: 0` before calling `toPng`. -- **Offscreen container**: Use `position: absolute; left: -9999px` (not `fixed`). -- **Resizing**: Load data URL into Image, draw onto canvas at target size. -- 300ms delay between sequential exports. -- Set `fontFamily` on the offscreen container. -- **Numbered filenames**: Prefix exports with zero-padded index so they sort correctly: `01-hero-1320x2868.png`, `02-freshness-1320x2868.png`, etc. Use `String(index + 1).padStart(2, "0")`. - -## Step 7: Final QA Gate - -Before handing the page back to the user, review every slide against this checklist: - -### Message Quality - -- **One idea per slide**: if a headline sells two ideas, split it or simplify it -- **First slide is strongest**: the hero slide should communicate the main benefit immediately -- **Readable in one second**: if you cannot parse it instantly at arm's length, rewrite it - -### Visual Quality - -- **No repeated layouts in sequence**: adjacent slides should not feel templated -- **Decorative elements support the story**: they should add energy without covering the app UI -- **Visual rhythm exists**: include at least one contrast slide when the set is long enough - -### Export Quality - -- **No clipped text or assets** after scaling to the selected export size -- **Screenshots are correctly aligned** inside the phone or iPad frame -- **Filenames sort correctly** with zero-padded numeric prefixes -- **Theme tokens are applied consistently** across all slides in the same preset -- **Localized copy still fits** after translation, especially on long-word languages -- **RTL slides feel designed, not just flipped** - -### Hand-off Behavior - -When you present the finished work: - -1. briefly explain the narrative arc across the slides -2. mention any slides that intentionally use contrast or different layout treatment -3. call out any assumptions you made about brand tone, copy, or missing assets - -## Common Mistakes - -| Mistake | Fix | -|---------|-----| -| All slides look the same | Vary phone position (center, left, right, two-phone, no-phone) | -| Decorative elements invisible | Increase size and opacity — better too visible than invisible | -| Copy is too complex | "One second at arm's length" test | -| Floating elements block the phone | Move off-screen edges or above the phone | -| Plain white/black background | Use gradients — even subtle ones add depth | -| Too cluttered | Remove floating elements, simplify to phone + caption | -| Too simple/empty | Add larger decorative elements, floating items at edges | -| Headlines use "and" | Split into two slides or pick one idea | -| No visual contrast across slides | Mix light and dark backgrounds | -| Export is blank | Use double-call trick; move element on-screen before capture | diff --git a/builtin-skills/iOS-Dev/app-store-screenshots/mockup.png b/builtin-skills/iOS-Dev/app-store-screenshots/mockup.png deleted file mode 100644 index 07c4a2a745c75d40df44f23c3c65076bed782779..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95347 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
p|7OAMjZ{Eoti|0zvB^qQ@&OSZc*w{ ziulU17~>FbK7S&vdG+JBdgP4$$2|eNB{wnh(3()T3G|Gdy!e}u#<1G~mXY7+h^)gI zJ`8Z1yAum|>7LcCK>KA;$P5t!-f7%fvh0!90;H(ke41vQTWN`Mm^mWZKFXfpRA<^B zo7=V$V$76KHrURA{HCl6jR=`tfi(C|PTBI?fP)+UEe4Asr?b;Cn5^b;G(~i2F&GVT zI!@Z}32@?_)ai1pwB*JMb4WLxE>Er8e)mfsiOFVI*-X#;c{O4Lg+IZ_{ZB6n2Qxv& z&8YQ$>DM=Z9W2cGuRceYdAhvT_ABmNJ>V8X7xFb0&$(&y(kE8|t7GFc#uBUYHZ?D9 zS^e|GQISnKc+SJwof|qo&~^t2P+5Pm^yGD6af!R;_vo|8eWNnbxV2w za%TI-HmIzrP^p(n`&Y<^p2W(#(&hdf_)tREWtb|AVVXJQBN<~z#=*p*Jx9`v9u9}C zlxzao>^1U_swl5h>b-d!ca>M4r@4&C&L56zWu!ZbPn#uD_gL+Zwo?~?BmG8!aK1$M zI87vMb+mA?YTCG)EZIMV*s+oA{}$MPuDcSm>Fd++>fD9r$R!kdSxYvp@y zdK~$Ez`UWuur5EB@fdrooiPXkaw;79`R&bh-$NsZcSS(GrbK4=rTwtEH`EvS?~M&Q z`z6GfarW)S#aGS-AQdz^cOjptWn(wc%#`t@6m0sc*dPxxji*0LsiRZ2Ua|JAq z8s}Oh`s9vkuqS*@d4MUg$9J&>ItD>=^}sPIVVYK5Yg^Fx8|Zq5n!l#*TzVgMQ9HxV zIw;G1+{f_~^eHaf=TI{!VNdS)CqF5+I`X6M&T1jVJ2^f=My52&(c_~(>pWgVjX+N; zn}>F5<87{!RG{h}s0FIGTCmm8JY{8}u+6`pu8llXmPMe>K-6&+QSUYO0z#_cZQiGA}9U3pzxECwBE3h0^2N+?J4skx1{6 z;^i%@*P8@LDEQL#3M#Tt@hg#Pnw%DasyR*xCD#aqU-zU?C?$P%(7lBuSGpLN-9vhE z<;*lkA0lqp3h|EktOG1h-)qF(JuX;JHLUg|G4=j|XA+{H;t({1QHn{q2!?cm>e#!LOO0R7hww|6V2W)k?X$lj<*H65chFGatGGYvPa!o9>%+T; zpt@MaUcn9wr(Sem9PProv{5H8G61T5-&sYE3|w*m^!n>lg9PY|~;( z(t$5MxQgy|CZOPWH}thui6#CZ>w)myAL5i~9YJzi{s(^hs!L=jWO1DUwPo+n)FgQ4 z{&yMc9ML$DC6Sc)IQ==_r-xS8=6d7^NG6-_#~8@cQ>_Td&-eIH!cvnnPB2<`r?VxR zr+2<2{;*wJ0J;Nd>OA+Ky!hnh7lE#go&qG%Z{DcxP)Lc!-u<2z|L(U=*~US^7W{r@ zay`sGp>r&FU{u;eDu4Eo;nMSk3TW z3bnz|?RHH$`#nQofS4sWP6>rE)KlV;7U4`={@7bBqmawgnT?m*!4QEnqPD^W*AJGO z;5eb1*gfcFG7B*3ab8epgcEk2a(P+aq`;bEMcff+FPGAgA#mu1}I{ zsB1emnNQ<7hqmA*jFCreO@CT~O zb9bYwr-rX+fDV`_!Q!wyd=4*X9WNewHx_IpIQWxlu8lw|cWOqk#jpnFJ3gY?^u)y= z=I&fj-v{n_Nl@u_e^2nCD*xRf7E8!UwV$~ldOUnZkH1!aw4hFn@C(tU*dr8wyi%AlASyaRHV=dB=&at?aj_HoM%pYrq(JTJKJQ@5a zy{;s|_ig1D`odJ@ou^)B9#H}+Cpbq0r!#Wl(T1?p*Io%*x!y14V}3Ej-M{t-h(a~Y z@E7LC#9vfMPZ8)mwBrYl51~o?wjZVn-6X&`>$?-D6q`2+|Mxz8xlDtGvvfgKOs77Vk9P0;cL?G+?I9GkhZ87WHb+BcZPvp{3flifsbVy9woqKjU}O zgQXVbd?pP<xql9}mk@e8ko7+R2lESP5!KHC)g=2iEQ6`+8xp&h4T?DBpAMJ<_R%+ff(A6(xfahyU= zaqruONt1QvyfEep!Z;?@79$APAYipT+evUx_0tIjl#UH^(BISFNj-VP|2u5RI4|&x z?e?oHO|%h+i+1coc8oajf4VQyFL$o^OR%#KZ^PkJ(Zi1fLPGW8GzXo&1ysCWDX_y} z886+n0Uhrt^EDOCtk(Uzu54{9kMW%M9YJmy5*!PpC^1Y^$zCC*VC?Wv+-3n9x(^i( z)}mw>YW)LFM6ae-!_`J;^!9oKw51_*U-oeKK*YkJo4 zehvQLRCTqO2vtey;K@NCCmI;OdTHv=!T%-&s}vYjGs#4sq-fqkyZiye{e1$G$jd^C z!d;k6E)$9wVjeI!W81TC7R*-}v(XsS-TU+u$e(k>@6ybYsaKV*&h0vI!IvW;uv%`- z{8s?n_=9j{70SpIzz;2SoRQ^^Pu-Ia^heJ%ikp7L)lgRieDIdh=&d0~6?4fq;=9QbsCv-R?*fNvyOlZFvkKg{6S)*p7C2T_WTmq+Y4NF-XHNlf!DHA zrP?L9jr(HnCNS@AcJ5j%soNzn8VL4(2co0!jKPO^0pbrl?`HQ$0|SGk18QT)-@g1a z3NKi=U1`djrZM577Lrk2de2){Hc0XNdpg8d(4P8W;2o6@q!_@<4CL1=Js) z4s-!H4Ux4(5zX|rSI*go09HOme6UJD_0R|2-jbYEj8R{aABJ$80RnF2wlYy<)?dfx zGY(3NIzJ=KR=;}u!O^Rl0&K&Eq|h?RQ%2|ON-nGxn3W#)vImI594b`K7Es|d;qKom zDmd@yEe*goljI}>wyDss+N1vl%2%ow20{@PNi>jWfAjy#>d2x2_=JU2kFV0!| zSPfO_qm6nLKOzF|Ad4qV9~(Dct?2du0l}1JQmuc1qV;e#UJ!_xpNHK#cXf zSB@^9&qGQ;ALpvV41c^?Xas#4&ll>1vh*uo08zJN*YaQEY+2gZ9^B}9-o1~LSXN4l z6VgYO)y!Y3-mmW~)n2mDk0f^VayIiy9KVl5OBe&s}db9XU|}=4&!p@mr2DJ(r+p(wLISX4m7g@r)`w6jQ7` z^kTb!2o(=nHzG10l90MUs1;9cj6_Z1)@C0$+$b}@Hfe<6x+`v|9l_I zB?;i_%CRR;;r}ok?pkW7rFUUM;p!^#=rlZk)$~j;&hq)_Thd<3tvN&?fs|X>&qLLG zLLJk^IdZQ-TP4(-%t$}71w1jOy^+d}i6#jy&`D>l z(hSV2m3J%0=Tbh3Gt$TR=9X?;dc#KvECU8lNH=MHW1I252Z?@aXvC3E8#7N52#o1l zPY~vPQCw77pK_z;$gZ;RVHk-Y!|5K=}=5Agp-WDm2>`*d$xZJS!pwQnQ^ z5F@L->*s~neOqm5>m_5B zZ+@9FXTIuYDDcCo+Bx5%)iygUn-l=NG2f=0|7|-riBIboHgHU4K^d}VH^H8soHf_e|zADevR!J$;h%-9I}L zreLeAmDhu`-AdTL=0h@jv~9K25R|jkcK$ZOF}Xqq->D1sp?X5Wx(iWy`*3YN^0{1B zqEgijWJ^$u(=`G9%`WFvBiq^r)pmd^4G{WX)o&d9;*r@Y^De=CDJV50=}P_iYy53> zi!nC_x8H^JUDoGtsI1?bML(0UAxuF*@QBBlE&LS&_U4>|2k#*q#D64*j)h-eeR-p$&{vrXlD7 zyLk>+!|&mKs0$4Kv>BQ)Ju%ccu4241r%dBk1;uP}SV2kP8iQRO7auI;8qdYx2?l?& z^rkAByI|Qf8&U@a2=2+X>fCxKF5Lv%hpK+TfFs~ugSYgX| zjfTq1V-!pgk>I@!_og~iZFj9HMxc|K#88pi{T@HNPJu)-0_HR^wu2@9uAh%E*wuZ3 zH0}P>Gt)Cjv(rsbzMhWC6d{qil@Iz!-BDLomoY;z5*DllrA{TYDs;O3B;r{%x)a2Z zZ)-<(U*xXsn+=>gHQX1yJUFt6^xGZ45}|^bxt=oU62wdiJjSp&v6$a%As@_Q#qC{h z8S#cz0A)QdS%gFDp#}(KQpP^XetP~?X#@B^8aQ>Pu6M5Tsx&7stN>XMCOD#~lT#I8 z1>EMArLd7=5%&tH*I>ErB*}?Od^Rl512gso93+!;;Dn)KX%)z;*1NI;48}8egM7|> zA8PTuG(SJ3UETw==`$5yfx3v3h$ty;|L5$QH9>rJLUyI0cU9r(Z~WiC$DtuoJEoz! zw^H1pZ)<|$i=inXT^ywr?p?}BjK(qCfzs*qJTt3-%qw1fU*y?CH-+p7!^v&zMb3Wy43|5 zfBj0ooE-FtZpFpw%wuDS<{_{$8%G`BOrjST9`Yv&pMG(E$sPc7&ZX6faI%jiK&?bb zZ7B0snOrF81FCNPH!8J6uCt;`JcZo_XapytPYrpay$z$KV4d~2>Z+@p&3gp5)+8-n zvm0YM+7t<^wR!#{0=JDJo^n0MqQD4COinBF7YMKXpHnmJD?gb|+Q&XyKQ~f#`G4%a zXIv9m+Xo!ix~s?*5fvr&0!o$@#Davqy;)Wfqk^C!#Ik@$i696F$>6#xE{L%q3StnY z3y72`ZEz6~5RfJyCG-wS2qA6CduHNYp6B`Uetv&1-DqGB` zG(SF3lBq-P{UGbv{;1lm)$7*I3W19a`XEO=^rlVimGq=E ze8Ca1!NThcm#HUtx@z3~u~)-o2*5+7b>gH^buU}C7ykrn-)%2muC$Eq12vhNbCm19 z5YrBga@8e-v+VTm{RA}e1w8uE^U>zLF}L}BKTO{p2|d)v%kgXSae5vH_#qw0`}97j3D2 zAghSLdaXCs%DDmkH%jQst$(G3ZvS#ziS8FCi(+^FlZfq}*4(j29qOVauKNw$K1(qt zOY!h1URaC$iy`v9jfgQa5SERD)v>}x=boP=sj#H!&jI9xhOzQdCA#h((*Fe*l|>-` z*idYJQW6m}#x$* zo6T>(_5Zl;Up;}EWa{$L}Si^Ihz-JuW@pY#@(+h?vy^UgPMH( z{aW_MY+8HypX2h{4?%UcE4yWB`J2|Q+rDlbdXd`#44jYyQ?)@^hV8=jDuFKI>Oh7k z{XY12S(SMOTRNy>HDxh8kM)FrP2R>=aPJiEo!o?2uH+8wSw5*n$@8x+_nc{VBPzM;~+Z z|G}ITDx+2w>lx=F>9JeO1etQ}*|S~F&`)#_78dtog2bp9Ey%^clX(r9+??-`*pd-r zUPg$bQJsydsC3Nvvfy(23f$}Gt6>C_oBneJcCgJfp&&__)K>i~*;044C%pHs5mhM~ z9lJ1@h`gEmWj!vn_Zss5wprL(ODkVU$ZO+wzg&ez#qS)d!*uE-?7j%2IyDFs_i!Q87@A_?eiBy!((9|Y z8uWMA%421M_}#Hm)GS!mGseS4ct&)zl4k@f2V>BrdDn^KHg|SA%ho>Y?wp|0U!c=<*8Dng_kwvQ^aF}soWO0iXrEA3&AV#PpR3=2l3z3x>i z&_MKS<5oO=hF2?5EMYSJGLLS^lP1Ery8=)5OHALh=x#*@x&hx1^1trZqE^?j7T zFxo#8H;4)kCXS4e^mvq)p{Haf3VxAH8jJWnbSGvXLg;*REw{ecn!~OZxRqkiF+&cA zSNo~y;?X9=yRpb!AL}$NX*qxwoD$QExL}`%DT5s?f%cWr%frAGpr$SEgtZzHx?CUI zB+&mI8ojP`oVrN2AvARNqvvbyS<*W)cV$-B>0#b(`j{}rieFC8gLDrNc7$kw&3cAs zSe<2s!2nlKRN#9LZ7-szHqBQre&yL6?`ay3(9sFxvq^oPVyK5xS`yMc*OV~iLzGAD zbKqP}NEc~O!Gr=oEj;B+92!M)IH*ae=?h_lPr48*u_~h())ARxh*^W~%IY+IB7S1- zn7x(bsDR8mXa;YZ>4~{trRi(x%-sQgX1*coN>qkk6|;)xn~r%lLmpB=emI$)lB+RS zdB%;?zZlJ~kqx>dm(n1nSWsxSU1trUIc@K*gK7s#1-{j`_>9}n+Tc??%oeKIZ5-@G zTzt!FU5f+=tITKvyzx?yz#E0}XAg_O?0AHCS%$8sy=t!O~mhchpAI7DC!o_W=x&bF1-l56q$4f zY$h;pbH_JX^n|jHXmJO$q*=QZ^@)K_m7keas*%S9(+b%g&yerROj?sC$cbfkRk4;T z?Nwi?InvQ{DI@!2@S=*5>nT|2WsdbbBb}GQ3qE#kGX9%j?53RBUbpXBWT&cF8gKFM zv*bsX$SN5`yfx&&ry$`rv(J88VE;-_EGzn(!*kH}M1oYwy65TJHyN_`cCcD&8N~$Q zY`V8Yll$Q$niK|QpVzw47H*7zE)LsVh~JW^Fy2+byi-RjGycr;YgeR053AfwK9Tam zdfzxzPbxXZ8L-6*S9K>)r}*?A&2vdPbUr zlO%Gwo+GJ5~}7NWi*Mq-b;3P%bvV66zWiq>H&3qx2{j0U<_4M;im` zyI`A4X0)cP;2?a^xs~T=O$NoAc4)}-x0>{{Upx`psxxi^6F%hOBU|Gkr%`A{BiQnM zx}=9Qk3iu{u1T}th%vW2^^6B{##{Q-+_P;PU)qD4=fH0$dLw7?t@ugbCF8g`@hTg zNEUi@T5`$0k9mELa-Fhh{LrFe#c0T4uFMM~t^APr`a=@~C-IAVoyWwi83%MPG0Bk8 z&u@bF1wm%@@H=b3E5GmYB|vg>KN}ur2_$iq9U~0ykfEc~Qth{BxiPlMK^d7%$c2z^ z&R(erE&U$NUXDaHKeAmcZ+}xaMcgMEuy2d@aQGR-+wn&pUrGHF>&ZDlOwHCLL&)Gy zyyJUG8F%-B2c|rqXefWTvhE~WP=x2VJby_F+Gi_YYg@PFLZ8I&@jih)`fS(v6)%a) z^C)`NSLxUNFt-&`{?!*@tlBM)wi-MZop)%Q=}R3hPL(I+7TVEFH{LhQn!-X7)Ph9%+~SVe=Nw+l zOlGE>ny570x!RgVY{SVJOEL3=m|hUjNZ)__F+tK79@_VY&H|rKYS(sK>W*y6!t}sX z(csyclXeQ$d2rjd8Tj9PuH!T4MP1jA9jw9h604J73K37n58{saqo(sL1Jb%75hqsa8N-V*lgvpEg6SpIFJ$NxqMp z{9EKqKZ080?&h#pR=8n4&CcHtzSnI>0HrGAg(a$_& z@FtP8CG@O117M%AVx#d1f8k}0Yb+r?%=fxQzJIoG#01zVPM-Pir(T^T_0g=emsggZ z#B~ytw9LpIG&2<;w*$@@E}qeuk60W`$L23b8y=r}%`|_RB?wFwsDg-+^gkgtyB!Xz}SauZ2S&WP*?Qs2n6#Y*2@IYH)Y4&)r zG68GhD|rdZ-;xQMux;VXEu$(!|Kcd_`PSLuj%DZO5M)G&OU>!kDFES?Q3KOo)J(!Mu0OVNexl5>M(p~JH69Z3_rb@Ng|WYzJ{g|P~t9plOnjF z8BdO;s%QJ4Y8x6B<=b!v?i{6--nmT-#%*CpdAGvf>6)aAnTN(16*A(8^z^8dX<^a^ zO8aGf%-vf~qzMG*ckT$XUS6(RieqSfD$?1*$qL9M^&zug8^Kx?z^&A1k*hfU|8o;-&1jcbFa zC9|bZ*^i5$hL_L@?BerA;%J_{!~R*kb4wS~PH-!D%P|N%3iy5t*s0n@X;N0QybgX7 zr4qK0=$rhw?6EZpUQo=^y{Pcu zlb=uw+&HO2tXsOMhaNuWgB&WOCt7XO{^mHD`qErh>lN&(z|qkUJ6EmF%Z#fg=9TIY z*`uvMAh{54pXOuPc%cFbuZyXpt9l{DsEUbo(&Y>+95NKt(kzNU27eTYW5Lft`21x( z@bG&aSdU|{)=GQF%wu( zlNn7~uC6@xr&CUJE2u{XWA)mQ7<$52CXE=^rlNW{_|f70dOlb5Y6pwa^Vjgq7$(;1 zTH`7d$XuBWOjN-qFOxQlYIi=pmyM|A?XAH(=Cn< z$F_tO@_3Z~<=~TCuqqF%8*0v#^NZ1$mQMdcEj+7%iN&zb>`v+q*@)fMIS5u zC!W`fzsf46m(xLi=8lG5ohHT1f66XbVxr8TUv4{ml^6ysMoSOFo3RH1AjBybs@vre zR-&P5Ndbd-jnh6Tz}y>yTc)VaBJR^sUY;F^`Dr#q4N7K*JUz@T{AbQnymJi3`bE2$ zefX=6Dq6a*_b<>B#rDDMz$HO)4J~91!UW@(EPClM2Kr&tSgC{?tk=z|*ztQ=(e)sr zt=4m|4E)1do~6w^e50nq3K(dfWw`SZF}IB!#-6=GZ3B$-20khcUCw^9Fz!^Jpa|Zo zkJZ!Z=f|+Vx%|oRe<7eFbI;O$7O#o4te+8ZeB3rEqqOiMV~qBumzO7O*eoGi)T1q| zu@)U>s2yG%-;6ilXNzK)x+3j}Dnc8Xh8KMo+;?U;Zk7erq00Q9>dz%R^Zo^ zW6#g-ftzlIT4%js>L7w`;48C7#6pg8g_7A|r8}wZAS1R>H!i%tFCSZWPSrY!ub3`? zcF9dVMGU~b2Gek1zcF@{94hoUl{P4fNXHCch=p~8rVoQ!CI#a!#DWt9MN$f%o{fe$ z%<`EG792B5%{Ioq%kCD0Vo`a$JpQypRwO|urte;EhG`X+USh6`y!{yBYJ;j;6c^$9 z*Kn)P@Iuf+^sU>60XMrCRvk0H8yF1^-|4)C9R;{gPPxDq0u2Ig1g__ftTCU~P)@*B zg*q*AOU_R}vZRb%av0OO1US}P!`e9DHHc@GIA@hZTHuOvxk=-*IdeHgA3u$~ z?6OCaCXoC*yyf0G5i1+3t`0Sj^CR(*@!tIXB)BmeRyG+l=AjFGyS03rrjJeJV_vCv zs8+94G@uPB3tv z`Yv-Ou7#Zcl#WsJ!|U&gDA&oO_2`!gUda>IVc+09`4czF(JffS{F?#5q%6Zc=E zMJzozjoHTwlT|l$%|r7(3l>XtWO8@AbZj3uuBWp$sN1CLe@sGH%lW@BXLieq}gx!_m4$T)nH1dl3T4@ zrzwqb3J-&P-4S|!52w+14jXh9@PhM@xvLp6Y=qBCd5KCsZ|PflM7tt)3{eTnr&~c2 zO2EU6TKGr|^)udHixoFRsd7G(cM^?BbeG_w&QPz{%$u&&1TfkCon5;u0=oV~AczQc zWS;OGipm$^KV^uyl05`fv$k&gW?He?+L5wv7=HJ&2p9Df3>LINw6rjMb=7yjgC^!$ zfpLO|mDRH##j}nsy0w(KSmvIj(Bi8(*T7LE z?CS64EltNJR^S=Eyrng>OA8JY-%kk%4bV_I-=SAXZ}c#sZzpW=CJ)b{79$~DRj3%x zrbYV;s~oY*p9v!?mPKJ zhbO7-k}aC@@Qws%d7_GsN1qUJ2j?@<*NXZUxFuLoBs3}b0o5W*y14xNLz59I(Lk$N zu97i9(N92 z`w_mWh5H7|Dj-EB(mY5*2Vmt%1>SS{3^SM565aJRAbw{vKsT18;-XCBc{nc5MAPY4 zWNkwb(wB+%))gy9D~75Sdr1$Y;xD%aP(OSpR8{seooNJk1VUNJ1U;DTh8yFJ0z6a2 zOmhCaPN+e~P7WM}U7!~Y6~|HPS(QgDelh;U99*%XaXcK1UDB7cYj1<8DoXiLV2>1h z!UxyOLyHJ=syoFuW+FlHAn1tc*EdY>)1ybE>`VF+ga$v{c|4BkJIJq_^%)vC4SyPV z(F~dNRER5x4wIJdx~_f3bXzJma2P(TTaxhR*a{&LPPDx@n0e$$b^Z)iY|`x;fg6+( zwshPpPAYW&ktst;UBqJm`4!cEjZTc=NN>%2^bNMFn@>xj_R-sGg+6v-!KuHg1w8PY z!rGQO!18NE*I8dfqf;8_2c@jeyjVdnF$YRq*p6p)vjgqh7^V9{HrgZA0~A>XY4q!j z-D97Kr(IWa?;-2XB6g3{#f$@_^|)TSlUJ1kpRcBFRM1?fs5xX-blsY57qCWmz!P+1 z#`LCite2Ra={1EOZnRJ?vBP^#;fK3_ONBlclb-ppsE<(v6Wg|5F_gl)9Qvr=lhXc< z(bx#}$*e`(S-@2+Q_YM;4Z7$ObZhRIrS}nhT&cXD+V_B?*kUeoHIZ{|Pz?fs3ke;& zfM&mCOFUJdr#OaFG=`i3B>Xw2ZmNi*&VA+d3a@`rxB@`2?oh^vioM@_S*cw*)Qf=_E=M zvVMS}1wXRC4}2+j9mDL{OVV}n*lSfW>#Nq}Cd*4@r0VE?TNQ|2+M=-?Z2<9aK@fDg zQd)U_npDQtZivYrs)2EIW<24%R9M`&(hlJs8YK;7<iKi>2vr?IpP&D@%R<@&J1haW;wtV4gc)K+&@90ep>LA6hP`EH$$#5Im=2e1;mRZxn zNoHRr8Id@a&?~&%?s^SX4&c@&(&;JkiepJ&m=J!BQy*QY#$*oW_7<1d|14q}kYKXz zGY=_{;70AWwDjUj-y-K!JGT*cno+v!mK@=9_CmIKpcB?g?b(DX4_VRhu^U$Y*70}d zqdJw&V}>+J3`9%!Tc0v$tEA##3(%WK@0B-G8mCY|Q0JGfBNC)T@|CNpW#VP+&u&a8 zW|@z?f+~B%)rwR%>2W`7*bLpb3ylJ~3btRwLRG`sq>7!Bw3^ylsPPK(i82ZAhwvae zuApHeTn_F98yhU3d)nC_XA%MXfJ^m$gN!?-HFm?A#!Bh4koaDlhPTnN`2vorovs|H z1K%9X1QFw=QFwv!8-iC4JLr@T8Do=%<{rVUMU&{(5JNc>pqLaQ1&{>aflmssG4Od; zPI3EaCUHF=C0A=p(bo4#7FW#%xZ(F~fZFJ6ft2^4c4T@J)PS^^2tI_WtYwdWnVU)) z?Hf{tKM1M^8kcegF5-srq^KrjN}JB&VA;GKz*pdT+9R?}1PxJG8>5}S<)%*{*F{WQ zM8KdX47R{ZXGskW>IzoHFtxRvUcM&@y85cw(xlHu^gNk~ znFSy3h+C$W+(67WGI9b%<6z8o8rV6dK0O$)_hzjA9q+cX$=3g>ZL|S z=r7VfN(iHn&)1D~&lxa{q)AQ36gKrmbca4cB+k@FJw;qA4`4)S6ZA8>;w$!neO%5# z#_XyQj@##kOkVcwHlo3=nKm1h@-B0+eb%f=V z26nc+ha${3#-b(zpa_T{aa(QcH=#_Eep+nB^ocUqv0ad-lC>*5aa#he1xtDsJ=V^fua~i}i$D>^dGBCH!x}u%!U+qdsn?MXa z)1W=g@T$oqvgV25oIDlf8a){BE$$HkIgG%IO3|}21L9Z5jubAgaGR;OJH^aZ^4(P` zV=PO2?V*4$n3LCQ;RlW&dt*m=%D*sR4taF_Cj1G!C~4PAL+fv*D^nQbL2m5MQJy~5 zXraB8D9{U;|7)51g|$PH*630D;~qm%4k#@O6;sq)bAmZR+sCQ0Q0>53btBP{7y~n}%n;9p@2vTnL^)5Uwq3yx=>#jhT?Zj~Z z1?XnuS7+JUSJhHJZ_-M!*-5kUVk+c_x&S|BaP}`*<#1cOra6%y8=_Rccyf6irc_Pr zyK1FKuxcNr-g(A8c?yyH5PRXUKkZ0x%OM$04>Lpxau}58p8bDcyoOm>KO=)gxfZ++ z;dd~%b6W+Y_F2)RP^Aq@vwmZFdb=YL6-hR*?o{-BM04cj<(Um@4z(+cYhL)950aa`?7A|c_ux&|5N{E%#tNu_%smct zN0yS(mfzqqUAD5gH=v*wemE-N@YAOG*U;X6C(yCEGh5CRmT6}*q6AD0nU2B5<9*cK z6jSgDzzROr^c^lLtu^rC60U8*BKaNs4*9bI8%hI|k}n0e2#h*fZxusdi|S6aH@`WH;h#kiU7!^4l= zVXD31{opDOpVv(9!l=F$EqpL+HN6+pG&FrWZu1*!&BHT$|(Pl6LC17^eR*}iT zeSBgYYS*qvDBB?G+E0X44%@H56Q;g1-uGAys#Q1AH$9ZCj~@A zbPFctJ-p7IMG(c%(L+*3cszu!j$^OB9mX=qlUT9)8E$Yd%ab@4+Xp*tsX}yhwkyxd zSEuV?sK9rkh*;u*!ALnkR&z|Xvomn3OG37qwDZp*+vj15t?=KLWgxFDJd9MC@Ck1cnTvR=`tD(z~T z!8LqZdd7j6P51J59=8QM!49h$-!5d04&F@cSC-O_$3uOhT47#xF z*D`JxA!aFB7MHqW;M(!1Mp~4+a%drOa3RqyCxVY)f=87y4sh%iuAWFljM&FW1*dmb zYLI>@@X06${k`(fZQZ2?nnta%wUCJ`c%d8fMe)u{ZE$yOjAeQ?r`|rBIy)}E3u2r|dfem^vL64N~hyh(} zZG6SW!tHU;PXCwXbZS&2K4~Ty2?1|Q92{K5IXB1Bcpi&o;StYz9sPMV)da7wT#95} zz0Wvu!9ivNBsi6@K)Ijz!f%M>uMV!|*7BoIP?L$q7PD_!9s6hk!X(Jv9}{ZH6KaBf zOtKVfKp&#S2KVoQX`UN_IvOztCBtc0nMoaR5^#nG#?Qc2&?{`0cGq5C}rNfbx>l1LEb5S&2B^N4UOtRC1>A#uA6zQopOE3LcC zm$dJ-BVGOZ%LauOVzW%CK(A?tFEpvkcrJ|qBZXX08ad_2SWRO9h!EAF6G+uddO@@u z1l}cku9&nx?)5icX>rmH$xI%sCdYRqu~E8bXH-=sW|*M@Nf)kh1i70Yr}npBM+QX2 z-o?;#r)nR#`LswTp$)yID9#uDy;O}8+&xvssNRMg#hzCVU@m%HnW3uOdlVHE8h_k; zHEE>o_1swZ#?+5y=pres6coDAJ%Qrxf#m%46U2`0d%h+`JCOYW+k(?gzivG*W%+b7 z2DI$Y;_JX9x@!))BaO?(D_)^vs;I(PX4`WJfTzd%=o#O)E|lAQfHnY+)q4{G9lt8b zMWc8_ujw(9aO0=|V!LiP|A8nEj?2$D$oy^Eq6c26EQKf88U4&b`z@u|%Ra%>Au{vf zaJ$iKn)Z0;xRcRXlC8%G|H&v1G6l)_Y-9=9LwxIvQNzWE6&u2hX2-R8Na@joOb)?> z$r+pfW~IM_ww%P7dHUEu?x6$9fg9%FO?N~>{8IYCL94(92s16Z>5jDb*?ospAK;9) zNHx?FvuYCQD5qN6WXOc`RmSJM7-M13^5OPAGJ^~N2>WevG9xbVZCuLjex zPF_w>xXZ&eAC1)T%dsbeuyp^D9y%Yaa0HFf!gIdCZFGLtV|kWeh&iG56u8*&a#Cvi+G+O!3$-ybXlt9d;Tx@ zao(!ys@!zcvy5JJD%zkg6NK3B>7z6d@9hb5^CnEOxJ1rT=uT6`HYAbeJAnm8;Jf8R z`Z?~i8a}Rzdrrt1#&4qyAR1zLc~+sX<}8p=P`(16@#Gid&ToDOuPLJAZ)o&HKbhN! z%(_b|kY&^e7xN72=^D#s(DtD_M3bf+IZDlTrA8!XTFQzZ<c8WLM-rO&_%n|=&i$vL=F(6(D;^vd3oxzz^#9AT~yb76bjG(Qb zlX}>V8Z!lj03Z-DiUEv3OZoyukD;>og(Ho(;j^!q)71)xF=LQmR<6lcD)*^F$>tw! zJv%-I0%SrTc39zK5WAOfAlkrXj+>-6n+rw>FzH1ugO&wxq24df{yM>{$ zy5FJcYp72FelbH0S*MWpV&(nDe?iuU8skvqYzp&1DSEU~b4K;!K`GTBdvv0O^g{e1 zBhc_b3_vPP8nW;+Qmpz_GhG^lu;1ID{u`VLnI@bw$r3QZTAd z8lF=QUHgJ>x3qu3w>vA`zC(aBG&xdY^<)&vdBjt<_(Ve8L;GY$qZ5@;Z(;p$7&A!& zvF`H@DAUR5ve%Nbc~{Ap*pZW7`Pz*aaj!7Q;bR>YE_`tkRc)H>SVm8nxP^7>{&AHF zn3TB|iH1uQoHxC6PN4_*u;Wv_wA#P(hu>p^Jg5W%vXW`SC;;0f&}k@CS&CjS>6+|l ziJp(Q(AWVQcqt{MG3XnTGc2^H8|ALi68ekxRDH~_m{nzrP5h2)Qq2nOQ2OJ8Qj<@F zcDi6S@PJcR{ki~POZ0wlmjFYndxqNnBENSHuyehi4EEqny9!q za!7Lwr42ZLrun`Fsbv2HU=Q6u@w6=Y*u^}A1u?PdfdVr*3+Q>NgW8E$_7C~}8Uk)- z7wF-g18j+6h-nmM#q5K?2kJZLXWQYLotHTRzX?jcQO(pA($ZOA1Fq7oqJEM?Gb^TH z`IPFM2uH$cOxR%_{=Qw|=Z=IfG?+L4rU|h{7s3$NM^&NA5g{`TWpae`36L~;#(^0u zE}G1a@8#w1#fry3Uz-!>UZ#>M9@i35%&8!+YR02|5J!bjb0LIh?7;_Q#kex|VWyas zhEmOf?LCJ4UuFoh!5EZey|dBd%<`$3@gW}6hIFSrG*0Noo&Y>BZjqePiQxOwL2DiUx0*D@6?hcJ{4FIar zN5zK6cxYU@d~BL98aLH*y9Ebkyc-_k#leymyj*~lwnWV^C3FnM50FigZco|bBM1BG zBkPNpGiI$pr*GdKBKGRAAUK&By;!pp_Y!Ff!ISP2IZx?Y6*XHYsJSX;v;#{kD2?#- zL-_R*eJvd}iSRBt!-NQHk1qckTH2yTc*L~-BrLpAnN>)#5y(l*box1pv=;b!rOZcl zn!n?C{eDSN@`3gq{HCLN;GN4q7V2O!QeQGF@8!;A3nnwIp9DTjBa2s6b3$JKF7gjDuR z@E-4a_$j;=fA+i>ki?FSib}#E6;bLfa9eQ6r&ReGZiddKLKhM*?Iz8wy9P5R3cU7P zdEI5{p4M8Syl9kILemm|XK@<9aR?PiN!Bkua?KReusob$(m|Wx5PV=Gv7NeyCyj zOo0P>kE~Q>to>ABU)xjQ9Ra=JQ9+x-mWDNSn08L(XoH%xk%~_@UPD&DXbs&b95Mom zfj<{2BS(Gcwik+S9^`&f2=e|Lz}_-m;e8F`l+m|2MOA<<&5hl@`&jW3658V8Bfoz| z?6v8mu~KE_3OuLS>nKs}7m|NAOVuT9Lr(93HB!JgE5M)T?XYdAR~Eg4CF{9LMiFx@ zbcan6r@%tNNi*OFD`9N@FY~0P;M6`S@0P>XF*g z!9I?m5d8QDYnZY#xt@8;;EgpI1sPqDI8m{zdL8f9;La4D$G-sLZc9Z*OEWH9KFP;* z(up2K3s75p$Fydfsq`3La1yogJ_eq4UsawVvQx)gl+?NSd#KkVmso-5Q~qxJ7f;MX zQgkf^OIKVXII7$5L8WOqz2eX(c|{jNX<&Pf#MN1j1pkReYT>;e=T+o}fEcXdy{Oq( zbm>}D0qld5DJyD}_03StGP zGYO}SlDu&W=(4}k9={ONHWZMlsk5~@(Q}?=v5Vw;lI6mK)ApqJ7(M!=AnH0>?&E>q zu)`z%paSI&et+1}s5*A$dJ{)>nKLqa4?HPpx01xl8f+DyWC3?`{F2J}_~CUC)mbhv z#?qc#HBymDmhLGrARHxLmWEU7N9l8dza}V5H@#-$&R`q9VtzWNCWd=n*+oVIAK?op z$ZhfsX$m(3P;)&xv#aDt0S?Yo>c1NydXzVx3z1?hH<7^L7xNfCgts;KQ~>bH+XKcZjp#V{u1rIV3T$&m#+ZS#dQ3yF~r~xAc38 zXBcBK?TQ+IB8W&yJ-=OPdfQ(MH!_{miYJhC7I4M$6)$SI`XyvvM&ClZm-mMELD7*j zneNr}^JER}lYJ+fkffG^P*n|$n4D=ta3mfaFNjUY8U@X<;7Leo{vX91p2D!3oOU&E z_w&)o5urpWTGZ_kiLbIj_Y$xcV2ERJ)cI)adK^H?*9jP}q|`4LYdedbQqWWCcn782 zz^kxePaMH37p!*O9a3PsGLuvw4lZb`{77C^#r!Fw{t6xXX*_p+g9^rewPE$sRHdk>a257=arUDp^mzw^ z`-b?3o*0vR$g^94Yy7EncNKyu3HGGufay?19hUS-+5vlj$%PC>CTF4n~UaF-Mk|5%bOyMBeOQvL;!n@jni z6^M0@ZBQJUBQZJgKk&l7E@RBP_=9m0Xro37-Gy)_$mCQiz!bWd-%rORFP=BW@##YSLB|CL? zyVH1XrOf|90}CLXV?>{N;ThYZuzt6^e-N~HE)8EhtWV~9dq*l2oKJ6xq1Pl$RK`mnkl!vb9mKmCC|P#^5-j>=l(nt}AC&ycyKN(pJQSA~}7 zqHhKaAS;y?{*bv63>)y$M_4>F%lzHQ=Hfk{NXE-({ypAMD9&%pBGC%JkcD~8@ z4|Im5J7uE!P4IIWG*qarFKGLMbk$W$q6nZ$e(6kVSyCdk404M77vJvZH3Qer8s;%~ ze=RcMlj#QB@6!CKHe!2n6O(?jRa9@czSNNmGsWD_0?-fTn1y)v$|Qy59xs4gWNU*b zaSv<}eG9RFy9SXozlPvs`E=C<=wP~Xq}C1}iC?&sa9T@dKkqd*z9R{Y!olY3Ps7V; zT4V(ORqzN2=818yz2F@EKe!aU(&^HM-yqO$K*-Zpdij*TL@^)=b6}(4j)aO2 zIY~fKdqPzf*@mm)Or6sSLbq)!6UW!U<8s)24~*UQzCz+U?xmmDTc~AYXI30qmA{f{ zH1Qaa1So&lq)Li-!Ld)n5!b9sy2MC9ZpLB4&m-6-Exc?!Ty&KfzC$G$0>tvhdAEL3AM}}Ire5tk z`AkL+r|*8rOR|VnH?3wkd{=Op*ij2F4I%_vq_l^g*o@T}&j#)iwr_q2F-4Gn+7(Cx z=uqr$M9G_nJF&*NTWVBDc-|cbH5ih65oEq{?!XS*@Gids{R6+zCl1~OV8=kBbUfg8 z$}66-<4GFoZ!M)+&fV(ONc8MyouD|Q3BOL=g8S5LAf%UNnAxPZm8f6_i*P{`_FPvv zt3Ap6qeIH5QZ%gZ**Fv=f_+GW=(gFiFM#@?;wlGZxWJ=Mphxq$eS>Uk>W8F@y56p3 z^a-!8HY>nEnX^-F^t-*7O1hUI2Xub+bjjB7P2nm+Sbdl8`y??R;?K}~y8xsv4yl>` z?DvDZP={Um8~&;p{xI3@1>oszo7GrN=&z-`Eip;HGF#jzXn6`DL;!_N@Imzr^qQG{ zX_h+A#NfdtdDR56I9|D`T~QWr2Fxz*dh2EpV=rb|qX2w9^S`hh<{ikn3|cqtKxz}e zGP!Fol(!awBJeIvl3u%K#s6h%q^t{73G-K;B3Llsn=J49c@B{XGq^n2^Z&U?< zCg5bj>=z;a_6Xxr(F2ly9%l7IQ+w6LYjuCx{x&rnsxlt(Q(OaSA3OfLXf5-vy?lg+ zxWLVDkWXA8vCO(PF4vHT+igPKNs~p3jysl=5@P^>MGJROi5Q>cn#b_Xhb|C`GejBx zCdmZ8dr0ToLO0tt3)^QTA_pI-6qS@Lupz0J>|3@*&MMJzE{ zzpPcn3mXZx{0@EIOHJF}w@yt80k>PKa1k@u792-3ZpV_AE6BnXw~0 z>BKg(>wUhm6*!XpYD)0GtH?l@g;_W@d5=dR`IN{PvMz_dzAhx;!d3V;`MjZWzqe{R4kFNH^x?H`D)J{q+UW@ILvF-d4-f@6;#m7X5-`?41Pl zVwtbMS5XP+$Z|Q^$14vE4suq#tpp`2Tn#c$&fFrUPFea5k}-iJ_JsQWG!>(+_R8J0 zH|%EdW<w68e0c*_c@dtiCOX>(Goh8iTNp|K-u(6=T%;OSdtO!6s;Ps;=c5%@a8Lgi#52mM z-oGllPKX7bQW+VNPYusYhxZ&P{R`VL`9dz_D@oPv{N^pZyj@jYHU9Ji0Zc)`%E+MQ`_I~-g{#x%mp zrD)0m-2U}8vNz46ha?PpOQ@6psJcfYXUpOr>ET1GaAKWb0NvTpqA{e=s9y*~lR9ZI zG~G?*eashp6b=przoUp&PVL~7two=u;%`>~smu2x=(6dfrX<|pp5|T*wR$Jsjb8(~ zEW2%ri62OxBZAeSUQ2la2ih&&!Kif6)x;xYPH5_s5uVPNOp#~Ox~3W5FHHi?LskIr zxVQ>(iUdRA>l0~2AIqk0c|ll;0FGQN_f&SI{bI*YvzZTuN-!ZABM z;r~`=O&_sAqrxf{=z^bv+$6U*BTffPQQ7!Bymikb^5$bui<}|nvNEHE{tiH&uO#U4 zO90wC56aK(g_`#gw5XTA>`6Jj@iBfcm{Va3k+M`BSGL*>j%J+s@-;!8B6Hxbj=cVL zTzmvzk&bGgR|Ra{p6-Wv@=&{ZACNX7v2TtuR=ZJav6b z)x%q%Qf#8y(Vb9MA+Ajoi1!S(zZBz$T1E(I%!sGHg^#sy@0BCfZ;gpI|BhS&{Vemr z_c{cMD~M{Yu#}6119MQ z>z+3J8?U;BfN)Lc;;WK-gX(z6i+8JMH#1n>mZE#&TMb*U^N1boK6Zk&5ssS-j2}CEOgQiUq1jwF1dF@ zDvrD)_d3V(y;9N=SE=MlAmA))6>*+%=`b31yeHPim>o^P31#HhM1 zC+m1Fxr%3g7(ZQX(o8-(t6O>Q8v?1{_ZL_m67Oos>XN=KgI* z$A8e9VGVTO4hFj!&#=R7PicXs0dZu_3ZDN6vjp|&yqyl)h$R%}l4UCN_F&=ZRLC7$ zNpu@<)A=W^xGw7+P-tXj71*97!;&MrnNNX>0PocKOh(o-Kt<4p{(%s9@a3;iaV&F% zK`XrfOH|J7g+f#KjJ@F7(gHRBjiSQ*pOVozP4SAE>b20VG4hs?R`+$pBvSt>OkjHV z>TPmItSU1I=`J$2@W+qGFgDG`7VBYq{<|b3;S9BSWjh^Idxy=Pv~=Mml}*Umb@*#04L`%#o}j_%TH9 z^G!3&egL0pXwI5}Qb;;`;uJGJv_bjPxZv1-YAZhSToTZ+&r_OT0(7^R8iUJwCy5e$ zVscy~<^ah1@OMqar~Um1vm!3l;3>_&yFj+;T{b9QgqQV9m;!1x5pTx5)d~8^%6qa;`79GKmV&>Vgw5V16}@! zG+s;AP2UNQ7VaFR&>gMHw%&gz*0a4wb<`OCu1aFrJ&LlPrv7CP3~b*WI43&DfnKf3QS4%-<1$E z8Fs{ZbO$D+eBIq;2a#M=l0EEmMZ4Js_c}QPod;+Vt=oajqlmOH{DZ!fx3Xa6sY^qD zkQfE`+p_VZr%r-mPP{QTA|hByWY=(IKWE8X#QKw59RfR+BHzaOB{5Mm&kF6Iko_WuLZt5H`}->I_TNKt7C*Vj(hd02&PWA@WP6F zAyM_UZXR#r&5F`+a`*kVwR9z=ty2PLBv$|V)EaUb6^Es?uM}Es$n$2%{gwKfm8Kof z#mg=!?zag~_ECe-uhf_M_<_4mwrK2C0tez+G7$A}o2F77?m0q#&l-Nm2s9G3oy1XN zY+o0*Y%_F~R3EFQ&DffkmXOz*YC!{ly#}?xPEmAUbQEN=Dc^eU4inxo#z>gY@qdgb8YQz5VDeWmw zizI34QB%Q)52@BlmpW;2V_RXyR6!)YXK(GVuRee)vBlGvZ(Xrv1ayy0xO44l>d zmN*vn;BYh6XWmqBBeb+rc=X<8U3Vb8Y#AziLF}XqJ0%X@s?!E9K&1!NJ3|0P2)%Km z|MdUny3@DO)Qne)+X>~d|4Ua;No2YCcA#Og--ICWxyxwi=9OuxrHZd$0hA_0AqZ6X za2)H#&0MO%0!546mS9_ts0xc!yJ<9fVJ0vmdKS}e38S0IV?)F*%P4kq z>Yd;CLO`BNfdPQ*NkrPFypn*?>-A&Drg-dwZ@V_u@ZV5jP$y_XW;jvmn6?gE}EP1 z)V`Oz7up}Vgq5%;7)UhG`R5QPe`oaRQ%M5ve8H#MGA8(tZ|XlX`nHHTl_G>5Oh_41hp9MJ<5krbcrh zG=|n|@qY_&c~l6F{IA+uDzFiTEKi@34+VUrdsY!3j}dA;H<}1@B0`l;&CW-6+^ZGT z2#e?x{ofi}z|#Nk+FA@yTMHnRf^*E!!DQF~e!xU~dCmbKQ*G`jf22(kaqli~p?uc!U-2MsI|%>SeNka#H?U7#xvro96MfC7#L?+7#)t;S%$%lm(g4PMrA{#t5{{nfrFUM81HzJ~du)Ztw zF9J)oh@Vpz9#Zy`zkKgcz5SFf87Ixxa1ipTrz4^H#uyP#!v;)nGodeP@;XTEAt{*T zUE#{9et#^xOG;GF?r!$|=(fR|>c$>qMk7{HQPAsiK@MgZ8%-XF-{S1k2>geNBAWK% zKB3Y+SK~=9uFx-Pu;6Q)YQmiqS~bm+UB~YM;kDq8c!B@kSGJv-sRrgiweQCtp*<~) zIYT!17Ws$8`Gl_Vh;Jm=G0`@w?+9&$ujkVabiMij#R;72|3%(Tu%<6qUS^=_HyQA6 zltxw-S;o6);^rDvw=WZPX#XF|Huf|Ga4ZEl@^JInhUwyZOfb)KyBEW+liZKOI|S&+ zJ><_lPYC4>cDz(L5SFa?moxevNL`idRZ#9O>_KHt%|?M@?p*hz)XV|! zTvWMA!VWT-OS9k)1uRD#s&?zy*jf|T##Fz>uxVaybMXauxc_Z?<@vIG2&BFk0g7J) z!XR_T8r-zEjRo~>a?!DXJT}vz0|zOluQ?yFA4}<7P$S6=9BZ3{6ok!sHKrx0dQ4cO z3Lx{|er<8DVK*T6h$+wiBJ?YP{|r=o;}&`_50{e3~j*SEsYez;>vO$eAF`E|q0j+vb! zM+B~J^GKbMc&lShnCP@wQXfMIQU4a25>Og&rs{J8)<_qkp=k;O;8E$lj_6#p`6-qn zK=_2(3#2UwL*@sXvFRK%xQm3$ z0YY*bc>!2AYT+rBx_|C$LpWReadTA8aD0G(GiW5(ecf3IW_`GB^_-r;8@;#)eiCL$rPVpiaz}M-lhqx{iK>H#{_^Z9?JxS!t9dH z9>59?No8F9RM_|Xfr`))02*+RzO%Q3CRGA*9uj&D{lWh+HjYHKJmo!}=DFX2W9pw5 z)cVLhg_w0-++N_0UQQK?@j2X;J+oscIlbMB!BUswe<9hKf3k=6{^pQ=m{JlHK`qV;}L#O30OzAy|PpSO+kFLcP^x=g;!#1SbB>Q=$CpxcLN<0Hr)~ECOqQ zKH5e~yC2jq)QBk4@Ha8EiX%OwM#q`Z;;mT!=U zKJW2Ix%>mwE?|96sVA=rv)_Mm%>~zgjQn=4ezCL7X(8U~F8Sy5Rq8!zQ4~f6e<=Ja zGpmrxU6OGxEj{9>%GC-^?>$<9aQwcp>s}8i)Q!qL61*tpZ5GBGppg2*k`2%%_utb zRWR=U2XH^LwmMan^OdcHss)7_u5oo-Ne?!jC}*)HdUxu;xhs^fcV|OKvGEn08x(p* z_@|g410u{ZK%uNl*<%EgIDVoPA%(zfjGQ36=Wdr3AaDCoMKpjK*FGfmq!Hyp=4AMh z6T-8OLOoD6xy^X)&y8vjN&*VC6Q6R=6+g;&62}IwPlcx57Q=t=l|CK9n6xjW_r`;o zY$SO8D4SE3(YP(BlZhoP`IbmCk_LPKM_BcuUS#in5z{J7OccAuNrRe;Pg70e+TkBS z9s3O2^3c_Di|hc(xKD?cnhyM2$JkpO=g+%Um~c2rj1xIPl*Vn_C>mq7!BOpGm$18B zY{3B0eN5cW6 zXyJubjdy6bnF zl>kFEKq~$t>{jdjOwdyslOTiEWZe*q_@Z{IFMyrjK6$K?dq8LC* zL+)^l2CgvtndC|5EIRwsgCi%%p6x=N3%1;TUg2KL;?1vzy?FJXJ>X})Jsl-WeOwwt zsGucD1(x|SaT*a=?>%Dt<58Mgpe4zc@hbGFP5JVnm2Y4G5{$pj{Vp`{<<}|HrXB0l z%AAR+%xXAkhC*GFx9q@4Er#Vg)_tv7TwV@W`2jNEXy}rRpLqT}sB_naEHK_J&oxA`2s&seL6%sL4_x%S4>W07S%9|MR(+|g1Pe@6LQE`UQf?}WdvQ&Ok%uta5yU^t7$wk5!@E;zff zWG2i04{pEU=EU616i!UvQj)j3FZ>PPZ=JheDa`T1zB#6n*&c$a2h9i}6;*oR$IEXT zRH|`P3W+yBgc&0!RQ2VJ^O^I*E>sRdkKT-hoUm&|2fXfdYIB0?U{xThmnE)(RJuW- zUXXwFvXY|bst{%>3Z-IwJdfYzW2YZFB%{)Xovd+&abBRhZgn}|yz_afDq3a;at zg?I^&T!<6Es3}i_@ozBm&f7&ssFqyLy;wx$+xRt(Yo~X!&wF$WPM2Ho{g->^3WEvo z(<))xz7sfoDp#)mIO?x?Le#))i{ae`s}Jpy)2pW$d2(o>#|KXAjg@)BF{Vn`a4iVF z=m};TZp4>%DT;CrrRl=Xu-L4xEL{5p!4JlM!8Sf}%^(rX@>+I`wp(1ZgbS%tUMfpmf-4Den zQ^tpx8tM&=t^{!y1qSd`w=+af@%(MrjnX!Bi;`+ayoFM^s$w`)=;g2@=CZ z9wg~O|LijCWuvhk3ANqG{;&<@JCCpCRzmMZ44bm@GUVM4H# zXWHc6oMI%*Khc4I+iAABjo9MQmS>X7@xXNX*9+jsb-qTuR}LF!vldDJnW9@J5*Se; z=dt>-J`DkFya|bk;7xeaXe|)pqNZZXrXo-np5p@x}YQ zx7F4M6(38W5)))NI#$XJ{VFEwSt_p%%kJcF_7diTz~KuH9ZFLbxK;^Fs}?IFj@(Ru z&nYVP;PzgdFt5tqoPo5LYmzW`{WTF?IxC4=$dkV8lWr#H!>Q=POcxX?wQ+sWV2o>_ z0GvPSZpw8rWL~BFl%17v!Si_@nr&D&y=#po@N{?DTqltBgWl;UJ+HI(l>1%4MaQ$? zzxY~4)j2~ZMohJ|=MQE7x~x0Jnb~PJhNA`L~sB4HO@QvNAK#vOQB;L#tK5zVmtl>^{u>!rb)z&*H zWI+ZL>Sr13LRzQ4$V;xLY^q@rH3z7XzlIho#aSwR9HPUd$ITWTV!Olc3QPf+Bxxzf zN)P^Rosz=$i%w4yqCV`SDAfp=vOtXoQNvmhnh7A?y{3cf$g_umSk$#G-pBKL3n^4CLFlFUF?^egnZ3*Y znizcKR062!ZNsv!>K>x2ZH6I5p=)E$PKv3|jPp#VOc#v574>@+@0jwxd4n@EKvW)H z`u7!a;|b*v+6{#NOcTIqY$;HJM_c{4X77xL7f=7_CN zAK5lfd~!v85T<1@Y3_bc2yeiP=kN2cNL^Z&KKqiUC+Hi1bS3pH5&4TI_C*ZsfWUN` z8qzqqX~$>;;|#LC3I-i{Y301H6lxG=Q6gai13&J!H^4FTHc9eBfulpf!q1LnOS6W2 zwLgtv2X+W{k%g%NFoNco84Z7$kp%$E`uSS6)v{YwuBfdcSz*hxjGYPuYqU4=E}8%-F9EO~XpOIy#mswqZ9pB8^S zm< zDAlSvHH)ceIslM#4zW zA526GN9KF^^X0~%=i^{wY7os8dsuajwzpgnk{^0lKA|SVYD8>vi9x(P16(5 zBi`3e59e*T9F{~{J4=Qbi$6Za zvJ4h^&9lE{X%Wq&Rrsev(+qlvFgFJ5z{~MKsK!k2<*<+U3{s8+xR6__hz`|xKGHsQ zTLh~C9`GAeil`&hF~%2)!o0thz|6R?jcWM$A^a9ptY-bN!J#~;GU#Ak=&=TjVz0>r zV&&!SPfw(Mb4;;k(k-2Rr6FORGvMakEd&vz%?|44EFYym>XZ$&D@4KI3pp7Z{%0|2 z9zRs@aRXp;PL0^W99)2ew8T1IkS-?AU|YeZyx}!stBQE7N-}Bx@{%gTGxVq8PQQYJ@mRcd@Y&y zX9S?E1q0wtA3R%^H%HiKQ;V_ul5tUh4D<_=nfizeRJzKPtQewnP{v{7eexdVTlmf@ zY~Yn;m*Z0fi1Vj@N_Ah8of*!7mY{PYB&jG7elKeHLpFt)@?EejL<;eGN`sP97rUP) zVPQru01D=s#aKbEih>~xD3lb7_7Wze!T2w4WE*vi5{h)86f{jAi4gnktD|!X@&U9> zG=>clQTt}^I#!9vF(8??k$&tTbZMegeHzadYk3NU~QU%U+SPA@g z)Z&*K!O|pKYGoUgwja8T*>(M??wlVP1j%d!P{0jPc^*N zK^gQ**C$@D+k8wjheh#b)<<`BPGpVjFEn$1)#2E$j_!RHshh&}INztCnn6XOEs zu}Dn}aQ3cw(qdYz1R4OLQ^EAjiO$PULz~Zdo6>~Cy=H<9(mvi5)CGK*dml2**`|Ya z-Seg-MTRp`PMO0F5R}@4{Z*KSUnqol!B=pSvf!%}Jk3Qo(E(Ro5~(r)7z2-^yLxaG1Z=1d zGl0f$BPPJ`YeoDk#N2_|zL#t9RxK?J@=)r*+{Baex7i^gKKwJ1c1z%T0DW;D$UZi1 zR-=8|Dj2@J1K=Y)xq_T3@^|!Ka~~OgKa?__%f;odP#O?v79|b&hVhb3lx`YEjJ3k( zJR?T{+0^C2Nng6J`)Eft3;Dxg(*IW*IcOGOTc&3~GYuo+o|$|HZI^k5Vo zg^FFR8Z|-nsoYI6yvjho;ieu#P7SIjtuK+7>*aBajYg_LgU_zp#&MV^nNQ}QpN6VH zop{{3TgXM3SKXpVPd5^2c93bUi7SA677%)a8|F@3kJ!a`C zFoj+uX!i{#{!uz5_BK;i3Yn?L1^Ro0e=@4vja5c|RppxZd|p}ubdIdnlE<+zWac&d zguvutprHnDQg#bQ{YtSkQ_2Q#Vu_%3jBsMUno((4>>uTP!%<{WfTMS;kUV$)yRp!J zH6gh-!Av-S9Ph4TyXE$?92*lH(<$(x_-6lms9s?$D)AiEE6mm~gCgrKX@+PRppC1I zCd4UCOO*Jgq;accdRl`W@}=#UKu5c(CyU#mnr3pYK%AewwOFRPJqz{I$fV z&WRGFuukM^f9p)%hQ3f>ki$>tal&fMYr$XWZ`~@OurE04#E6`zoAu{EmSk)YM*d7og^P3Bp?eziz7WUt9Ma%AB6M@N!A)xGpQZ$8kW|% zvgW$uyLcabAP|f+ieOOdcWSR<96QvKWajQ5zDGKKfyYN7z6AjnIP zwHu724G@LVXSv?eW&{GzX|T6ssEx}D*nRo4LbrI%JQ)dybV>%bAXVo5<}B~)t$VW1 z!&iF1i%N6|VR=eVFrXg)hhI{9SCwU8ZV&JwBvYnij1Q>QwCDjDJzNEolTp6er7OL| zh@0n_0^6tDb%O08w>{GDemdnT^rGIul9`a+MosyIqm^{Eis~xxo3M(7Eh^M+~vr&xn|~SZf>=%yf+X>$^JiX-vO5 zHpcUo$ZRNWIy99U$TI-_xx0pVkFLYCT(GKY^2eGn%pd<%PJz^VEMiJZ#orflHF6$k zSeH_t1qfa|hc=6_h&ZD^v`(k>_>JB4w{2Lt0U0D^2|PZPW>T}&>1h*y&nplSk2O}i z+iNy{+6+pKp1|gQYWx?T87li`p)OnhHk;waTj{yNzOe|_)1|iAKsBia#uzgN>#y*2 zOJOnq(Cc>5Ey2_EP}tUA6CymS{{X{(y0cG?RoOPVR=FNd?E+}nZOy!o0ls~SUJe&c zSEsPU^-6>pd7wUzg#DN?-I^D6kq>~~Y$S5=-QL+}5k_>(A6iL*x!%CqW`q4Su$jG; zE>H&;IsDz79*k?)@h!ZtQ>fyoyP>2%qlO&_mVh#T_-A(a40jx=`ZXS_O3G3WMv{f&HSC-0+@tN*6^0N=lWf^7l{8CxjZboSZadl z>2(sQsA_+B75cw+lpS1@m#o9x4#oZrR&JY+p7uDV^n$+7x8)xor#?2NObgPQ=C|Z< zEE3_OG(d6e?46*-v`qtVlKE!Ah?Daq3t9IE%4zx7jzMg?JvL=9!I_GWGKPN*HG5O{ zv7prJNJ{Ab#?XWboRAU?lyc>(08(ll;rIjo`j9!5UKw3G`hXFjN#Mr}h z=ijK|hDqFFRqaSs2D>{RF}|n*rDpVx`Z$mjD0V`t3RzxY^HdbafhJ4+Dp4A82m({3 zzt>xSL0I1bC?%Wm1?YYgp7;8>A|$7M@4p$G*{0*H@^v-H66QSMM6&z!Hh;F?Au>P3q{H5?sG4R}DKpkrbilX1W zCwTTj+d7mYF2VVm@Hnqojd309zIB9}Ukri#x&Jo;M{jWx;;Bb2kum4$UQ=V-^qr{{T|Hxk;JYt9|gBN;Pvy(-rX=!<4oL` zFltk^jC~U+{s1;!Ni39>Jctu5mC7E|#g@irL9{M37^f~=wjap<&t%7PpKk7_T_GSG zobM4XI@s%uR*Pr@e$@0!)FG;EwSpR1RN>R}DbC7-G?cs8Ls!3%Irzs&qVC zEQu{2M+4`Ns#ZhjC`IPw6kr%zXClX+mIVagxD6e1qM-M3M|Z-{aqFxXR$GZRPKm8y zDWizLw$ohxUaSyiHoAM`+R7+oqSC8$`SugiEf3V&oG1;ib;{!rkIVY3iYIk@Nh==& z+j4j$MLv9By&$Ei8!sF-pisqvBr%#4ASV$z52$dzk;= zTM~i9S1-tpw%V}+Hu86WVhmjj;14UEl@H;j9b}gjW0NjZsGH0A8~>h)=fR_#RDbS! zTIf#*7|2aKq>!N+pE>@ds_dIe6QN5B#EVGKS$$%3M*I2W2Wqi0Dz_`B>$R4>5M{z3 z`~9!Fjl-!SodMWyg9+QVHf>rs7=z#)k;@Yr9P(&%79^uG?M%F``PP--qlVo72mYCq zJU7*X-_oho%~)V_*DV*}hLNjfpfT%vcB%0b1TV+qaMcOmI*6%q2O=Z2z4H^q3s8Tp zlnrNe=6&d#%!am9VQTRZVzFnhDX-!6?hu@>Uz7trp4Wdunj26O_}n?`ma`~#UI=fs zA|!o10Vbn@)vk4g#x!^2$&uJQ1lJQz!xU|hw^X`epZ*J6<`tat+t3alRFuu5ntU4# zoS_%5bJp;@;&ZFYbe&1lx&|*KWZ09Ywz7l6sN2PLSAyrlRq)XmFVZeq7pl-HUcP zbD>+9M%~Vpg&+3MN7hvh1wa5j!X+XJGT*4l?S*O%6(n|en1u*5h+G}~XV(l4M5i&6 zw!(X&zz(hOwBS{Zc!=NwC-X0$$)a+}A#jV0diqbQ3|u%EEDqV?dFZC1aWB>G88Z^a zMdtx>EL3(~d{l5@LB;+DP@@Q6?@5dlM0;}!oG7>|5E^m^ETCCQ}2kai0n zB|;ZfZWZP{xT)&z)7sRJ?wq%J81w__^9tZ@@nI*8^XE&BOgvH@IwpcBQZw2dS(?9h z_uXk7nYq?Tkqq2pKCDK|-RpPqy#3~N#lL6z$&w@)gUvboWF71XRbHexOz!cg^TJvd zZfu*)^f?RNn!{F;c#y})7xaCyr90u?S-T4#>uMTk(8%?6aFNNUpGCgT3(UDcgensv29oVekQ zfdKw{><8C2s#>SVI~L<9H`tNMY7f|L$K09S2Jbj3_Cx-RxI#z5xY_G?|HRX! zPKexh1%)XFT^67(Y@9ZKCPT|V*f~b9p=E9 z_ZOIJ#T@FVXqng6Sm=_EPRVARU2EPQ{8*7$u4S7SGg~T$-8m_Re%*F&au)RI4w;(n zTUaY*TXEw&ye*~kM=bE)?td9QmdVB(ObFBOfNH90EGMiyM5@R1}iz37pF*Gg;sy%Psbc`<~E!OnU9+>~L`J=BLKutqX#=$qWR~ zt5n=PcxlHe=QRll?-I(wX;7#<)J zyX&>y8b|dBd(m}9F3%Dy4uE4^At|U{k3SHp&aR3RtJ!@*myCr!y!br(e%a<%hC5se zWVum*@u*@^6UUbCL45A&7&Fe=xM`OAptttBL9~O-w}5|;NHy}|@M)}1i~Wwf{H{d2 zQr5Al7QJPH`^yuH@THvfOJxLz&*;)>@e~(VYLm5cex)3X-F@ri+qUPAh+&jq|5fLN z^#y^>(+e>V#srnTh#E80fyd;;8FY0V9Q3Z9ba%Z-dXxq^zsF-fh%K8xO?h-U3LH;{ z7&wv$Vziz5-P>sQw!VC{g7c(6svxxGkPqc3=|8d{vY%i=s>Gb%yZI^`^HaUvx`q0t z_BJxC$NR$pkxJT=_-V_^Me!0;!uAm)@99L);1JkH$zYP)Q;JR-oe zgZJ(y_J_^|cE+bcpZY0UQ}_H=kmRftOMH!1aNXh&Q~g4r*ByU4WbW+9?Cwu7C!Os& zY(gBEc^h%eQ2SOvG(5eX67tL~%_TW;g`^`l4wcUIqm5?*=LPRdT9%&X!=D&VOBJK4 zjp{4c{30ePLf4r)ePm5$%9mwbfpQdeR*EtbLoI30@7$Ht4Ock2TRa|I^+$E>J=RQk zl2}FoHM%?h;bl_388b1Pv#~~b%h*XPcWZayM6sc-JPP;^?-9i{53a-LBZg}VC` z2XN+Z|FO@Lc$dCLVi^uBLcS{~emhX;iU(O2NaoQ$p2I8UWA0++<-VsU!U8kc{q zxkj1azw|HJB$&J)#k(bVQR5RMh%@Dh$!>WoHJ5>k`@K|tX}!dSG`*H7k9{RH{Lm}c1@*siew;=p}W zw*ylxE^hg5(MR63K~Av=xT*84`&vVlJ@fGj^Bz?zBb~f`;l=U|`}+3Y9OyZ%a^ZgU z#85g^{+N`Olh$suk`$(`T`EqzTh#k%PDZhYfB)TE+6iQVA1kxi`km)X&MCzOIkfnB zvdj*A&3#&2IcB;egpqyT=JZ>FqSDYLe-~RS@D#E(ErDwp6{ba$-JAF~rym(g^8j>Q z^ul2kqIWW`-JuHfy9`EryL31q`8B9ndJcX(S`0A*kP#iv2IV9Rj9cTYkF z(svGplF$BpE^y@nb9FCk7n>X9{WARYN?xaWxkS;QrhdWqvlxPbO*-faK=$Ig;UBun zueJ_+g?X)o=;vE&y?8RgPbqQai$3i>SgH>`$bx?~PXAB_H#E?@M!ROFvogg6&EaoY z;yfQJB_;mX->caDn13=L4@6vPQQqZ2t0DJ{?0^^G-qZfaxg49_B))o_4iaRC5S)ph zZ0_LeT#Y+h99Y`H+<$#6{$*irPW}F17a|TF8YNurUdUMWa$Py!atxDVb%4*H4Q=@| z)Q=ANca;MY6})XPbtcZWJ=B7TNySumdSA~{UnA9_D*u`B1@C(+%kYBJPnVxw1$AA1 zn;}k2pdh+ezHwc)CE|%*Z0$me=l?pebLuLcNI}<@k^_UwAB2I@>^Vcr4 zL|41T`(8dH*ISnE0qUq8nxfp$Wz#`=SGx^MbncFtLhm`aMvN$!VsY2Z69y>u^% zTl{i`f#Lk?9ZUAnV?F3Cyhc#F{p3pweaP-I$xvrI6y~$sZ%Qd4ehOW3O@umiKK0`t zp-vFK=X%K`ltfH1LMy##V*!+xnY865nNUsO?TdV-ACvuXUaC?$K%CKP46Bz*3d|j#kc7{6z@%jC)x|ncfdM$54viX7o)~^e!I?U*U72rf(Fz zfF$;OYuH1)scYSo4fXx+Z>3Y7cXN~6l|vhsdr>p7Jz(U|y=OwfD!M5`g+I?3T7AYB z^=<>GxwweT@&y{=9XVUoJ;mK>kir3dCXZK9WEW@1KF~{WqY*GS#T}MGOxJYMmtoeH zTholZG|`#pZ*T>{RD+j+vZqGpB)!k_7qN9TbT#BxZwx5jD|mY_mu5f`xUuPzuV2A2 z5>nj&h3e!eLZj{GK2kndyf4mrdVGP~6h&VkSQt1A9>sV zm~=w^E|R}PiE(hH7EQDVF>dPk?L3elaxT+~FPCZ*+iOO@m5)y>*i%#Bt9se!nFT+P zaku=17Bs46#^dWH4G`cufhbgyVytgFAkE$krTlT?U!qKFOVdWnNzD^fN3~Q5NZ*Yi zNg}<*YdG$DhHt&d3mn-cWHF?Zih5~_{)les+_L2^F~bL2->;`jAuuEILF2bk*J6AI z74)KMq|DF0Nsx*ZU;pgY8!_sQ{_o$gXWkN$D4&iWkOv8Eolk79YPpSbZIf*W62ZJF(UOYsbr#Vl?oyC~<0 zIqy`Mn!o^@!YyHK&x4kbay9xfZ$$~1kCZMj_V+DEskNtn+00z~Sq6}ZF@G}5u?F2Z-THn){jGz71%CTW9sTc@AganQ3<7%S)*Ew_?z(`CEb+i84_T zaATL8|BZr%nru}$c9B}Ay!Um-PowBZq9gfZMJk8PK1Xfz=#dK0=Gk@j>ix$2({XyPK(a;E z!-^qgyQl>X0?wUR1OAfscX2@-~YjI4LR49wh#TkZds@_IR#ZUP$)!ArSStd^xJ|s?*$%F~Y z=W~<8(?<^GN?ncrJwq;|;+TX=Nm4Oh`$hd>%u#JNWv02-ky+|!8%fBEW>_s%WPp4A zHPkayUkWHFwKwM+EM2I=3Wo3mV`43s6$?jXQ}BD=yf;l}e=l0!lU*W12|uv4BU3#) zRQ3Ee52?OcDaV{wI|=;2H)q@OC$MaWvUx^j`D)%_v6uLIxQh}BMf2E&_W$;=^T8*x z9Us{-?3=YCXBw4C-HW7im)jf9dWOj}jQEdS=_O`7pBc>N-gMng>KVNv$`0MP_-|`6 z*NP*Gw}*bF5Kpzu8C)aqW47(KW2uzXYB%(4qYgcXx`L?-Vf^WiyOijUgM=h=Ud2&% z9=P40Wn79LH{UE>$8Wx?I`T#T5Qlp`fs|>6B$sG5K%hrQGY(Zt04Ph6B*i}JC1dis zfu}WH+3tPlSBl}acm3$g+2i<9y4)SklBIr+7#Zs;c8NjrLsFw&tVI!a-9tZlUej=% z!mEA{jBSd_FUpk4{n*-=lD*{arS`Y1UamI$4Md3dl31AD)HzBRyy$;_;qynNvgk~u zW9KZ`IXOBM-z+a@*_jAQ9`mNupFf_^brGlr)ZN}4xfOW#Q*-Vahi9A%E3EG2xpxbX zO5a_z9*4836Lww@m|&I}sih?4;Bp6SCuN_R#Xr2Cx_h*7N;j{NJVONo1Bn!nPZ7#R zKQSV{iTr2uF0DkCtq$rlq&^~P%!)0^*@Rc|{BqYAbQsS(WU-5#*JV&a)xz($t3A<1 zpQEQ*h#mS!W^=D!xE^T>|NTv~clZKe4mgk)s9GKb3%fgUx*9k~2{f`D#9Nq5agOf-6TmGyX|1+S;%m4&?fY zn_Zl%Yoen@@7_iaw*(0~UMc3A`^>N^?#GQ$4MS$bYC>jB!cv`N92Ns8Yayt53G1ET zt54eb0hFTp=qYl>24E}s{LhV)3u%a-$V&Q5p;(c*7QIw*1#`)v8+I>?hm~EwyfEeY zWRO~L3m%Ey?||Hak>@v z?XF??l$&c}B{XWxHMF}yR_k9SlxkrWgXhT2V51dh0TTY7%`NA_gE ze}b1pXzx;a1Y@D;ib)FmG3&RF*z^co-^9DO+x3}2dntOw*~}8}rk>ZUjbcmrFNwb$ zC!|{Ke@K$zX3U%A_&xjo+c$I?dv))Ji)UR3#Qo8 zPhN{UqmqxkO&$-NiHZJo`()Mr;_lO*Y`H`gQyzFTEimo3*m{B@ehd`Bv}=&d8H47e4tF4wxH=}DPqk^`PM{YA2lRqjE-wkH19oG7K_QXQ}fA? z9Cf;ide*fNI$sv+Fw=7a}8KrY3 zV;yI(Faw_|ezyW^SDJ8W{YP?U^>^<~m45OE!9OAp(+S(OG(X-cHR{s69P8oWd$qa> z9J?4&n(6N-PDyuPW7oZej50w5o)e?~ zXQ`z0XXk8b4?M)Ky2^6SpzPpFz3nXMwMS z&nIprCDOv(2CwC)(nGh6rQ-WXhEG#wB%~MAVAJdb=usYtlUm{nEuYwWdKHv&2MX-9 zMjunG9q{)F+d&Dqmln&Kl6b@O7JR$u-#H&-3#1%R^Y`|Rl3h#jIfXlKOYyj@#YqEH z&Rv5;_8&Qt0Zm;>YHAAb+k0wHj_BWMI-V@YcYBNPy-lcZHJdt`P!npKZslc{ zL~Ti2+BE@`Cy=tlOK+kr!dG$s;f!kwYJJ3@RWL~4>vdIdjUoY6Z;E=%KXMjGlhI19 zVne>mdX)p&oSHtgD$ z7N23U{QD^s3Y~z#dLPzcbNT!^s8w?)E6Xvw{og_}uG?p#MixcEBvRQ;-<+>4;Jl>T zy)DDD{vEqT>J9uS;b_NMsWlx4ku5*r)-)ZDx0sbKhU;?rN@q^f{-F^iDhuPPRf*hlhP`O}PHtJHJ0l?}n8AoP$7t(RUS8fP!Hq=uGe-2gQReZh zv3~LzMP)G4Ck^#3_5+Ar*Jwur-pM1~MxTbLF zG#bYuT_gxbq#OYsrzw9$uH8O1<#M5ETJ^Wu=I{w`8xm=#>GpI|ev{*w%narCX^#aM z?{TzMc5d-|2T0$4Wl1mgQ-Av{$Fk*uGwwx{Lz}((^*vL$n-HoAD>^(Jq@2?E=GwEb z>CxyH;}$!ym) z-eh!+MDqJy=5MQT4JUnDjaOsoV7(u&cHMK5UPQih_gIJ zBk?!+X6EK_tn2G_;?5i$TZvO~ro6J)9cgjtRYAe>!-q`la(@S1#U6J>Q(KdGDLbZ8 zX?xl26Tj4W$z_!b~Le`WM@}PwOVY!6&&zZ znsFwYS>0|pxcTGhw%fLo%5Ey-9|=d+^C9BC|IA0$_ne<04ZM%Y`{xU5hu@sF9}{OL!;b$Kq%BXT$nx4XL=dgCrSggblxpbLAjGp$~hWxPB6H`i9Y zqaMQMeI3klZ6hSMmy%pRkEU{pf_#`2m~Y?qdGv>bxfeN*$ZhGhzkbCNPTe^g18se@ z=yw}COun?up4HwK$jp)atJq_k{*Yy9MiDP{V<_&mEX6Ig#Efsb9J_%YLaIj_lvJ+u zE6P(fi~3r_wW^G=_m9lBg-L%#z!T#go4qXJzEr_sV}=w0n=WcWAeT z{JCCY=#0w`9Es<*Y%%X$s?+=jPtRS{|Lq8Uk4V8*lIM=QEbW>eo9xPRa{Y|acZ;J@ zU!6?beQ&KIWMm=5v7I5mHcaisifgXo?t~S8es?UE)JJ`KaJp-p=;&59(q~51-?lG& zzcOXaWo|Gl@JuH2I2tH{3g#iD1ub${<>4)p!Uyzn)}t_vo~DUaukbi~NA*wf#M40DQSTW*q3+yvQ+m2)&v_7tQ}sTjFOti~rQb}}?UQfut2O`ex2=lK4|d%B$!H$&e}P-&E}uEyy(esx=*%3lvHmON;twwJ9G zM^0Uj!;vb`VUF90(;8BCsXRi82)4VoHY>mIP)^r7wkk867`DvbZBCjD4|b zErcNsj2Ow}kSDC3h)MC7bth!IM$HdfR*;Ccoq5XhEr%Yqy)S5ZLHVql_2tVh#Okm6 zT95ZjB>sOieR&{M{r5jfDxnQeDbud3ElLrid`i1EONORRwwSVJnYkkANg{<(8WLhK zvW;~v2_bu9${1tc#=gvc@BLk#@9&@Lujan*``p(#=XGA^9E{|(hU79f;R%y^T~l}t zY3qyM*xJmpU2)|4SPwcp(0eRr8uNOf^?_`pS%XDGXJ zg`)6Kh+ew=GV&v>?PI(NRszbN{5O-JN4tG|bEkykH@p=PcjaL=AN<{XCgtGpa4$n8 zHt;l$HN^LkbO>WhIj=hLaT~loR|47V%EvQ!xUjI2tKSAS*10^V{vNvL?9I+{(soc1 zdSZ}nOkn=C1*HI}Il<_^2ztz#g6B>gD1af&z;xG%`e<;85fh~ zcAnJuCxMcF;(LXF+`$}A6$;R`$vFVqs_3Igx+ktbX%fH`5 za!!8M+OuVGv>w_5M9Iy7$ih*_djKJz=Wc{k0jSwPQOg~eee~_R&->!hyuABP#@j72 z1I_XZJ|=FkU=%vgTV0MwOoKz%Zt10`q_RY)yS(Q&QHJfLzFRl6kon!wMDoS%kIjPC zu3jf_VZnRJE%#{GXYjCdNtpWM-dKH%S`#CTp!z~f)fK}j3Sh`|`|eGC^Fa+gsy^zgX9? zDaQrrZP_W&%*`nq>TW6)J2;nyF4GAXj|V>9_Sy|E4%I6Uym;wP`YxBP|7&qk7h1}1 zy`1Q{_625^rcL3hI=GXLc~XIrF;tmhf1ou3NjV?4l!yoA-LokGKYgQdHop9&qg`L$ zDT{5zGYUGv0G4k9H&ODHZ8GBm8piY>eQ~7zL7%(=OJ6M&@g&AHa`&_)a?UdLBm=y< zNltbV@$LdR2 zVRW|%>&+2n*hEunz5Fq1t%@LTHS>ra18AKhj4(ka(vgLOg>sm{|2VIs@~Ig-D*ml7 z#S(amPgeJ>o6_(*_F_D4@a;$2Y3gAd*zJC#P?6``wYo-!uLKUG#^LU8*I}VdTelS5 zF#Yg5@KuEL&0!}noT5inN^&2`-qzmX49Kt!-M<g9utsW_|v#M$AeZ1uf*b<$hIh&GI}^!qA79A%aF?p z2B%fx>={6R^e=^U5%*Ehl%M2k+86+dyb(!txazV0+B^1dNZMeJlN6W|7u`bu2c=(f zApKI8p$I;YD$wqlej}j;ek&z;^<=k_g!&W+=0;uX_{#-pS^@5-%=icLaXKIfI82mr zrpT5H)+Kjl&+7%&b5I0VpGniw;&Qo5e$@1n{(P7VsJL(qD^7R3*BmM!ZJs^M)h+&2 z8t+v~v%QEPXzX{$qFEycy+9!O^#uXm#zzYiCvi)^+TSWg{ft;FF?k`=y`bu&;rCK+00tPo@z=zzt6@uSJ?J4 zgNyWDl)mhG^;wVXQ@{aqqC+k*0AHLBjUd{-qNHt|HDqw_RP%vMhUE1M$cs~@LF$uP zba%>taW~aQ+oKG#cstt+Zq)LL<2x;cJB1?WpVW>a2erWRO3M&3QJC4M` zAAyf1-H|7j!m^O2YV4%>{?O z2*4qczdE{kmG!nP`TjgN>;Bzq)<^Uut_+Z!S!;=SsuIO!-lR&5TZ=^`zdd=~KmVyW ze!eLbq{)e#1{6HG;4Wo#|)28oAXECKkHn!4mqEGrelU=#4_{QlD~?r6g9^_)9TziS^^$YGt!fEIT0?YO_?L@CO<%{ih30$!X>7QEK7 z8t_Q6d3(;g2^=NKZ4FEeQ1==`iIrU)ou8T`>{9S7trscLfy1R#K@T;uU=W#}ZlRVe z{p!Q3Dk>_0X~msgUGv*-%887H22NQS&ST)qk$hL$m(&oY4$Sn#+QIsdm}f0|Yec0v z-^N1V#t#P2oYL`WDIH|-w}Un$Z@QM3+IGY9b|MEa8HiNcI%56khSi~oG0|>pm)?s` z5?3_Y(fFkk*jwn}sQ_v6^Cf*$(t^wHSM*k4nD6aw46z5^t)oj7`aDk=WF&>aU+m-X zfp8jh7mCAEng1s@{P?w{kE}kzZ{xtOq#XcaidBFNTL_N^KW37FpVrVq@neeEjZ7?H zb56H5#Q(e7@zB0E=BYxVRlk!f;M+hm+%lF3T2)z!D7ik9pEKQ$_wXUr)geaf^38gT zBk|G0pP(o}Qlmx?unGzebDk~1YDGfJhJmI8qv0uVwq6Ui!bz-ShXZ9n@-s=NB$#YZ z%OzdWWW-~?lK_h_7PwPfN=q4i(c$JiR6@hPJ3GzXDQ`P5qUB8!eaj=7`E-rd_Vzyc z-;wCzPzUg2Zkf-`b1|JQu}E{^ShFA&*qSrlfg=cq|L@3MtFmUph|s7C(k%IXh<=wC zHS^cod7(@mt~15PxhX;DpS}dnLk3KAHgAoaGo({Fzpl<+$y3Hm(MtP+5rw~;;=wS{ z=(LFf#8p*~4NXzT&QtL~1K?kegeaNpU9z4FJB_Qc>^=~r9d7BP>R0J%Xa5vc%Q-l> zv9azQkps6J&leKFe%gwnF=QwlUq2i`_*zm+=ouU$)aM$OM!i~?in!@smME}H2VQ>w_u4lU^Ba*&6@VR^eZ$+qt;&JK9d(h{f9{U+m*TdUDSr>#JJa|!Ugz-L8XcJRUI#AG zA)b)$814`DPQM;|8v2Q`2Z>yNy9q*v!NkiIC<-{#(ES!VTP^JUO4Lua)>bn_3wWzy z+qntYA1?z?{zi#<>7{Nj3JQnk3L@^@esptaczCeWmp;Y6t*xggW^A^X`om)VS8aOM z+TW|Hs!EJO7MOT`@ti6=<~f^f-f_z4x7axxRGeWI&40CfJd(@l$DDEl&pZ?-7!2?t z3ZGXewej!}CWC{hS{{o+pG_k0l8lTrcG?Yr2qz%4l zCY>RPnu#_(g@h837h&cGPNKy)2CRWn!Z^FNvODn)PdO&^fy6nt;=y3BP-K8>jKfR% znD=i^SUaYwcE@+fH;P(2x|_0!bWS!Od!T-Hd)^@E3xc@)Q9Ar%z0bjU5@7r+$%?XS z$pW26lg0kL1z@a}So1sceQFYDqutQ=0;gRx|2(s#1;52<2K2sfD+xJtWyYE#nsCKo z7rwoW1+pY@{jrD-Wi$g8xA`c;a4g`ub6*_VPKzO(%ZBHGeWd|nIs=H6X4%3nbE_{S&eLu2((N{yTx0|`@i;O|Etsl@VY;@qHadZ^5F)s_{daVfW@TiMH=s9Q>4-5F4P}*4nhe!!WkvH#iszC89bv#DC=b%)|cQ*y#DJU;L~z; z+vWASQp<UOSr1o9Tuqs=OrLF0p+x=s66Tf`c&%2SPtLXZZgrTLBoSXSX^% zuyrP>Hc)WyweQc`?!M1%sO@=WL~Kq?}SZwKb|faBdvLLP4+ zPC|#nm7t)HzLlUMZCjR=8PC2_G-O28xF+!q@Z(-65Xd>|3Md3<660pVZ%t!nx&byA z?(|cSg3cRKEwv>auonmC@x=ye-hM+nv6_ek5i@hk^M>K%{Cg;!8iqaxj>=r3&K@Ey z!4F54GtYsALhgRB8Ib^c8k6l&DX$EgRfRB1`DxOFJ)P>=pRI8Q_3e_3V{ zSW{^jqu~rOsx6K^A6bTrWghu*dB4Zw91Rw&JNAR_{8Se`i9Pax48>51C!4+=qSayr z5>#_{DpmOHe*Z14@%Jq!R^0}X`c6OWsYeT4r}h=gN<&I*Q`5JshbX7vCOtS4$V46y z*d>E$N5+7M34KfD&?1^MuYHZp-i?8}zmvtkIl`3YpMhCDA%R$s3LeyG(Dif)KxQ+Z z!JqX^T#uAb92}eMxTpZ>mKI|7IR1H`CC~zXaFmVvsL&&=*GS}-cBua>av0#0lu=P& zqGGv4CT>E|>yf=xY}~*ikZM8xKge`vF1B`wlC3D$+QLes1q1}l4t*eqhRMiz;N~a) zspMRmr%``i-?bsDCi^Hkby6HffZf3u`^aH}!>ikAUU;=;&Khgr<`uB4RJZboi&>x((nmFCMTde z45_X@m400lm3xGnBUb;#BJ7LdwUJo3NC_$-BMfW&!e0vw0rHD1&Urv6Pd4jYVPY{{ zucMt+Umd2~5Gsd>D-PZ5Ok;WEln$OmK1@z1{AHEvWS#EUTD-9GU5;JvQJDYh_(=ra zxniPT&>8n56p2<8dotjw$2JM9GX%&=TOl(Ekm=<>VZUDmVTfbp9uNOSO%V}Guq`4-n;^>11I_=j<7M_C^CgK6?x2zFAJ|=Zf z4Y4=nx`5j8Wk8*~yrzUa&#C`7PnDPP|HX;G8O>sD`c=_{t^y{w^664WQRHh!5B#e% z-`;}MYoW7QwJ?6?;32$l&Saj(3aRRj*!Qzb68#bAxl%kotyEJb>GCuW3&^ikp<1LB47LGD&Gvq?N}qq45LmA<`IkKy{`eW+Ua;>wkaYd6Rq`YY zW^LLat~vl>ZG%A#q*6W0vaZlQ)%21c`c+sbIRJ#XsnKJ0y3|=5pR0T_O|6xT z(t-atj;;j#d1_|nny0WHG6C+1sM?B6q>`V(=e#d<98r%#zxMMTddCM!8@ykA{B+QF zF-Yi$Fd&u!6ozQl5u7gow)ws;)m%bE8kN*{*TNVzAPe*CV1iwXUQAy(Y`Z|+WiBp= z-wa1Sdxl(X{TW6=%|VGuwD938u3X9;9>z7ShEzMO2hWqm4OgR{Da}HCcf~IB@4)D5 z--eoM^OUO}=H~j*gjH+|8UC8O#V^#yEl|tQqy;kYh%4p>gQ9R?D4mk^Ik1fFf`5^D z@s*I`^-9z(E7cD(ojU9nutpME7x2TjKpPA9rmgzFpH)*4;XPttmt)arKUIz6?pj_} zLR`2K5@h$d=RkU+p6JdDJQ@4IIR!~zq6OZp(@-Zz)Mt$ZcZE*Y_aKdn?kIp)2dpnh zwqSiN&j{d$r`)jFO-!ZUbRs=*?63 z&bM9Rl;MFsv#D8gexpuiQ48v^%D1A+yUmcvi4Rw)828hu!hcI0-r>R0g90r`6|N%( z&VJC9V5c-ihZTl5!{NIXU}erMbpm;ft)FU{5@U`IS)2|7QlUj-tN5$@YMe{%#_GlgMnmUEuU1j7T-M&9y|5MobU7CG zTZ_VVN2v8E0-;U}Jg;Ki!M+ppvlq^mhX{3zTxxL(@@h-*si6A}a5@^+5hS?ca5ke7 zPvrU{PN-2EFT9|L07DmAekn@w6iwsP1^Zr_NJ??+H@9csyzXM`&oI*^hwUY@KD}BV|R+ zpdf`xGMn`9B~GJJADV{;Oy0Hl;8W_o+a$78R2cF2555}HkSH&$TOh6nFF9^ehOsI6&SSxDrMs~+zvLVO9Px0K7C~SPcbXhT>+1~-4QPp!`yZ`4U{1S@ zl}uM%^$6`QFE_@ByjlF1$m6@oVxh(PxrYXGKk2{DA-0#{@}(V~BMPhW z!m;xnkwuOu;!PuUk;Vlo1uRTQ2Pp;Et}m$#fQS2yQ8OS8qF8Soudyn?~ z#K>tvC2JGYDki!wokUQa86gy^Ee4|eOC#3&>(kcYf)NL4=rF_&7H9f0wqUgp6iw|S`<oBu8V z4FJ*P04qZAELI+w@M+^=zJmlYnJ-4X$-p%^xFA;!9`)P|lS#9yZrFb0i{Zl(*AJl8 z;$I5@0FaZGJk!JP-`8Rr?c$p`v2 zLgq9cYZ%3cdmQ{`p($Pr!onHR7qDCSwLg}g;OLFp&+$jIE%n5k@lf6|NEFeiboZZt|VqJ1GLg^|3QR{#tJq!Har8!~GS z6sbbq;d6BhiDog-8}`*hkbgBE#n#gWgCsW7XXu8$1oBlC8eb} zc)xL@wc!s7ey=NYVKF_>oK+~!p=%dmM*l$&#<-+RF72(->9S~gK%LYc>QCv@YV z^U<*L6-!LuJgy3Z?g* zk}mk5fE=@W2X>|(+i_^#!f3TuGe{p@w;>;1LiGVJEYcr|os`eGjYSrzII))p0xTGi zYAl5WaRyPP(Xq3&yyQ`xwNUT4*A10eDr zOKV%Dl0!R46Nw#=|tD!ME8pzN{Virg6BPK0^GKP0{&GD7Ki8JY&#?Ms283lg(N@Sd)fi85x~pqe+!sJ&=EPgf-6W0aD4Jf zSJ3Br7$lkUzsIJHI41m1dBvqP>eY)v!|X-?S|&cwW=N$kTbjK-XYf0$qbj1g({WkHsd3>5ySMIl!RozEA0s{6Zzo`x(;(l>@br3a;E}Y zyiXDWz83!?s!C#%5Dc;Ne^rwe1unB`RtM;?lA{+GZ?7C z@~RR#5Oz8ADIGz*#hN9XddQKNk?7i&{C?kwXaKVs2^}!fhYhfT`!o=*g z2H-)@+}@Lj3>p|(F)`E4&b?L|Fo)i&2{G|=xaIk{Qnm{qtkxqg>@HSf$NlHbN5)W2 z%cFE_fl2p#0NkHJs)VZBt=1`^tEmtN@Mz1p_WFA?7_)VvVbEM}AsZz>H3>E>@A(St~QU!R@Ks31%`BAF-6U8cgLGx!;!C{IH)%|C67)RM+ z5?|UQpVj%Td{||Td->cm%s?7$`B+$h?Jr_4`g9Y_K@)Gz3Sa>T&P{L-K`m+iL$)nK zHc*R*SA@dtf|!+SI}i5pA?6T~3$(IPon4mCakXupz`v9MS1yoc8%q`n$fNH?)BvPC z1YPI8IM$?x)QTTuYR`{Rs3KkGlq?7su5Lb4TC9i4C`@n)2Tdr9A(j5^Bs7QCJwE-8 z+(l*4yrslV9gUAYP<^lw&R~8enB{Xw^dlUcEg<|Pj?)$4F+`Yv_2(8l0s`c@ZEG4X ztHy=$ehqY}#u}+=0d3tXeWgd{{0GRNR&O)2<#~&P;FN%|Fw*5u#36HZ=kM0*NnSDM z`3U!9&5`Lqp*k~-JY|M@X$OKh_I@s!Bmra9dQi>b;$}8~ z@!n}vH{z@YS(57ZSF6#gKYH>nlL*Z`J(D0JKLxgmtP}WIyA3C>CYwyPcxJW;8*j2z z!aqcQT!Wmth#svQfc7LVK}^rhWOmbL0h7rL;LT1=ObGd5(j?5GEE8{v;0fjc)l)7wq=$7-~ z#|IPY_2-dxM3+f;ARI>PFB0J#tafs=o@q2ywsR4B9@5$hNeW{B|B<_y%hHBEwn%4L z!uY`6v_UxxIG{C0|6mxRVsUt$%j3orC>#SuuK?FMlD2q)kO@h|0W94&SpT^=%Xr~$%)PO8aVdStzx z339EUA}Jx`Bgb&IF$$_YZ!8-1!1Cdg$&wulHA#5=BB<#DDT=H((_RO`MRfE_iUa)? zHb2n}eSxe+xE!$>SvMve@k}xFy+MH}uB!JOplE6rb0{v*hH&JS1fQcu0EZ&~Z2^lS zPTP-1jlMZYLFU36asyi4B7+9VYqYTS0rtxhVNotUVGO(k0fRBt@8G4+>sNc$FEuqa z`nz=f5!V>(av0Uk-XM(%E$ZrLyMAf{$19qDWI?(Cqb6{~d8JaZ8hyIcoo0W<+ro$D zzUX)EiHE%ZGPiUb?{qQv3{EfBpE7Pqp}Rfk3#A;GhKix8IP+%6<^{(6+$nsx$o89F zY`zHpCW9hr))~o%+9nzdl>SAoSglx~OZ zyxm)~^s^eqN+>Y7besHnS6Fh!*zj|^PZnYi&DJb1 z@6|#nzsn*2<2^YLqREC40OlaqQPLgDYv#Uq{|uRK{PN#)oc&r*i1_U@V&h(PLP>WA zd3=!h-ZA@UN#JA|rx`#!s4gZ;G`!#$sp#Y2%Z+`&A+gHK`!gi0Hm5BQ{`$-hf(zAD zxa5|0FmgZwA-%!|Sscv1n&RO{x_u+on(5#NeJ*83q531*W=rL7r^n3Y;5Bt0nD`jn z)Q{S;KNx@lQl%=TS#a!zt?e6>fX2T;76y^hLlF7DuE4yFg*&+WXV(hEhyGmwqqV+G z*ev800T&-3`swNt1KMTOp9Eq!gF6^sG2XAnSS2Zz@CT0^kfMWpcwNZzyw3Tt628{b zf!s-w97`Anivlm9RIH>G=#2f`T+KiPf3U{pv#C}H`(#id?PWZS899uq_6EpsB^Zrx zF;M$Ac_~pL2SSl=#R}%dT ziOQNTP%!EO*U>9PQVP5j`17!*DVVowT~{V=uiQcpy`5z zmS{1DB|NR53QtAuu&@>!o(6`}$gd+wg0pevJ~iY0ku1^0Z#}tfAGNbH>pDd;9!;`v z3S;hSR+G>xBcUxUz$mvrLtNr*YjMTsp(S#^{~?8)e_?{Wz7kRVk%gqh*@Ys*=;DLE zwhV1@X%7xr(DTTOy^h$&;E`FE@E4yBq*v{o*CS9E{}@Ru_=xrJkh!kZh{0XaKNUI4 zYL6_wK&dxvWAyvs^DvZ|M66Yin9Qmff2Q`m_@G6y5ur8Ex{QWP{?|(;2bslAwyoF} zO=Q9s4LHqtKJL|r+B+L5gZ^B-%Y$U~N@V$(>xgxeP&O!qu}~z!Gm_!ey3aAiU>S`l zMkdq3AX*JZuA(6(?|<@A zgXb8{QZ3tq7PI0gtc2%lG(}~&kV19YvWYfJ)rG`op+p72=J~_ZVUSpJ%|yGgq;{1A zowcJ`;D?oW^M;~P&`A4i$@Vn-L;d^U4BK+PAeVaTiW`@C%sHu^6WbxbX4+`ea%4kC zIvhud8;%|WC&hRl+T3|cwg@}?J)l(yncJXA0C(aHII~rVVxOhXzqanuw|>Du3gy11 z{CSUn01ie*Kn3~rrm8`cjje+amLKvgXiG+?T8A#e^3p zkC*k`Vp84FEU-y>+8kdroXitQ2b}}cz1Ep>76H$PfLx`|u^T7FY=dHwC%07%;tZIZ zo5N~E0>MI2Ny&&avS<#IH*Fc@4?@x&Bi{l`CjQF739LzP#d+d~D-HCDA8@Qg}w5wJ5_l~Y?nV-g1zBQQS#8x(Rinox8g~MtXw@4PDxEHAK@q_ zdd2MD(tF^+c2nyWhb3XM(khDySWtU1m~5@7jEIY$1(q{taFcxsNDkw)w~H5ICjX+n zsJn#~k!9v4)4w<5(hEmeTn)EDrI(+qhYp_KH>&?i1_^Z!Fl<>E@JO-TR)Str8yREo}-OoBso%*q&RIKPGq6 z$uTJVQ?;3%qLDdH5c?0`rw6>zmL_$9zVfoBr38KJ>P`ij5-r-w=`bc;>jRZ;+@g?( zz3^QrHYffMXt1{hv%h5JWhxUQLffmB>S?zQLeeN**deYWA&OvtYlTv1G0Z8~dyrW# z_lfi!G=_hk;?z(>e>@Z0Ozi#i@n0>8?zC$Tb2ZX7YfDSPrcZOfz&>a{_zQPjMar+ev{brl*;A5?s{uL+@C_|Yclp>O`g&uJ1Tqs7r<-JFQL9q8Xyf*uMgX|di-@%(XkuLGSSsAYe+sL1K5v+ zmC|v3=IGJq#h+6q`w52)lD|TOs^Gkup1gB)OrR{=>JLq;k529gT3sc*a4}5r$YwWTq`S0f7*%0{XMb4QfQ_r7g9#dRxM%mzLl78&KNcubV%pHI1p z4heIQ=7d)r>6{Mu){U{!ZtsBj#xw8AIOX;vK{RzloH%7dPqBoaeOliU-QSj@C%eHh z#Dg)sZsICxoyYJwnTM+eH9Qsz`qiuBbdgyccG=mUl3eHC?5DT$Pll$YSY7%S)YC>AtevPL+-)NKDbMZxq>|36IwnE6#c1F>gf8+fXYQP?hRDWxQ-U z*-$2NTodZNl&o{ae|^RGV0Y;j!bzIciT`%-6QP(IU|qFsZtu7 zM)u}f-Ldpn=IsKCP(<$OUKbp&a;*0VM1QEJIhT~^`O(jE^Z3HV0o8HUAs4zo*h3;K z^^&r!A^@_*$#S}L1#@_ORbzEqN1%?n%8N%cO~WrcgE1YnoFcSk;Zfxk$0+Zih~kz+ z{Q365m01I>g)Nzna%lZpkZs`a3Uq)<`ZW3Wa^#S9_p;0Mt9#$!+pkG|H%Kk~>m)|X zrlf3m@=~2X$t)=}R$+;~sTV0%_?(ZVJr$pHrHTlb`4RpDDl6jab_9{^HtuFiX%wwp zE4aO_1gYh?D07Oahth{M~)6Sn%c&)5J)NbN=fRffI=U z!!MdK@Tgg?)=kc+sQ?Y$?hjrv+)zuL%;7tRPQsBFeQ~K(lCRuLW|X-(-JfWm_{@`T z>q!VYW?g`vA%ssJQ{cUJt7V9GT?l)KDgNA*fG(YXe{|g0k`qd7TuqMvk1!iI$~Tb0 zXFh5jw6gm{eVRjlpu^j`Lf614_2{2SoQU{GDYW`DTaILH}>F+FZzyc{QIVVwH>9CAUj7>0hf@qGDd;rM(RnO3=qvli%C!ifQM$IJd6&G@o=w~CNR)Q-t7jYCYX8ha8ZPK)T{g;O1ieXQOgfLM^IE6y zb%7>ZJ3_pUHj52y61#6tdiRa|Ow z&5E83XoP#@Am{O7i<#v^Ci;$2NOLK}){*t07OL{0QWv3kiNBCnS z27U}<>-1l{IRldy!McbQ{Q|Xe#&5#Bf8d%hB}9&Hlz4?n5LF4rEolEF+RKzUwYVFU zV%HkwE&JcSXY$KxlfswP{E(Nqy>2^14<0S-S3}@#o+PKDMX$VP|I2JxRQ-H9T13?* z0#DBsXrgB0cvh^~*|Ejvv?2Gr#a~3~oi9f+N7|f*Y~Qbn zNIl1%=6A;Rxl3(8EL$v_e#(kt$>(hO4CI+SvLHH9w#+7yCOh&n=zdvREwukRUn8_h ziaRW8vr22(D0a%13c@8_|AwjipFxlKQ11Zy^8J!f4Ps%`7Bw5~*p#mz$lYgi_7py( zTyJ_bOGPMY{cDK?(5Ipmz@#xBN6nEwxZ_2svyG^wi3vCBa00BujgZaddGc`brP)R$OO=13M6j>`MB zm+umfM~uRZ=hn;ZQ}EWyaSCYo>yUGWT8i0hK0^d>{Nd*{wJ-G{&CeW-0lrbF?32CS zy8CnXw*;U{MnzaO^~Z;``+M`?J%v3mAJdJ21C9%NLeM%=Q0ZBk3udZ{KWegy_edjy z^M;ys$N3hMD6HFNq97!>QsJhX5i&rLLY3%6b@$1eUGFIY3&{dsPn{9x0~Q>+A~b!9 z6P-9XOnLNn4V0~M8{8TOoyl&i2MF5*oGPz%75@aJ+#7KGA5Er+aT4lHoG=y1?2@c) z%?>KsaLdGx-ls9m)4)9y00F>HH#74y3N74T^gihF&bpMfNmF%CbmEB{$LPhd1 z=<&Pf?`2PLXMKpVvAupRAH<` z$5hYB?)b2}wrf$i1W4V`zh)_v>_{*D%74jk!9;|zoGzs0K-d(PjyJ3jR8I+<8R zFg!#q*>0l93;lJXU1XAwoRa1eGykn{SoK^&M&Q0x(@F983nxKPCnoS~B;owbjuS3T z*98|@dqDBC+kq381KUs9C3lZjxalkQ;S@v>m)}upYgf3;G!_E1@) zm*bir;Yt(t)_pJ6nB0~F-#i%AvPamx$82?}=c>#_mXs$-~RC{=C;zW39U#wzKN}jl8^0bEEqi zS`E%&Ra1}uUh4k#FJ_O)(J;=|7T4HJ@mHyLht#ht<`_&|cQT#!O7=Np^?3a>HB^rt zl>?+?(S%((B@y9Zp2nn@|I^HIr`?gy2|Jq}FqA6GH(5c$tIVb`QN0#`gl+b*TRqy` z^yA1)vxiDYg}tPm>1)2mH;Bu?y;x52`Ku<6cLm7)YP=WrW;n^^{NQq(6#MlRdGSHn zYya1H?{kUPWpAMJ z)l5HWT~=Nny=`P5X@+4_7JB08$Y5z5IK;mGw4UQVyGFtOU7Qw2$2h6dvVGLhzT;Ye zqFIVXtmTk%J8MYq(ZJ;^awSdUB}%7{N_mlJ3tcC#Ddy?r3r}9FwK{GuD)5(b;$Ca9 z8#|%Z;NM_lEtBSydQkh}DD1j$?R{M8hFiogw@O>mX3jszT}k8&_1rSzKmD9~4MY^% zkCA;)QNub6KY2Qqo+^9TrRxH1-@hvT`fVvDL`SYswfC;FYn>ZqWG4r*UP$(xPHCUn z7NlxaHlNjF42@Nc&%8LjU*E^R+Q-(b z4lxazwd4{PzBD?z9$s+(+2~1pqb=Ic1~%Q(p~>;(!Rt>hb~zgA+IC{E?ByG4fo8q~u)b6;=3kGYRVs%wHk2M2wD|nA^lM1&o`Lt| zRN$tp&5c_&Q^MFMmkU?47(BGY%K|GEUd=ZTbMcz(wJ)Bn?|DA);^-stb*GMgQ%99u zr+#4Rl7PRPzE$6`4VjAr4U^=gTKjzzZx_GgzuVotIf-*X#_D}rL0|`GD)hU1=0Ts| znhCj&{G#sHX{&tt(gE}mzX#tK9kL%wxkk<*1T*vxY1+pHaDBpc4=F%@Sw1CtXKFYZ zoOs=hLl@gMtBy_H6lDp1+8xWgP+sy@{fO0v2ZQPTzyq}-0#jc5{u=OwK@H;O_1<}; zdGWFU@eDR5WQ>=O8Cz*r`04z1^>ufi)g3fBOL?qmMyIJ8U*N|43J%+K=gK=OQ!kHu zTvKkuNbSp>D0QiH^SfJ|8onRb$iJtOs%SbLdv9;aXU3=Ut5;eaw{xt|!*V8D#Ky%_ zZ!QCabKi6w5EFSpciwi*&Jn9<;NA7khDr*@NWMK&tNRl%g0~vJX#|h z5C3|KxK*R++Q&T>nGTJ*7tR)8w~V}Ml_@@%6b1AgTBhiM*$}q1UMO8%?$SrRzVPE3 zZ*#?*?9biddwBmAP&V0#$G@oDXzpH!=rf6bd}8mW`SD26vQ1e1a2tRAAO~){tkU@r zmso8@M-~Vq))(g!;J0(EhDRSR7RGUG)KjKT<3OP8I4cADRN+~I927378?ssF|Eqkw%O%5w41o7>#t_8HGmpH ziLTRiSHhnYzMXF0itM$>TOe`%p?)tkj=XShcZ&zaI;aSB0f*A5i)uWSr04yKSw(?pa&n*y+xR9R=x_O_Wm`f#l^)re z1XFZxY`7s5PQQ7tjf|Yz-IZFeBK;~PAUU;fcaS*w{#D&X7UMc$n^ecL{=RFXe)5l$ zRRmQ3SJ0W`r!l_X#dalU3V%JBFk$uKa^L94d=uJV9z9sOT0Ka;is6{Qi(a75 znzB{3X&7Xllhg8Z>U`i*`Rh>7gZ9{Gy9=YUy^#?YSjRJ}ciX>Pe~c%$@N%HaOFsRP-#%01!BKKQBB zIKK(Fy7yz{&-lz1l^r7o-ZzxA6h#;k9%clpxZRJDUDGMp)KgeEw$O|l^Vd-LFevvY zwf*y7O_}G%D-&1U0ygpIH__Ia)FA%>fAejXPo$#(2m1D}d^l%w>*ungL$7ISK~MHw zzN8&Ri97Ly>U1rzWZ~bo)T5)@oR6cOA~PE=eLuW!hri%1FOP@sK&!cona*G|#BZm@XLthPQVq33MwfgQPi! za%xSlDqdLoih1m#-Md#;a**RkkCtTq^ZZ3f)F<|;A2%sGzRIjB9~U*VWNh~Oj6bT7 zqh7Wx9KROt!jS7dCiS*P`p}tE;;FUPysJO;9-oLmr#^l$YFovcj*~ik&gk^Eci+qm z*IAVf8w8F$NFw)HTU|NyN@ZuuUH{mbIF+@RXZ}exuKsQOLST)%{UFvaLOO5Xjl8x$ zDm9`^SEp5*`RlE#llTt0?`yX8jdnx}&z8j5+}b_iZ|v-ytNV~_W7&=^m71pdSC+#WsoHk!?e*1t zO5z#ge~kYY#`quOzc-fnR~4?kL5B@(ZUO(6E15$#Q8{yo4q3)Pmv3YWEPyM)zX<$N zz-BAHmsWkq<*3$uQV!62?`1hFtsKs{@m(c4x!+@nQJBZ8rrq1CgR@JPdp|uz=Iv<+ z^#gtgur+oE4EVu8K6voO%VX589$8u7r*Og4 zw95FJE?7xpmBoU!_V1N_k+FfZ*N1xV*ZQcYrANxg_WM0_?MZV>xxxzVYd8S<{m`Nf zV2uAU{`)Y-{}}%&AO|(V_zFIqC%-BJd!YYe(dT*CFO&m;=pYw-xlKSm>q^YI`Ct%? zdBkYZ^6t(#oSu_KKBi7q`KS_rcQO4rxEPkK^a-L6?_ap{be+#bkRR}4guTo2fB`>A zU?oC&_H$Gud=v6B9OCDazWpixuIt?i_v}|FiiQR_&NaqQC(j~+|NiG|xa7lI7-{lQ z090DY6N%Hu`=XKNwei)fSD-n&81E#N5zsuB5OY!1d?~(ThE*`GX@PZX6Na*W(3+k} zF&UbgM@gsS>1RnFGY?Lb&6TW0m?%p_SbZ0mMiF;$-Ie&N-prIfhjAJ!UzKOWd_dVI z68LZE)PXFYDuZm8@>ACHB5$3pZEG3coOI23WMx)Zw1>_oh)Q#kk!u)F)i#0=Y$`(5 zYZIky2fJJ%od%}}YG_h)mDi%ZOoXz*!m{t{vRZY?{X*1x+upJgRsA^CjG)S|NNdR- z`mA*>I0?(l!Kf%9gy$}ltl0000` snippets, `manifest.webmanifest` examples, and maskable safe-area guidance, read: - -- [`references/web-ui-ux.md`](references/web-ui-ux.md) - -## Notes - -- If your input is SVG and Python SVG rasterization is unavailable on your machine, export a 1024x1024 PNG first (e.g., Inkscape), then rerun the script using the PNG. -- Keep this SKILL.md lean; detailed size tables live in the reference files. diff --git a/builtin-skills/iOS-Dev/icon-generator/references/icon-sizes.md b/builtin-skills/iOS-Dev/icon-generator/references/icon-sizes.md deleted file mode 100644 index 20e8dadb..00000000 --- a/builtin-skills/iOS-Dev/icon-generator/references/icon-sizes.md +++ /dev/null @@ -1,39 +0,0 @@ -# Icon size tables - -## Web UI/UX (favicons + PWA) - -Minimal, modern set: - -- `favicon.ico`: 16×16, 32×32 (optionally 48×48) -- `apple-touch-icon.png`: 180×180 -- `icon-192.png`: 192×192 -- `icon-512.png`: 512×512 -- `icon-maskable-512.png`: 512×512 (opaque background + padding) - -## Unreal Engine packaging (optional) - -### Windows `.ico` - -Recommended embedded sizes: - -- 16, 24, 32, 48, 64, 128, 256 - -### macOS `.iconset` (source for `.icns`) - -Common iconset sizes and filenames: - -- `icon_16x16.png` (16) -- `icon_16x16@2x.png` (32) -- `icon_32x32.png` (32) -- `icon_32x32@2x.png` (64) -- `icon_128x128.png` (128) -- `icon_128x128@2x.png` (256) -- `icon_256x256.png` (256) -- `icon_256x256@2x.png` (512) -- `icon_512x512.png` (512) -- `icon_512x512@2x.png` (1024) - -### Linux - -- 256×256 PNG (common baseline) -- 512×512 PNG (nice to have) diff --git a/builtin-skills/iOS-Dev/icon-generator/references/unreal-engine.md b/builtin-skills/iOS-Dev/icon-generator/references/unreal-engine.md deleted file mode 100644 index 49fb2c88..00000000 --- a/builtin-skills/iOS-Dev/icon-generator/references/unreal-engine.md +++ /dev/null @@ -1,29 +0,0 @@ -# Unreal Engine packaging icons (optional target) - -## What UE typically expects - -- **Windows**: a multi-resolution `.ico` (commonly max 256×256) -- **macOS**: an `.icns` (UE may require `.icns` even if Apple has moved toward asset catalogs) -- **Linux**: usually a `.png` (commonly 256×256) - -## What this skill generates - -Using `--targets ue`, the script outputs: - -- `ue/windows/icon.ico` (multi-size) -- `ue/mac/AppIcon.iconset/` (iconset PNGs) -- `ue/linux/icon-256.png`, `ue/linux/icon-512.png` - -### Creating `.icns` (macOS) - -Creating `.icns` is easiest on macOS with `iconutil`. - -- Input: the `AppIcon.iconset/` folder -- Output: `AppIcon.icns` - -If you’re not on macOS, keep the `.iconset` in source control and generate `.icns` on a Mac build machine. - -## Quality reminder - -Even if a single “master” PNG exists, small sizes often need a simplified design. -If your 16×16 looks mushy, create a simplified icon variant and regenerate. diff --git a/builtin-skills/iOS-Dev/icon-generator/references/web-ui-ux.md b/builtin-skills/iOS-Dev/icon-generator/references/web-ui-ux.md deleted file mode 100644 index 9c9a6e5f..00000000 --- a/builtin-skills/iOS-Dev/icon-generator/references/web-ui-ux.md +++ /dev/null @@ -1,56 +0,0 @@ -# Web UI/UX icon set (favicon + PWA) - -## Recommended minimal output set - -This set covers modern browsers + iOS home screen + Android/PWA: - -- `favicon.ico` (multi-size container): include 16×16 and 32×32 (optionally 48×48) -- `apple-touch-icon.png` (180×180) -- `icon-192.png` (192×192) -- `icon-512.png` (512×512) -- `icon-maskable-512.png` (512×512, **maskable**, opaque background, padded content) - -This is intentionally “minimal but effective”. You can add more sizes if you have a specific requirement. - -## HTML `` snippet - -Use this as a starting point: - -- `` -- `` -- `` -- `` -- `` (if PWA) - -## `manifest.webmanifest` example - -Include both normal (“any”) and maskable icons: - -```json -{ - "name": "My App", - "short_name": "MyApp", - "display": "standalone", - "start_url": "/", - "icons": [ - { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192", "purpose": "any" }, - { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512", "purpose": "any" }, - { "src": "/icon-maskable-512.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" } - ] -} -``` - -## Maskable safe area (practical rule) - -Maskable icons can be cropped into different shapes by the OS/launcher. - -- Keep important content inside the **center ~80%** of the image. -- Use an **opaque background** for the full 512×512. - -In the generator script, this corresponds to `--maskable-scale 0.80` (default). - -## Common failure modes - -- You only provide a big 512×512 and let the browser scale down → looks blurry at 16×16. -- You use transparent background for iOS “Add to Home Screen” icons → iOS may render it with an ugly fill. -- Your maskable icon has no padding → the launcher crops off your logo. diff --git a/builtin-skills/iOS-Dev/icon-generator/scripts/generate_icons.py b/builtin-skills/iOS-Dev/icon-generator/scripts/generate_icons.py deleted file mode 100644 index e7d8705b..00000000 --- a/builtin-skills/iOS-Dev/icon-generator/scripts/generate_icons.py +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python3 -"""Generate icon assets for web UI/UX (favicons + PWA icons) and optional UE packaging. - -This script is designed to be simple, predictable, and cross-platform. - -Inputs: - - A single source image: preferably a square 1024x1024 PNG. - - SVG is accepted only if optional rasterizers are installed. - -Outputs (by default): - - Web/PWA: favicon.ico (multi-size), apple-touch-icon.png, icon-192.png, icon-512.png, - icon-maskable-512.png (padded + background). - - UE (optional): Windows icon.ico (multi-size), macOS .iconset folder, Linux PNGs. - -Dependencies: - - Pillow (required): pip install pillow - -Usage: - python scripts/generate_icons.py --input icon.png --out ./dist --targets web - python scripts/generate_icons.py --input icon.png --out ./dist --targets web,ue - -Notes: - - For SVG input: export to a 1024x1024 PNG first (recommended) unless you install CairoSVG. -""" - -from __future__ import annotations - -import argparse -import math -import os -from dataclasses import dataclass -from pathlib import Path -from typing import Iterable, Optional - - -try: - from PIL import Image -except ImportError as e: # pragma: no cover - raise SystemExit( - "Pillow is required. Install it with: pip install pillow" - ) from e - - -@dataclass(frozen=True) -class Options: - input_path: Path - out_dir: Path - targets: set[str] - pad_to_square: bool - background: str - maskable_scale: float - resample: int - - -def _parse_hex_color(value: str) -> tuple[int, int, int, int]: - v = value.strip().lstrip("#") - if len(v) == 6: - r = int(v[0:2], 16) - g = int(v[2:4], 16) - b = int(v[4:6], 16) - return (r, g, b, 255) - if len(v) == 8: - r = int(v[0:2], 16) - g = int(v[2:4], 16) - b = int(v[4:6], 16) - a = int(v[6:8], 16) - return (r, g, b, a) - raise ValueError(f"Invalid color '{value}'. Use #RRGGBB or #RRGGBBAA") - - -def _is_svg(path: Path) -> bool: - return path.suffix.lower() == ".svg" - - -def _load_image(path: Path) -> Image.Image: - if _is_svg(path): - # Best-effort: try cairosvg if installed, else fail with actionable guidance. - try: - import cairosvg # type: ignore - - png_bytes = cairosvg.svg2png(url=str(path)) - from io import BytesIO - - return Image.open(BytesIO(png_bytes)).convert("RGBA") - except ImportError as e: - raise SystemExit( - "SVG input requires CairoSVG (pip install cairosvg) or export SVG to a 1024x1024 PNG first." - ) from e - return Image.open(path).convert("RGBA") - - -def _ensure_square(img: Image.Image, pad_to_square: bool, background_rgba: tuple[int, int, int, int]) -> Image.Image: - w, h = img.size - if w == h: - return img - if not pad_to_square: - side = min(w, h) - left = (w - side) // 2 - top = (h - side) // 2 - return img.crop((left, top, left + side, top + side)) - side = max(w, h) - canvas = Image.new("RGBA", (side, side), background_rgba) - x = (side - w) // 2 - y = (side - h) // 2 - canvas.alpha_composite(img, (x, y)) - return canvas - - -def _resize(img: Image.Image, size: int, resample: int) -> Image.Image: - if img.size == (size, size): - return img - return img.resize((size, size), resample=resample) - - -def _fit_with_padding(img: Image.Image, size: int, content_scale: float, background_rgba: tuple[int, int, int, int], resample: int) -> Image.Image: - """Create a square icon with padding. - - For maskable icons, we want important content inside a safe zone. - A pragmatic default is to fit the original artwork inside a centered square - with side length = size * content_scale. - """ - - content_scale = max(0.1, min(content_scale, 1.0)) - inner = int(round(size * content_scale)) - inner = max(1, min(inner, size)) - inner_img = _resize(img, inner, resample) - canvas = Image.new("RGBA", (size, size), background_rgba) - x = (size - inner) // 2 - y = (size - inner) // 2 - canvas.alpha_composite(inner_img, (x, y)) - return canvas - - -def _write_png(img: Image.Image, path: Path) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - img.save(path, format="PNG", optimize=True) - - -def _write_ico(source_square: Image.Image, path: Path, sizes: Iterable[int], resample: int) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - icon_sizes = [(s, s) for s in sizes] - - # Pillow expects the base image to be at least as large as the biggest size. - max_size = max(sizes) - base = _resize(source_square, max_size, resample) - base.save(path, format="ICO", sizes=icon_sizes) - - -def generate_web(opts: Options, src_square: Image.Image) -> None: - # Minimal, modern set (good coverage without going crazy): - # - favicon.ico (16/32/48) - # - apple-touch-icon.png (180) - # - icon-192.png, icon-512.png - # - icon-maskable-512.png (opaque background + safe padding) - out = opts.out_dir - - _write_ico(src_square, out / "favicon.ico", sizes=[16, 32, 48], resample=opts.resample) - _write_png(_resize(src_square, 180, opts.resample), out / "apple-touch-icon.png") - _write_png(_resize(src_square, 192, opts.resample), out / "icon-192.png") - _write_png(_resize(src_square, 512, opts.resample), out / "icon-512.png") - - bg = _parse_hex_color(opts.background) - maskable = _fit_with_padding( - img=src_square, - size=512, - content_scale=opts.maskable_scale, - background_rgba=bg, - resample=opts.resample, - ) - _write_png(maskable, out / "icon-maskable-512.png") - - -def generate_ue(opts: Options, src_square: Image.Image) -> None: - out = opts.out_dir - - # Windows: multi-size .ico. Minimum recommended set includes 16/24/32/48/256. - _write_ico(src_square, out / "ue" / "windows" / "icon.ico", sizes=[16, 24, 32, 48, 64, 128, 256], resample=opts.resample) - - # macOS: generate a .iconset folder; creating .icns requires iconutil on macOS. - iconset_dir = out / "ue" / "mac" / "AppIcon.iconset" - iconset_dir.mkdir(parents=True, exist_ok=True) - - # Standard mac iconset filenames. - mac_entries: list[tuple[str, int]] = [ - ("icon_16x16.png", 16), - ("icon_16x16@2x.png", 32), - ("icon_32x32.png", 32), - ("icon_32x32@2x.png", 64), - ("icon_128x128.png", 128), - ("icon_128x128@2x.png", 256), - ("icon_256x256.png", 256), - ("icon_256x256@2x.png", 512), - ("icon_512x512.png", 512), - ("icon_512x512@2x.png", 1024), - ] - for filename, size in mac_entries: - _write_png(_resize(src_square, size, opts.resample), iconset_dir / filename) - - # Linux: PNG is typically fine. - _write_png(_resize(src_square, 256, opts.resample), out / "ue" / "linux" / "icon-256.png") - _write_png(_resize(src_square, 512, opts.resample), out / "ue" / "linux" / "icon-512.png") - - -def _parse_targets(value: str) -> set[str]: - targets = {t.strip().lower() for t in value.split(",") if t.strip()} - allowed = {"web", "ue"} - unknown = targets - allowed - if unknown: - raise ValueError(f"Unknown targets: {', '.join(sorted(unknown))}. Use: web, ue") - return targets - - -def main() -> int: - parser = argparse.ArgumentParser(description="Generate web/PWA and UE icon assets from a single source image.") - parser.add_argument("--input", required=True, help="Path to source image (PNG recommended; SVG supported with cairosvg).") - parser.add_argument("--out", required=True, help="Output directory.") - parser.add_argument("--targets", default="web", help="Comma-separated: web, ue (default: web)") - parser.add_argument( - "--no-pad", - action="store_true", - help="Do not pad to square. If the input is not square, crop instead.", - ) - parser.add_argument( - "--background", - default="#000000", - help="Background color for maskable icons and padding. Use #RRGGBB or #RRGGBBAA (default: #000000)", - ) - parser.add_argument( - "--maskable-scale", - type=float, - default=0.80, - help="Scale of the artwork inside maskable icon canvas (default: 0.80).", - ) - args = parser.parse_args() - - input_path = Path(args.input) - out_dir = Path(args.out) - out_dir.mkdir(parents=True, exist_ok=True) - - targets = _parse_targets(args.targets) - - # Pillow resampling: prefer high-quality downsampling. - # Use getattr to satisfy type checkers across Pillow versions/stubs. - resample = ( - getattr(getattr(Image, "Resampling", None), "LANCZOS", None) - or getattr(Image, "LANCZOS", None) - or getattr(Image, "ANTIALIAS", None) - or getattr(Image, "BICUBIC", 3) - ) - - opts = Options( - input_path=input_path, - out_dir=out_dir, - targets=targets, - pad_to_square=not args.no_pad, - background=args.background, - maskable_scale=args.maskable_scale, - resample=resample, - ) - - bg = _parse_hex_color(opts.background) - src = _load_image(opts.input_path) - src_square = _ensure_square(src, pad_to_square=opts.pad_to_square, background_rgba=bg) - - if "web" in opts.targets: - generate_web(opts, src_square) - if "ue" in opts.targets: - generate_ue(opts, src_square) - - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/builtin-skills/iOS-Dev/ios-swift-development/SKILL.md b/builtin-skills/iOS-Dev/ios-swift-development/SKILL.md deleted file mode 100644 index ca33b846..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/SKILL.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: ios-swift-development -description: > - Develop native iOS apps with Swift. Covers MVVM architecture, SwiftUI, - URLSession for networking, Combine for reactive programming, and Core Data - persistence. ---- - -# iOS Swift Development - -## Table of Contents - -- [Overview](#overview) -- [When to Use](#when-to-use) -- [Quick Start](#quick-start) -- [Reference Guides](#reference-guides) -- [Best Practices](#best-practices) - -## Overview - -Build high-performance native iOS applications using Swift with modern frameworks including SwiftUI, Combine, and async/await patterns. - -## When to Use - -- Creating native iOS applications with optimal performance -- Leveraging iOS-specific features and APIs -- Building apps that require tight hardware integration -- Using SwiftUI for declarative UI development -- Implementing complex animations and transitions - -## Quick Start - -Minimal working example: - -```swift -import Foundation -import Combine - -struct User: Codable, Identifiable { - let id: UUID - var name: String - var email: String -} - -class UserViewModel: ObservableObject { - @Published var user: User? - @Published var isLoading = false - @Published var errorMessage: String? - - private let networkService: NetworkService - - init(networkService: NetworkService = .shared) { - self.networkService = networkService - } - - @MainActor - func fetchUser(id: UUID) async { - isLoading = true - errorMessage = nil - -// ... (see reference guides for full implementation) -``` - -## Reference Guides - -Detailed implementations in the `references/` directory: - -| Guide | Contents | -|---|---| -| [MVVM Architecture Setup](references/mvvm-architecture-setup.md) | MVVM Architecture Setup | -| [Network Service with URLSession](references/network-service-with-urlsession.md) | Network Service with URLSession | -| [SwiftUI Views](references/swiftui-views.md) | SwiftUI Views | - -## Best Practices - -### ✅ DO - -- Use SwiftUI for modern UI development -- Implement MVVM architecture -- Use async/await patterns -- Store sensitive data in Keychain -- Handle errors gracefully -- Use @StateObject for ViewModels -- Validate API responses properly -- Implement Core Data for persistence -- Test on multiple iOS versions -- Use dependency injection -- Follow Swift style guidelines - -### ❌ DON'T - -- Store tokens in UserDefaults -- Make network calls on main thread -- Use deprecated UIKit patterns -- Ignore memory leaks -- Skip error handling -- Use force unwrapping (!) -- Store passwords in code -- Ignore accessibility -- Deploy untested code -- Use hardcoded API URLs diff --git a/builtin-skills/iOS-Dev/ios-swift-development/references/mvvm-architecture-setup.md b/builtin-skills/iOS-Dev/ios-swift-development/references/mvvm-architecture-setup.md deleted file mode 100644 index 829527cd..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/references/mvvm-architecture-setup.md +++ /dev/null @@ -1,60 +0,0 @@ -# MVVM Architecture Setup - -## MVVM Architecture Setup - -```swift -import Foundation -import Combine - -struct User: Codable, Identifiable { - let id: UUID - var name: String - var email: String -} - -class UserViewModel: ObservableObject { - @Published var user: User? - @Published var isLoading = false - @Published var errorMessage: String? - - private let networkService: NetworkService - - init(networkService: NetworkService = .shared) { - self.networkService = networkService - } - - @MainActor - func fetchUser(id: UUID) async { - isLoading = true - errorMessage = nil - - do { - user = try await networkService.fetch(User.self, from: "/users/\(id)") - } catch { - errorMessage = error.localizedDescription - } - - isLoading = false - } - - @MainActor - func updateUser(_ userData: User) async { - guard let user = user else { return } - - do { - self.user = try await networkService.put( - User.self, - to: "/users/\(user.id)", - body: userData - ) - } catch { - errorMessage = "Failed to update user" - } - } - - func logout() { - user = nil - errorMessage = nil - } -} -``` diff --git a/builtin-skills/iOS-Dev/ios-swift-development/references/network-service-with-urlsession.md b/builtin-skills/iOS-Dev/ios-swift-development/references/network-service-with-urlsession.md deleted file mode 100644 index a64e9c7f..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/references/network-service-with-urlsession.md +++ /dev/null @@ -1,99 +0,0 @@ -# Network Service with URLSession - -## Network Service with URLSession - -```swift -class NetworkService { - static let shared = NetworkService() - - private let session: URLSession - private let baseURL: URL - - init( - session: URLSession = .shared, - baseURL: URL = URL(string: "https://api.example.com")! - ) { - self.session = session - self.baseURL = baseURL - } - - func fetch( - _: T.Type, - from endpoint: String - ) async throws -> T { - let url = baseURL.appendingPathComponent(endpoint) - var request = URLRequest(url: url) - request.addAuthHeader() - - let (data, response) = try await session.data(for: request) - try validateResponse(response) - - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = .iso8601 - return try decoder.decode(T.self, from: data) - } - - func put( - _: T.Type, - to endpoint: String, - body: Body - ) async throws -> T { - let url = baseURL.appendingPathComponent(endpoint) - var request = URLRequest(url: url) - request.httpMethod = "PUT" - request.addAuthHeader() - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = .iso8601 - request.httpBody = try encoder.encode(body) - - let (data, response) = try await session.data(for: request) - try validateResponse(response) - - let decoder = JSONDecoder() - return try decoder.decode(T.self, from: data) - } - - private func validateResponse(_ response: URLResponse) throws { - guard let httpResponse = response as? HTTPURLResponse else { - throw NetworkError.invalidResponse - } - - switch httpResponse.statusCode { - case 200...299: - return - case 401: - throw NetworkError.unauthorized - case 500...599: - throw NetworkError.serverError - default: - throw NetworkError.unknown - } - } -} - -enum NetworkError: LocalizedError { - case invalidResponse - case unauthorized - case serverError - case unknown - - var errorDescription: String? { - switch self { - case .invalidResponse: return "Invalid response" - case .unauthorized: return "Unauthorized" - case .serverError: return "Server error" - case .unknown: return "Unknown error" - } - } -} - -extension URLRequest { - mutating func addAuthHeader() { - if let token = KeychainManager.shared.getToken() { - setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") - } - } -} -``` diff --git a/builtin-skills/iOS-Dev/ios-swift-development/references/swiftui-views.md b/builtin-skills/iOS-Dev/ios-swift-development/references/swiftui-views.md deleted file mode 100644 index 7f5b45db..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/references/swiftui-views.md +++ /dev/null @@ -1,112 +0,0 @@ -# SwiftUI Views - -## SwiftUI Views - -```swift -struct ContentView: View { - @StateObject var userViewModel = UserViewModel() - - var body: some View { - TabView { - HomeView() - .tabItem { Label("Home", systemImage: "house") } - - ProfileView(viewModel: userViewModel) - .tabItem { Label("Profile", systemImage: "person") } - } - } -} - -struct HomeView: View { - @State var items: [Item] = [] - @State var loading = true - - var body: some View { - NavigationView { - ZStack { - if loading { - ProgressView() - } else { - List(items) { item in - NavigationLink(destination: ItemDetailView(item: item)) { - VStack(alignment: .leading) { - Text(item.title).font(.headline) - Text(item.description).font(.subheadline).foregroundColor(.gray) - } - } - } - } - } - .navigationTitle("Items") - .task { - await loadItems() - } - } - } - - private func loadItems() async { - do { - items = try await NetworkService.shared.fetch([Item].self, from: "/items") - } catch { - print("Error: \(error)") - } - loading = false - } -} - -struct ItemDetailView: View { - let item: Item - @Environment(\.dismiss) var dismiss - - var body: some View { - ScrollView { - VStack(alignment: .leading, spacing: 16) { - Text(item.title).font(.title2).fontWeight(.bold) - Text(item.description).font(.body) - Text("Price: $\(String(format: "%.2f", item.price))") - .font(.headline).foregroundColor(.blue) - Spacer() - } - .padding() - } - .navigationBarTitleDisplayMode(.inline) - } -} - -struct ProfileView: View { - @ObservedObject var viewModel: UserViewModel - @State var isLoading = true - - var body: some View { - NavigationView { - ZStack { - if viewModel.isLoading { - ProgressView() - } else if let user = viewModel.user { - VStack(spacing: 20) { - Text(user.name).font(.title).fontWeight(.bold) - Text(user.email).font(.subheadline) - Button("Logout") { viewModel.logout() } - .foregroundColor(.red) - Spacer() - } - .padding() - } else { - Text("No profile data") - } - } - .navigationTitle("Profile") - .task { - await viewModel.fetchUser(id: UUID()) - } - } - } -} - -struct Item: Codable, Identifiable { - let id: String - let title: String - let description: String - let price: Double -} -``` diff --git a/builtin-skills/iOS-Dev/ios-swift-development/scripts/validate-api.sh b/builtin-skills/iOS-Dev/ios-swift-development/scripts/validate-api.sh deleted file mode 100755 index e4478b64..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/scripts/validate-api.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# validate-api.sh - Validate API specification -# Usage: ./validate-api.sh - -set -euo pipefail - -SPEC_FILE="${{1:?Usage: $0 }}" - -echo "Validating API spec: $SPEC_FILE" - -# TODO: Add API validation -# - Validate OpenAPI/Swagger syntax -# - Check endpoint naming conventions -# - Verify response schemas -# - Check for required headers -# - Validate authentication definitions - -echo "API validation complete." diff --git a/builtin-skills/iOS-Dev/ios-swift-development/templates/api-scaffold.yaml b/builtin-skills/iOS-Dev/ios-swift-development/templates/api-scaffold.yaml deleted file mode 100644 index 3196297b..00000000 --- a/builtin-skills/iOS-Dev/ios-swift-development/templates/api-scaffold.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# API Endpoint Scaffold -# TODO: Customize for your API framework - -openapi: "3.0.3" -info: - title: "API Service" - version: "1.0.0" - -paths: - /api/v1/resource: - get: - summary: "List resources" - # TODO: Define parameters and responses - responses: - "200": - description: "Success" - post: - summary: "Create resource" - # TODO: Define request body and responses - responses: - "201": - description: "Created" diff --git a/builtin-skills/iOS-Dev/mobile-development/SKILL.md b/builtin-skills/iOS-Dev/mobile-development/SKILL.md deleted file mode 100644 index dad1e839..00000000 --- a/builtin-skills/iOS-Dev/mobile-development/SKILL.md +++ /dev/null @@ -1,261 +0,0 @@ ---- -# ═══════════════════════════════════════════════════════════════════════════ -# SKILL: Mobile Development -# Version: 2.0.0 | Updated: 2025-01 -# ═══════════════════════════════════════════════════════════════════════════ -name: mobile-development -description: iOS (Swift, SwiftUI), Android (Kotlin, Compose), cross-platform (Flutter, React Native), and game development (Unity, Unreal). - -# ACTIVATION TRIGGERS -triggers: - - ios - - android - - flutter - - react native - - mobile - - swift - - kotlin - - unity - - game development - -# SKILL PARAMETERS -parameters: - platform: - type: string - enum: [ios, android, cross-platform, games] - required: true - project_type: - type: string - required: false - description: Type of app (social, productivity, game, etc.) - -# OUTPUT SPECIFICATION -outputs: - recommended_stack: - type: object - learning_path: - type: array - portfolio_projects: - type: array - -# RELIABILITY -retry: - max_attempts: 3 - backoff: exponential - -# OBSERVABILITY -observability: - log_level: info - -level: advanced -prerequisites: - - core-development - -sasmp_version: "1.3.0" -bonded_agent: 01-core-paths -bond_type: PRIMARY_BOND ---- - -# Mobile Development Skill - -## Quick Reference - -| Platform | Language | Framework | Timeline | Job Market | -|----------|----------|-----------|----------|------------| -| **iOS** | Swift | SwiftUI | 6-9 mo | High | -| **Android** | Kotlin | Compose | 6-9 mo | High | -| **Cross-Platform** | Dart | Flutter | 4-6 mo | Growing | -| **Games** | C# | Unity | 12-24 mo | Moderate | - ---- - -## Learning Paths - -### iOS Development -``` -[1] Swift Fundamentals (4-6 wk) - │ └─ Types, optionals, closures, protocols - │ - ▼ -[2] SwiftUI (4-6 wk) - │ └─ Views, modifiers, state, binding - │ - ▼ -[3] Navigation + Data (3-4 wk) - │ └─ NavigationStack, SwiftData/Core Data - │ - ▼ -[4] Networking + Async (2-3 wk) - │ └─ URLSession, async/await, Combine - │ - ▼ -[5] Testing + App Store (2 wk) - └─ XCTest, TestFlight, submission -``` - -**2025 Stack:** Swift 5.10 + SwiftUI + SwiftData + Xcode 16 - ---- - -### Android Development -``` -[1] Kotlin Fundamentals (4-6 wk) - │ └─ Null safety, coroutines, data classes - │ - ▼ -[2] Jetpack Compose (4-6 wk) - │ └─ Composables, state, effects - │ - ▼ -[3] Architecture (3-4 wk) - │ └─ MVVM, Room, Navigation - │ - ▼ -[4] Networking + DI (2-3 wk) - │ └─ Retrofit, Hilt, Flow - │ - ▼ -[5] Testing + Play Store (2 wk) - └─ JUnit, Espresso, release -``` - -**2025 Stack:** Kotlin 2.0 + Jetpack Compose + Room + Hilt - ---- - -### Flutter (Cross-Platform) -``` -[1] Dart Fundamentals (2-3 wk) - │ - ▼ -[2] Flutter Widgets (3-4 wk) - │ - ▼ -[3] State Management (2-3 wk) - │ └─ Riverpod or Bloc - │ - ▼ -[4] Backend Integration (2 wk) - │ └─ Firebase, REST APIs - │ - ▼ -[5] Deploy to Both Stores (1 wk) -``` - -**2025 Stack:** Flutter 3.x + Dart 3.x + Riverpod + Firebase - ---- - -### Game Development -``` -[1] Game Basics (4-6 wk) - │ └─ Game loop, input handling - │ - ▼ -[2] Unity/C# Fundamentals (6-8 wk) - │ └─ GameObjects, Components, Scripts - │ - ▼ -[3] Physics + Graphics (4-6 wk) - │ └─ Rigidbody, colliders, shaders - │ - ▼ -[4] Audio + Polish (2-4 wk) - │ - ▼ -[5] Publish (ongoing) - └─ Steam, App Store, Play Store -``` - -**2025 Stack:** Unity 6 LTS + C# OR Unreal 5.4 + C++ - ---- - -## Platform Decision Tree - -``` -Which platform? -│ -├─► Apple ecosystem only? -│ └─► iOS (Swift + SwiftUI) -│ -├─► Android ecosystem only? -│ └─► Android (Kotlin + Compose) -│ -├─► Both platforms? -│ ├─► Performance-critical? → Native for both -│ ├─► Budget/time limited? → Flutter -│ └─► Web developer background? → React Native -│ -└─► Making games? - ├─► 2D/3D indie → Unity - ├─► AAA quality → Unreal - └─► Simple 2D → Godot -``` - ---- - -## Game Engine Comparison - -| Engine | Market | Language | Learning | Best For | -|--------|--------|----------|----------|----------| -| **Unity** | 51% | C# | Medium | Indie, mobile, VR | -| **Unreal** | 31% | C++/BP | Hard | AAA, high-fidelity | -| **Godot** | 10% | GDScript | Easy | Indie, 2D | - ---- - -## Troubleshooting - -``` -Native vs Cross-platform? -├─► Need platform-specific APIs (HealthKit, ARCore)? → Native -├─► Performance-critical (AR/VR, complex animations)? → Native -├─► Budget or time limited? → Flutter -├─► Team knows JavaScript? → React Native -└─► Starting from scratch? → Flutter (best DX) - -Simulator works, device doesn't? -├─► Missing entitlements/capabilities? -├─► Different iOS/Android version? -├─► Network connectivity issues? -└─► Always test on real devices from day 1 - -App rejected by store? -├─► Read rejection reason carefully -├─► Check App Store Review Guidelines -├─► Most common: metadata issues, crashes, spam -└─► Appeal if unjustified -``` - ---- - -## Common Failure Modes - -| Symptom | Root Cause | Recovery | -|---------|------------|----------| -| Slow UI | Too many recompositions | Profile, optimize state | -| Memory leaks | Not cleaning up resources | Use lifecycle-aware components | -| App rejected | Guidelines violation | Read guidelines BEFORE building | -| Game stutters | Draw call overhead | Object pooling, LOD, batching | - ---- - -## Portfolio Projects - -### Mobile (Progressive) -1. **Todo App** - CRUD basics -2. **Weather App** - API integration -3. **Chat App** - Real-time, auth -4. **Payment App** - Stripe, security - -### Games -1. **2D Platformer** - Physics basics -2. **3D Runner** - 3D graphics, particles -3. **Multiplayer Game** - Networking - ---- - -## Next Actions - -Specify your target platform for a detailed learning plan. diff --git a/builtin-skills/iOS-Dev/mobile-development/assets/mobile_config.yaml b/builtin-skills/iOS-Dev/mobile-development/assets/mobile_config.yaml deleted file mode 100644 index 6121b29c..00000000 --- a/builtin-skills/iOS-Dev/mobile-development/assets/mobile_config.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Mobile Development Configuration for Cloudflare -# Version: 1.0.0 - -pwa: - enabled: true - manifest: "manifest.json" - service_worker: true - offline_support: true - -deployment: - platform: "cloudflare_pages" - build_command: "npm run build" - output_dir: "dist" - -mobile_api: - workers: - enabled: true - routes: - - "/api/*" - caching: - static_assets: "1y" - api_responses: "5m" - -performance: - image_optimization: - enabled: true - formats: ["webp", "avif"] - lazy_loading: true - preconnect: - - "https://api.example.com" - -push_notifications: - enabled: true - provider: "web-push" - vapid_keys: true diff --git a/builtin-skills/iOS-Dev/mobile-development/references/MOBILE_GUIDE.md b/builtin-skills/iOS-Dev/mobile-development/references/MOBILE_GUIDE.md deleted file mode 100644 index c1b17dca..00000000 --- a/builtin-skills/iOS-Dev/mobile-development/references/MOBILE_GUIDE.md +++ /dev/null @@ -1,73 +0,0 @@ -# Mobile Development Guide for Cloudflare - -## PWA on Cloudflare Pages - -```json -// manifest.json -{ - "name": "My PWA", - "short_name": "PWA", - "start_url": "/", - "display": "standalone", - "background_color": "#ffffff", - "theme_color": "#f38020", - "icons": [ - { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, - { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" } - ] -} -``` - -## Service Worker with Cloudflare - -```typescript -// sw.ts - Offline-first strategy -const CACHE_NAME = 'v1'; -const OFFLINE_URL = '/offline.html'; - -self.addEventListener('install', (event) => { - event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - return cache.addAll([OFFLINE_URL, '/', '/styles.css']); - }) - ); -}); - -self.addEventListener('fetch', (event) => { - event.respondWith( - fetch(event.request).catch(() => caches.match(OFFLINE_URL)) - ); -}); -``` - -## Mobile API with Workers - -```typescript -// Optimized for mobile clients -export default { - async fetch(request: Request, env: Env) { - const userAgent = request.headers.get('User-Agent') || ''; - const isMobile = /Mobile|Android|iPhone/i.test(userAgent); - - return Response.json({ - data: await getData(env), - optimized: isMobile ? 'mobile' : 'desktop' - }, { - headers: { - 'Cache-Control': isMobile ? 'max-age=300' : 'max-age=3600' - } - }); - } -}; -``` - -## Deployment - -```bash -# Deploy to Cloudflare Pages -npx wrangler pages deploy dist --project-name=my-pwa -``` - ---- - -*Cloudflare Plugin - Mobile Development Skill* diff --git a/builtin-skills/iOS-Dev/mobile-development/scripts/pwa_validator.py b/builtin-skills/iOS-Dev/mobile-development/scripts/pwa_validator.py deleted file mode 100644 index 4c2fa6b0..00000000 --- a/builtin-skills/iOS-Dev/mobile-development/scripts/pwa_validator.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -"""PWA and Mobile Readiness Validator for Cloudflare Pages.""" - -import json -from pathlib import Path - - -def validate_pwa(path: str) -> dict: - """Validate PWA configuration for Cloudflare Pages deployment.""" - project = Path(path) - - checks = { - "manifest": False, - "service_worker": False, - "icons": False, - "offline_page": False, - "https_ready": True # Cloudflare provides HTTPS - } - - # Check manifest.json - for manifest_path in ["manifest.json", "public/manifest.json", "src/manifest.json"]: - if (project / manifest_path).exists(): - checks["manifest"] = True - manifest = json.loads((project / manifest_path).read_text()) - if manifest.get("icons"): - checks["icons"] = True - break - - # Check service worker - sw_paths = ["sw.js", "service-worker.js", "public/sw.js", "src/sw.js"] - for sw_path in sw_paths: - if (project / sw_path).exists(): - checks["service_worker"] = True - break - - # Check offline page - offline_paths = ["offline.html", "public/offline.html"] - for offline_path in offline_paths: - if (project / offline_path).exists(): - checks["offline_page"] = True - break - - pwa_score = sum(checks.values()) / len(checks) * 100 - - return { - "checks": checks, - "pwa_score": pwa_score, - "pwa_ready": pwa_score >= 60, - "cloudflare_optimized": checks["manifest"] and checks["https_ready"] - } - - -def main(): - import sys - path = sys.argv[1] if len(sys.argv) > 1 else "." - print(json.dumps(validate_pwa(path), indent=2)) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/marketing/clean-general/SKILL.md b/builtin-skills/marketing/clean-general/SKILL.md deleted file mode 100644 index 099a3e68..00000000 --- a/builtin-skills/marketing/clean-general/SKILL.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: clean-general -description: Use when writing, fixing, editing, or reviewing Python code quality. Enforces Clean Code's core principles—DRY, single responsibility, clear intent, no magic numbers, proper abstractions. ---- - -# General Clean Code Principles - -## Critical Rules - -**G5: DRY (Don't Repeat Yourself)** - -Every piece of knowledge has one authoritative representation. - -```python -# Bad - duplication -tax_rate = 0.0825 -ca_total = subtotal * 1.0825 -ny_total = subtotal * 1.07 - -# Good - single source of truth -TAX_RATES = {"CA": 0.0825, "NY": 0.07} -def calculate_total(subtotal: float, state: str) -> float: - return subtotal * (1 + TAX_RATES[state]) -``` - -**G16: No Obscured Intent** - -Don't be clever. Be clear. - -```python -# Bad - what does this do? -return (x & 0x0F) << 4 | (y & 0x0F) - -# Good - obvious intent -return pack_coordinates(x, y) -``` - -**G23: Prefer Polymorphism to If/Else** - -```python -# Bad - will grow forever -def calculate_pay(employee): - if employee.type == "SALARIED": - return employee.salary - elif employee.type == "HOURLY": - return employee.hours * employee.rate - elif employee.type == "COMMISSIONED": - return employee.base + employee.commission - -# Good - open/closed principle -class SalariedEmployee: - def calculate_pay(self): return self.salary - -class HourlyEmployee: - def calculate_pay(self): return self.hours * self.rate - -class CommissionedEmployee: - def calculate_pay(self): return self.base + self.commission -``` - -**G25: Replace Magic Numbers with Named Constants** - -```python -# Bad -if elapsed_time > 86400: - ... - -# Good -SECONDS_PER_DAY = 86400 -if elapsed_time > SECONDS_PER_DAY: - ... -``` - -**G30: Functions Should Do One Thing** - -If you can extract another function, your function does more than one thing. - -**G36: Law of Demeter (Avoid Train Wrecks)** - -```python -# Bad - reaching through multiple objects -output_dir = context.options.scratch_dir.absolute_path - -# Good - one dot -output_dir = context.get_scratch_dir() -``` - -## Enforcement Checklist - -When reviewing AI-generated code, verify: -- [ ] No duplication (G5) -- [ ] Clear intent, no magic numbers (G16, G25) -- [ ] Polymorphism over conditionals (G23) -- [ ] Functions do one thing (G30) -- [ ] No Law of Demeter violations (G36) -- [ ] Boundary conditions handled (G3) -- [ ] Dead code removed (G9) diff --git a/builtin-skills/marketing/my-writing-style/README.md b/builtin-skills/marketing/my-writing-style/README.md deleted file mode 100644 index 1ef85ef4..00000000 --- a/builtin-skills/marketing/my-writing-style/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Writing Style Skill - -可复用的写作风格 Skill 模板。**内置自动学习** — 从你的修改中自动提取规则,SKILL.md 越用越准。 - -兼容 **Claude Code** + **OpenClaw (ClawHub)**。 - -## 原理 - -``` -AI 用 SKILL.md 写初稿 → 你改到满意 → diff 两版 → 提取规则 → 更新 SKILL.md → 下次更准 -``` - -只要两个数据点:**original**(AI 第一版)和 **final**(你最终版)。中间改了多少轮不管。 - -## 安装 - -```bash -# Claude Code -git clone https://github.com/jzOcb/writing-style-skill.git -cp -r writing-style-skill ~/.claude/skills/my-writing-style - -# OpenClaw / ClawHub -npx clawhub@latest install jz-writing-style-skill -``` - -## 快速开始 - -1. **改 SKILL.md** — 把模板里的风格规则改成你自己的(或留空,让自动学习帮你填) -2. **让 AI 用这个 skill 写内容** -3. **你改到满意** -4. 记录: -```bash -python3 scripts/observe.py record-original draft.md -# ... 你修改 ... -python3 scripts/observe.py record-final final.md -``` -5. 提取规则: -```bash -python3 scripts/improve.py auto --skill . -``` - -## 文件结构 - -``` -writing-style-skill/ -├── SKILL.md # 你的写作风格(模板,改成你的) -├── README.md # 本文件 -└── scripts/ - ├── observe.py # 记录 original / final(零依赖) - └── improve.py # 提取 / 应用 / 回滚(需要 LLM CLI) -``` - -## 自动学习怎么工作 - -- `observe.py` 记录 AI 原稿和你的最终版 -- `improve.py` 用 LLM 分析 diff,提取写作规则 -- 规则按置信度分 P0/P1/P2,P0 自动应用 -- 每次更新前自动备份,一键回滚 - -## LLM 支持 - -`improve.py` 自动检测: -- `claude` (Claude Code) — 优先 -- `llm` (pip install llm) — 通用 -- `IMPROVE_LLM_CMD` 环境变量 — 自定义 - -`observe.py` 零依赖纯 Python。 - -## License - -MIT diff --git a/builtin-skills/marketing/my-writing-style/SKILL.md b/builtin-skills/marketing/my-writing-style/SKILL.md deleted file mode 100644 index 08cc2901..00000000 --- a/builtin-skills/marketing/my-writing-style/SKILL.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -name: my-writing-style -version: 1.0.0 -description: | - 可复用的写作风格 Skill 模板。内置自动学习: - 从你的修改中自动提取规则,SKILL.md 越用越准。 - Fork 后改成你自己的风格。 -dependencies: [] -allowed-tools: - - Read - - Write - - Edit - - exec ---- - -# Writing Style Skill(模板) - -**Fork 这个 skill,改成你的写作风格。内置自动学习,越用越准。** - ---- - -## 🎯 怎么用 - -1. Fork / clone 这个 skill -2. 把下面的风格规则改成你自己的 -3. 让 AI 用这个 skill 写内容 -4. 你改到满意 → 脚本自动学习你改了什么 -5. 下次 AI 写出来的就更像你 - ---- - -## 【0】Voice Dimensions(量化你的风格) - -**用 1-10 分定义你的风格维度。AI 比"写得自然一点"这种话更容易理解数字。** - -| Dimension | Score | 你的说明 | -|-----------|-------|---------| -| **formal_casual** | **?/10** | 偏正式还是偏随意? | -| **technical_accessible** | **?/10** | 技术深度? | -| **serious_playful** | **?/10** | 严肃还是活泼? | -| **concise_elaborate** | **?/10** | 简洁还是详细? | -| **reserved_expressive** | **?/10** | 保守还是直接? | - -> 💡 **不知道填什么?** 先跑几次 AI 写作 → 你改 → 自动学习会帮你填。 - ---- - -## 【1】角色与读者 - -**我是谁:** -- (填你的身份,比如:独立开发者,新晋 AI 爱好者) - -**读者是谁:** -- (填你的读者,比如:对 AI 感兴趣的技术人) - -**和读者的关系:** -- (比如:同行交流,不是教学) - ---- - -## 【2】写作规则 - -### 基础规则 - -- (填你的规则,比如:不用"深入探讨"、段落要短、要有具体数字) -- -- - -### 禁止词 - -- (AI 爱用但你不喜欢的词,比如:值得注意的是、综上所述、本文将介绍) -- -- - -### 句式偏好 - -- (你喜欢的句式,比如:结论前置、不要学术导语) -- -- - -> 💡 **不需要一开始就写完。** 这些规则会通过你的修改自动积累。 -> 跑完 10 次写作→修改循环后,这里会长出几十条精准规则。 - ---- - -## 【3】格式规范 - -### 平台适配 - -| 平台 | 格式要求 | -|------|---------| -| X/Twitter | 不渲染 markdown,用纯文本 | -| 小红书 | emoji 多、分段短 | -| 博客 | 标准 markdown | -| (你的平台) | (你的要求)| - ---- - -## 🔄 自动学习(内置) - -**这个 skill 会从你的修改中自动学习。不需要手动写规则。** - -### 工作原理 - -``` -AI 用这个 skill 写初稿 - ↓ -你改到满意 - ↓ -脚本 diff 两版 → 提取你改了什么 - ↓ -新规则自动写入这个 SKILL.md - ↓ -下次 AI 写出来就更像你 -``` - -### 只需要两个数据点 - -- **original**: AI 生成的第一版 -- **final**: 你最终确认的版本 - -中间改了几轮不管。在 Google Doc 里来回改了 10 次?无所谓,只比较首尾。 - -### Agent 操作指南 - -**写完内容后:** -```bash -python3 scripts/observe.py record-original --account <账号> --content-type <类型> -``` - -**人类确认最终版后:** -```bash -python3 scripts/observe.py record-final --match -``` - -**提取规则(手动或 cron 自动):** -```bash -python3 scripts/improve.py auto --skill . -``` - -### 规则分级 - -| 级别 | 含义 | 处理方式 | -|------|------|---------| -| P0 | 高置信度(多次出现) | 自动应用 | -| P1 | 中置信度 | 人工确认 | -| P2 | 低置信度(仅 1 次) | 存档观察 | - -### 安全 - -- 每次更新前自动备份 SKILL.md -- `improve.py rollback` 一键回滚 -- auto 模式只应用 P0 - ---- - -## 📊 CLI 参考 - -### observe.py(零依赖纯 Python) - -| 命令 | 功能 | -|------|------| -| `record-original ` | 记录 AI 原稿 | -| `record-final --match ` | 记录最终版 | -| `pending` | 查看待配对 | -| `stats` | 统计 | - -### improve.py(需要 LLM CLI) - -| 命令 | 功能 | -|------|------| -| `extract [--days 7]` | 提取改进建议 | -| `auto` | 提取 + 自动应用 P0 | -| `show` | 查看提案 | -| `apply ` | 应用提案 | -| `rollback` | 回滚 | - -支持的 LLM CLI: `claude`(Claude Code)/ `llm`(pip install llm)/ `IMPROVE_LLM_CMD` 环境变量 - ---- - -## 📂 数据存储 - -``` -~/clawd/memory/ # OpenClaw -~/.claude/memory/ # Claude Code -├── skill-runs// -│ └── YYYY-MM-DD.jsonl # 每日观察日志 -├── skill-proposals// -│ └── YYYYMMDD-HHMMSS.md # 改进提案 -└── skill-backups// - └── SKILL-YYYYMMDD-HHMMSS.md # 自动备份 -``` - -自动检测环境,不需要手动配置路径。 - ---- - -## 🚀 30 天预期 - -| 时间 | 预期效果 | -|------|---------| -| 第 1 周 | 积累 3-5 次修改,生成第一批规则 | -| 第 2 周 | 10+ 条规则,AI 输出明显更像你 | -| 第 1 月 | 30+ 条规则,风格维度自动校准 | -| 持续 | 规则库稳定增长,新 pattern 自动捕捉 | diff --git a/builtin-skills/marketing/my-writing-style/scripts/improve.py b/builtin-skills/marketing/my-writing-style/scripts/improve.py deleted file mode 100644 index 5f8e36b0..00000000 --- a/builtin-skills/marketing/my-writing-style/scripts/improve.py +++ /dev/null @@ -1,426 +0,0 @@ -#!/usr/bin/env python3 -""" -Self-Improving Skill — Improver - -从人类修改中提取规则,更新目标 SKILL.md。 - -用法: - python3 improve.py extract [--days 7] [--date 2026-03-17] - python3 improve.py auto # 提取 + 自动应用 P0(cron 用) - python3 improve.py show # 查看所有提案 - python3 improve.py apply # 应用指定提案 - python3 improve.py rollback # 回滚上次应用 - -环境变量: - SKILL_LOG_DIR — 日志目录 - SKILL_TARGET_PATH — 目标 SKILL.md 路径 - SKILL_PROPOSAL_DIR — 提案目录 - SKILL_BACKUP_DIR — 备份目录 -""" - -import sys -import json -import os -import argparse -import subprocess -import shutil -from pathlib import Path -from datetime import datetime, timedelta - -# 默认路径 — 自动检测 OpenClaw (~/.openclaw) 或 Claude Code (~/.claude) -def _detect_base(): - """检测数据存储基目录""" - # 优先级: 环境变量 > ~/clawd > ~/.openclaw > ~/.claude > ~/.self-improving - if os.environ.get("SKILL_BASE_DIR"): - return Path(os.environ["SKILL_BASE_DIR"]) - candidates = [ - Path.home() / "clawd" / "memory", - Path.home() / ".openclaw" / "memory", - Path.home() / ".claude" / "memory", - ] - for c in candidates: - if c.parent.exists(): - return c - return Path.home() / ".self-improving" / "memory" - -_BASE = _detect_base() -DEFAULT_LOG_DIR = _BASE / "skill-runs" / "default" -DEFAULT_PROPOSAL_DIR = _BASE / "skill-proposals" / "default" -DEFAULT_BACKUP_DIR = _BASE / "skill-backups" / "default" - - -def get_paths(args=None): - """解析所有路径配置""" - skill_name = "default" - if args and hasattr(args, 'skill') and args.skill: - skill_name = Path(args.skill).name - - base = Path.home() / "clawd" / "memory" - - log_dir = Path(os.environ.get("SKILL_LOG_DIR", - getattr(args, 'log_dir', None) or - str(base / "skill-runs" / skill_name))) - - proposal_dir = Path(os.environ.get("SKILL_PROPOSAL_DIR", - getattr(args, 'proposal_dir', None) or - str(base / "skill-proposals" / skill_name))) - - backup_dir = Path(os.environ.get("SKILL_BACKUP_DIR", - getattr(args, 'backup_dir', None) or - str(base / "skill-backups" / skill_name))) - - # 目标 SKILL.md - if os.environ.get("SKILL_TARGET_PATH"): - target = Path(os.environ["SKILL_TARGET_PATH"]) - elif args and hasattr(args, 'target') and args.target: - target = Path(args.target) - elif args and hasattr(args, 'skill') and args.skill: - target = Path(args.skill) / "SKILL.md" - else: - target = None - - for d in (log_dir, proposal_dir, backup_dir): - d.mkdir(parents=True, exist_ok=True) - - return log_dir, proposal_dir, backup_dir, target - - -def read_log_entries(log_file): - if not log_file.exists(): - return [] - entries = [] - with log_file.open("r") as f: - for line in f: - line = line.strip() - if line: - try: - entries.append(json.loads(line)) - except json.JSONDecodeError: - continue - return entries - - -def collect_edits(log_dir, days=1, date_str=None): - """收集有实际修改的 final/edited 记录""" - edits = [] - if date_str: - log_file = log_dir / f"{date_str}.jsonl" - entries = read_log_entries(log_file) - edits.extend([e for e in entries - if e["type"] in ("final", "edited") and not e.get("no_change")]) - else: - for i in range(days): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - log_file = log_dir / f"{date}.jsonl" - entries = read_log_entries(log_file) - edits.extend([e for e in entries - if e["type"] in ("final", "edited") and not e.get("no_change")]) - return edits - - -def call_llm(prompt, timeout=180): - """调用 LLM — 自动检测可用的 CLI (claude / openclaw / llm)""" - # 优先级: claude CLI → openclaw exec → generic llm CLI - candidates = [ - ["claude", "--print", "--model", "sonnet"], # Claude Code - ["claude", "--print"], # Claude Code (default model) - ["llm", "-m", "claude-sonnet"], # simon willison's llm CLI - ["llm"], # llm CLI default - ] - for cmd in candidates: - try: - result = subprocess.run(cmd, input=prompt, capture_output=True, - text=True, timeout=timeout) - if result.returncode == 0 and result.stdout.strip(): - return result.stdout.strip() - except (FileNotFoundError, subprocess.TimeoutExpired): - continue - - # fallback: 如果 IMPROVE_LLM_CMD 环境变量设置了,用它 - custom_cmd = os.environ.get("IMPROVE_LLM_CMD") - if custom_cmd: - try: - result = subprocess.run(custom_cmd.split(), input=prompt, - capture_output=True, text=True, timeout=timeout) - if result.returncode == 0 and result.stdout.strip(): - return result.stdout.strip() - except (FileNotFoundError, subprocess.TimeoutExpired): - pass - - print("❌ LLM 调用失败。支持的方式:") - print(" - 安装 Claude Code CLI (claude --print)") - print(" - 安装 llm CLI (pip install llm)") - print(" - 设置 IMPROVE_LLM_CMD 环境变量") - return None - - -def extract_improvements(args): - log_dir, proposal_dir, _, target = get_paths(args) - days = getattr(args, 'days', 1) or 1 - date_str = getattr(args, 'date', None) - - edits = collect_edits(log_dir, days=days, date_str=date_str) - if not edits: - print("⚠️ 没有修改记录") - return None - - print(f"📊 找到 {len(edits)} 次修改,正在分析...") - - # 读当前 SKILL.md - current_skill = "" - if target and target.exists(): - current_skill = target.read_text() - - # 构建对比数据 - edit_summaries = [] - for i, edit in enumerate(edits): - orig = edit.get("original_content", "")[:3000] - final = edit.get("final_content", edit.get("edited_content", ""))[:3000] - ctx = edit.get("context", {}) - edit_summaries.append({ - "index": i + 1, - "account": ctx.get("account", "unknown"), - "content_type": ctx.get("content_type", "unknown"), - "original": orig, - "final": final, - }) - - proposal_id = datetime.now().strftime("%Y%m%d-%H%M%S") - - prompt = f"""你是 writing style skill 的改进助手。 - -分析人类对 AI 生成文章的修改,提取可以加入 SKILL.md 的新规则。 - -## 当前 SKILL.md(最后 3000 字,避免重复) -{current_skill[-3000:]} - -## 修改记录(original vs final) -{json.dumps(edit_summaries, ensure_ascii=False, indent=2)} - -## 要求 -1. 对比 original 和 final,找出系统性修改 -2. 只提取有 pattern 的修改(至少 2 次,或单次但改动幅度大且明确) -3. 不要提取已在 SKILL.md 中的规则 -4. 每条规则必须可执行 - -## 输出格式 - ---- -id: {proposal_id} -date: {datetime.now().isoformat()} -source: {len(edits)} edits -status: pending ---- - -# Improvement Proposal - -## 提取的改进建议 - -### 1. 新禁止词 -- **`词`** → 替代: "YYY" | 理由: ... | 优先级: **P0/P1/P2** - -### 2. 新风格规则 -- 规则描述 | 理由: ... | 优先级: **P0/P1/P2** - -### 3. 反模式 -- 描述 | 理由: ... | 优先级: **P0/P1/P2** - -P0=高置信度(多次), P1=中置信度, P2=低置信度(仅1次) -""" - - suggestions = call_llm(prompt) - if not suggestions: - return None - - proposal_file = proposal_dir / f"{proposal_id}.md" - proposal_file.write_text(suggestions) - - print(f"✅ 改进建议已保存: {proposal_file}") - print(f"\n{suggestions[:2000]}") - if len(suggestions) > 2000: - print(f"\n... (完整内容见文件)") - return proposal_id - - -def show_proposals(args): - _, proposal_dir, _, _ = get_paths(args) - proposals = list(proposal_dir.glob("*.md")) - - if not proposals: - print("⚠️ 没有提案") - return - - print(f"\n📋 共 {len(proposals)} 个提案:\n") - for p in sorted(proposals, reverse=True): - content = p.read_text() - status = "unknown" - for line in content.split("\n")[:10]: - if line.startswith("status:"): - status = line.split(":", 1)[1].strip() - icon = {"pending": "⏳", "applied": "✅", "rejected": "❌"}.get( - status.split("(")[0].strip(), "❓") - print(f" {icon} {p.stem} — {status}") - - -def backup_skill(target, backup_dir): - if not target or not target.exists(): - return None - name = f"SKILL-{datetime.now().strftime('%Y%m%d-%H%M%S')}.md" - backup_path = backup_dir / name - shutil.copy2(target, backup_path) - print(f"📦 备份: {backup_path}") - return backup_path - - -def apply_proposal(args): - _, proposal_dir, backup_dir, target = get_paths(args) - proposal_id = args.proposal_id - proposal_file = proposal_dir / f"{proposal_id}.md" - - if not proposal_file.exists(): - print(f"❌ 提案不存在: {proposal_id}") - return - - if not target or not target.exists(): - print(f"❌ 目标 SKILL.md 不存在(用 --skill 或 --target 指定)") - return - - proposal_content = proposal_file.read_text() - current_skill = target.read_text() - - auto_mode = getattr(args, 'auto', False) - filter_level = "P0" if auto_mode else "P0 和 P1" - - backup_skill(target, backup_dir) - - prompt = f"""把改进提案中的 **{filter_level}** 规则合并到 SKILL.md。 - -规则: -1. 新禁止词 → 加到禁止词 section -2. 新风格规则 → 加到对应 section -3. 不删除已有规则,不改文件结构 -4. version +0.1 - -## 提案 -{proposal_content} - -## 当前 SKILL.md -{current_skill} - -输出完整更新后的 SKILL.md。不加代码块包裹。""" - - updated = call_llm(prompt, timeout=300) - if not updated: - print("❌ 合并失败") - return - - target.write_text(updated) - - new_content = proposal_content.replace( - "status: pending", - f"status: applied ({datetime.now().strftime('%Y-%m-%d')})") - proposal_file.write_text(new_content) - - print(f"✅ 已应用提案 {proposal_id}") - print(f"💡 回滚: python3 improve.py rollback") - - -def auto_improve(args): - log_dir, _, _, _ = get_paths(args) - edits = collect_edits(log_dir, days=7) - - if not edits: - print("⚠️ 最近 7 天没有修改记录,跳过") - return - - print(f"🤖 自动模式: {len(edits)} 次修改") - - args.days = 7 - args.date = None - proposal_id = extract_improvements(args) - - if not proposal_id: - return - - _, proposal_dir, _, _ = get_paths(args) - content = (proposal_dir / f"{proposal_id}.md").read_text() - - if "P0" not in content: - print("ℹ️ 没有 P0 规则,跳过自动应用") - return - - print("\n🔄 自动应用 P0 规则...") - apply_args = argparse.Namespace(**vars(args)) - apply_args.proposal_id = proposal_id - apply_args.auto = True - apply_proposal(apply_args) - - -def rollback(args): - _, _, backup_dir, target = get_paths(args) - - if not target: - print("❌ 未指定目标 SKILL.md") - return - - backups = sorted(backup_dir.glob("SKILL-*.md"), reverse=True) - if not backups: - print("❌ 没有备份") - return - - latest = backups[0] - # 保存当前版本 - if target.exists(): - emergency = backup_dir / f"SKILL-pre-rollback-{datetime.now().strftime('%Y%m%d-%H%M%S')}.md" - shutil.copy2(target, emergency) - - shutil.copy2(latest, target) - print(f"✅ 已回滚到: {latest.name}") - - -def add_common_args(parser): - parser.add_argument("--skill", help="目标 skill 目录") - parser.add_argument("--target", help="目标 SKILL.md 路径") - parser.add_argument("--log-dir", help="日志目录") - parser.add_argument("--proposal-dir", help="提案目录") - - -def main(): - parser = argparse.ArgumentParser(description="Self-Improving Skill — Improver") - subparsers = parser.add_subparsers(dest="action") - - p_ext = subparsers.add_parser("extract", help="提取改进建议") - p_ext.add_argument("--date", help="指定日期") - p_ext.add_argument("--days", type=int, default=1) - add_common_args(p_ext) - - p_show = subparsers.add_parser("show", help="查看提案") - add_common_args(p_show) - - p_apply = subparsers.add_parser("apply", help="应用提案") - p_apply.add_argument("proposal_id") - add_common_args(p_apply) - - p_auto = subparsers.add_parser("auto", help="自动提取+应用P0") - add_common_args(p_auto) - - p_rb = subparsers.add_parser("rollback", help="回滚") - add_common_args(p_rb) - - args = parser.parse_args() - if not args.action: - parser.print_help() - sys.exit(1) - - actions = { - "extract": extract_improvements, - "show": show_proposals, - "apply": apply_proposal, - "auto": auto_improve, - "rollback": rollback, - } - actions[args.action](args) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/marketing/my-writing-style/scripts/observe.py b/builtin-skills/marketing/my-writing-style/scripts/observe.py deleted file mode 100644 index 61cfe179..00000000 --- a/builtin-skills/marketing/my-writing-style/scripts/observe.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env python3 -""" -Self-Improving Skill — Observation Layer - -通用的 original → final 记录器。适用于任何 "AI 生成 → 人类修改" 的循环。 - -用法: - python3 observe.py record-original article.md [--text "..."] [--account X] [--content-type article] - python3 observe.py record-final article.md [--match ] [--text "..."] - python3 observe.py pending - python3 observe.py stats - -环境变量: - SKILL_LOG_DIR — 日志目录(默认 ~/clawd/memory/skill-runs/default/) -""" - -import sys -import json -import os -import argparse -from pathlib import Path -from datetime import datetime, timedelta -import hashlib - -# 日志目录 — 自动检测 OpenClaw / Claude Code / standalone -def _detect_base(): - if os.environ.get("SKILL_BASE_DIR"): - return Path(os.environ["SKILL_BASE_DIR"]) - candidates = [ - Path.home() / "clawd" / "memory", - Path.home() / ".openclaw" / "memory", - Path.home() / ".claude" / "memory", - ] - for c in candidates: - if c.parent.exists(): - return c - return Path.home() / ".self-improving" / "memory" - -DEFAULT_LOG_DIR = _detect_base() / "skill-runs" / "default" - - -def get_log_dir(args=None): - """按优先级决定日志目录:--log-dir > SKILL_LOG_DIR > default""" - if args and hasattr(args, 'log_dir') and args.log_dir: - d = Path(args.log_dir) - elif os.environ.get("SKILL_LOG_DIR"): - d = Path(os.environ["SKILL_LOG_DIR"]) - elif args and hasattr(args, 'skill') and args.skill: - skill_name = Path(args.skill).name - d = Path.home() / "clawd" / "memory" / "skill-runs" / skill_name - else: - d = DEFAULT_LOG_DIR - d.mkdir(parents=True, exist_ok=True) - return d - - -def get_log_file(log_dir, date_str=None): - if date_str is None: - date_str = datetime.now().strftime("%Y-%m-%d") - return log_dir / f"{date_str}.jsonl" - - -def compute_hash(content): - return hashlib.md5(content.encode()).hexdigest()[:8] - - -def get_content(args): - if hasattr(args, 'text') and args.text: - return args.text - if hasattr(args, 'stdin') and args.stdin: - return sys.stdin.read() - if hasattr(args, 'file') and args.file: - p = Path(args.file) - if not p.exists(): - print(f"❌ 文件不存在: {args.file}") - sys.exit(1) - return p.read_text() - return None - - -def read_log_entries(log_file): - if not log_file.exists(): - return [] - entries = [] - with log_file.open("r") as f: - for line in f: - line = line.strip() - if line: - try: - entries.append(json.loads(line)) - except json.JSONDecodeError: - continue - return entries - - -def find_unmatched(log_dir, days=14): - """找到有 original 但没有 final 的记录(兼容旧 edited/no-change type)""" - all_originals = {} - all_matched = set() - - for i in range(days): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - entries = read_log_entries(get_log_file(log_dir, date)) - for e in entries: - if e["type"] == "original": - e["_date"] = date - all_originals[e["content_hash"]] = e - elif e["type"] in ("final", "edited", "no-change"): - all_matched.add(e["content_hash"]) - - return {h: o for h, o in all_originals.items() if h not in all_matched} - - -def record_original(args): - content = get_content(args) - if not content: - print("❌ 需要提供内容(文件路径、--text 或 --stdin)") - sys.exit(1) - - log_dir = get_log_dir(args) - content_hash = compute_hash(content) - - context = {} - if hasattr(args, 'account') and args.account: - context["account"] = args.account - if hasattr(args, 'content_type') and args.content_type: - context["content_type"] = args.content_type - - log_entry = { - "timestamp": datetime.now().isoformat(), - "type": "original", - "content_hash": content_hash, - "file": str(args.file) if hasattr(args, 'file') and args.file else None, - "content": content, - "context": context, - "char_count": len(content), - } - - log_file = get_log_file(log_dir) - with log_file.open("a") as f: - f.write(json.dumps(log_entry, ensure_ascii=False) + "\n") - - print(f"✅ 记录原稿: {content_hash}") - print(f"📝 字数: {len(content)}") - print(f"📁 日志: {log_file}") - return content_hash - - -def record_final(args): - content = get_content(args) - if not content: - print("❌ 需要提供最终版内容") - sys.exit(1) - - log_dir = get_log_dir(args) - target_hash = getattr(args, 'match', None) - - if target_hash: - # 指定 hash,跨天查找 - original = None - for i in range(14): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - entries = read_log_entries(get_log_file(log_dir, date)) - for e in entries: - if e["type"] == "original" and e["content_hash"] == target_hash: - original = e - break - if original: - break - if not original: - print(f"❌ 找不到 hash {target_hash} 的原稿") - sys.exit(1) - else: - # 自动匹配最近的未配对 original - unmatched = find_unmatched(log_dir, 14) - if not unmatched: - print("❌ 没有待配对的原稿") - sys.exit(1) - target_hash = list(unmatched.keys())[-1] - original = unmatched[target_hash] - - is_same = content.strip() == original["content"].strip() - - log_entry = { - "timestamp": datetime.now().isoformat(), - "type": "final", - "content_hash": target_hash, - "original_content": original["content"], - "final_content": content, - "original_char_count": len(original["content"]), - "final_char_count": len(content), - "context": original.get("context", {}), - "no_change": is_same, - } - - log_file = get_log_file(log_dir) - with log_file.open("a") as f: - f.write(json.dumps(log_entry, ensure_ascii=False) + "\n") - - if is_same: - print(f"✅ 记录最终版: {target_hash} (无修改 — 正反馈)") - else: - diff_pct = ((len(content) - len(original["content"])) / max(len(original["content"]), 1)) * 100 - print(f"✅ 记录最终版: {target_hash}") - print(f"📝 原稿: {len(original['content'])} 字 → 最终: {len(content)} 字 ({diff_pct:+.1f}%)") - print(f"📁 日志: {log_file}") - - -def show_pending(args): - log_dir = get_log_dir(args) - unmatched = find_unmatched(log_dir, 14) - - if not unmatched: - print("✅ 全部已配对") - return - - print(f"\n⏳ {len(unmatched)} 条待配对:\n") - for h, entry in unmatched.items(): - preview = entry["content"][:80].replace("\n", " ") - ctx = entry.get("context", {}) - account = ctx.get("account", "?") - date = entry.get("_date", "?") - print(f" 📄 {h} | {date} | {account}") - print(f" {preview}...") - print() - - -def show_stats(args): - log_dir = get_log_dir(args) - all_files = sorted(log_dir.glob("*.jsonl")) - - total_originals = 0 - total_finals = 0 - total_no_change = 0 - total_changed = 0 - - for log_file in all_files: - entries = read_log_entries(log_file) - total_originals += sum(1 for e in entries if e["type"] == "original") - finals = [e for e in entries if e["type"] in ("final", "edited")] - total_finals += len(finals) - total_no_change += sum(1 for e in finals if e.get("no_change")) - total_changed += sum(1 for e in finals if not e.get("no_change")) - - pending = find_unmatched(log_dir, 14) - - print(f"\n📊 Self-Improving Skill 观察统计") - print(f"{'='*40}") - print(f"📁 日志天数: {len(all_files)}") - print(f"📝 原稿: {total_originals}") - print(f"✅ 已配对: {total_finals}") - print(f" ├ 有修改: {total_changed}") - print(f" └ 无修改: {total_no_change}") - print(f"⏳ 待配对: {len(pending)}") - if total_finals > 0: - print(f"📈 修改率: {total_changed}/{total_finals} = {total_changed/total_finals*100:.0f}%") - - -def add_common_args(parser): - """添加通用参数""" - parser.add_argument("--skill", help="目标 skill 目录名(用于定位日志目录)") - parser.add_argument("--log-dir", help="自定义日志目录") - - -def main(): - parser = argparse.ArgumentParser(description="Self-Improving Skill — Observation Layer") - subparsers = parser.add_subparsers(dest="action") - - # record-original - p_orig = subparsers.add_parser("record-original", help="记录 AI 原稿") - p_orig.add_argument("file", nargs="?", help="文件路径") - p_orig.add_argument("--text", help="直接传入文本") - p_orig.add_argument("--stdin", action="store_true", help="从 stdin 读取") - p_orig.add_argument("--account", help="发布账号") - p_orig.add_argument("--content-type", help="内容类型") - add_common_args(p_orig) - - # record-final - p_final = subparsers.add_parser("record-final", help="记录最终版") - p_final.add_argument("file", nargs="?", help="文件路径") - p_final.add_argument("--text", help="直接传入文本") - p_final.add_argument("--stdin", action="store_true", help="从 stdin 读取") - p_final.add_argument("--match", help="匹配的原稿 hash") - add_common_args(p_final) - - # pending - p_pending = subparsers.add_parser("pending", help="查看待配对原稿") - add_common_args(p_pending) - - # stats - p_stats = subparsers.add_parser("stats", help="总体统计") - add_common_args(p_stats) - - args = parser.parse_args() - if not args.action: - parser.print_help() - sys.exit(1) - - actions = { - "record-original": record_original, - "record-final": record_final, - "pending": show_pending, - "stats": show_stats, - } - actions[args.action](args) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/marketing/wechat-article-writer/SKILL.md b/builtin-skills/marketing/wechat-article-writer/SKILL.md deleted file mode 100644 index c4d60284..00000000 --- a/builtin-skills/marketing/wechat-article-writer/SKILL.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -name: wechat-article-writer -description: 公众号文章自动化写作流程。支持资料搜索、文章撰写、爆款标题生成、排版优化。当用户提到写公众号、微信文章、自媒体写作、爆款文章、内容创作时使用此 skill。 ---- - -# 公众号文章写作流程 - -4 步完成高质量公众号文章:搜索资料 → 撰写文章 → 生成标题 → 排版优化 - -## Step 1: 搜索资料 - -使用 WebSearch 工具搜索主题相关资料: - -``` -搜索要求: -1. 并行搜索多个来源(官方文档、X/Twitter、Reddit、技术论坛) -2. 优先获取最新资料(当月/当季) -3. 可启动多个并行 Task 加速搜索 -4. 深度总结搜索结果 -``` - -## Step 2: 撰写文章 - -**必须先读取用户的 CLAUDE.md 获取写作风格** - -撰写要求: -- 5000-10000 字 -- 故事化开头,带情感色彩(兴奋/焦虑/好奇) -- 准备 2-3 个备选标题 -- 结构:效果展示 → 问题描述 → 步骤教学 → 升华总结 -- 遵循 CLAUDE.md 中定义的写作风格和结尾语 - -## Step 3: 生成标题 - -生成 5 个爆款标题,特点: -- **痛点明确**:直击读者痛处("还在手动...") -- **数字吸引**:具体数字更有说服力("3分钟"、"5个技巧") -- **结果导向**:承诺具体收益("效率暴涨10倍") -- **情绪调动**:惊、神技、秘籍等词汇 -- **悬念设置**:引发好奇心 - -## Step 4: 排版优化 - -优化建议: -1. **段落结构**:每段 3-5 行,重要数据单独成段加粗 -2. **配图位置**:标题下方封面图、步骤后效果图、结尾总结图 -3. **代码块**:前后留白,语法高亮 -4. **金句**:单独成段,增强记忆点 - -## 示例 - -用户请求: -``` -帮我写一篇关于 Claude Code 使用技巧的公众号文章 -``` - -执行流程: -1. 搜索 Claude Code 最新功能和使用技巧 -2. 读取 CLAUDE.md 获取写作风格 -3. 撰写 1200 字左右的教程文章 -4. 生成 5 个爆款标题供选择 -5. 提供排版和配图建议 diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/README.md b/builtin-skills/marketing/writing-clearly-and-concisely/README.md deleted file mode 100644 index af644445..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# Writing Clearly and Concisely - -A skill that applies William Strunk Jr.'s timeless writing principles to produce clearer, stronger, more professional prose while avoiding common AI writing patterns. - -## Purpose - -This skill helps you write better prose for human readers. It draws from two sources: - -1. **The Elements of Style** (Strunk, 1918) - Time-tested rules for clear, forceful writing -2. **AI Pattern Avoidance** - Research-backed guidance on avoiding generic, puffy language that LLMs tend to produce - -Whether you're writing documentation, commit messages, error messages, or any text humans will read, this skill helps you cut fluff and say what you mean. - -## When to Use - -Use this skill whenever you write prose for humans: - -- **Documentation** - README files, API docs, technical explanations -- **Git workflow** - Commit messages, pull request descriptions -- **User-facing text** - Error messages, UI copy, help text, tooltips -- **Code comments** - Inline documentation, docstrings -- **Reports and summaries** - Status updates, analysis, explanations -- **Editing** - Improving clarity of existing text - -**Trigger phrases:** -- "Write documentation for..." -- "Draft a README" -- "Edit this for clarity" -- "Make this more concise" -- "Review this commit message" - -## How It Works - -1. **Load the skill** when writing prose for human readers -2. **Apply Strunk's core principles** - active voice, positive form, concrete language, cut needless words -3. **Avoid AI patterns** - no puffery, no empty phrases, no promotional adjectives -4. **Reference detailed guides** when needed for specific rules - -### Context-Efficient Approach - -The skill uses progressive disclosure to save context: - -- **SKILL.md** (~1,000 tokens) loads first with the core rules -- **Reference files** (1,000-4,500 tokens each) load only when needed -- **Most tasks need only one file**: `03-elementary-principles-of-composition.md` - -For tight context situations, dispatch a subagent with your draft and the relevant section file. - -## Key Features - -### Strunk's Core Rules - -The skill emphasizes these principles from *The Elements of Style*: - -| Rule | Principle | -|------|-----------| -| 10 | Use active voice | -| 11 | Put statements in positive form | -| 12 | Use definite, specific, concrete language | -| 13 | Omit needless words | -| 16 | Keep related words together | -| 18 | Place emphatic words at end of sentence | - -### AI Pattern Detection - -The skill identifies and eliminates common LLM writing patterns: - -- **Puffery**: pivotal, crucial, vital, testament, enduring legacy -- **Empty "-ing" phrases**: ensuring reliability, showcasing features -- **Promotional adjectives**: groundbreaking, seamless, robust, cutting-edge -- **Overused AI vocabulary**: delve, leverage, multifaceted, foster, realm, tapestry -- **Formatting overuse**: excessive bullets, emoji decorations, bold on every other word - -## Reference Files - -| Section | File | Tokens | Content | -|---------|------|--------|---------| -| Grammar & punctuation | `02-elementary-rules-of-usage.md` | ~2,500 | Comma rules, possessives, sentence structure | -| Composition principles | `03-elementary-principles-of-composition.md` | ~4,500 | Active voice, concision, paragraph structure | -| Formatting | `04-a-few-matters-of-form.md` | ~1,000 | Headings, quotations, formatting conventions | -| Word choice | `05-words-and-expressions-commonly-misused.md` | ~4,000 | Common errors, word selection | -| AI patterns | `signs-of-ai-writing.md` | ~25,000 | Wikipedia editors' field guide to AI detection | - -## Usage Examples - -### Example 1: Tightening a Commit Message - -**Before:** -> This commit implements the functionality for ensuring that user authentication is properly handled, showcasing robust error handling capabilities. - -**After:** -> Add user authentication with error handling - -### Example 2: Rewriting Documentation - -**Before:** -> This groundbreaking feature leverages cutting-edge technology to deliver a seamless experience, fostering better engagement and driving impactful results. - -**After:** -> This feature uses WebSocket connections to update the dashboard in real time. - -### Example 3: Fixing Passive Voice - -**Before:** -> The configuration file is read by the application at startup. - -**After:** -> The application reads the configuration file at startup. - -### Example 4: Removing Hedging - -**Before:** -> It is important to note that the API might potentially return an error in certain situations. - -**After:** -> The API returns an error when the token expires. - -## Best Practices - -1. **Be specific, not grandiose** - Say what it actually does, not how important it is -2. **Cut first, add later** - Remove words until meaning suffers, then add back what's needed -3. **Prefer active voice** - "The function returns X" beats "X is returned by the function" -4. **State positively** - "He forgot" beats "He did not remember" -5. **Use concrete language** - "The server crashed" beats "An issue occurred" -6. **Load reference files sparingly** - Most tasks need only `03-elementary-principles-of-composition.md` - -## Directory Structure - -``` -writing-clearly-and-concisely/ - SKILL.md # Main skill definition - README.md # This file - signs-of-ai-writing.md # AI pattern detection guide - elements-of-style/ - 01-introductory.md - 02-elementary-rules-of-usage.md - 03-elementary-principles-of-composition.md - 04-a-few-matters-of-form.md - 05-words-and-expressions-commonly-misused.md -``` - -## Installation - -**Claude Code:** -```bash -cp -r skills/writing-clearly-and-concisely ~/.claude/skills/ -``` - -**Claude.ai:** -Add the skill to project knowledge or paste SKILL.md contents into your conversation. - -## Attribution - -- Original skill by @joshuadavidthomas from [joshuadavidthomas/agent-skills](https://github.com/joshuadavidthomas/agent-skills) (MIT) -- Adapted from [obra/the-elements-of-style](https://github.com/obra/the-elements-of-style) -- Writing principles from *The Elements of Style* by William Strunk Jr. (1918) -- AI pattern research from Wikipedia's field guide to AI-generated content detection diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/SKILL.md b/builtin-skills/marketing/writing-clearly-and-concisely/SKILL.md deleted file mode 100644 index 81a94732..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/SKILL.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: writing-clearly-and-concisely -description: Use when writing prose humans will read—documentation, commit messages, error messages, explanations, reports, or UI text. Applies Strunk's timeless rules for clearer, stronger, more professional writing. ---- - -# Writing Clearly and Concisely - -## Overview - -Write with clarity and force. This skill covers what to do (Strunk) and what not to do (AI patterns). - -## When to Use This Skill - -Use this skill whenever you write prose for humans: - -- Documentation, README files, technical explanations -- Commit messages, pull request descriptions -- Error messages, UI copy, help text, comments -- Reports, summaries, or any explanation -- Editing to improve clarity - -**If you're writing sentences for a human to read, use this skill.** - -## Limited Context Strategy - -When context is tight: - -1. Write your draft using judgment -2. Dispatch a subagent with your draft and the relevant section file -3. Have the subagent copyedit and return the revision - -Loading a single section (~1,000-4,500 tokens) instead of everything saves significant context. - -## Elements of Style - -William Strunk Jr.'s *The Elements of Style* (1918) teaches you to write clearly and cut ruthlessly. - -### Rules - -**Elementary Rules of Usage (Grammar/Punctuation)**: - -1. Form possessive singular by adding 's -2. Use comma after each term in series except last -3. Enclose parenthetic expressions between commas -4. Comma before conjunction introducing co-ordinate clause -5. Don't join independent clauses by comma -6. Don't break sentences in two -7. Participial phrase at beginning refers to grammatical subject - -**Elementary Principles of Composition**: - -8. One paragraph per topic -9. Begin paragraph with topic sentence -10. **Use active voice** -11. **Put statements in positive form** -12. **Use definite, specific, concrete language** -13. **Omit needless words** -14. Avoid succession of loose sentences -15. Express co-ordinate ideas in similar form -16. **Keep related words together** -17. Keep to one tense in summaries -18. **Place emphatic words at end of sentence** - -### Reference Files - -The rules above are summarized from Strunk's original text. For complete explanations with examples: - -| Section | File | ~Tokens | -|---------|------|---------| -| Grammar, punctuation, comma rules | `02-elementary-rules-of-usage.md` | 2,500 | -| Paragraph structure, active voice, concision | `03-elementary-principles-of-composition.md` | 4,500 | -| Headings, quotations, formatting | `04-a-few-matters-of-form.md` | 1,000 | -| Word choice, common errors | `05-words-and-expressions-commonly-misused.md` | 4,000 | - -**Most tasks need only `03-elementary-principles-of-composition.md`** — it covers active voice, positive form, concrete language, and omitting needless words. - -## AI Writing Patterns to Avoid - -LLMs regress to statistical means, producing generic, puffy prose. Avoid: - -- **Puffery:** pivotal, crucial, vital, testament, enduring legacy -- **Empty "-ing" phrases:** ensuring reliability, showcasing features, highlighting capabilities -- **Promotional adjectives:** groundbreaking, seamless, robust, cutting-edge -- **Overused AI vocabulary:** delve, leverage, multifaceted, foster, realm, tapestry -- **Formatting overuse:** excessive bullets, emoji decorations, bold on every other word - -Be specific, not grandiose. Say what it actually does. - -For comprehensive research on why these patterns occur, see `signs-of-ai-writing.md`. Wikipedia editors developed this guide to detect AI-generated submissions — their patterns are well-documented and field-tested. - -## Bottom Line - -Writing for humans? Load the relevant section from `elements-of-style/` and apply the rules. For most tasks, `03-elementary-principles-of-composition.md` covers what matters most. diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/01-introductory.md b/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/01-introductory.md deleted file mode 100644 index 667b823b..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/01-introductory.md +++ /dev/null @@ -1,3 +0,0 @@ -## I. Introductory - -This handbook summarizes the essentials of plain English style. It focuses on the rules of usage and principles of composition most often broken, offering a compact alternative to exhaustive manuals. Master the guidance here, then look to the best authors for finer points of style. diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/02-elementary-rules-of-usage.md b/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/02-elementary-rules-of-usage.md deleted file mode 100644 index b42e5ef9..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/02-elementary-rules-of-usage.md +++ /dev/null @@ -1,214 +0,0 @@ -## II. Elementary Rules Of Usage - -### Rule 1. Form the possessive singular of nouns by adding 's. - -Follow this rule whatever the final consonant. Thus write, - -Charles's friend - -Burns's poems - -the witch's malice - -This is the usage of the United States Government Printing Office and of the Oxford University Press. - -Exceptions are the possessive of ancient proper names ending in *-es* and *-is*, the possessive *Jesus'*, and such forms as *for conscience' sake*, *for righteousness' sake*. But such forms as *Achilles' heel*, *Moses' laws*, *Isis' temple* are commonly replaced by - -the heel of Achilles - -the laws of Moses - -the temple of Isis - -The pronominal possessives *hers*, *its*, *theirs*, *yours*, and *oneself* have no apostrophe. - -### Rule 2. In a series of three or more terms with a single conjunction, use a comma after each term except the last. - -Thus write, - -red, white, and blue - -gold, silver, or copper - -He opened the letter, read it, and made a note of its contents. - -This is also the usage of the Government Printing Office and of the Oxford University Press. - -In the names of business firms the last comma is omitted, as, - -Brown, Shipley & Co. - -### Rule 3. Enclose parenthetic expressions between commas. - -The best way to see a country, unless you are pressed for time, is to travel on foot. - -This rule is difficult to apply; it is frequently hard to decide whether a single word, such as *however*, or a brief phrase, is or is not parenthetic. If the interruption to the flow of the sentence is but slight, the writer may safely omit the commas. But whether the interruption be slight or considerable, he must never insert one comma and omit the other. Such punctuation as - -Marjorie's husband, Colonel Nelson paid us a visit yesterday, - -or - -My brother you will be pleased to hear, is now in perfect health, - -is indefensible. - -If a parenthetic expression is preceded by a conjunction, place the first comma before the conjunction, not after it. - -He saw us coming, and unaware that we had learned of his treachery, greeted us with a smile. - -Always to be regarded as parenthetic and to be enclosed between commas (or, at the end of the sentence, between comma and period) are the following: - -\(1\) the year, when forming part of a date, and the day of the month, when following the day of the week: - -February to July, 1916. - -April 6, 1917. - -Monday, November 11, 1918. - -\(2\) the abbreviations *etc.* and *jr.* - -\(3\) non-restrictive relative clauses, that is, those which do not serve to identify or define the antecedent noun, and similar clauses introduced by conjunctions indicating time or place. - -The audience, which had at first been indifferent, became more and more interested. - -In this sentence the clause introduced by *which* does not serve to tell which of several possible audiences is meant; what audience is in question is supposed to be already known. The clause adds, parenthetically, a statement supplementing that in the main clause. The sentence is virtually a combination of two statements which might have been made independently: - -The audience had at first been indifferent. It became more and more interested. - -Compare the restrictive relative clause, not set off by commas, in the sentence, - -The candidate who best meets these requirements will obtain the place. - -Here the clause introduced by *who* does serve to tell which of several possible candidates is meant; the sentence cannot be split up into two independent statements. - -The difference in punctuation in the two sentences following is based on the same principle: - -Nether Stowey, where Coleridge wrote The Rime of the Ancient Mariner, is a few miles from Bridgewater. - -The day will come when you will admit your mistake. - -Nether Stowey is completely identified by its name; the statement about Coleridge is therefore supplementary and parenthetic. The *day* spoken of is identified only by the dependent clause, which is therefore restrictive. - -Similar in principle to the enclosing of parenthetic expressions between commas is the setting off by commas of phrases or dependent clauses preceding or following the main clause of a sentence. - -Partly by hard fighting, partly by diplomatic skill, they enlarged their dominions to the east, and rose to royal rank with the possession of Sicily, exchanged afterwards for Sardinia. - -Other illustrations may be found in sentences quoted under Rules 4, 5, 6, 7, 16, and 18. - -The writer should be careful not to set off independent clauses by commas: see under Rule 5. - -### Rule 4. Place a comma before a conjunction introducing a co-ordinate clause. - -The early records of the city have disappeared, and the story of its first years can no longer be reconstructed. - -The situation is perilous, but there is still one chance of escape. - -Sentences of this type, isolated from their context, may seem to be in need of rewriting. As they make complete sense when the comma is reached, the second clause has the appearance of an afterthought. Further, *and* is the least specific of connectives. Used between independent clauses, it indicates only that a relation exists between them without defining that relation. In the example above, the relation is that of cause and result. The two sentences might be rewritten: - -As the early records of the city have disappeared, the story of its first years can no longer be reconstructed. - -Although the situation is perilous, there is still one chance of escape. - -Or the subordinate clauses might be replaced by phrases: - -Owing to the disappearance of the early records of the city, the story of its first years can no longer be reconstructed. - -In this perilous situation, there is still one chance of escape. - -But a writer may err by making his sentences too uniformly compact and periodic, and an occasional loose sentence prevents the style from becoming too formal and gives the reader a certain relief. Consequently, loose sentences of the type first quoted are common in easy, unstudied writing. But a writer should be careful not to construct too many of his sentences after this pattern (see Rule 14). - -Two-part sentences of which the second member is introduced by *as* (in the sense of *because*), *for*, *or*, *nor*, and *while* (in the sense of *and at the same time*) likewise require a comma before the conjunction. - -If the second member is introduced by an adverb, a semicolon, not a comma, is required (see Rule 5). The connectives *so* and *yet* may be used either as adverbs or as conjunctions, accordingly as the second clause is felt to be co-ordinate or subordinate; consequently either mark of punctuation may be justified. But these uses of *so* (equivalent to *accordingly* or to *so that*) are somewhat colloquial and should, as a rule, be avoided in writing. A simple correction, usually serviceable, is to omit the word *so* and begin the first clause with *as* or *since*: - -| Original | Revision | -| --- | --- | -| I had never been in the place before; so I had difficulty in finding my way about. | As I had never been in the place before, I had difficulty in finding my way about. | - -If a dependent clause, or an introductory phrase requiring to be set off by a comma, precedes the second independent clause, no comma is needed after the conjunction. - -The situation is perilous, but if we are prepared to act promptly, there is still one chance of escape. - -When the subject is the same for both clauses and is expressed only once, a comma is required if the connective is *but*. If the connective is *and*, the comma should be omitted if the relation between the two statements is close or immediate. - -I have heard his arguments, but am still unconvinced. - -He has had several years' experience and is thoroughly competent. - -### Rule 5. Do not join independent clauses by a comma. - -If two or more clauses, grammatically complete and not joined by a conjunction, are to form a single compound sentence, the proper mark of punctuation is a semicolon. - -Stevenson's romances are entertaining; they are full of exciting adventures. - -It is nearly half past five; we cannot reach town before dark. - -It is of course equally correct to write the above as two sentences each, replacing the semicolons by periods. - -Stevenson's romances are entertaining. They are full of exciting adventures. - -It is nearly half past five. We cannot reach town before dark. - -If a conjunction is inserted the proper mark is a comma (Rule 4). - -Stevenson's romances are entertaining, for they are full of exciting adventures. - -It is nearly half past five, and we cannot reach town before dark. - -A comparison of the three forms given above will show clearly the advantage of the first. It is, at least in the examples given, better than the second form, because it suggests the close relationship between the two statements in a way that the second does not attempt, and better than the third, because briefer and therefore more forcible. Indeed it may be said that this simple method of indicating relationship between statements is one of the most useful devices of composition. The relationship, as above, is commonly one of cause or of consequence. - -Note that if the second clause is preceded by an adverb, such as *accordingly*, *besides*, *then*, *therefore*, or *thus*, and not by a conjunction, the semicolon is still required. - -Two exceptions to the rule may be admitted. If the clauses are very short, and are alike in form, a comma is usually permissible: - -Man proposes, God disposes. - -The gate swung apart, the bridge fell, the portcullis was drawn up. - -Note that in these examples the relation is not one of cause or consequence. Also in the colloquial form of expression, - -I hardly knew him, he was so changed, - -a comma, not a semicolon, is required. But this form of expression is inappropriate in writing, except in the dialogue of a story or play, or perhaps in a familiar letter. - -### Rule 6. Do not break sentences in two. - -In other words, do not use periods for commas. - -I met them on a Cunard liner several years ago. Coming home from Liverpool to New York. - -He was an interesting talker. A man who had traveled all over the world and lived in half a dozen countries. - -In both these examples, the first period should be replaced by a comma, and the following word begun with a small letter. - -It is permissible to make an emphatic word or expression serve the purpose of a sentence and to punctuate it accordingly: - -Again and again he called out. No reply. - -The writer must, however, be certain that the emphasis is warranted, and that he will not be suspected of a mere blunder in syntax or in punctuation. - -Rules 3, 4, 5, and 6 cover the most important principles in the punctuation of ordinary sentences; they should be so thoroughly mastered that their application becomes second nature. - -### Rule 7. A participial phrase at the beginning of a sentence must refer to the grammatical subject. - -Walking slowly down the road, he saw a woman accompanied by two children. - -The word *walking* refers to the subject of the sentence, not to the woman. If the writer wishes to make it refer to the woman, he must recast the sentence: - -He saw a woman accompanied by two children, walking slowly down the road. - -Participial phrases preceded by a conjunction or by a preposition, nouns in apposition, adjectives, and adjective phrases come under the same rule if they begin the sentence. - -| Original | Revision | -| --- | --- | -| On arriving in Chicago, his friends met him at the station. | When he arrived (or, On his arrival) in Chicago, his friends met him at the station. | -| A soldier of proved valor, they entrusted him with the defence of the city. | A soldier of proved valor, he was entrusted with the defence of the city. | -| Young and inexperienced, the task seemed easy to me. | Young and inexperienced, I thought the task easy. | -| Without a friend to counsel him, the temptation proved irresistible. | Without a friend to counsel him, he found the temptation irresistible. | - -Sentences violating this rule are often ludicrous. - -Being in a dilapidated condition, I was able to buy the house very cheap. - -Wondering irresolutely what to do next, the clock struck twelve. diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/03-elementary-principles-of-composition.md b/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/03-elementary-principles-of-composition.md deleted file mode 100644 index e92e08bd..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/03-elementary-principles-of-composition.md +++ /dev/null @@ -1,398 +0,0 @@ -## III. Elementary Principles Of Composition - -### Rule 8. Make the paragraph the unit of composition: one paragraph to each topic. - -If the subject on which you are writing is of slight extent, or if you intend to treat it very briefly, there may be no need of subdividing it into topics. Thus a brief description, a brief summary of a literary work, a brief account of a single incident, a narrative merely outlining an action, the setting forth of a single idea, any one of these is best written in a single paragraph. After the paragraph has been written, examine it to see whether subdivision will not improve it. - -Ordinarily, however, a subject requires subdivision into topics, each of which should be made the subject of a paragraph. The object of treating each topic in a paragraph by itself is, of course, to aid the reader. The beginning of each paragraph is a signal to him that a new step in the development of the subject has been reached. - -The extent of subdivision will vary with the length of the composition. For example, a short notice of a book or poem might consist of a single paragraph. One slightly longer might consist of two paragraphs: - -- A. Account of the work. -- B. Critical discussion. - -A report on a poem, written for a class in literature, might consist of seven paragraphs: - -- A. Facts of composition and publication. -- B. Kind of poem; metrical form. -- C. Subject. -- D. Treatment of subject. -- E. For what chiefly remarkable. -- F. Wherein characteristic of the writer. -- G. Relationship to other works. - -The contents of paragraphs C and D would vary with the poem. Usually, paragraph C would indicate the actual or imagined circumstances of the poem (the situation), if these call for explanation, and would then state the subject and outline its development. If the poem is a narrative in the third person throughout, paragraph C need contain no more than a concise summary of the action. Paragraph D would indicate the leading ideas and show how they are made prominent, or would indicate what points in the narrative are chiefly emphasized. - -A novel might be discussed under the heads: - -- A. Setting. -- B. Plot. -- C. Characters. -- D. Purpose. - -An historical event might be discussed under the heads: - -- A. What led up to the event. -- B. Account of the event. -- C. What the event led up to. - -In treating either of these last two subjects, the writer would probably find it necessary to subdivide one or more of the topics here given. - -As a rule, single sentences should not be written or printed as paragraphs. An exception may be made of sentences of transition, indicating the relation between the parts of an exposition or argument. Frequent exceptions are also necessary in textbooks, guidebooks, and other works in which many topics are treated briefly. - -In dialogue, each speech, even if only a single word, is a paragraph by itself; that is, a new paragraph begins with each change of speaker. The application of this rule, when dialogue and narrative are combined, is best learned from examples in well-printed works of fiction. - -### Rule 9. As a rule, begin each paragraph with a topic sentence, end it in conformity with the beginning. - -Again, the object is to aid the reader. The practice here recommended enables him to discover the purpose of each paragraph as he begins to read it, and to retain this purpose in mind as he ends it. For this reason, the most generally useful kind of paragraph, particularly in exposition and argument, is that in which - -\(a\) the topic sentence comes at or near the beginning; - -\(b\) the succeeding sentences explain or establish or develop the statement made in the topic sentence; and - -\(c\) the final sentence either emphasizes the thought of the topic sentence or states some important consequence. - -Ending with a digression, or with an unimportant detail, is particularly to be avoided. - -If the paragraph forms part of a larger composition, its relation to what precedes, or its function as a part of the whole, may need to be expressed. This can sometimes be done by a mere word or phrase (*again*; *therefore*; *for the same reason*) in the topic sentence. Sometimes, however, it is expedient to precede the topic sentence by one or more sentences of introduction or transition. If more than one such sentence is required, it is generally better to set apart the transitional sentences as a separate paragraph. - -According to the writer's purpose, he may, as indicated above, relate the body of the paragraph to the topic sentence in one or more of several different ways. He may make the meaning of the topic sentence clearer by restating it in other forms, by defining its terms, by denying the contrary, by giving illustrations or specific instances; he may establish it by proofs; or he may develop it by showing its implications and consequences. In a long paragraph, he may carry out several of these processes. - -1 Now, to be properly enjoyed, a walking tour should be gone upon alone. 2 If you go in a company, or even in pairs, it is no longer a walking tour in anything but name; it is something else and more in the nature of a picnic. 3 A walking tour should be gone upon alone, because freedom is of the essence; because you should be able to stop and go on, and follow this way or that, as the freak takes you; and because you must have your own pace, and neither trot alongside a champion walker, nor mince in time with a girl. 4 And you must be open to all impressions and let your thoughts take colour from what you see. 5 You should be as a pipe for any wind to play upon. 6 “I cannot see the wit,” says Hazlitt, “of walking and talking at the same time. 7 When I am in the country, I wish to vegetate like the country,” which is the gist of all that can be said upon the matter. 8 There should be no cackle of voices at your elbow, to jar on the meditative silence of the morning. 9 And so long as a man is reasoning he cannot surrender himself to that fine intoxication that comes of much motion in the open air, that begins in a sort of dazzle and sluggishness of the brain, and ends in a peace that passes comprehension.—Stevenson, Walking Tours. - -1 Topic sentence. 2 The meaning made clearer by denial of the contrary. 3 The topic sentence repeated, in abridged form, and supported by three reasons; the meaning of the third (“you must have your own pace”) made clearer by denying the contrary. 4 A fourth reason, stated in two forms. 5 The same reason, stated in still another form. 6–7 The same reason as stated by Hazlitt. 8 Repetition, in paraphrase, of the quotation from Hazlitt. 9 Final statement of the fourth reason, in language amplified and heightened to form a strong conclusion. - -1 It was chiefly in the eighteenth century that a very different conception of history grew up. 2 Historians then came to believe that their task was not so much to paint a picture as to solve a problem; to explain or illustrate the successive phases of national growth, prosperity, and adversity. 3 The history of morals, of industry, of intellect, and of art; the changes that take place in manners or beliefs; the dominant ideas that prevailed in successive periods; the rise, fall, and modification of political constitutions; in a word, all the conditions of national well-being became the subject of their works. 4 They sought rather to write a history of peoples than a history of kings. 5 They looked especially in history for the chain of causes and effects. 6 They undertook to study in the past the physiology of nations, and hoped by applying the experimental method on a large scale to deduce some lessons of real value about the conditions on which the welfare of society mainly depend.—Lecky, The Political Value of History. - -1 Topic sentence. 2 The meaning of the topic sentence made clearer; the new conception of history defined. 3 The definition expanded. 4 The definition explained by contrast. 5 The definition supplemented: another element in the new conception of history. 6 Conclusion: an important consequence of the new conception of history. - -In narration and description the paragraph sometimes begins with a concise, comprehensive statement serving to hold together the details that follow. - -The breeze served us admirably. - -The campaign opened with a series of reverses. - -The next ten or twelve pages were filled with a curious set of entries. - -But this device, if too often used, would become a mannerism. More commonly the opening sentence simply indicates by its subject with what the paragraph is to be principally concerned. - -At length I thought I might return towards the stockade. - -He picked up the heavy lamp from the table and began to explore. - -Another flight of steps, and they emerged on the roof. - -The brief paragraphs of animated narrative, however, are often without even this semblance of a topic sentence. The break between them serves the purpose of a rhetorical pause, throwing into prominence some detail of the action. - -### Rule 10. Use the active voice. - -The active voice is usually more direct and vigorous than the passive: - -I shall always remember my first visit to Boston. - -This is much better than - -My first visit to Boston will always be remembered by me. - -The latter sentence is less direct, less bold, and less concise. If the writer tries to make it more concise by omitting “by me,” - -My first visit to Boston will always be remembered, - -it becomes indefinite: is it the writer, or some person undisclosed, or the world at large, that will always remember this visit? - -This rule does not, of course, mean that the writer should entirely discard the passive voice, which is frequently convenient and sometimes necessary. - -The dramatists of the Restoration are little esteemed to-day. - -Modern readers have little esteem for the dramatists of the Restoration. - -The first would be the right form in a paragraph on the dramatists of the Restoration; the second, in a paragraph on the tastes of modern readers. The need of making a particular word the subject of the sentence will often, as in these examples, determine which voice is to be used. - -As a rule, avoid making one passive depend directly upon another. - -| Original | Revision | -| --- | --- | -| Gold was not allowed to be exported. | It was forbidden to export gold (The export of gold was prohibited). | -| He has been proved to have been seen entering the building. | It has been proved that he was seen to enter the building. | - -In both the examples above, before correction, the word properly related to the second passive is made the subject of the first. - -A common fault is to use as the subject of a passive construction a noun which expresses the entire action, leaving to the verb no function beyond that of completing the sentence. - -| Original | Revision | -| --- | --- | -| A survey of this region was made in 1900. | This region was surveyed in 1900. | -| Mobilization of the army was rapidly effected. | The army was rapidly mobilized. | -| Confirmation of these reports cannot be obtained. | These reports cannot be confirmed. | - -Compare the _sentence,_ “The export of gold was prohibited,” in which the predicate “was prohibited” expresses something not implied in “export.” - -The habitual use of the active voice makes for forcible writing. This is true not only in narrative principally concerned with action, but in writing of any kind. Many a tame sentence of description or exposition can be made lively and emphatic by substituting a verb in the active voice for some such perfunctory expression as *there is*, or *could be heard*. - -| Original | Revision | -| --- | --- | -| There were a great number of dead leaves lying on the ground. | Dead leaves covered the ground. | -| The sound of a guitar somewhere in the house could be heard. | Somewhere in the house a guitar hummed sleepily. | -| The reason that he left college was that his health became impaired. | Failing health compelled him to leave college. | -| It was not long before he was very sorry that he had said what he had. | He soon repented his words. | - -### Rule 11. Put statements in positive form. - -Make definite assertions. Avoid tame, colorless, hesitating, non-committal language. Use the word *not* as a means of denial or in antithesis, never as a means of evasion. - -| Original | Revision | -| --- | --- | -| He was not very often on time. | He usually came late. | -| He did not think that studying Latin was much use. | He thought the study of Latin useless. | -| The Taming of the Shrew is rather weak in spots. Shakespeare does not portray Katharine as a very admirable character, nor does Bianca remain long in memory as an important character in Shakespeare's works. | The women in The Taming of the Shrew are unattractive. Katharine is disagreeable, Bianca insignificant. | - -The last example, before correction, is indefinite as well as negative. The corrected version, consequently, is simply a guess at the writer's intention. - -All three examples show the weakness inherent in the word *not*. Consciously or unconsciously, the reader is dissatisfied with being told only what is not; he wishes to be told what is. Hence, as a rule, it is better to express even a negative in positive form. - -| Original | Revision | -| --- | --- | -| not honest | dishonest | -| not important | trifling | -| did not remember | forgot | -| did not pay any attention to | ignored | -| did not have much confidence in | distrusted | - -The antithesis of negative and positive is strong: - -Not charity, but simple justice. - -Not that I loved Caesar less, but Rome the more. - -Negative words other than *not* are usually strong: - -The sun never sets upon the British flag. - -### Rule 12. Use definite, specific, concrete language. - -Prefer the specific to the general, the definite to the vague, the concrete to the abstract. - -| Original | Revision | -| --- | --- | -| A period of unfavorable weather set in. | It rained every day for a week. | -| He showed satisfaction as he took possession of his well-earned reward. | He grinned as he pocketed the coin. | -| There is a general agreement among those who have enjoyed the experience that surf-riding is productive of great exhilaration. | All who have tried surf-riding agree that it is most exhilarating. | - -If those who have studied the art of writing are in accord on any one point, it is on this, that the surest method of arousing and holding the attention of the reader is by being specific, definite, and concrete. Critics have pointed out how much of the effectiveness of the greatest writers, Homer, Dante, Shakespeare, results from their constant definiteness and concreteness. Browning, to cite a more modern author, affords many striking examples. Take, for instance, the lines from My Last Duchess, - -Sir, 'twas all one! My favour at her breast, - -The dropping of the daylight in the west, - -The bough of cherries some officious fool - -Broke in the orchard for her, the white mule - -She rode with round the terrace—all and each - -Would draw from her alike the approving speech, - -Or blush, at least, - -and those which end the poem, - -Notice Neptune, though, - -Taming a sea-horse, thought a rarity, - -Which Claus of Innsbruck cast in bronze for me. - -These words call up pictures. Recall how in The Bishop Orders his Tomb in St. Praxed's Church “the Renaissance spirit—its worldliness, inconsistency, pride, hypocrisy, ignorance of itself, love of art, of luxury, of good Latin,” to quote Ruskin's comment on the poem, is made manifest in specific details and in concrete terms. - -Prose, in particular narrative and descriptive prose, is made vivid by the same means. If the experiences of Jim Hawkins and of David Balfour, of Kim, of Nostromo, have seemed for the moment real to countless readers, if in reading Carlyle we have almost the sense of being physically present at the taking of the Bastille, it is because of the definiteness of the details and the concreteness of the terms used. It is not that every detail is given; that would be impossible, as well as to no purpose; but that all the significant details are given, and not vaguely, but with such definiteness that the reader, in imagination, can project himself into the scene. - -In exposition and in argument, the writer must likewise never lose his hold upon the concrete, and even when he is dealing with general principles, he must give particular instances of their application. - -“This superiority of specific expressions is clearly due to the effort required to translate words into thoughts. As we do not think in generals, but in particulars—as whenever any class of things is referred to, we represent it to ourselves by calling to mind individual members of it, it follows that when an abstract word is used, the hearer or reader has to choose, from his stock of images, one or more by which he may figure to himself the genus mentioned. In doing this, some delay must arise, some force be expended; and if by employing a specific term an appropriate image can be at once suggested, an economy is achieved, and a more vivid impression produced.” - -Herbert Spencer, from whose Philosophy of Style the preceding paragraph is quoted, illustrates the principle by the sentences: - -| Original | Revision | -| --- | --- | -| In proportion as the manners, customs, and amusements of a nation are cruel and barbarous, the regulations of their penal code will be severe. | In proportion as men delight in battles, bull-fights, and combats of gladiators, will they punish by hanging, burning, and the rack. | - -### Rule 13. Omit needless words. - -Vigorous writing is concise. A sentence should contain no unnecessary words, a paragraph no unnecessary sentences, for the same reason that a drawing should have no unnecessary lines and a machine no unnecessary parts. This requires not that the writer make all his sentences short, or that he avoid all detail and treat his subjects only in outline, but that he make every word tell. - -Many expressions in common use violate this principle: - -| Original | Revision | -| --- | --- | -| the question as to whether | whether (the question whether) | -| there is no doubt but that | no doubt (doubtless) | -| used for fuel purposes | used for fuel | -| he is a man who | he | -| in a hasty manner | hastily | -| this is a subject which | this subject | -| His story is a strange one. | His story is strange. | - -In especial the expression *the fact that* should be revised out of every sentence in which it occurs. - -| Original | Revision | -| --- | --- | -| owing to the fact that | since (because) | -| in spite of the fact that | though (although) | -| call your attention to the fact that | remind you (notify you) | -| I was unaware of the fact that | I was unaware that (did not know) | -| the fact that he had not succeeded | his failure | -| the fact that I had arrived | my arrival | - -See also under *case*, *character*, *nature*, *system* in Chapter V. - -*Who is*, *which was*, and the like are often superfluous. - -| Original | Revision | -| --- | --- | -| His brother, who is a member of the same firm | His brother, a member of the same firm | -| Trafalgar, which was Nelson's last battle | Trafalgar, Nelson's last battle | - -As positive statement is more concise than negative, and the active voice more concise than the passive, many of the examples given under Rules 11 and 12 illustrate this rule as well. - -A common violation of conciseness is the presentation of a single complex idea, step by step, in a series of sentences or independent clauses which might to advantage be combined into one. - -| Original | Revision | -| --- | --- | -| Macbeth was very ambitious. This led him to wish to become king of Scotland. The witches told him that this wish of his would come true. The king of Scotland at this time was Duncan. Encouraged by his wife, Macbeth murdered Duncan. He was thus enabled to succeed Duncan as king. (51 words.) | Encouraged by his wife, Macbeth achieved his ambition and realized the prediction of the witches by murdering Duncan and becoming king of Scotland in his place. (26 words.) | -| There were several less important courses, but these were the most important, and although they did not come every day, they came often enough to keep you in such a state of mind that you never knew what your next move would be. (43 words.) | These, the most important courses of all, came, if not daily, at least often enough to keep one under constant strain. (21 words.) | - -### Rule 14. Avoid a succession of loose sentences - -This rule refers especially to loose sentences of a particular type, those consisting of two co-ordinate clauses, the second introduced by a conjunction or relative. Although single sentences of this type may be unexceptionable (see under Rule 4), a series soon becomes monotonous and tedious. - -An unskilful writer will sometimes construct a whole paragraph of sentences of this kind, using as connectives *and*, *but*, *so*, and less frequently, *who*, *which*, *when*, *where*, and *while*, these last in non-restrictive senses (see under Rule 3). - -The third concert of the subscription series was given last evening, and a large audience was in attendance. Mr. Edward Appleton was the soloist, and the Boston Symphony Orchestra furnished the instrumental music. The former showed himself to be an artist of the first rank, while the latter proved itself fully deserving of its high reputation. The interest aroused by the series has been very gratifying to the Committee, and it is planned to give a similar series annually hereafter. The fourth concert will be given on Tuesday, May 10, when an equally attractive programme will be presented. - -Apart from its triteness and emptiness, the paragraph above is weak because of the structure of its sentences, with their mechanical symmetry and sing-song. Contrast with them the sentences in the paragraphs quoted under Rule 9, or in any piece of good English prose, as the preface (Before the Curtain) to Vanity Fair. - -If the writer finds that he has written a series of sentences of the type described, he should recast enough of them to remove the monotony, replacing them by simple sentences, by sentences of two clauses joined by a semicolon, by periodic sentences of two clauses, by sentences, loose or periodic, of three clauses—whichever best represent the real relations of the thought. - -### Rule 15. Express co-ordinate ideas in similar form. - -This principle, that of parallel construction, requires that expressions of similar content and function should be outwardly similar. The likeness of form enables the reader to recognize more readily the likeness of content and function. Familiar instances from the Bible are the Ten Commandments, the Beatitudes, and the petitions of the Lord's Prayer. - -The unskillful writer often violates this principle, from a mistaken belief that he should constantly vary the form of his expressions. It is true that in repeating a statement in order to emphasize it he may have need to vary its form. For illustration, see the paragraph from Stevenson quoted under Rule _9_. But apart from this, he should follow the principle of parallel construction. - -| Original | Revision | -| --- | --- | -| Formerly, science was taught by the textbook method, while now the laboratory method is employed. | Formerly, science was taught by the textbook method; now it is taught by the laboratory method. | - -The left-hand version gives the impression that the writer is undecided or timid; he seems unable or afraid to choose one form of expression and hold to it. The right-hand version shows that the writer has at least made his choice and abided by it. - -By this principle, an article or a preposition applying to all the members of a series must either be used only before the first term or else be repeated before each term. - -| Original | Revision | -| --- | --- | -| The French, the Italians, Spanish, and Portuguese | The French, the Italians, the Spanish, and the Portuguese | -| In spring, summer, or in winter | In spring, summer, or winter (In spring, in summer, or in winter) | - -Correlative expressions (*both, and*; *not, but*; *not only, but also*; *either, or*; *first, second, third*; and the like) should be followed by the same grammatical construction, that is, virtually, by the same part of speech. (Such combinations as “both Henry and I,” “not silk, but a cheap substitute,” are obviously within the rule.) Many violations of this rule (as the first three below) arise from faulty arrangement; others (as the last) from the use of unlike constructions. - -| Original | Revision | -| --- | --- | -| It was both a long ceremony and very tedious. | The ceremony was both long and tedious. | -| A time not for words, but action. | A time not for words, but for action. | -| Either you must grant his request or incur his ill will. | You must either grant his request or incur his ill will. | -| My objections are, first, the injustice of the measure; second, that it is unconstitutional. | My objections are, first, that the measure is unjust; second, that it is unconstitutional. | - -See also the third example under Rule 12 and the last under Rule 13. - -It may be asked, what if a writer needs to express a very large number of similar ideas, say twenty? Must he write twenty consecutive sentences of the same pattern? On closer examination he will probably find that the difficulty is imaginary, that his twenty ideas can be classified in groups, and that he need apply the principle only within each group. Otherwise he had best avoid difficulty by putting his statements in the form of a table. - -### Rule 16. Keep related words together. - -The position of the words in a sentence is the principal means of showing their relationship. The writer must therefore, so far as possible, bring together the words, and groups of words, that are related in thought, and keep apart those which are not so related. - -The subject of a sentence and the principal verb should not, as a rule, be separated by a phrase or clause that can be transferred to the beginning. - -| Original | Revision | -| --- | --- | -| Wordsworth, in the fifth book of The Excursion, gives a minute description of this church. | In the fifth book of The Excursion, Wordsworth gives a minute description of this church. | -| Cast iron, when treated in a Bessemer converter, is changed into steel. | By treatment in a Bessemer converter, cast iron is changed into steel. | - -The objection is that the interposed phrase or clause needlessly interrupts the natural order of the main clause. Usually, however, this objection does not hold when the order is interrupted only by a relative clause or by an expression in apposition. Nor does it hold in periodic sentences in which the interruption is a deliberately used means of creating suspense (see examples under Rule 18). - -The relative pronoun should come, as a rule, immediately after its antecedent. - -| Original | Revision | -| --- | --- | -| There was a look in his eye that boded mischief. | In his eye was a look that boded mischief. | -| He wrote three articles about his adventures in Spain, which were published in Harper's Magazine. | He published in Harper's Magazine three articles about his adventures in Spain. | -| This is a portrait of Benjamin Harrison, grandson of William Henry Harrison, who became President in 1889. | This is a portrait of Benjamin Harrison, grandson of William Henry Harrison. He became President in 1889. | - -If the antecedent consists of a group of words, the relative comes at the end of the group, unless this would cause ambiguity. - -The Superintendent of the Chicago Division, who - -| Original | Revision | -| --- | --- | -| A proposal to amend the Sherman Act, which has been variously judged. | A proposal, which has been variously judged, to amend the Sherman Act. | -| — | A proposal to amend the much-debated Sherman Act. | -| The grandson of William Henry Harrison, who | William Henry Harrison's grandson, who | - -A noun in apposition may come between antecedent and relative, because in such a combination no real ambiguity can arise. - -The Duke of York, his brother, who was regarded with hostility by the Whigs - -Modifiers should come, if possible, next to the word they modify. If several expressions modify the same word, they should be so arranged that no wrong relation is suggested. - -| Original | Revision | -| --- | --- | -| All the members were not present. | Not all the members were present. | -| He only found two mistakes. | He found only two mistakes. | -| Major R. E. Joyce will give a lecture on Tuesday evening in Bailey Hall, to which the public is invited, on “My Experiences in Mesopotamia” at eight P. M. | On Tuesday evening at eight P. M., Major R. E. Joyce will give in Bailey Hall a lecture on “My Experiences in Mesopotamia.” The public is invited. | - -### Rule 17. In summaries, keep to one tense. - -In summarizing the action of a drama, the writer should always use the present tense. In summarizing a poem, story, or novel, he should preferably use the present, though he may use the past if he prefers. If the summary is in the present tense, antecedent action should be expressed by the perfect; if in the past, by the past perfect. - -An unforeseen chance prevents Friar John from delivering Friar Lawrence's letter to Romeo. Meanwhile, owing to her father's arbitrary change of the day set for her wedding, Juliet has been compelled to drink the potion on Tuesday night, with the result that Balthasar informs Romeo of her supposed death before Friar Lawrence learns of the non-delivery of the letter. - -But whichever tense be used in the summary, a past tense in indirect discourse or in indirect question remains unchanged. - -The Friar confesses that it was he who married them. - -Apart from the exceptions noted, whichever tense the writer chooses, he should use throughout. Shifting from one tense to the other gives the appearance of uncertainty and irresolution (compare Rule 15). - -In presenting the statements or the thought of some one else, as in summarizing an essay or reporting a speech, the writer should avoid intercalating such expressions as “he said,” “he stated,” “the speaker added,” “the speaker then went on to say,” “the author also thinks,” or the like. He should indicate clearly at the outset, once for all, that what follows is summary, and then waste no words in repeating the notification. - -In notebooks, in newspapers, in handbooks of literature, summaries of one kind or another may be indispensable, and for children in primary schools it is a useful exercise to retell a story in their own words. But in the criticism or interpretation of literature the writer should be careful to avoid dropping into summary. He may find it necessary to devote one or two sentences to indicating the subject, or the opening situation, of the work he is discussing; he may cite numerous details to illustrate its qualities. But he should aim to write an orderly discussion supported by evidence, not a summary with occasional comment. Similarly, if the scope of his discussion includes a number of works, he will as a rule do better not to take them up singly in chronological order, but to aim from the beginning at establishing general conclusions. - -### Rule 18. Place the emphatic words of a sentence at the end. - -The proper place in the sentence for the word, or group of words, which the writer desires to make most prominent is usually the end. - -| Original | Revision | -| --- | --- | -| Humanity has hardly advanced in fortitude since that time, though it has advanced in many other ways. | Humanity, since that time, has advanced in many other ways, but it has hardly advanced in fortitude. | -| This steel is principally used for making razors, because of its hardness. | Because of its hardness, this steel is principally used in making razors. | - -The word or group of words entitled to this position of prominence is usually the logical predicate, that is, the *new* element in the sentence, as it is in the second example. - -The effectiveness of the periodic sentence arises from the prominence which it gives to the main statement. - -Four centuries ago, Christopher Columbus, one of the Italian mariners whom the decline of their own republics had put at the service of the world and of adventure, seeking for Spain a westward passage to the Indies as a set-off against the achievements of Portuguese discoverers, lighted on America. - -With these hopes and in this belief I would urge you, laying aside all hindrance, thrusting away all private aims, to devote yourself unswervingly and unflinchingly to the vigorous and successful prosecution of this war. - -The other prominent position in the sentence is the beginning. Any element in the sentence, other than the subject, may become emphatic when placed first. - -Deceit or treachery he could never forgive. - -So vast and rude, fretted by the action of nearly three thousand years, the fragments of this architecture may often seem, at first sight, like works of nature. - -A subject coming first in its sentence may be emphatic, but hardly by its position alone. In the sentence, - -Great kings worshipped at his shrine, - -the emphasis upon *kings* arises largely from its meaning and from the context. To receive special emphasis, the subject of a sentence must take the position of the predicate. - -Through the middle of the valley flowed a winding stream. - -The principle that the proper place for what is to be made most prominent is the end applies equally to the words of a sentence, to the sentences of a paragraph, and to the paragraphs of a composition. diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/04-a-few-matters-of-form.md b/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/04-a-few-matters-of-form.md deleted file mode 100644 index 8cb24ecb..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/04-a-few-matters-of-form.md +++ /dev/null @@ -1,89 +0,0 @@ -## IV. A Few Matters of Form - -**Headings.** Leave a blank line, or its equivalent in space, after the title or heading of a manuscript. On succeeding pages, if using ruled paper, begin on the first line. - -**Numerals.** Do not spell out dates or other serial numbers. Write them in figures or in Roman notation, as may be appropriate. - -August 9, 1918 (9 August 1918) - -Rule 3 - -Chapter XII - -352nd Infantry - -**Parentheses.** A sentence containing an expression in parenthesis is punctuated, outside of the marks of parenthesis, exactly as if the expression in parenthesis were absent. The expression within is punctuated as if it stood by itself, except that the final stop is omitted unless it is a question mark or an exclamation point. - -I went to his house yesterday (my third attempt to see him), but he had left town. - -He declares (and why should we doubt his good faith?) that he is now certain of success. - -(When a wholly detached expression or sentence is parenthesized, the final stop comes before the last mark of parenthesis.) - -**Quotations.** Formal quotations, cited as documentary evidence, are introduced by a colon and enclosed in quotation marks. - -The provision of the Constitution is: “No tax or duty shall be laid on articles exported from any state.” - -Quotations grammatically in apposition or the direct objects of verbs are preceded by a comma and enclosed in quotation marks. - -[](https://www.gutenberg.org/files/37134/37134-h/37134-h.htm "34")I recall the maxim of La Rochefoucauld, “Gratitude is a lively sense of benefits to come.” - -Aristotle says, “Art is an imitation of nature.” - -Quotations of an entire line, or more, of verse, are begun on a fresh line and centered, but need not be enclosed in quotation marks. - -Wordsworth's enthusiasm for the Revolution was at first unbounded: - -Bliss was it in that dawn to be alive, - -But to be young was very heaven! - -Quotations introduced by _that_ are regarded as in indirect discourse and not enclosed in quotation marks. - -Keats declares that beauty is truth, truth beauty. - -Proverbial expressions and familiar phrases of literary origin require no quotation marks. - -These are the times that try men's souls. - -He lives far from the madding crowd. - -The same is true of colloquialisms and slang. - -**References.** In scholarly work requiring exact references, abbreviate titles that occur frequently, giving the full forms in an alphabetical list at the end. As a general practice, give the references in parenthesis or in footnotes, not in the body of the sentence. Omit the words _act_, _scene_, _line_, _book_, _volume_, _page_, except when referring by only one of them. Punctuate as indicated below. - -In the second scene of the third act In III.ii (still better, simply insert III.ii in parenthesis at the proper place in the sentence) - -After the killing of Polonius, Hamlet is placed under guard (IV.ii. 14). - -2 Samuel i:17–27 - -Othello II.iii. 264–267, III.iii. 155–161. - -**Syllabication.** If there is room at the end of a line for one or more syllables of a word, but not for the whole word, divide the word, unless this involves cutting off only a [](https://www.gutenberg.org/files/37134/37134-h/37134-h.htm "35") single letter, or cutting off only two letters of a long word. No hard and fast rule for all words can be laid down. The principles most frequently applicable are: - -(a) Divide the word according to its formation: - -know-ledge (not knowl-edge); Shake-speare (not Shakes-peare); de-scribe (not des-cribe); atmo-sphere (not atmos-phere); - -(b) Divide “on the vowel:” - -edi-ble (not ed-ible); propo-sition; ordi-nary; espe-cial; reli-gious; oppo-nents; regu-lar; classi-fi-ca-tion (three divisions allowable); deco-rative; presi-dent; - -(c) Divide between double letters, unless they come at the end of the simple form of the word: - -Apen-nines; Cincin-nati; refer-ring; but tell-ing. - -(d) Do not divide before final _-ed_ if the _e_ is silent: - -treat-ed (but not roam-ed or nam-ed). - -The treatment of consonants in combination is best shown from examples: - -for-tune; pic-ture; sin-gle; presump-tuous; illus-tration; sub-stan-tial (either division); indus-try; instruc-tion; sug-ges-tion; incen-diary. - -The student will do well to examine the syllable-division in a number of pages of any carefully printed book. - -**Titles.** For the titles of literary works, scholarly usage prefers italics with capitalized initials. The usage of editors and publishers varies, some using italics with capitalized initials, others using Roman with capitalized initials and with or without quotation marks. Use italics (indicated in manuscript by underscoring), except in writing for a periodical that follows a different practice. Omit initial _A_ or _The_ from titles when you place the possessive before them. - -The Iliad; the Odyssey; As You Like It; To a Skylark; The Newcomes; A Tale of Two Cities; Dickens's Tale of Two Cities. diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/05-words-and-expressions-commonly-misused.md b/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/05-words-and-expressions-commonly-misused.md deleted file mode 100644 index 3e379cbc..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/elements-of-style/05-words-and-expressions-commonly-misused.md +++ /dev/null @@ -1,348 +0,0 @@ -## V. Words And Expressions Commonly Misused - -(Some of the forms here listed, as *like I did*, are downright bad English; others, as the split infinitive, have their defenders, but are in such general disfavor that it is at least inadvisable to use them; still others, as *case*, *factor*, *feature*, *interesting*, *one of the most*, are good in their place, but are constantly obtruding themselves into places where they have no right to be. If the writer will make it his purpose from the beginning to express accurately his own individual thought, and will refuse to be satisfied with a ready-made formula that saves him the trouble of doing so, this last set of expressions will cause him little trouble. But if he finds that in a moment of inadvertence he has used one of them, his proper course will probably be not to patch up the sentence by substituting one word or set of words for another, but to recast it completely, as illustrated in a number of examples below and in others under Rules 12 and 13.) - -**All right.** Idiomatic in familiar speech as a detached phrase in the sense, “Agreed,” or “Go ahead.” In other uses better avoided. Always written as two words. - -**As good or better than.** Expressions of this type should be corrected by rearranging the sentence. - -| Original | Revision | -| --- | --- | -| My opinion is as good or better than his. | My opinion is as good as his, or better (if not better). | - -**As to whether.** *Whether* is sufficient; see under Rule 13. - -**Bid.** Takes the infinitive without *to*. The past tense in the sense, _“ordered,”_ is *bade*. - -**But.** Unnecessary after *doubt* and *help*. - -| Original | Revision | -| --- | --- | -| I have no doubt but that | I have no doubt that | -| He could not help see but that | He could not help seeing that | - -The too frequent use of *but* as a conjunction leads to the fault discussed under Rule 14. A loose sentence formed with *but* can always be converted into a periodic sentence formed with *although*, as illustrated under Rule 4. - -Particularly awkward is the following of one *but* by another, making a contrast to a contrast or a reservation to a reservation. This is easily corrected by re-arrangement. - -| Original | Revision | -| --- | --- | -| America had vast resources, but she seemed almost wholly unprepared for war. But within a year she had created an army of four million men. | America seemed almost wholly unprepared for war, but she had vast resources. Within a year she had created an army of four million men. | - -**Can.** Means *am (is, are) able*. Not to be used as a substitute for *may*. - -**Case.** The Concise Oxford Dictionary begins its definition of this word: “instance of a thing's occurring; usual state of affairs.” In these two senses, the word is usually unnecessary. - -| Original | Revision | -| --- | --- | -| In many cases, the rooms were poorly ventilated. | Many of the rooms were poorly ventilated. | -| It has rarely been the case that any mistake has been made. | Few mistakes have been made. | - -See Wood, Suggestions to Authors, pp. 68–71, and Quiller-Couch, The Art of Writing, pp. 103–106. - -**Certainly.** Used indiscriminately by some writers, much as others use *very*, to intensify any and every statement. A mannerism of this kind, bad in speech, is even worse in writing. - -**Character.** Often simply redundant, used from a mere habit of wordiness. - -| Original | Revision | -| --- | --- | -| Acts of a hostile character | Hostile acts | - -**Claim, vb.** With object-noun, means *lay claim to*. May be used with a dependent clause if this sense is clearly involved: “He claimed that he was the sole surviving heir.” (But even here, “claimed to be” would be better.) Not to be used as a substitute for *declare*, *maintain*, or *charge*. - -**Clever.** This word has been greatly overused; it is best restricted to ingenuity displayed in small matters. - -**Compare.** To *compare to* is to point out or imply resemblances, between objects regarded as essentially of different order; to *compare with* is mainly to point out differences, between objects regarded as essentially of the same order. Thus life has been compared to a pilgrimage, to a drama, to a battle; Congress may be compared with the British Parliament. Paris has been compared to ancient Athens; it may be compared with modern London. - -**Consider.** Not followed by *as* when it means “believe to be.” “I consider him thoroughly competent.” Compare, “The lecturer considered Cromwell first as soldier and second as administrator,” where “considered” means “examined” or “discussed.” - -**Data.** A plural, like *phenomena* and *strata*. - -These data were tabulated. - -**Dependable.** A needless substitute for *reliable*, *trustworthy*. - -**Different than.** Not permissible. Substitute *different from*, *other than*, or *unlike*. - -**Divided into.** Not to be misused for *composed of*. The line is sometimes difficult to draw; doubtless plays are divided into acts, but poems are composed of stanzas. - -**Don't.** Contraction of *do not*. The contraction of *does not* is *doesn't*. - -**Due to.** Incorrectly used for *through*, *because of*, or *owing to*, in adverbial phrases: “He lost the first game, due to carelessness.” In correct use related as predicate or as modifier to a particular noun: “This invention is due to Edison;” “losses due to preventable fires.” - -**Folk.** A collective noun, equivalent to *people*. Use the singular form only. - -**Effect.** As noun, means *result*; as verb, means *_to_ bring about*, *accomplish* (not to be confused with *affect*, which means “to influence”). - -As noun, often loosely used in perfunctory writing about fashions, music, painting, and other arts: “an Oriental effect;” “effects in pale green;” “very delicate effects;” “broad effects;” “subtle effects;” “a charming effect was produced by.” The writer who has a definite meaning to express will not take refuge in such vagueness. - -**Etc.** Equivalent to *and the rest*, *and so forth*, and hence not to be used if one of these would be insufficient, that is, if the reader would be left in doubt as to any important particulars. Least open to objection when it represents the last terms of a list already given in full, or immaterial words at the end of a quotation. - -At the end of a list introduced by *such as*, *for example*, or any similar expression, *etc.* is incorrect. - -**Fact.** Use this word only of matters of a kind capable of direct verification, not of matters of judgment. That a particular event happened on a given date, that lead melts at a certain temperature, are facts. But such conclusions as that Napoleon was the greatest of modern generals, or that the climate of California is delightful, however incontestable they _may be_, are not properly facts. - -On the formula *the fact that*, see under Rule 13. - -**Factor.** A hackneyed word; the expressions of which it forms part can usually be replaced by something more direct and idiomatic. - -| Original | Revision | -| --- | --- | -| His superior training was the great factor in his winning the match. | He won the match by being better trained. | -| Heavy artillery has become an increasingly important factor in deciding battles. | Heavy artillery has played a constantly larger part in deciding battles. | - -**Feature.** Another hackneyed word; like *factor* it usually adds nothing to the sentence in which it occurs. - -| Original | Revision | -| --- | --- | -| A feature of the entertainment especially worthy of mention was the singing of Miss A. | (Better use the same number of words to tell what Miss A. sang, or if the programme has already been given, to tell how she sang.) | - -As a verb, in the advertising sense of *offer as a special attraction*, to be avoided. - -**Fix.** Colloquial in America for *arrange*, *prepare*, *mend*. In writing restrict it to its literary senses, *fasten*, *make firm or immovable*, etc. - -**Get.** The colloquial *have got* for *have* should not be used in writing. The preferable form of the participle is *got*. - -**He is a man who.** A common type of redundant expression; see Rule 13. - -| Original | Revision | -| --- | --- | -| He is a man who is very ambitious. | He is very ambitious. | -| Spain is a country which I have always wanted to visit. | I have always wanted to visit Spain. | - -**Help.** See under **But**. - -**However.** In the meaning *nevertheless*, not to come first in its sentence or clause. - -| Original | Revision | -| --- | --- | -| The roads were almost impassable. However, we at last succeeded in reaching camp. | The roads were almost impassable. At last, however, we succeeded in reaching camp. | - -When *however* comes first, it means *in whatever way* or *to whatever extent*. - -However you advise him, he will probably do as he thinks best. - -However discouraging the prospect, he never lost heart. - -**Interesting.** Avoid this word as a perfunctory means of introduction. Instead of announcing that what you are about to tell is interesting, make it so. - -| Original | Revision | -| --- | --- | -| An interesting story is told of | (Tell the story without preamble.) | -| In connection with the anticipated visit of Mr. B. to America, it is interesting to recall that he | Mr. B., who it is expected will soon visit America | - -**Kind of.** Not to be used as a substitute for *rather* (before adjectives and verbs), or except in familiar style, for *something like* (before nouns). Restrict it to its literal sense: “Amber is a kind of fossil resin;” “I dislike that kind of notoriety.” The same holds true of *sort of*. - -**Less.** Should not be misused for *fewer*. - -| Original | Revision | -| --- | --- | -| He had less men than in the previous campaign | He had fewer men than in the previous campaign | - -*Less* refers to quantity, *fewer* to number. “His troubles are less than mine” means “His troubles are not so great as mine.” “His troubles are fewer than mine” means “His troubles are not so numerous as mine.” It is, however, correct to say, “The signers of the petition were less than a hundred,” where the round number *a hundred* is something like a collective noun, and *less* is thought of as meaning a less quantity or amount. - -**Like.** Not to be misused for *as*. *Like* governs nouns and pronouns; before phrases and clauses the equivalent word is *as*. - -| Original | Revision | -| --- | --- | -| We spent the evening like in the old days. | We spent the evening as in the old days. | -| He thought like I did. | He thought as I did (like me). | - -**Line, along these lines.** *Line* in the sense of *course of procedure*, *conduct*, *thought*, is allowable, but has been so much overworked, particularly in the phrase *along these lines*, that a writer who aims at freshness or originality had better discard it entirely. - -| Original | Revision | -| --- | --- | -| Mr. B. also spoke along the same lines. | Mr. B. also spoke, to the same effect. | -| He is studying along the line of French literature. | He is studying French literature. | - -**Literal, literally.** Often incorrectly used in support of exaggeration or violent metaphor. - -| Original | Revision | -| --- | --- | -| A literal flood of abuse. | A flood of abuse. | -| Literally dead with fatigue | Almost dead with fatigue (dead tired) | - -**Lose out.** Meant to be more emphatic than *lose*, but actually less so, because of its commonness. The same holds true of *try out*, *win out*, *sign up*, *register up*. With a number of verbs, *out* and *up* form idiomatic combinations: *find out*, *run out*, *turn out*, *cheer up*, *dry up*, *make up*, and others, each distinguishable in meaning from the simple verb. *Lose out* is not. - -**Most.** Not to be used for *almost*. - -| Original | Revision | -| --- | --- | -| Most everybody | Almost everybody | -| Most all the time | Almost all the time | - -**Nature.** Often simply redundant, used like *character*. - -| Original | Revision | -| --- | --- | -| Acts of a hostile _nature_ | Hostile acts | - -Often vaguely used in such expressions as a “lover of nature;” “poems about nature.” Unless more specific statements follow, the reader cannot tell whether the poems have to do with natural scenery, rural life, the sunset, the untracked wilderness, or the habits of squirrels. - -**Near by.** Adverbial phrase, not yet fully accepted as good English, though the analogy of *close by* and *hard by* seems to justify it. *Near*, or *near at hand*, is as good, if not better. - -Not to be used as an adjective; use *neighboring*. - -**Oftentimes, ofttimes.** Archaic forms, no longer in good use. The modern word is *often*. - -**One hundred and one.** Retain the *and* in this and similar expressions, in accordance with the unvarying usage of English prose from Old English times. - -**One of the most.** Avoid beginning essays or paragraphs with this formula, as, “One of the most interesting developments of modern science is, etc.;” “Switzerland is one of the most interesting countries of Europe.” There is nothing wrong in this; it is simply threadbare and forcible-feeble. - -A common blunder is to use a singular verb in a relative clause following this or a similar expression, when the relative is the subject. - -| Original | Revision | -| --- | --- | -| One of the ablest men that has attacked this problem. | One of the ablest men that have attacked this problem. | - -**Participle for verbal noun.** - -| Original | Revision | -| --- | --- | -| Do you mind me asking a question? | Do you mind my asking a question? | -| There was little prospect of the Senate accepting even this compromise. | There was little prospect of the Senate's accepting even this compromise. | - -In the left-hand column, *asking* and *accepting* are present participles; in the right-hand column, they are verbal nouns (gerunds). The construction shown in the left-hand column is occasionally found, and has its defenders. Yet it is easy to see that the second sentence has to do not with a prospect of the Senate, but with a prospect of accepting. In this example, at least, the construction is plainly illogical. - -As the authors of The King's English point out, there are sentences apparently, but not really, of this type, in which the possessive is not called for. - -I cannot imagine Lincoln refusing his assent to this measure. - -In this sentence, what the writer cannot imagine is Lincoln himself, in the act of refusing his assent. Yet the meaning would be virtually the same, except for a slight loss of vividness, if he had written, - -I cannot imagine Lincoln's refusing his assent to this measure. - -By using the possessive, the writer will always be on the safe side. - -In the examples above, the subject of the action is a single, unmodified term, immediately preceding the verbal noun, and the construction is as good as any that could be used. But in any sentence in which it is a mere clumsy substitute for something simpler, or in which the use of the possessive is awkward or impossible, should of course be recast. - -| Original | Revision | -| --- | --- | -| In the event of a reconsideration of the whole matter's becoming necessary | If it should become necessary to reconsider the whole matter | -| There was great dissatisfaction with the decision of the arbitrators being favorable to the company. | There was great dissatisfaction that the arbitrators should have decided in favor of the company. | - -**People.** *The people* is a political term, not to be confused with *the public*. From the people comes political support or opposition; from the public comes artistic appreciation or commercial patronage. - -**Phase.** Means a stage of transition or development: “the phases of the moon;” “the last phase.” Not to be used for *aspect* or *topic*. - -| Original | Revision | -| --- | --- | -| Another phase of the subject | Another point (another question) | - -**Possess.** Not to be used as a mere substitute for *have* or *own*. - -| Original | Revision | -| --- | --- | -| He possessed great courage. | He had great courage (was very brave). | -| He was the fortunate possessor of | He owned | - -**Prove.** The past participle is *proved*. - -**Respective, respectively.** These words may usually be omitted with advantage. - -| Original | Revision | -| --- | --- | -| Works of fiction are listed under the names of their respective authors. | Works of fiction are listed under the names of their authors. | -| The one mile and two mile runs were won by Jones and Cummings respectively. | The one mile and two mile runs were won by Jones and by Cummings. | - -In some kinds of formal writing, as geometrical proofs, it may be necessary to use *respectively*, but it should not appear in writing on ordinary subjects. - -**Shall, Will.** The future tense requires *shall* for the first person, *will* for the second and third. The formula to express the speaker's belief regarding his future action or state is *I shall*; *I will* expresses his determination or his consent. - -**Should.** See under **Would**. - -**So.** Avoid, in writing, the use of *so* as an intensifier: “so good;” “so warm;” “so delightful.” - -On the use of *so* to introduce clauses, see Rule 4. - -**Sort of.** See under **Kind of**. - -**Split Infinitive.** There is precedent from the fourteenth century downward for interposing an adverb between *to* and the infinitive which it governs, but the construction is in disfavor and is avoided by nearly all careful writers. - -| Original | Revision | -| --- | --- | -| To diligently inquire | To inquire diligently | - -**State.** Not to be used as a mere substitute for *say*, *remark*. Restrict it to the sense of *express fully or clearly*, as, “He refused to state his objections.” - -**Student Body.** A needless and awkward expression meaning no more than the simple word *students*. - -| Original | Revision | -| --- | --- | -| A member of the student body | A student | -| Popular with the student body | Liked by the students | -| The student body passed resolutions. | The students passed resolutions. | - -**System.** Frequently used without need. - -| Original | Revision | -| --- | --- | -| Dayton has adopted the commission system of _government._ | Dayton has adopted government by commission. | -| The dormitory system | Dormitories | - -**Thanking You in Advance.** This sounds as if the writer meant, “It will not be worth my while to write to you again.” In making your request, write, “Will you please,” or “I shall be obliged,” and if anything further seems necessary write a letter of acknowledgment later. - -**They.** A common inaccuracy is the use of the plural pronoun when the antecedent is a distributive expression such as *each*, *each one*, *everybody*, *every one*, *many a man*, which, though implying more than one person, requires the pronoun to be in the singular. Similar to this, but with even less justification, is the use of the plural pronoun with the antecedent *anybody*, *any one*, *somebody*, *some one*, the intention being either to avoid the awkward “he or she,” or to avoid committing oneself to either. Some bashful speakers even say, “A friend of mine told me that they, etc.” - -Use *he* with all the above words, unless the antecedent is or must be feminine. - -**Very.** Use this word sparingly. Where emphasis is necessary, use words strong in themselves. - -**Viewpoint.** Write *point of view*, but do not misuse this, as many do, for *view* or *opinion*. - -**While.** Avoid the indiscriminate use of this word for *and*, *but*, and *although*. Many writers use it frequently as a substitute for *and* or *but*, either from a mere desire to vary the connective, or from uncertainty which of the two connectives is the more appropriate. In this use it is best replaced by a semicolon. - -| Original | Revision | -| --- | --- | -| The office and salesrooms are on the ground floor, while the rest of the building is devoted to manufacturing. | The office and salesrooms are on the ground floor; the rest of the building is devoted to manufacturing. | - -Its use as a virtual equivalent of *although* is allowable in sentences where this leads to no ambiguity or absurdity. - -While I admire his energy, I wish it were employed in a better cause. - -This is entirely correct, as shown by the paraphrase, - -I admire his energy; at the same time I wish it were employed in a better cause. - -Compare: - -| Original | Revision | -| --- | --- | -| While the temperature reaches 90 or 95 degrees in the daytime, the nights are often chilly. | Although the temperature reaches 90 or 95 degrees in the daytime, the nights are often chilly. | - -The paraphrase, - -The temperature reaches 90 or 95 degrees in the daytime; at the same time the nights are often chilly, - -shows why the use of *while* is incorrect. - -In general, the writer will do well to use *while* only with strict literalness, in the sense of *during the time that*. - -**Whom.** Often incorrectly used for *who* before *he said* or similar expressions, when it is really the subject of a following verb. - -| Original | Revision | -| --- | --- | -| His brother, whom he said would send him the money | His brother, who he said would send him the money | -| The man whom he thought was his friend | The man who (that) he thought was his friend (whom he thought his friend) | - -**Worth while.** Overworked as a term of vague approval and (with *not*) of disapproval. Strictly applicable only to actions: “Is it worth while to telegraph?” - -| Original | Revision | -| --- | --- | -| His books are not worth while. | His books are not worth reading (are not worth one's while to read; do not repay reading; are worthless). | - -The use of *worth while* before a noun (“a worth while story”) is indefensible. - -**Would.** A conditional statement in the first person requires *should*, not *would*. - -I should not have succeeded without his help. - -The equivalent of *shall* in indirect quotation after a verb in the past tense is *should*, not *would*. - -He predicted that before long we should have a great surprise. - -To express habitual or repeated action, the past tense, without *would*, is usually sufficient, and from its brevity, more emphatic. - -| Original | Revision | -| --- | --- | -| Once a year he would visit the old mansion. | Once a year he visited the old mansion. | diff --git a/builtin-skills/marketing/writing-clearly-and-concisely/signs-of-ai-writing.md b/builtin-skills/marketing/writing-clearly-and-concisely/signs-of-ai-writing.md deleted file mode 100644 index 727c3969..00000000 --- a/builtin-skills/marketing/writing-clearly-and-concisely/signs-of-ai-writing.md +++ /dev/null @@ -1,901 +0,0 @@ -# Signs of AI Writing - -[![A screenshot of ChatGPT reading: "[header] Legacy & Interpretation [body] The "Black Hole Edition" is not just a meme — it's a celebration of grassroots car culture, where ideas are limitless and fun is more important than spec sheets. Whether powered by a rotary engine, a V8 swap, or an imagined fighter jet turbine, the Miata remains the canvas for car enthusiasts worldwide."](https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/ChatGPT_response_screenshot_1.jpg/250px-ChatGPT_response_screenshot_1.jpg)](https://en.wikipedia.org/wiki/File:ChatGPT_response_screenshot_1.jpg) - -*LLMs tend to have an identifiable writing style.* - -This is a list of writing and formatting conventions typical of [AI chatbots](https://en.wikipedia.org/wiki/AI_chatbot "AI chatbot") such as [ChatGPT](https://en.wikipedia.org/wiki/ChatGPT "ChatGPT"), with real examples taken from Wikipedia articles and drafts. It is a [field guide](https://en.wikipedia.org/wiki/Field_guide "Field guide") to help detect [undisclosed AI-generated content](https://en.wikipedia.org/wiki/Wikipedia:LLMDISCLOSE "Wikipedia:LLMDISCLOSE") on Wikipedia. This list is *descriptive*, not *prescriptive*; it consists of observations, not rules. Advice about formatting or language to avoid in Wikipedia articles can be found in the [policies and guidelines](https://en.wikipedia.org/wiki/Wikipedia:PAG "Wikipedia:PAG") and the [Manual of Style](https://en.wikipedia.org/wiki/Wikipedia:MOS "Wikipedia:MOS"), but does not belong on this page. - -This list is *not* a ban on certain words, phrases, or punctuation. Not all text featuring these indicators is AI-generated, as the [large language models](https://en.wikipedia.org/wiki/Large_language_model "Large language model") that power AI chatbots are trained on human writing, including the writing of Wikipedia editors. This is simply a catalog of very common patterns observed over many thousands of instances of AI-generated text, *specific to Wikipedia.* While some of its advice may be broadly applicable, some signs—particularly those involving punctuation and formatting—may not apply in a non-Wikipedia context. - -The patterns here are also only potential *signs* of a problem, not *the problem itself*. While many of these issues are immediately obvious and easy to fix—e.g., excessive boldface, poor use of language and punctuation, broken markup, citation style quirks—they can point to less outwardly visible problems that carry [much more serious policy risks](https://en.wikipedia.org/wiki/Wikipedia:AIFAIL "Wikipedia:AIFAIL"). If LLM-generated text is polished enough (initially or subsequently), those surface defects might not be present, but deeper problems can be. Please do not merely treat these signs as the problems to be fixed; that could just make detection harder. The actual problems are those deeper concerns, so make sure to address them, either yourself or by flagging them, per the advice at [Wikipedia:Large language models §Handling suspected LLM-generated content](https://en.wikipedia.org/wiki/Wikipedia:Large_language_models#Handling_suspected_LLM-generated_content "Wikipedia:Large language models") and [Wikipedia:WikiProject AI Cleanup/Guide](https://en.wikipedia.org/wiki/Wikipedia:WikiProject_AI_Cleanup/Guide "Wikipedia:WikiProject AI Cleanup/Guide"). - -The [speedy deletion policy](https://en.wikipedia.org/wiki/Wikipedia:Speedy_deletion "Wikipedia:Speedy deletion") criterion [G15](https://en.wikipedia.org/wiki/Wikipedia:G15 "Wikipedia:G15") (LLM-generated pages without human review) is limited to the most objective and least contestable indications that the page's content was generated by an LLM. There are three such indicators, the first of which can be found in [§Communication intended for the user](#communication-intended-for-the-user) and the other two in [§Citations](#citations). - -Do not solely rely on [artificial intelligence content detection](https://en.wikipedia.org/wiki/Artificial_intelligence_content_detection "Artificial intelligence content detection") tools (such as [GPTZero](https://en.wikipedia.org/wiki/GPTZero "GPTZero")) to evaluate whether text is LLM-generated. While they perform better than might be achieved by chance, these tools have non-trivial error rates and cannot replace human judgment.[^1] Detectors can be brittle to multiple factors such as text modifications (e.g. paraphrasing and spacing changes) and the use of generative models not seen during detector training.[^2] By the same token, do not trust too much in your own interpretation. Research shows that people who use LLMs heavily themselves can correctly determine whether an article was generated by AI about 90% of the time, which means that if you are an expert user of LLMs and you tag 10 pages as being AI-generated, you've probably falsely accused one editor.[^3] People who don't personally use LLMs much do only slightly better than random chance (in both directions) for identifying AI-generated articles.[^3] - ---- - -## Regression to the Mean - -LLMs (and [artificial neural networks](https://en.wikipedia.org/wiki/Artificial_neural_network "Artificial neural network") in general) use statistical algorithms to guess (infer) what should come next based on a large corpus of training material. It thus tends to [regress to the mean](https://en.wikipedia.org/wiki/Regression_to_the_mean "Regression to the mean"); that is, the result tends toward the most statistically likely result that applies to the widest variety of cases. It can simultaneously be a strength and a "tell" for detecting AI-generated content. - -For example, LLMs are usually trained on data from the internet in which famous people are generally described with positive, important-sounding language. Consequently, the LLM tends to omit specific, unusual, nuanced facts (which are statistically rare) and replace them with more generic, positive descriptions (which are statistically common). Thus the highly specific "inventor of the first train-coupling device" might become "a revolutionary titan of industry." It is like shouting louder and louder that a portrait shows a uniquely important person, while the portrait itself is fading from a sharp photograph into a blurry, generic sketch. The subject becomes simultaneously less specific and more exaggerated.[^4] - -This statistical regression to the mean, a smoothing over of specific facts into generic statements, that could equally apply to many topics, makes AI-generated content easier to detect. - -### Undue emphasis on symbolism, legacy, and importance - -**Words to watch:** *stands/serves as*, *is a testament/reminder*, *plays a vital/significant/crucial/pivotal role*, *underscores/highlights its importance/significance*, *reflects broader*, *symbolizing its ongoing/enduring/lasting impact*, *key turning point*, *indelible mark*, *deeply rooted*, *profound heritage*, *steadfast dedication*... - -LLM writing often puffs up the importance of the subject matter by adding statements about how arbitrary aspects of the topic represent or contribute to a broader topic.[^5] There is a distinct and easily identifiable repertoire of ways that it writes these statements.[^6] - -> The Statistical Institute of Catalonia was officially established in 1989, marking a pivotal moment in the evolution of regional statistics in Spain. [...] -> -> The founding of Idescat represented a significant shift toward regional statistical independence, enabling [Catalonia](https://en.wikipedia.org/wiki/Catalonia "Catalonia") to develop a statistical system tailored to its unique socio-economic context. This initiative was part of a broader movement across Spain to decentralize administrative functions and enhance regional governance. - -> Kumba has long been an important center for trade and agriculture. [...] The establishment of road networks connecting Kumba to other parts of the Southwest Region, such as Mamfe and Buea, helped solidify its role as a regional hub. - -LLMs may include these statements for even the most mundane of subjects like etymology or population data. Sometimes, they add hedging preambles acknowledging that the subject is relatively unimportant or low-profile, before talking about its importance anyway. - -**Examples** - -> During the [Spanish colonial period](https://en.wikipedia.org/wiki/Spanish_Colonial_Period_(Philippines) "Spanish Colonial Period (Philippines)"), the name *Bakunutan* was hispanized to *Bacnotan*, a modification reflected in official documents preserved in the [National Archives](https://en.wikipedia.org/wiki/National_Archives_of_the_Philippines "National Archives of the Philippines") in Manila. This etymology highlights the enduring legacy of the community's resistance and the transformative power of unity in shaping its identity. - -> Though it saw only limited application, it contributes to the broader history of early aviation engineering and reflects the influence of French rotary designs on German manufacturers. - -When talking about biology (e.g., when asked to discuss an animal or plant species), LLMs tend to over-emphasize connections to the broader ecosystem or environment, even when those connections are tenuous or generic. LLMs also tend to belabor the species' conservation status and research and preservation efforts, even if the status is unknown and no serious efforts exist. - -**Examples** - -> It plays a role in the ecosystem and contributes to Hawaii's rich cultural heritage. [...] Preserving this endemic species is vital not only for ecological diversity but also for sustaining the cultural traditions connected to Hawaii's native flora. - -> Currently, there is no specific conservation assessment for *Lethrinops lethrinus* by the International Union for Conservation of Nature (IUCN). However, the general health of the Lake Malawi ecosystem is crucial for the survival of this and other endemic species. Factors such as overfishing, pollution, and habitat destruction could potentially impact their populations. - -### Undue emphasis on notability, attribution, and media coverage - -**Words to watch:** *independent coverage*, *local/regional/national/[country name] media outlets*, *music/business/tech outlets*, *active social media presence* - -Similarly, LLMs act as if the best way to prove that a subject is notable is to hit readers over the head with claims of notability, often by listing sources that a subject has been covered in. They may or may not provide additional context as to what those sources have actually said about the subject, and often inaccurately attribute their own [superficial analyses](#superficial-analyses) to the source. This is more common in text from newer AI tools (2025 or later). - -Human-written press releases have of course also cited news clippings for decades, but LLMs specifically asked to write a Wikipedia article often echo the exact wording of [Wikipedia's guidelines](https://en.wikipedia.org/wiki/Wikipedia:N "Wikipedia:N"), such as "independent coverage." - -**Examples** - -> She spoke about AI on CNN, and was featured in Vogue, Wired, Toronto Star, and other media. [...] Her insights have also been featured in *Wired*, *Refinery29*, and other prominent media outlets. - -> Her views have been cited in *The New York Times*, *BBC*, *Financial Times*, and *The Hindu*. - -> Its significance is documented in archived school event programs and regional press coverage, including the *Mesabi Daily News*, which regularly reviewed performances held there. - -On Wikipedia specifically, LLMs often painstakingly emphasize their sources in the body text—even for trivial coverage, uncontroversial facts, or other situations where a human Wikipedia editor would be more likely to either provide an inline citation or no source at all. - -**Examples** - -> The restaurant has also been mentioned in [ABC News](https://en.wikipedia.org/wiki/ABC_News_(Australia) "ABC News (Australia)") coverage relating to incidents in the surrounding precinct, underscoring its role as a well-known late-night venue in the city [of [Adelaide](https://en.wikipedia.org/wiki/Adelaide "Adelaide")]. - -> In the United States, university-based incubators and accelerators have expanded alongside these centers; an official Library of Congress review found that 31.5% of SBA [[Small Business Administration](https://en.wikipedia.org/wiki/Small_Business_Administration "Small Business Administration")] Growth Accelerator Fund Competition winners from 2014–2016 were university-based programs. - -In articles about people/entities who use social media, LLMs will often note that they "maintain an active social media presence" or something similar. This wording is particularly idiosyncratic to AI text and relatively uncommon on Wikipedia before ~2024. - -> The mall maintains a strong digital presence, particularly on Instagram, where it actively shares the latest updates and events. Forum Kochi has consistently demonstrated excellence in digital promotions, with high-quality, engaging, and impactful video content playing a key role in its outreach. - -### Superficial analyses - -**Words to watch:** *ensuring ...*, *highlighting ...*, *emphasizing ...*, *reflecting ...*, *underscoring ...*, *showcasing ...*, *aligns with...*, *contributing to...* - -AI chatbots tend to insert superficial analysis of information, often in relation to its significance, recognition, or impact.[^7] This is often done by attaching a [present participle](https://en.wikipedia.org/wiki/Participle#Forms "Participle") ("-ing") phrase at the end of sentences, sometimes with [vague attributions](#vague-attributions-of-opinion) to third parties (see below).[^7][^5] - -While [many of these words are strong AI tells on their own](https://en.wikipedia.org/wiki/Wikipedia:AIWORDS "Wikipedia:AIWORDS"),[^6][^8] an even stronger tell is when the subjects of these verbs are facts, events, or other inanimate things. A person, for example, can highlight or emphasize something, but a fact or event cannot. The "highlighting" or "underscoring" is not something that is actually happening; it is a claim by a disembodied narrator about what something means.[^5] - -Such comments are usually [synthesis](https://en.wikipedia.org/wiki/Wikipedia:SYNTH "Wikipedia:SYNTH") and/or unattributed opinions in wikivoice. Newer chatbots with [retrieval-augmented generation](https://en.wikipedia.org/wiki/Retrieval-augmented_generation "Retrieval-augmented generation") (for example, an AI chatbot that can search the web) may attach these statements to [named sources](#undue-emphasis-on-notability-attribution-and-media-coverage)—e.g., "Roger Ebert highlighted the lasting influence"—regardless of whether those sources say anything close. - -**Examples** - -> Douera enjoys close proximity to the capital city, Algiers, further enhancing its significance as a dynamic hub of activity and culture. - -> The civil rights movement emerged as a powerful continuation of this struggle, emphasizing the importance of solidarity and collective action in the fight for justice. This historical legacy has influenced contemporary African-American families, shaping their values, community structures, and approaches to political engagement. Economically, the enduring impacts of systemic inequality have led to both challenges and innovations within African-American communities, driving a commitment to empowerment and social change that echoes through generations. - -> Its bilingual monument sign, with inscriptions in both English and Spanish, underscores its role in bringing together Latter-day Saints from the United States and Mexico. - -> These citations, spanning more than six decades and appearing in recognized academic publications, illustrate Blois' lasting influence in computational linguistics, grammar, and neology. - -> It holds a pivotal place in the [East Central Railway Zone](https://en.wikipedia.org/wiki/East_Central_Railway_Zone "East Central Railway Zone") of [Indian Railways](https://en.wikipedia.org/wiki/Indian_Railways "Indian Railways"), serving as a major railway hub with historical significance. The station has [1,676 mm](https://en.wikipedia.org/wiki/5_ft_6_in_gauge_railway "5 ft 6 in gauge railway") (5 ft 6 in) [broad gauge](https://en.wikipedia.org/wiki/Broad_gauge "Broad gauge") along with 8 tracks and 6 platforms. [...] Historically, it has been crucial for linking [Darbhanga](https://en.wikipedia.org/wiki/Darbhanga "Darbhanga") with significant cities like [Delhi](https://en.wikipedia.org/wiki/Delhi "Delhi"), [Patna](https://en.wikipedia.org/wiki/Patna "Patna"), and [Kolkata](https://en.wikipedia.org/wiki/Kolkata "Kolkata"), facilitating the movement of passengers and goods. The station has supported various services, including passenger trains and express trains like the [Satyagrah Express](https://en.wikipedia.org/wiki/Satyagrah_Express "Satyagrah Express") and [Mithila Express](https://en.wikipedia.org/wiki/Mithila_Express "Mithila Express"), contributing to the socio-economic development of the region. [...] Over the years, Darbhanga Junction has seen several upgrades and modernization efforts aimed at improving facilities and operational efficiency, reflecting its continued relevance in the regional and national transportation landscape. - -### Promotional and advertisement-like language - -**Words to watch:** *continues to captivate*, *groundbreaking* (in the figurative sense), *stunning natural beauty*, *enduring/lasting legacy*, *nestled*, *in the heart of*, *boasts a*... - -LLMs have serious problems keeping a neutral tone, especially when writing about something that could be considered "cultural heritage"—in which case they [constantly remind the reader of its importance](#undue-emphasis-on-symbolism-legacy-and-importance). - -**Examples** - -> Nestled within the breathtaking region of Gonder in Ethiopia, Alamata Raya Kobo stands as a vibrant town with a rich cultural heritage and a significant place within the Amhara region. From its scenic landscapes to its historical landmarks, Alamata Raya Kobo offers visitors a fascinating glimpse into the diverse tapestry of Ethiopia. In this article, we will explore the unique characteristics that make Alamata Raya Kobo a town worth visiting and shed light on its significance within the Amhara region. - -> TTDC acts as the gateway to Tamil Nadu's diverse attractions, seamlessly connecting the beginning and end of every traveller's journey. It offers dependable, value-driven experiences that showcase the state's rich history, spiritual heritage, and natural beauty. - -In a similar way, LLM chatbots also add promotional/positive-sounding language to text about companies, business, and products, such that it sounds more like the transcript of a TV commercial. - -> In general, AEO focuses on improving data consistency and machine readability so that information can be accurately understood by emerging "answer engines." Commonly discussed practices include using structured data formats such as [JSON-LD](https://en.wikipedia.org/wiki/JSON-LD "JSON-LD") and [schema.org](https://en.wikipedia.org/wiki/Schema.org "Schema.org"), maintaining the freshness and accuracy of published information, and aligning digital entities with open web standards like [Wikidata](https://en.wikipedia.org/wiki/Wikidata "Wikidata") and Schema.org. - -> The SOLLEI's exterior design communicates a powerful emotional presence, staying true to Cadillac's signature bold proportions. Its low, elongated silhouette is highlighted by a wide stance and an extended coupe door, which enhances accessibility to the spacious rear cabin. Smooth, uninterrupted surfaces and a pronounced A-line accentuate the vehicle's overall length, while a sleek, low tail imparts a sense of refined dynamism. A mid-body line runs seamlessly from the headlamps to the taillights, reinforcing the car's cohesive and elegant design. Traditional door handles have been replaced with discrete buttons, preserving the vehicle's clean and modern profile. In a nod to Cadillac's legacy of bold color choices, the exterior is finished in "Manila Cream"—a distinctive hue originally offered in 1957 and 1958. This heritage color has been thoughtfully revived and hand-painted by Cadillac artisans, showcasing the brand's dedication to craftsmanship and historical reverence. - -### Didactic, editorializing disclaimers - -**Words to watch:** *it's important/critical/crucial to note/remember/consider*, *may vary*... - -LLMs often tell the reader about things "it's important to remember." This frequently takes the form of "disclaimers" to an imagined reader regarding safety or controversial topics, or disambiguating topics that vary in different locales/jurisdictions. - -**Examples** - -> The emergence of these informal groups reflects a growing recognition of the interconnected nature of urban issues and the potential for ANCs to play a role in shaping citywide policies. However, it's important to note that these caucuses operate outside the formal ANC structure and their influence on policy decisions may vary. - -> It is crucial to differentiate the independent AI research company based in Yerevan, Armenia, which is the subject of this report, from these unrelated organizations to prevent confusion. - -> It's important to remember that what's free in one country might not be free in another, so always check before you use something. - -### Summaries and conclusions - -**Words to watch:** *In summary*, *In conclusion*, *Overall*... - -When generating longer outputs (such as when told to "write an article"), LLMs often add a section titled "Conclusion" or similar, and will often end a paragraph or section by summarizing and restating its core idea.[^9] - -**Examples** - -> In summary, the educational and training trajectory for nurse scientists typically involves a progression from a master's degree in nursing to a Doctor of Philosophy in Nursing, followed by postdoctoral training in nursing research. This structured pathway ensures that nurse scientists acquire the necessary knowledge and skills to engage in rigorous research and contribute meaningfully to the advancement of nursing science. - -### Outline-like conclusions about challenges and future prospects - -**Words to watch:** *Despite its... faces several challenges...*, *Despite these challenges*, *Challenges and Legacy*, *Future Outlook*... - -Many LLM-generated Wikipedia articles include a "Challenges" section, which typically begins with a sentence like "Despite its [positive/promotional words], [article subject] faces challenges..." and ends with either a vaguely positive assessment of the article subject,[^1] or speculation about how ongoing or potential initiatives could benefit the subject. Such paragraphs usually appear at the end of articles with a rigid outline structure, which may also include a separate section for "Future Prospects." - -Note: This sign is about the rigid formula, not simply the mention of challenges or challenging. - -**Examples** - -> Despite its industrial and residential prosperity, Korattur faces challenges typical of urban areas, including[...] With its strategic location and ongoing initiatives, Korattur continues to thrive as an integral part of the Ambattur industrial zone, embodying the synergy between industry and residential living. - -> Despite its success, the Panama Canal faces challenges, including[...] Future investments in technology, such as automated navigation systems, and potential further expansions could enhance the canal's efficiency and maintain its relevance in global trade. - -> Despite their promising applications, pyroelectric materials face several challenges that must be addressed for broader adoption. One key limitation is[...] Despite these challenges, the versatility of pyroelectric materials positions them as critical components for sustainable energy solutions and next-generation sensor technologies. - -> The future of hydrocarbon economies faces several challenges, including[...] This section would speculate on potential developments and the changing landscape of global energy. - -> Operating in the current Afghan media environment presents numerous challenges, including[...] Despite these challenges, Amu TV has managed to continue to provide a vital service to the Afghan population​​. - -> For example, while the methodology supports transdisciplinary collaboration in principle, applying it effectively in large, heterogeneous teams can be challenging. [...] SCE continues to evolve in response to these challenges. - -### Leads treating Wikipedia lists or broad article titles as proper nouns - -In AI-generated articles about topics with a title that is not a [proper name](https://en.wikipedia.org/wiki/Proper_name "Proper name"), such as a [list](https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Lists "Wikipedia:Manual of Style/Lists"), the first sentence of the lead may introduce and/or define the article's title as if it were a standalone real-world entity. While the [MOS](https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Lead_section#Format_of_the_first_sentence "Wikipedia:Manual of Style/Lead section") does allow such titles to be included at the beginning of the lead "in a natural way"; these AI leads tend not to be so natural. - -**Examples** - -> "The Effects of Foreign language anxiety on Learning" refers to the feelings of tension, nervousness, and apprehension experienced when learning or using a language other than one's native tongue. - -> EuroGames editions is the chronological list of the biennial EuroGames, a European LGBT+ multi-sport event organized by the European Gay and Lesbian Sport Federation (EGLSF). - -> The "**List of songs about Mexico**" is a curated compilation of musical works that reference Mexico its culture, geography, or identity as a central theme. - ---- - -## Language and Grammar - -### Overused "AI vocabulary" words - -**Words to watch:** *align/aligns/aligning with*,[^6][^8] *crucial*,[^1] *delve/delves/delving* (pre-2025),[^6][^8][^1] *emphasizing*,[^6][^8] *enduring*,[^8] *enhance/enhances/enhancing*,[^8][^1] *fostering*,[^8][^1] *garnered/garnering*,[^6][^8] *highlight/highlighted/highlighting/highlights* (as a verb),[^1] *interplay*,[^8] *intricate/intricacies*,[^6][^8][^7] *key* (as an adjective), *landscape*,[^8] *leveraging*,[^1] *multifaceted*,[^6][^8][^7] *notably*,[^8] *nuanced*,[^6][^8] *realm*,[^8] *robust*,[^1] *seamless/seamlessly*,[^1] *shed light on*, *showcasing*,[^8] *streamline*,[^1] *tapestry*,[^8] *testament*,[^1][^8] *underpin/underpins/underpinning*,[^8] *underscore/underscores/underscoring*,[^8] *vibrant*,[^8][^7] *vital*,[^1] ... - -Many studies have demonstrated that LLMs overuse certain words – especially compared to pre-2022 text, which is almost certain to be human-written.[^6] These "AI vocabulary" words are also ubiquitous in AI-generated encyclopedias, such as [Grokipedia](https://en.wikipedia.org/wiki/Grokipedia "Grokipedia"), and in AI-generated Wikipedia text. They often co-occur in LLM output: where there is one, there are likely others.[^10] An edit introducing one or two of these words may not be a big deal, but an edit (post-2022) introducing lots of them, lots of times, is one of the strongest tells for AI use. - -The distribution of "AI vocabulary" is slightly different depending on which chatbot or LLM was used,[^7] and has changed over time. For instance, the word *delve* was famously overused by ChatGPT until 2025, when its incidence dropped off sharply.[^11] - -Please keep context in mind. For example, while the word "underscore" is overused in AI text, it can also refer to a literal underline mark, or to [incidental music](https://en.wikipedia.org/wiki/Incidental_music "Incidental music"). - -**Examples** - -> Somali cuisine is an intricate and diverse fusion of a multitude of culinary influences, drawing from the rich tapestry of [Arab](https://en.wikipedia.org/wiki/Arab_cuisine "Arab cuisine"), [Indian](https://en.wikipedia.org/wiki/Indian_cuisine "Indian cuisine"), and [Italian](https://en.wikipedia.org/wiki/Italian_cuisine "Italian cuisine") flavours. This culinary tapestry is a direct result of Somalia's longstanding heritage of vibrant trade and bustling commerce. [...] -> -> Additionally, a distinctive feature of Somali culinary tradition is the incorporation of [camel](https://en.wikipedia.org/wiki/Camel "Camel") [meat](https://en.wikipedia.org/wiki/Meat "Meat") and [milk](https://en.wikipedia.org/wiki/Milk "Milk"). They are considered a delicacy and serve as cherished and fundamental elements in the rich tapestry of Somali cuisine. [...] -> -> An enduring testament to the influence of [Italian colonial rule in Somalia](https://en.wikipedia.org/wiki/Italian_Somaliland "Italian Somaliland") is the widespread adoption of [pasta](https://en.wikipedia.org/wiki/Pasta "Pasta") and [lasagne](https://en.wikipedia.org/wiki/Lasagna "Lasagna") in the local culinary landscape, espicially in the south, showcasing how these dishes have integrated into the traditional diet alongside rice. [...] -> -> Additionally, Somali merchants played a pivotal role in the global coffee trade, being one of the first to export coffee beans. - -### Negative parallelisms - -Parallel constructions involving "not", "but", or "however" such as "Not only ... but ..." or "It is not just about ..., it's ..." are common in LLM writing but are often unsuitable for writing in a neutral tone.[^1][^11] - -**Examples** - -> **Self-Portrait** by Yayoi Kusama, executed in 2010 and currently preserved in the famous Uffizi Gallery in Florence, constitutes not only a work of self-representation, but a visual document of her obsessions, visual strategies and psychobiographical narratives. - -> It's not just about the beat riding under the vocals; it's part of the aggression and atmosphere. - -Here is an example of a negative parallelism across multiple sentences: - -> He hailed from the esteemed Duse family, renowned for their theatrical legacy. Eugenio's life, however, took a path that intertwined both personal ambition and familial complexities. - -### Outlines of negatives - -On rare occasions, user messages that appear AI-generated may also include short sentences describing items that are either absent from something else or would be considered useless in comparison to a previous, useful item. Some of these may read something along the lines of "no ..., no ..., just ..." or "What matters is ..., not ..., not ...". - -**Examples** - -> There are no long-form profiles. No editorial insights. No coverage of her game dev career. No notable accolades. Just TikTok recaps and callouts. - ---- - -> The process demands rigor — not emotional fatigue, not personal offense, and certainly not a premature exit masked as moral high ground. - ---- - -> Not a career, not a body of work, not sustained relevance — just an algorithmic moment. - ---- - -> This is not a close call. It is not a gray area. This page should be gone, fully, cleanly, and without delay. No redirect. No merge. Just delete. - ---- - -> Wikipedia's general notability guideline (WP:GNG) is crystal clear: significant coverage in reliable, independent, secondary sources. Not a few throwaway articles echoing Twitter drama. Not reactionary posts exploiting culture war tension. Not foreign-language gossip magazines translating controversy for clicks. - ---- - -> What actually matters — and what continues to be completely absent — is significant, in-depth coverage in reliable, independent secondary sources. Not gossip sites. Not recycled outrage. Not tabloid blurbs about one viral controversy. And certainly not basic directory-style mentions of someone being a "video game writer" or TikTok creator. - -### Rule of three - -LLMs overuse the '[rule of three](https://en.wikipedia.org/wiki/Rule_of_three_(writing) "Rule of three (writing)")'. This can take different forms, from "adjective, adjective, adjective" to "short phrase, short phrase, and short phrase".[^1] LLMs often use this structure to make [superficial analyses](#superficial-analyses) appear more comprehensive. - -**Examples** - -> The Amaze Conference brings together global SEO professionals, marketing experts, and growth hackers to discuss the latest trends in digital marketing. The event features keynote sessions, panel discussions, and networking opportunities. - -### Vague attributions of opinion - -**Words to watch:** *Industry reports*, *Observers have cited*, *Some critics argue*... - -AI chatbots tend to attribute opinions or claims to some vague authority—a practice called [weasel wording](https://en.wikipedia.org/wiki/Weasel_wording "Weasel wording")—while citing only one or two sources that may or may not actually express such view. They also tend to overgeneralize the perspective of one or few sources into that of a wider group. - -**Examples** - -> His [Nick Ford's] compositions have been described as exploring conceptual themes and bridging the gaps between artistic media. - -— From [Draft:Nick Ford (musician)](https://en.wikipedia.org/wiki/Draft:Nick_Ford_(musician) "Draft:Nick Ford (musician)"). Here, the weasel wording implies the opinion comes from an independent source, but it actually cites Nick Ford's own website. - -> Due to its unique characteristics, the Haolai River is of interest to researchers and conservationists. Efforts are ongoing to monitor its ecological health and preserve the surrounding grassland environment, which is part of a larger initiative to protect China's semi-arid ecosystems from degradation. - -> The Kwararafa (Kororofa) confederacy is described in scholarship as a shifting [Benue valley](https://en.wikipedia.org/wiki/Benue_valley "Benue valley") coalition led by [Jukun](https://en.wikipedia.org/wiki/Jukun "Jukun") groups and incorporating a range of [Middle Belt](https://en.wikipedia.org/wiki/Middle_Belt "Middle Belt") peoples. Because much of the historical record derives from [Hausa](https://en.wikipedia.org/wiki/Hausa "Hausa") chronicles, Bornu sources and oral tradition, modern researchers treat Kwararafa as a fluid political and cultural formation rather than a fixed state. As a result, lists of member groups vary by period and source. - -### Excessive synonym variance / elegant variation - -Generative AI has a repetition-penalty code, meant to discourage it from reusing words too often.[^5] For instance, the output might give a main character's name and then repeatedly use a different synonym or related term (e.g., protagonist, key player, eponymous character) when mentioning it again. - -Note: If a user adds multiple pieces of AI-generated content in separate edits, this tell may not apply, as each piece of text may have been generated in isolation. - -**Examples** - -> Vierny, after a visit in Moscow in the early 1970's, committed to supporting artists resisting the constraints of socialist realism and discovered Yankilevskly, among others such as Ilya Kabakov and Erik Bulatov. In the challenging climate of Soviet artistic constraints, Yankilevsky, alongside other non-conformist artists, faced obstacles in expressing their creativity freely. Dina Vierny, recognizing the immense talent and the struggle these artists endured, played a pivotal role in aiding their artistic aspirations. [...] -> -> In this new chapter of his life, Yankilevsky found himself amidst a community of like-minded artists who, despite diverse styles, shared a common goal—to break free from the confines of state-imposed artistic norms, particularly socialist realism. [...] -> -> The move to Paris facilitated an environment where Yankilevsky could further explore and exhibit his distinctive artistic vision without the constraints imposed by the Soviet regime. Dina Vierny's unwavering support and commitment to the Russian avant-garde artists played a crucial role in fostering a space where their creativity could flourish, contributing to the rich tapestry of artistic expression in the vibrant cultural landscape of Paris. Vierny's commitment culminated in the groundbreaking exhibition "Russian Avant-Garde - Moscow 1973" at her Saint-Germain-des-Prés gallery, showcasing the diverse yet united front of non-conformist artists challenging the artistic norms of their time. - -### False ranges - -When *from ... to ...* constructions are not used figuratively, they are used to indicate the lower and upper bounds of a scale. The scale is either quantitative, involving an explicit or implicit numerical range (e.g. from 1990 to 2000, from 15 to 20 ounces, from winter to autumn), or qualitative, involving categorical bounds (e.g. "from seed to tree", "from mild to severe", "from white belt to black belt"). The same constructions may be used to form a [merism](https://en.wikipedia.org/wiki/Merism "Merism")—a figure of speech that combines the two extremes as two contrasting parts of the whole to refer to the whole. This is a figurative meaning, but it has the same structure as the non-figurative usage, because it still requires an identifiable scale: from head to toe (the length of a body denoting the whole body), [from soup to nuts](https://en.wiktionary.org/wiki/from_soup_to_nuts "wikt:from soup to nuts") (clearly based on time), etc. This is *not* a false range. - -LLMs really like mixing it up, such as when giving examples of items within a set (instead of simply mentioning them one after another). An important consideration is whether some middle ground can be identified without changing the endpoints. If the middle requires switching from one scale to another scale, or there is no scale to begin with or a coherent whole that could be conceived, the construction is a **false range**. LLMs often employ "figurative" (often simply: meaningless) "from ... to ..." constructions that purport to signify a scale, while the endpoints are loosely related or even unrelated things and no meaningful scale can be inferred. LLMs do this because such meaningless language is used in persuasive writing to impress and woo, and LLMs are heavily influenced by examples of persuasive writing during their training. - -**Example** - -> Our journey through the universe has taken us from the singularity of the Big Bang to the grand cosmic web, from the birth and death of stars that forge the elements of life, to the enigmatic dance of dark matter and dark energy that shape its destiny. -> -> [...] Intelligence and Creativity: From problem-solving and tool-making to scientific discovery, artistic expression, and technological innovation, human intelligence is characterized by its adaptability and capacity for novel solutions. [...] Continued Scientific Discovery: The quest to understand the universe, life, and ourselves will continue to drive scientific breakthroughs, from fundamental physics to medicine and neuroscience. - -### Title case in section headings - -In section headings, AI chatbots strongly tend to capitalize all main words.[^1] - -**Examples** - -> Global Context: Critical Mineral Demand -> -> According to a 2023 report by [Goldman Sachs](https://en.wikipedia.org/wiki/Goldman_Sachs "Goldman Sachs"), the global market for critical minerals [...] -> -> Strategic Negotiations and Global Partnerships -> -> In 2014, Katalayi was appointed senior executive adviser to the chairman of the board of [Gécamines](https://en.wikipedia.org/wiki/G%C3%A9camines "Gécamines") [...] -> -> High-Stakes Deals: Glencore, China, and Russia -> -> There was also interest from [Moscow](https://en.wikipedia.org/wiki/Moscow "Moscow") for strategic Congolese assets. [...] - ---- - -## Punctuation and Formatting - -### Excessive use of boldface - -AI chatbots may display various phrases in [boldface](https://en.wikipedia.org/wiki/Boldface "Boldface") for emphasis in an excessive, mechanical manner. One of their tendencies, inherited from readmes, fan wikis, how-tos, sales pitches, slide decks, listicles and other materials that heavily use boldface, is to emphasize every instance of a chosen word or phrase, often in a "key takeaways" fashion. Some newer large language models or apps have instructions to avoid overuse of boldface. - -**Examples** - -> It blends **OKRs (Objectives and Key Results)**, **KPIs (Key Performance Indicators)**, and visual strategy tools such as the **Business Model Canvas (BMC)** and **Balanced Scorecard (BSC)**. OPC is designed to bridge the gap between strategy and execution by fostering a unified mindset and shared direction within organizations. - -> A **leveraged buyout (LBO)** is characterized by the extensive use of **debt financing** to acquire a company. This financing structure enables **private equity firms** and **financial sponsors** to control businesses while investing a relatively small portion of their own equity. The acquired company's **assets and future cash flows** serve as collateral for the debt, making lenders more willing to provide financing. - -> **50 Scientists and Thinkers in AI Safety with significant** influence on the field of alignment, containment, and risk mitigation. The list includes their **Productive Years**, their estimated **P(doom)** (probability of existential catastrophe), a **one-sentence summary of their contribution to AI Safety**, and their Wikipedia link. - -### Inline-header vertical lists - -AI chatbots output often includes vertical lists formatted in a specific way: an ordered or unordered list where the list marker (number, bullet, dash, etc.) is followed by an inline boldfaced header, separated with a colon from the remaining descriptive text. - -Instead of [proper wikitext](https://en.wikipedia.org/wiki/H:LIST "H:LIST"), a bullet point in an unordered list may appear as a bullet character (•), hyphen (-), en dash (–), hash (#), emoji, or similar character. Ordered lists (i.e. numbered lists) may use explicit numbers (such as `1.`) instead of standard wikitext. When copied as bare text appearing on the screen, some of the formatting information is lost, and line breaks may be lost as well. - -**Examples** - -> 1. Historical Context Post-WWII Era: The world was rapidly changing after WWII, [...] 2. Nuclear Arms Race: Following the U.S. atomic bombings, the Soviet Union detonated its first bomb in 1949, [...] 3. Key Figures Edward Teller: A Hungarian physicist who advocated for the development of more powerful nuclear weapons, [...] 4. Technical Details of Sundial Hydrogen Bomb: The design of Sundial involved a hydrogen bomb [...] 5. Destructive Potential: If detonated, Sundial would create a fireball up to 50 kilometers in diameter, [...] 6. Consequences and Reactions Global Impact: The explosion would lead to an apocalyptic nuclear winter, [...] 7. Political Reactions: The U.S. military and scientists expressed horror at the implications of such a weapon, [...] 8. Modern Implications Current Nuclear Arsenal: Today, there are approximately 12,000 nuclear weapons worldwide, [...] 9. Key Takeaways Understanding the Madness: The concept of Project Sundial highlights the extremes of human ingenuity [...] 10. Questions to Consider What were the motivations behind the development of Project Sundial? [...] - -> Conflict of Interest (COI)/Autobiography: While I understand the concern regarding my username [...] -> -> Notability (GNG and NPOLITICIAN): I have revised the article to focus on factual details [...] -> -> Original Research (WP) and Promotional Tone: I have worked on removing original research [...] -> -> Article Move to Main Namespace: Moving the draft to the main namespace after the AFC review [...] - -### Emojis - -AI chatbots love using [emojis](https://en.wikipedia.org/wiki/Emoji "Emoji").[^11] In particular, they sometimes decorate section headings or bullet points by placing emojis in front of them. This is most noticeable in talkpage comments. - -**Examples** - -> Let's decode exactly what's happening here: -> -> 🧠 Cognitive Dissonance Pattern: -> -> You've proven authorship, demonstrated originality, and introduced new frameworks, yet they're defending a system that explicitly disallows recognition of originators unless a third party writes about them first. -> -> [...] -> -> 🧱 Structural Gatekeeping: -> -> Wikipedia policy favors: -> -> [...] -> -> 🚨 Underlying Motivation: -> -> Why would a human fight you on this? -> -> [...] -> -> 🧭 What You're Actually Dealing With: -> -> This is not a debate about rules. -> -> [...] - -> 🪷 Traditional Sanskrit Name: Trikoṇamiti -> -> Tri = Three -> -> Koṇa = Angle -> -> Miti = Measurement 🧭 "Measurement of three angles" — the ancient Indian art of triangle and angle mathematics. -> -> 🕰️ 1. Vedic Era (c. 1200 BCE – 500 BCE) -> -> [...] -> -> 🔭 2. Sine of the Bow: Sanskrit Terminology -> -> [...] -> -> 🌕 3. Āryabhaṭa (476 CE) -> -> [...] -> -> 🌀 4. Varāhamihira (6th Century CE) -> -> [...] -> -> 🌠 5. Bhāskarācārya II (12th Century CE) -> -> [...] -> -> 📤 Indian Legacy Spreads - -### Overuse of em dashes - -While human editors and writers often like [em dashes](https://en.wikipedia.org/wiki/Em_dash "Em dash") (—), AI *loves* them.[^11] LLM output uses them more often than nonprofessional human-written text of the same genre, and uses them in places where humans are more likely to use commas, parentheses, colons, or (misused) hyphens (-). LLMs especially tend to use em dashes in a formulaic, pat way, often mimicking "punched up" sales-like writing by over-emphasizing clauses or parallelisms. - -This sign is most useful when taken in combination with other indicators, not by itself. - -**Examples** - -> The term "Dutch Caribbean" is **not used in the statute** and is primarily promoted by **Dutch institutions**, not by the **people of the autonomous countries** themselves. In practice, many Dutch organizations and businesses use it for **their own convenience**, even placing it in addresses — e.g., "Curaçao, Dutch Caribbean" — but this only **adds confusion** internationally and **erases national identity**. You don't say **"Netherlands, Europe"** as an address — yet this kind of mislabeling continues. - -> you're right about one thing — we do seem to have different interpretations of what policy-based discussion entails. [...] -> -> When WP:BLP1E says "one event," it's shorthand — and the supporting essays, past AfD precedents, and practical enforcement show that "two incidents of fleeting attention" still often fall under the protective scope of BLP1E. This isn't "imagining" what policy should be — it's recognizing how community consensus has shaped its application. -> -> Yes, WP:GNG, WP:NOTNEWS, WP:NOTGOSSIP, and the rest of WP:BLP all matter — and I've cited or echoed each of them throughout. [...] If a subject lacks enduring, in-depth, independent coverage — and instead rides waves of sensational, short-lived attention — then we're not talking about encyclopedic significance. [...] -> -> [...] And consensus doesn't grow from silence — it grows from critique, correction, and clarity. -> -> If we disagree on that, then yes — we're speaking different languages. - -> The current revision of the article fully complies with Wikipedia's core content policies — including WP:V (Verifiability), WP:RS (Reliable Sources), and WP:BLP (Biographies of Living Persons) — with all significant claims supported by multiple independent and reputable international sources. -> -> [...] However, to date, no editor — including yourself — has identified any specific passages in the current version that were generated by AI or that fail to meet Wikipedia's content standards. [...] -> -> Given the article's current state — well-sourced, policy-compliant, and collaboratively improved — the continued presence of the "LLM advisory" banner is unwarranted. - -### Curly quotation marks and apostrophes - -AI chatbots typically use curly quotation marks ("..." or '...') instead of straight quotation marks ("..." or '...'). In some cases, AI chatbots inconsistently use pairs of curly and straight quotation marks in the same response. They also tend to use the curly apostrophe ('), the same character as the curly [right single quotation mark](https://en.wikipedia.org/wiki/Right_single_quotation_mark "Right single quotation mark"), instead of the straight apostrophe ('), such as in [contractions](https://en.wikipedia.org/wiki/Contraction_(grammar) "Contraction (grammar)") and [possessive forms](https://en.wikipedia.org/wiki/English_possessive "English possessive"). They may also do this inconsistently. - -Curly quotes alone do not prove LLM use. [Microsoft Word](https://en.wikipedia.org/wiki/Microsoft_Word "Microsoft Word") as well as [macOS](https://en.wikipedia.org/wiki/MacOS "MacOS") and [iOS](https://en.wikipedia.org/wiki/IOS "IOS") devices have a "[smart quotes](https://en.wikipedia.org/wiki/Smart_quotes "Smart quotes")" feature that converts straight quotes to curly quotes. Grammar correcting tools such as [LanguageTool](https://en.wikipedia.org/wiki/LanguageTool "LanguageTool") may also have such a feature. Curly quotation marks and apostrophes are common in professionally typeset works such as major newspapers. Citation tools like [Citer](https://citer.toolforge.org/) may repeat those that appear in the title of a web page: for example, - -> McClelland, Mac (2017-09-27). ["When 'Not Guilty' Is a Life Sentence"](https://www.nytimes.com/2017/09/27/magazine/when-not-guilty-is-a-life-sentence.html). *The New York Times*. Retrieved 2025-08-03. - -Note that Wikipedia allows users to customize the fonts used to display text. Some fonts display matched curly apostrophes as straight, in which case the distinction is invisible to the user. - -### Subject lines - -User messages and [unblock requests](https://en.wikipedia.org/wiki/Wikipedia:Identifying_LLM_unblock_requests "Wikipedia:Identifying LLM unblock requests") generated by AI chatbots sometimes begin with text that is intended to be pasted into the *Subject* field on an email form. - -**Examples** - -> Subject: Request for Permission to Edit Wikipedia Article - "Dog" - -> Subject: Request for Review and Clarification Regarding Draft Article - ---- - -## Communication Intended for the User - -### Collaborative communication - -**Words to watch:** *I hope this helps*, *Of course!*, *Certainly!*, *You're absolutely right!*, *Would you like...*, *is there anything else*, *let me know*, *more detailed breakdown*, *here is a*... - -Editors sometimes paste text from an AI chatbot that was meant as correspondence, prewriting or advice, rather than article content. This may appear in article text or within comments (``). Chatbots prompted to produce a Wikipedia article or comment may also explicitly state that the text is meant for Wikipedia, and may mention various [policies and guidelines](https://en.wikipedia.org/wiki/Wikipedia:PG "Wikipedia:PG") in the output—often explicitly specifying that they're *Wikipedia's* conventions. - -**Examples** - -> In this section, we will discuss the background information related to the topic of the report. This will include a discussion of relevant literature, previous research, and any theoretical frameworks or concepts that underpin the study. The purpose is to provide a comprehensive understanding of the subject matter and to inform the reader about the existing knowledge and gaps in the field. - -> Including photos of the forge (as above) and its tools would enrich the article's section on culture or economy, giving readers a visual sense of Ronco's industrial heritage. Visual resources can also highlight Ronco Canavese's landscape and landmarks. For instance, a map of the Soana Valley or Ronco's location in Piedmont could be added to orient readers geographically. The village's scenery [...] could be illustrated with an image. Several such photographs are available (e.g., on Wikimedia Commons) that show Ronco's panoramic view, [...] Historical images, if any exist (such as early 20th-century photos of villagers in traditional dress or of old alpine trades), would also add depth to the article. Additionally, the town's notable buildings and sites can be visually presented: [...] Including an image of the Santuario di San Besso [...] could further engage readers. By leveraging these visual aids – maps, photographs of natural and cultural sites – the expanded article can provide a richer, more immersive picture of Ronco Canavese. - -> If you plan to add this information to the "Animal Cruelty Controversy" section of Foshan's Wikipedia page, ensure that the content is presented in a neutral tone, supported by reliable sources, and adheres to Wikipedia's guidelines on verifiability and neutrality. - -> Here's a template for your wiki user page. You can copy and paste this onto your user page and customize it further. - -> Final important tip: The ~~~~ at the very end is Wikipedia markup that automatically - -### Knowledge-cutoff disclaimers and speculation about gaps in sources - -**Words to watch:** *as of [date]*,[^a] *Up to my last training update*, *as of my last knowledge update*, *While specific details are limited/scarce...*, *not widely available/documented/disclosed*, *...in the provided/available sources/search results...*, *based on available information*... - -A knowledge-cutoff disclaimer is a statement used by the AI chatbot to indicate that the information provided may be incomplete, inaccurate, or outdated. - -If an LLM has a fixed [knowledge cutoff](https://en.wikipedia.org/wiki/Knowledge_cutoff "Knowledge cutoff") (usually the model's last training update), it is unable to provide any information on events or developments past that time, and it often outputs a disclaimer to remind the user of this cutoff, which usually takes the form of a statement that says the information provided is accurate only up to a certain date. - -If an LLM with retrieval-augmented generation fails to find sources on a given topic, or if information is not included in sources a user provides, it often outputs a statement to that effect, which is similar to a knowledge-cutoff disclaimer. It may also pair it with text about what that information "likely" may be and why it is significant. This information is entirely [speculative](https://en.wikipedia.org/wiki/Wikipedia:OR "Wikipedia:OR") (including the very claim that it's "not documented") and may be based on loosely related topics or completely fabricated. - -**Examples** - -> While specific details about Kumarapediya's history or economy are not extensively documented in readily available sources, ... - -> While specific information about the fauna of Studniční hora is limited in the provided search results, the mountain likely supports... - -> Though the details of these resistance efforts aren't widely documented, they highlight her bravery... - -> No significant public controversies or security incidents affecting Outpost24 have been documented as of June 2025. - -> As of my last knowledge update in January 2022, I don't have specific information about the current status or developments related to the "Chester Mental Health Center" in today's era. - -> Below is a detailed overview based on available information: - -### Prompt refusals - -**Words to watch:** *as an AI language model*, *as a large language model*, *I'm sorry*... - -Occasionally, the AI chatbot declines to answer a prompt as written, usually with an apology and a reminder that it is "an AI language model". Attempting to be helpful, it often gives suggestions or an answer to an alternative, similar request. Outright refusals have become increasingly rare. - -Prompt refusals are obviously unacceptable for Wikipedia articles, so if a user includes one anyway, it may indicate that they did not review the text and/or may not be proficient in English. Remember to [assume good faith](https://en.wikipedia.org/wiki/Wikipedia:Assume_good_faith "Wikipedia:Assume good faith"), because that editor may genuinely want to improve our coverage of [knowledge gaps](https://en.wikipedia.org/wiki/Wikipedia:Systemic_bias "Wikipedia:Systemic bias"). - -**Examples** - -> As an AI language model, I can't directly add content to Wikipedia for you, but I can help you draft your bibliography. - -### Phrasal templates and placeholder text - -AI chatbots may generate responses with fill-in-the-blank [phrasal templates](https://en.wikipedia.org/wiki/Phrasal_template "Phrasal template") (as seen in the game *[Mad Libs](https://en.wikipedia.org/wiki/Mad_Libs "Mad Libs")*) for the LLM user to replace with words and phrases pertaining to their use case. However, some LLM users forget to fill in those blanks. Note that non-LLM-generated templates exist for drafts and new articles, such as [Wikipedia:Artist biography article template/Preload](https://en.wikipedia.org/wiki/Wikipedia:Artist_biography_article_template/Preload "Wikipedia:Artist biography article template/Preload") and pages in [Category:Article creation templates](https://en.wikipedia.org/wiki/Category:Article_creation_templates "Category:Article creation templates"). - -**Examples** - -> Subject: Concerns about Inaccurate Information -> -> Dear Wikipedia -> -> I am writing to express my deep concern about the spread of misinformation on your platform. Specifically, I am referring to the article about [Entertainer's Name], which I believe contains inaccurate and harmful information. - -> Subject: Edit Request for Wikipedia Entry -> -> Dear Wikipedia Editors, -> -> I hope this message finds you well. I am writing to request an edit for the Wikipedia entry -> -> I have identified an area within the article that requires updating/improvement. [Describe the specific section or content that needs editing and provide clear reasons why the edit is necessary, including reliable sources if applicable]. - -Large-language models may also insert placeholder dates like "2025-xx-xx" into citation fields, particularly the access-date parameter and rarely the date parameter as well, producing errors. - -**Examples** - -``` -{{cite web - |title=Canadian Screen Music Awards 2025 Winners and Nominees - |url=URL - |website=Canadian Screen Music Awards - |date=2025 - |access-date=2025-XX-XX -}} - -{{cite web - |title=Best Original Score, Dramatic Series or Special – Winner: "Murder on the Inca Trail" - |url=URL - |website=Canadian Screen Music Awards - |date=2025 - |access-date=2025-XX-XX -}} -``` - -LLM-generated infobox edits may contain placeholder comments alongside unused fields, specifying that text or images should be added. - -**Examples** - -``` -| leader_name = -``` - ---- - -## Markup - -### Use of Markdown - -AI chatbots are not proficient in [wikitext](https://en.wikipedia.org/wiki/H:WT "H:WT"), the [markup language](https://en.wikipedia.org/wiki/Markup_language "Markup language") used to instruct Wikipedia's [MediaWiki](https://en.wikipedia.org/wiki/MediaWiki "MediaWiki") software how to format an article. As wikitext is a niche markup language, found mostly on wikis running on MediaWiki and other MediaWiki-based platforms like [Miraheze](https://en.wikipedia.org/wiki/Miraheze "Miraheze"), LLMs tend to lack wikitext-formatted training data. While the corpora of chatbots did ingest millions of Wikipedia articles, these articles would not have been processed as text files containing wikitext syntax. This is compounded by the fact that most chatbots are factory-tuned to use another, conceptually similar but much more diversely applied markup language: [Markdown](https://en.wikipedia.org/wiki/Markdown "Markdown"). Their system-level instructions direct them to format outputs using it, and the chatbot apps render its syntax as formatted text on a user's screen, enabling the display of headings, bulleted and numbered lists, tables, etc, just as MediaWiki renders wikitext to make Wikipedia articles look like formatted documents. - -When asked about its "formatting guidelines", a chatbot willing to reveal some of its system-level instructions typically generates some variation of the following (this is [Microsoft Copilot](https://en.wikipedia.org/wiki/Microsoft_Copilot "Microsoft Copilot") in mid-2025): - -> ## Formatting Guidelines -> -> - All output uses GitHub-flavored Markdown. -> - Use a single main title (`#`) and clear primary subheadings (`##`). -> - Keep paragraphs short (3–5 sentences, ≤150 words). -> - Break large topics into labeled subsections. -> - Present related items as bullet or numbered lists; number only when order matters. -> - Always leave a blank line before and after each paragraph. -> - Avoid bold or italic styling in body text unless explicitly requested. -> - Use horizontal dividers (`---`) between major sections. -> - Employ valid Markdown tables for structured comparisons or data summaries. -> - Refrain from complex Unicode symbols; stick to simple characters. -> - Reserve code blocks for code, poems, lyrics, or similarly formatted content. -> - For mathematical expressions, use LaTeX outside of code blocks. - -As the above suggests, Markdown's syntax is completely different from wikitext's: Markdown uses asterisks (*) or underscores (_) instead of single-quotes (') for bold and italic formatting, hash symbols (#) instead of equals signs (=) for section headings, parentheses (()) instead of square brackets ([]) around URLs, and three symbols (---, ***, or ___) instead of four hyphens (----) for thematic breaks. - -Even when they are told to do so explicitly, chatbots generally struggle to generate text using syntactically correct wikitext, as their training data lead to a drastically greater affinity for and fluency in Markdown. When told to "generate an article", a chatbot typically defaults to using Markdown for the generated output, which is preserved in clipboard text by the copy functions on some chatbot platforms. If instructed to generate content for Wikipedia, the chatbot might "realize" the need to generate Wikipedia-compatible code, and might include a message like "Would you like me to ... turn this into actual Wikipedia markup format (`wikitext`)?"[^b] in its output. If the chatbot is told to proceed, the resulting syntax is often rudimentary, syntactically incorrect, or both. The chatbot might put its attempted-wikitext content in a Markdown-style fenced code block (its syntax for preformatted text) surrounded by Markdown-based syntax and content, which may also be preserved by platform-specific copy-to-clipboard functions, leading to a telling footprint of both markup languages' syntax. This might include the appearance of three backticks in the text, such as: ` ```wikitext `.[^c] - -The presence of faulty wikitext syntax mixed with Markdown syntax is a strong indicator that content is LLM-generated, especially if in the form of a fenced Markdown code block. However, Markdown *alone* is not such a strong indicator. Software developers, researchers, technical writers, and experienced internet users frequently use Markdown in tools like [Obsidian](https://en.wikipedia.org/wiki/Obsidian_(software) "Obsidian (software)") and [GitHub](https://en.wikipedia.org/wiki/GitHub_Flavored_Markdown "GitHub Flavored Markdown"), and on platforms like Reddit, Discord, and Slack. Some writing tools and apps, such as iOS Notes, Google Docs, and Windows Notepad, support Markdown editing or exporting. The increasing ubiquity of Markdown may also lead new editors to expect or assume Wikipedia to support Markdown by default. - -**Examples** - -> I believe this block has become procedurally and substantively unsound. Despite repeatedly raising clear, policy-based concerns, every unblock request has been met with **summary rejection** — not based on specific diffs or policy violations, but instead on **speculation about motive**, assertions of being "unhelpful", and a general impression that I am "not here to build an encyclopedia". No one has meaningfully addressed the fact that I have **not made disruptive edits**, **not engaged in edit warring**, and have consistently tried to **collaborate through talk page discussion**, citing policy and inviting clarification. Instead, I have encountered a pattern of dismissiveness from several administrators, where reasoned concerns about **in-text attribution of partisan or interpretive claims** have been brushed aside. Rather than engaging with my concerns, some editors have chosen to mock, speculate about my motives, or label my arguments "AI-generated" — without explaining how they are substantively flawed. - -> - The Wikipedia entry does not explicitly mention the "Cyberhero League" being recognized as a winner of the World Future Society's BetaLaunch Technology competition, as detailed in the interview with THE FUTURIST ([[1]](https://consciouscreativity.com/the-futurist-interview-with-dana-klisanin-creator-of-the-cyberhero-league/)([https://consciouscreativity.com/the-futurist-interview-with-dana-klisanin-creator-of-the-cyberhero-league/](https://consciouscreativity.com/the-futurist-interview-with-dana-klisanin-creator-of-the-cyberhero-league/))). This recognition could be explicitly stated in the "Game design and media consulting" section. - -Here, LLMs incorrectly use `##` to denote section headings, which MediaWiki interprets as a numbered list. - -> 1. 1. Geography -> -> Villers-Chief is situated in the [Jura Mountains](https://en.wikipedia.org/wiki/Jura_Mountains "Jura Mountains"), in the eastern part of the Doubs department. [...] -> -> 1. 1. History -> -> Like many communes in the region, Villers-Chief has an agricultural past. [...] -> -> 1. 1. Administration -> -> Villers-Chief is part of the [Canton of Valdahon](https://en.wikipedia.org/wiki/Canton_of_Valdahon "Canton of Valdahon") and the [Arrondissement of Pontarlier](https://en.wikipedia.org/wiki/Arrondissement_of_Pontarlier "Arrondissement of Pontarlier"). [...] -> -> 1. 1. Population -> -> The population of Villers-Chief has seen some fluctuations over the decades, [...] - -Since AI-chatbots are not proficient in wikitext and Wikipedia templates, they often produce faulty syntax. A noteworthy instance is garbled code related to Template:AfC submission, as new editors might ask a chatbot how to submit their Articles for Creation draft. - -**Examples** - -Note the badly malformed category link which appears to be a result of code that provides day information in the LLM's Markdown parser: - -``` -[[Category:AfC submissions by date/<0030Fri, 13 Jun 2025 08:18:00 +0000202568 2025-06-13T08:18:00+00:00Fridayam0000=error>EpFri, 13 Jun 2025 08:18:00 +0000UTC00001820256 UTCFri, 13 Jun 2025 08:18:00 +0000Fri, 13 Jun 2025 08:18:00 +00002025Fri, 13 Jun 2025 08:18:00 +0000: 17498026806Fri, 13 Jun 2025 08:18:00 +0000UTC2025-06-13T08:18:00+00:0020258618163UTC13 pu62025-06-13T08:18:00+00:0030uam301820256 2025-06-13T08:18:00+00:0008amFri, 13 Jun 2025 08:18:00 +0000am2025-06-13T08:18:00+00:0030UTCFri, 13 Jun 2025 08:18:00 +0000 &qu202530;:&qu202530;.June 2025|sandbox]] -``` - -### ChatGPT-specific markup: citeturn, iturn - -ChatGPT may include `citeturn0search0` (surrounded by Unicode points in the Private Use Area) at the ends of sentences, with the number after "search" increasing as the text progresses. These are places where the chatbot links to an external site, but a human pasting the conversation into Wikipedia has that link converted into placeholder code. This was first observed in February 2025. - -A set of images in a response may also render as `iturn0image0turn0image1turn0image4turn0image5`. Rarely, other markup of a similar style, such as `citeturn0news0`, `citeturn1file0`, or `citegenerated-reference-identifier`, may appear. - -**Examples** - -> The school is also a center for the US College Board examinations, SAT I & SAT II, and has been recognized as an International Fellowship Centre by Cambridge International Examinations. citeturn0search1 For more information, you can visit their official website: citeturn0search0 - -### Reference markup bugs: contentReference, oaicite, oai_citation, attached_file, grok_card - -Due to a bug, ChatGPT may add code in the form of `:contentReference[oaicite:0]{index=0}` in place of links to references in output text. Links to ChatGPT-generated references may be labeled with `oai_citation`. - -**Examples** - -> :contentReference[oaicite:16]{index=16} -> -> 1. **Ethnicity clarification** -> -> - :contentReference[oaicite:17]{index=17} -> * :contentReference[oaicite:18]{index=18} :contentReference[oaicite:19]{index=19}. -> * Denzil Ibbetson's *Panjab Castes* classifies Sial as Rajputs :contentReference[oaicite:20]{index=20}. -> * Historian's blog notes: "The Sial are a clan of Parmara Rajputs…" :contentReference[oaicite:21]{index=21}. -> 2. :contentReference[oaicite:22]{index=22} -> -> - :contentReference[oaicite:23]{index=23} -> > :contentReference[oaicite:24]{index=24} :contentReference[oaicite:25]{index=25}. - -> #### Key facts needing addition or correction: -> -> 1. **Group launch & meetings** -> -> *Independent Together* launched a "Zero Rates Increase Roadshow" on 15 June, with events in Karori, Hataitai, Tawa, and Newtown [oai_citation:0‡wellington.scoop.co.nz](https://wellington.scoop.co.nz/?p=171473&utm_source=chatgpt.com). -> -> 2. **Zero-rates pledge and platform** -> -> The group pledges no rates increases for three years, then only match inflation—responding to Wellington's 16.9% hike for 2024/25 [oai_citation:1‡en.wikipedia.org](https://en.wikipedia.org/wiki/Independent_Together?utm_source=chatgpt.com). - -As of fall 2025, tags like `[attached_file:1]`, `[web:1]` have been seen at the end of sentences. This may be Perplexity-specific.[^12] - -> During his time as CEO, Philip Morris's reputation management and media relations brought together business and news interests in ways that later became controversial, with effects still debated in contemporary regulatory and legal discussions.[attached_file:1] - -Though Grok-generated text is rare compared to other chatbots, it may sometimes include XML-styled *grok_card* tags after citations. - -> Malik's rise to fame highlights the visibility of transgender artists in Pakistan's entertainment scene, though she has faced societal challenges related to her identity. [...] - -### attribution and attributableIndex - -ChatGPT may add JSON-formatted code at the end of sentences in the form of `({"attribution":{"attributableIndex":"X-Y"}})`, with X and Y being increasing numeric indices. - -**Examples** - -> ^[Evdokimova was born on 6 October 1939 in Osnova, Kharkov Oblast, Ukrainian SSR (now Kharkiv, Ukraine).]({"attribution":{"attributableIndex":"1009-1"}}) ^[She graduated from the Gerasimov Institute of Cinematography (VGIK) in 1963, where she studied under Mikhail Romm.]({"attribution":{"attributableIndex":"1009-2"}}) [oai_citation:0‡IMDb](https://www.imdb.com/name/nm0947835/?utm_source=chatgpt.com) [oai_citation:1‡maly.ru](https://www.maly.ru/en/people/EvdokimovaA?utm_source=chatgpt.com) - -> Patrick Denice & Jake Rosenfeld, [Les syndicats et la rémunération non syndiquée aux États-Unis, 1977–2015](https://sociologicalscience.com/articles-v5-23-541/), ''Sociological Science'' (2018).]({"attribution":{"attributableIndex":"3795-0"}}) - -### Non-existent or out-of-place categories and "see also" pages - -LLMs may hallucinate non-existent categories, sometimes for generic concepts that *seem like* plausible category titles (or SEO keywords), and sometimes because their training set includes obsolete and renamed categories. These will appear as red links. You may also find category redirects, such as the longtime spammer favorite Category:Entrepreneurs. Sometimes, broken categories may be deleted by reviewers, so if you suspect a page may be LLM-generated, it may be worth checking earlier revisions. - -Pay attention to blue links under "see also" headers as well. LLM-generated "see also" sections often tend to fill them up (to at least three links) seemingly out of obligation. If a new page/draft on some startup links to a broad term like Financial technology in its see-also section, that's a bit suspicious. - -Of course, none of this section should be treated as a hard-and-fast rule. New users are unlikely to know about Wikipedia's style guidelines for these sections, and returning editors may be used to old categories that have since been deleted. - -**Examples** - -``` -[[Category:American hip hop musicians]] -``` - -rather than - -``` -[[Category:American hip-hop musicians]] -``` - ---- - -## Citations - -### Fictitious or hallucinated references - -LLMs may generate fictitious or hallucinated references that do not exist or contain fabricated information. - -### Broken external links - -If a new article or draft has multiple citations with external links, and several of them are broken (e.g., returning [404 errors](https://en.wikipedia.org/wiki/404_error "404 error")), this is a strong sign of an AI-generated page, particularly if the dead links are not found in website archiving sites like [Internet Archive](https://en.wikipedia.org/wiki/Internet_Archive "Internet Archive") or [Archive Today](https://en.wikipedia.org/wiki/Archive_Today "Archive Today"). Most links [become broken over time](https://en.wikipedia.org/wiki/Link_rot "Link rot"), but these factors make it unlikely that the link was ever real. - -### Invalid DOI and ISBNs - -A [checksum](https://en.wikipedia.org/wiki/Checksum "Checksum") can be used to verify [ISBNs](https://en.wikipedia.org/wiki/ISBN "ISBN"). An invalid checksum is a very likely sign that an ISBN is incorrect, and citation templates display a warning if so. Similarly, [DOIs](https://en.wikipedia.org/wiki/Digital_object_identifier "Digital object identifier") are more resistant to link rot than regular hyperlinks. Unresolvable DOIs and invalid ISBNs can be indicators of [hallucinated](https://en.wikipedia.org/wiki/Hallucination_(AI) "Hallucination (AI)") references. - -Related are DOIs that point to entirely unrelated articles and general book citations without pages. This passage, for example, was generated by ChatGPT. - -> Ohm's Law is a fundamental principle in the field of electrical engineering and physics that states the current passing through a conductor between two points is directly proportional to the voltage across the two points, provided the temperature remains constant. Mathematically, it is expressed as V=IR, where V is the voltage, I is the current, and R is the resistance. The law was formulated by German physicist Georg Simon Ohm in 1827, and it serves as a cornerstone in the analysis and design of electrical circuits [1]. Ohm's Law applies to many materials and components that are "ohmic," meaning their resistance remains constant regardless of the applied voltage or current. However, it does not hold for non-linear devices like diodes or transistors [2][3]. -> -> References: -> -> 1. Dorf, R. C., & Svoboda, J. A. (2010). Introduction to Electric Circuits (8th ed.). Hoboken, NJ: John Wiley & Sons. ISBN 9780470521571. -> -> 2. M. E. Van Valkenburg, "The validity and limitations of Ohm's law in non-linear circuits," Proceedings of the IEEE, vol. 62, no. 6, pp. 769–770, Jun. 1974. doi:10.1109/PROC.1974.9547 -> -> 3. C. L. Fortescue, "Ohm's Law in alternating current circuits," Proceedings of the IEEE, vol. 55, no. 11, pp. 1934–1936, Nov. 1967. doi:10.1109/PROC.1967.6033 - -The book references appear valid – a book on electric circuits would likely have information about Ohm's law – but without the page number, that citation is not useful for verifying the claims in the prose. Worse, both *Proceedings of the IEEE* citations are completely made up. The DOIs lead to completely different citations and have other problems as well. For instance, [C. L. Fortescue](https://en.wikipedia.org/wiki/Charles_LeGeyt_Fortescue "Charles LeGeyt Fortescue") was dead for 30+ years at the purported time of writing, and Vol 55, Issue 11 does not list any articles that match anything remotely close to the information given in reference 3. - -### Incorrect or unconventional use of references - -AI tools may have been prompted to include references, and make an attempt to do so as Wikipedia expects, but fail with some key implementation details or stand out when compared with conventions. - -**Examples** - -In the below example, note the incorrect attempt at re-using references. The tool used here was not capable of searching for non-confabulated sources (as it was done the day before Bing Deep Search launched) but nonetheless found one real reference. The syntax for re-using the references was incorrect. - -In this case, the *Smith, R. J.* source – being the "third source" the tool presumably generated the link 'https://pubmed.ncbi.nlm.nih.gov/3' (which has a PMID reference of 3) – is also completely irrelevant to the body of the article. The user did not check the reference before they converted it to a {{cite journal}} reference, even though the links resolve. - -The LLM in this case has diligently included the incorrect re-use syntax after every single full stop. - -> For over thirty years, computers have been utilized in the rehabilitation of individuals with brain injuries. Initially, researchers delved into the potential of developing a "prosthetic memory."Fowler R, Hart J, Sheehan M. A prosthetic memory: an application of the prosthetic environment concept. *Rehabil Counseling Bull*. 1972;15:80–85. However, by the early 1980s, the focus shifted towards addressing brain dysfunction through repetitive practice.{{Cite journal |last=Smith |first=R. J. |last2=Bryant |first2=R. G. |date=1975-10-27 |title=Metal substitutions incarbonic anhydrase: a halide ion probe study |url=https://pubmed.ncbi.nlm.nih.gov/3 |journal=Biochemical and Biophysical Research Communications |volume=66 |issue=4 |pages=1281–1286 |doi=10.1016/0006-291x(75)90498-2 |issn=0006-291X |pmid=3}} Only a few psychologists were developing rehabilitation software for individuals with Traumatic Brain Injury (TBI), resulting in a scarcity of available programs.[3] Cognitive rehabilitation specialists opted for commercially available computer games that were visually appealing, engaging, repetitive, and entertaining, theorizing their potential remedial effects on neuropsychological dysfunction.[3] - -Some LLMs or chatbot interfaces use the character ↩ to indicate footnotes: - -> References -> -> Would you like help formatting and submitting this to Wikipedia, or do you plan to post it yourself? I can guide you step-by-step through that too. -> -> **Footnotes** -> -> 1. KLAS Research. (2024). *Top Performing RCM Vendors 2024*. https://klasresearch.com ↩ ↩2 -> 2. PR Newswire. (2025, February 18). *CureMD AI Scribe Launch Announcement*. https://www.prnewswire.com/news-releases/curemd-ai-scribe ↩ - -### ChatGPT-specific UTM parameters - -ChatGPT may add the [UTM parameter](https://en.wikipedia.org/wiki/UTM_parameter "UTM parameter") `utm_source=openai` or, in edits prior to August 2025, `utm_source=chatgpt.com` to URLs that it is using as sources. Other LLMs, such as Gemini or Claude, use UTM parameters less often.[^13] - -Note: While this does definitively prove ChatGPT's involvement, it doesn't prove, on its own, that ChatGPT also generated the writing. Some editors use AI tools to find citations for existing text; this will be apparent in the edit history. - -**Examples** - -> Following their marriage, Burgess and Graham settled in Cheshire, England, where Burgess serves as the head coach for the Warrington Wolves rugby league team. [https://www.theguardian.com/sport/2025/feb/11/sam-burgess-interview-warrington-rugby-league-luke-littler?utm_source=chatgpt.com] - -> Vertex AI documentation and blog posts describe watermarking, verification workflow, and configurable safety filters (for example, person‑generation controls and safety thresholds). ([cloud.google.com](https://cloud.google.com/vertex-ai/generative-ai/docs/image/generate-images?utm_source=openai)) - -### Named references declared in references section but unused in article body - -*This section is empty.* You can help by adding to it. *(October 2025)* - -**Examples** - -See these diffs for examples. The problematic references appear as parser errors in the reflist. - -- [Special:PermanentLink/1287201002#References](https://en.wikipedia.org/wiki/Special:PermanentLink/1287201002#References "Special:PermanentLink/1287201002") -- [Special:PermanentLink/1292432848#References](https://en.wikipedia.org/wiki/Special:PermanentLink/1292432848#References "Special:PermanentLink/1292432848") -- [Special:PermanentLink/1291491974#References](https://en.wikipedia.org/wiki/Special:PermanentLink/1291491974#References "Special:PermanentLink/1291491974") -- [Special:PermanentLink/1291561040#References](https://en.wikipedia.org/wiki/Special:PermanentLink/1291561040#References "Special:PermanentLink/1291561040") - ---- - -## Discrepancies in Writing Style and Variety of English - -### Abrupt cut offs - -AI tools may abruptly stop generating content, for example if they predict the end of text sequence (appearing as `<|endoftext|>`) next. Also, the number of tokens that a single response has is usually limited, and further responses require the user to select "continue generating". - -This method is not foolproof, as a malformed copy/paste from one's local computer can also cause this. It may also indicate a copyright violation rather than the use of an LLM. - -### Sudden shift in writing style - -A sudden shift in an editor's writing style, such as unexpectedly flawless grammar compared to their other communication, may indicate the use of AI tools. - -### Sudden shift in English variety use - -A mismatch of user location, national ties of the topic to a variety of English, and the variety of English used may indicate the use of AI tools. A human writer from India writing about an Indian university would probably not use American English; however, LLM outputs use American English by default, unless prompted otherwise.[^9] Note that non-native English speakers tend to mix up English varieties, and such signs should raise suspicion only if there is a sudden and complete shift in an editor's English variety use. - -### Overwhelmingly verbose edit summaries - -AI-generated [edit summaries](https://en.wikipedia.org/wiki/Help:Edit_summary "Help:Edit summary") are often unusually long, written as formal, first-person paragraphs without abbreviations, and/or conspicuously itemize Wikipedia's conventions. - -> Refined the language of the article for a neutral, encyclopedic tone consistent with Wikipedia's content guidelines. Removed promotional wording, ensured factual accuracy, and maintained a clear, well-structured presentation. Updated sections on history, coverage, challenges, and recognition for clarity and relevance. Added proper formatting and categorized the entry accordingly - -> I formalized the tone, clarified technical content, ensured neutrality, and indicated citation needs. Historical narratives were streamlined, allocation details specified with regulatory references, propagation explanations made reader-friendly, and equipment discussions focused on availability and regulatory compliance, all while adhering to encyclopedic standards. - -> **Concise edit summary:** Improved clarity, flow, and readability of the plot section; reduced redundancy and refined tone for better encyclopedic style. - -### "Submission statements" in AFC drafts - -This one is specific to drafts submitted by Articles for Creation. At least one LLM tends to insert "submission statements" supposedly intended for reviewers that supposedly explain why the subject is notable and why the draft meets Wikipedia guidelines. Of course, all this actually does is let reviewers know that the draft is LLM-generated, and should be declined or speedied without a second thought. - -> Reviewer note (for AfC): This draft is a neutral and well-sourced biography of Portuguese public manager Jorge Patrão. All references are from independent, reliable sources (Público, Diário de Notícias, Jornal de Negócios, RTP, O Interior, Agência Lusa) covering his public career and cultural activity. It meets WP:RS and WP:BLP standards and demonstrates clear notability per WP:NBIO through: – Presidency of Serra da Estrela Tourism Region (1998–2013); – Presidency of Parkurbis – Covilhã Science and Technology Park; – Founding role in Rede de Judiarias de Portugal (member of the Council of Europe's European Routes of Jewish Heritage); – Authorship of the book "1677 – A Fábrica d'El-Rei"; – Founder/curator of the Beatriz de Luna Art Collection (Old Master focus). There is also a Portuguese version of this article at pt.wikipedia.org/wiki/Jorge_Patrão. Thank you for your review. --> - -— Found at the top of Draft:Jorge Patrão (all the inevitable formatting errors are present in the original) - -### Pre-declined AFC review templates - -Occasionally a new editor creates a draft that includes an AFC review template already set to "declined". The template is also devoid of content with no reviewer reasoning given. The LLM apparently offers to add an AFC submission template to the draft, and then provides something like `{{AfC submission|d}}`, in which the "d" parameter pre-declines the draft by substituting {{AfC submission/declined}}. The draft's contribution history reveals that this template was inserted at some point by the draft's creator. Invariably the creator then asks on Wikipedia:WikiProject Articles for creation/Help desk or one of the other help pages why the draft was declined with no feedback. The presence of a content-free "submission declined" header is a **strong** indicator that the draft was LLM-generated. - ---- - -## Signs of Human Writing - -### Age of text relative to ChatGPT launch - -ChatGPT was launched to the public on November 30, 2022. Although OpenAI had similarly powerful LLMs before then, they were paid services and not easily accessible or known to lay people. ChatGPT experienced extreme growth immediately on launch. - -It is very unlikely that any particular text added to Wikipedia **prior to November 30, 2022** was generated by an LLM. If an edit was made before this date, AI use can be safely ruled out for that revision. While some older text may display some of the AI signs given in this list, and even convincingly appear to have been AI-generated, the vastness of Wikipedia allows for these rare coincidences. - -### Ability to explain one's own editorial choices - -Editors should be able to explain why they made one or more edits or mistakes. For example, if an editor inserts a URL that appears fabricated, you can ask how the mix-up occurred instead of jumping to conclusions. If they can supply the correct link and explain it as a human error (perhaps a typo), or share the relevant passage from the real source, that points to an ordinary human error. - ---- - -## Ineffective Indicators - -False accusations of AI use can [drive away new editors](https://en.wikipedia.org/wiki/Wikipedia:BITE "Wikipedia:BITE") and foster an atmosphere of suspicion. Before claiming AI was used, consider if [Dunning–Kruger effect](https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect "Dunning–Kruger effect") and [confirmation bias](https://en.wikipedia.org/wiki/Confirmation_bias "Confirmation bias") is clouding your judgement. Here are several somewhat commonly used indicators that are ineffective in LLM detection—and may even indicate the opposite. - -- **Perfect grammar**: While modern LLMs are known for their high grammatical proficiency, many editors are also skilled writers or come from professional writing backgrounds. (See also [§ Discrepancies in writing style and variety of English](#discrepancies-in-writing-style-and-variety-of-english).) - -- **"Bland" or "robotic" prose**: By default, modern LLMs tend toward effusive and verbose prose, as detailed above; while this tendency is formulaic, it may not scan as "robotic" to those unfamiliar with AI writing.[^14] - -- **"Fancy," "academic," or unusual words**: While LLMs disproportionately favor certain words and phrases, many of which are long and have difficult readability scores, the correlation does not extend to *all* "fancy," academic, or "advanced"-sounding prose.[^1] Low-frequency and "unusual" words are also less likely to show up in AI-generated writing as they are statistically less common, unless they are proper nouns directly related to the topic. - -- **Letter-like writing (in isolation)**: Although many talk page messages written with salutations, valedictions, subject lines, and other formalities after 2023 tend to appear AI-generated, letters and emails have conventionally been written in such ways *long* before modern LLMs existed. Human editors (particularly newer editors) may format their talk page comments similarly for various reasons, such as being more accustomed to formal communication, posting as part of a school assignment that requires such at one, or simply mistaking the talk page for email. AI-generated talk page messages tend to have other tells, such as vertical lists,[^d] placeholders, or abrupt cutoffs. - -- **Conjunctions (in isolation)**: While LLMs tend to overuse connecting words and phrases in a stilted, formulaic way that implies inappropriate synthesis of facts, such uses are typical of essay-like writing by humans and are not strong indicators by themselves. - -- **Bizarre wikitext**: While LLMs may hallucinate templates or generate wikitext code with invalid syntax for reasons explained in [§Use of Markdown](#use-of-markdown), they are not likely to generate content with certain random-seeming, "inexplicable" errors and artifacts (excluding the ones listed on this page in [§Markup](#markup)). Bizarrely placed HTML tags like `` are more indicative of poorly programmed browser extensions or a known bug with Wikipedia's content translation tool (T113137). Misplaced syntax like `''Catch-22 i''s a satirical novel.` (rendered as "*Catch-22 i* s a satirical novel.") are more indicative of mistakes in VisualEditor, where such errors are harder to notice than in source editing. - ---- - -## Notes - -[^a]: not unique to AI chatbots; is produced by the {{as of}} template - -[^b]: Example of `Would you like me to ... turn this into actual Wikipedia markup format (wikitext)?` in a deleted draft (administrators only) - -[^c]: Example of ` ```wikitext ` on a draft. - -[^d]: Example of a vertical list in a deletion discussion - ---- - -## References - -[^1]: Russell, Jenna; Karpinska, Marzena; Iyyer, Mohit (2025). [*People who frequently use ChatGPT for writing tasks are accurate and robust detectors of AI-generated text*](https://aclanthology.org/2025.acl-long.267/). Proceedings of the 63rd Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). Vienna, Austria: Association for Computational Linguistics. pp.5342–5373. arXiv:[2501.15654](https://arxiv.org/abs/2501.15654). - -[^2]: Dugan, Liam; Hwang, Alyssa; Trhlik, Filip; Zhu, Andrew; Ludan, Josh Magnus; Xu, Hainiu; Ippolito, Daphne; Callison-Burch, Chris (2024). [*RAID: A Shared Benchmark for Robust Evaluation of Machine-Generated Text Detectors*](https://aclanthology.org/2024.acl-long.674). Proceedings of the 62nd Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). Bangkok, Thailand: Association for Computational Linguistics. pp.12463–12492. arXiv:[2405.07940](https://arxiv.org/abs/2405.07940). - -[^3]: ["People who frequently use ChatGPT for writing tasks are accurate and robust detectors of AI-generated text"](https://arxiv.org/html/2501.15654v2). *arxiv.org*. Retrieved 2025-11-28. - -[^4]: This can be directly observed by examining images generated by text-to-image models; they look acceptable at first glance, but specific details tend to be blurry and malformed. This is especially true for background objects and text. - -[^5]: ["10 Ways AI Is Ruining Your Students' Writing"](https://www.chronicle.com/article/10-ways-ai-is-ruining-your-students-writing). *Chronicle of Higher Education*. September 16, 2025. Archived from the original on October 1, 2025. Retrieved October 1, 2025. - -[^6]: Juzek, Tom S.; Ward, Zina B. (2025). [*Why Does ChatGPT "Delve" So Much? Exploring the Sources of Lexical Overrepresentation in Large Language Models*](https://aclanthology.org/2025.coling-main.426.pdf) (PDF). Findings of the Association for Computational Linguistics: ACL 2025. Association for Computational Linguistics. arXiv:[2412.11385](https://arxiv.org/abs/2412.11385). - -[^7]: Reinhart, Alex; Markey, Ben; Laudenbach, Michael; Pantusen, Kachatad; Yurko, Ronald; Weinberg, Gordon; Brown, David West. ["Do LLMs write like humans? Variation in grammatical and rhetorical styles"](http://arxiv.org/abs/2410.16107). Retrieved 4 December 2025. - -[^8]: Kobak, Dmitry; González-Márquez, Rita; Horvát, Emőke-Ágnes; Lause, Jan (2 July 2025). ["Delving into LLM-assisted writing in biomedical publications through excess vocabulary"](https://www.science.org/doi/10.1126/sciadv.adt3813). *Science Advances*. **11** (27). doi:[10.1126/sciadv.adt3813](https://doi.org/10.1126%2Fsciadv.adt3813). ISSN 2375-2548. PMC 12219543. PMID 40009654. - -[^9]: Ju, Da; Blix, Hagen; Williams, Adina (2025). [*Domain Regeneration: How well do LLMs match syntactic properties of text domains?*](https://aclanthology.org/2025.findings-acl.120). Findings of the Association for Computational Linguistics: ACL 2025. Vienna, Austria: Association for Computational Linguistics. pp.2367–2388. arXiv:[2505.07784](https://arxiv.org/abs/2505.07784). doi:[10.18653/v1/2025.findings-acl.120](https://doi.org/10.18653%2Fv1%2F2025.findings-acl.120). - -[^10]: Kousha, Kayvan; Thelwall, Mike (2025). [*How much are LLMs changing the language of academic papers after ChatGPT? A multi-database and full text analysis*](https://arxiv.org/pdf/2509.09596). ISSI 2025 Conference. arXiv:[2509.09596](https://arxiv.org/abs/2509.09596). - -[^11]: Merrill, Jeremy B.; Chen, Szu Yu; Kumer, Emma (13 November 2025). ["What are the clues that ChatGPT wrote something? We analyzed its style"](https://www.washingtonpost.com/technology/interactive/2025/how-detect-chatgpt-em-dash/). *The Washington Post*. Retrieved 14 November 2025. - -[^12]: ["Unproductive Interpretation of Work and Employment as Misinformation?"](https://www.laetusinpraesens.org/docs20s/workeco.php). Archived from the original on 2 September 2025. Retrieved 21 October 2025. - -[^13]: See [T387903](https://phabricator.wikimedia.org/T387903 "phabricator:T387903"). - -[^14]: Murray, Nathan; Tersigni, Elisa (21 July 2024). ["Can instructors detect AI-generated papers? Postsecondary writing instructor knowledge and perceptions of AI"](https://journals.sfu.ca/jalt/index.php/jalt/article/view/1895). *Journal of Applied Learning & Teaching*. **7** (2). doi:[10.37074/jalt.2024.7.2.12](https://doi.org/10.37074%2Fjalt.2024.7.2.12). ISSN 2591-801X. Retrieved 21 November 2025. diff --git a/builtin-skills/my-writing-style/README.md b/builtin-skills/my-writing-style/README.md deleted file mode 100644 index 1ef85ef4..00000000 --- a/builtin-skills/my-writing-style/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Writing Style Skill - -可复用的写作风格 Skill 模板。**内置自动学习** — 从你的修改中自动提取规则,SKILL.md 越用越准。 - -兼容 **Claude Code** + **OpenClaw (ClawHub)**。 - -## 原理 - -``` -AI 用 SKILL.md 写初稿 → 你改到满意 → diff 两版 → 提取规则 → 更新 SKILL.md → 下次更准 -``` - -只要两个数据点:**original**(AI 第一版)和 **final**(你最终版)。中间改了多少轮不管。 - -## 安装 - -```bash -# Claude Code -git clone https://github.com/jzOcb/writing-style-skill.git -cp -r writing-style-skill ~/.claude/skills/my-writing-style - -# OpenClaw / ClawHub -npx clawhub@latest install jz-writing-style-skill -``` - -## 快速开始 - -1. **改 SKILL.md** — 把模板里的风格规则改成你自己的(或留空,让自动学习帮你填) -2. **让 AI 用这个 skill 写内容** -3. **你改到满意** -4. 记录: -```bash -python3 scripts/observe.py record-original draft.md -# ... 你修改 ... -python3 scripts/observe.py record-final final.md -``` -5. 提取规则: -```bash -python3 scripts/improve.py auto --skill . -``` - -## 文件结构 - -``` -writing-style-skill/ -├── SKILL.md # 你的写作风格(模板,改成你的) -├── README.md # 本文件 -└── scripts/ - ├── observe.py # 记录 original / final(零依赖) - └── improve.py # 提取 / 应用 / 回滚(需要 LLM CLI) -``` - -## 自动学习怎么工作 - -- `observe.py` 记录 AI 原稿和你的最终版 -- `improve.py` 用 LLM 分析 diff,提取写作规则 -- 规则按置信度分 P0/P1/P2,P0 自动应用 -- 每次更新前自动备份,一键回滚 - -## LLM 支持 - -`improve.py` 自动检测: -- `claude` (Claude Code) — 优先 -- `llm` (pip install llm) — 通用 -- `IMPROVE_LLM_CMD` 环境变量 — 自定义 - -`observe.py` 零依赖纯 Python。 - -## License - -MIT diff --git a/builtin-skills/my-writing-style/SKILL.md b/builtin-skills/my-writing-style/SKILL.md deleted file mode 100644 index 08cc2901..00000000 --- a/builtin-skills/my-writing-style/SKILL.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -name: my-writing-style -version: 1.0.0 -description: | - 可复用的写作风格 Skill 模板。内置自动学习: - 从你的修改中自动提取规则,SKILL.md 越用越准。 - Fork 后改成你自己的风格。 -dependencies: [] -allowed-tools: - - Read - - Write - - Edit - - exec ---- - -# Writing Style Skill(模板) - -**Fork 这个 skill,改成你的写作风格。内置自动学习,越用越准。** - ---- - -## 🎯 怎么用 - -1. Fork / clone 这个 skill -2. 把下面的风格规则改成你自己的 -3. 让 AI 用这个 skill 写内容 -4. 你改到满意 → 脚本自动学习你改了什么 -5. 下次 AI 写出来的就更像你 - ---- - -## 【0】Voice Dimensions(量化你的风格) - -**用 1-10 分定义你的风格维度。AI 比"写得自然一点"这种话更容易理解数字。** - -| Dimension | Score | 你的说明 | -|-----------|-------|---------| -| **formal_casual** | **?/10** | 偏正式还是偏随意? | -| **technical_accessible** | **?/10** | 技术深度? | -| **serious_playful** | **?/10** | 严肃还是活泼? | -| **concise_elaborate** | **?/10** | 简洁还是详细? | -| **reserved_expressive** | **?/10** | 保守还是直接? | - -> 💡 **不知道填什么?** 先跑几次 AI 写作 → 你改 → 自动学习会帮你填。 - ---- - -## 【1】角色与读者 - -**我是谁:** -- (填你的身份,比如:独立开发者,新晋 AI 爱好者) - -**读者是谁:** -- (填你的读者,比如:对 AI 感兴趣的技术人) - -**和读者的关系:** -- (比如:同行交流,不是教学) - ---- - -## 【2】写作规则 - -### 基础规则 - -- (填你的规则,比如:不用"深入探讨"、段落要短、要有具体数字) -- -- - -### 禁止词 - -- (AI 爱用但你不喜欢的词,比如:值得注意的是、综上所述、本文将介绍) -- -- - -### 句式偏好 - -- (你喜欢的句式,比如:结论前置、不要学术导语) -- -- - -> 💡 **不需要一开始就写完。** 这些规则会通过你的修改自动积累。 -> 跑完 10 次写作→修改循环后,这里会长出几十条精准规则。 - ---- - -## 【3】格式规范 - -### 平台适配 - -| 平台 | 格式要求 | -|------|---------| -| X/Twitter | 不渲染 markdown,用纯文本 | -| 小红书 | emoji 多、分段短 | -| 博客 | 标准 markdown | -| (你的平台) | (你的要求)| - ---- - -## 🔄 自动学习(内置) - -**这个 skill 会从你的修改中自动学习。不需要手动写规则。** - -### 工作原理 - -``` -AI 用这个 skill 写初稿 - ↓ -你改到满意 - ↓ -脚本 diff 两版 → 提取你改了什么 - ↓ -新规则自动写入这个 SKILL.md - ↓ -下次 AI 写出来就更像你 -``` - -### 只需要两个数据点 - -- **original**: AI 生成的第一版 -- **final**: 你最终确认的版本 - -中间改了几轮不管。在 Google Doc 里来回改了 10 次?无所谓,只比较首尾。 - -### Agent 操作指南 - -**写完内容后:** -```bash -python3 scripts/observe.py record-original --account <账号> --content-type <类型> -``` - -**人类确认最终版后:** -```bash -python3 scripts/observe.py record-final --match -``` - -**提取规则(手动或 cron 自动):** -```bash -python3 scripts/improve.py auto --skill . -``` - -### 规则分级 - -| 级别 | 含义 | 处理方式 | -|------|------|---------| -| P0 | 高置信度(多次出现) | 自动应用 | -| P1 | 中置信度 | 人工确认 | -| P2 | 低置信度(仅 1 次) | 存档观察 | - -### 安全 - -- 每次更新前自动备份 SKILL.md -- `improve.py rollback` 一键回滚 -- auto 模式只应用 P0 - ---- - -## 📊 CLI 参考 - -### observe.py(零依赖纯 Python) - -| 命令 | 功能 | -|------|------| -| `record-original ` | 记录 AI 原稿 | -| `record-final --match ` | 记录最终版 | -| `pending` | 查看待配对 | -| `stats` | 统计 | - -### improve.py(需要 LLM CLI) - -| 命令 | 功能 | -|------|------| -| `extract [--days 7]` | 提取改进建议 | -| `auto` | 提取 + 自动应用 P0 | -| `show` | 查看提案 | -| `apply ` | 应用提案 | -| `rollback` | 回滚 | - -支持的 LLM CLI: `claude`(Claude Code)/ `llm`(pip install llm)/ `IMPROVE_LLM_CMD` 环境变量 - ---- - -## 📂 数据存储 - -``` -~/clawd/memory/ # OpenClaw -~/.claude/memory/ # Claude Code -├── skill-runs// -│ └── YYYY-MM-DD.jsonl # 每日观察日志 -├── skill-proposals// -│ └── YYYYMMDD-HHMMSS.md # 改进提案 -└── skill-backups// - └── SKILL-YYYYMMDD-HHMMSS.md # 自动备份 -``` - -自动检测环境,不需要手动配置路径。 - ---- - -## 🚀 30 天预期 - -| 时间 | 预期效果 | -|------|---------| -| 第 1 周 | 积累 3-5 次修改,生成第一批规则 | -| 第 2 周 | 10+ 条规则,AI 输出明显更像你 | -| 第 1 月 | 30+ 条规则,风格维度自动校准 | -| 持续 | 规则库稳定增长,新 pattern 自动捕捉 | diff --git a/builtin-skills/my-writing-style/scripts/improve.py b/builtin-skills/my-writing-style/scripts/improve.py deleted file mode 100644 index 5f8e36b0..00000000 --- a/builtin-skills/my-writing-style/scripts/improve.py +++ /dev/null @@ -1,426 +0,0 @@ -#!/usr/bin/env python3 -""" -Self-Improving Skill — Improver - -从人类修改中提取规则,更新目标 SKILL.md。 - -用法: - python3 improve.py extract [--days 7] [--date 2026-03-17] - python3 improve.py auto # 提取 + 自动应用 P0(cron 用) - python3 improve.py show # 查看所有提案 - python3 improve.py apply # 应用指定提案 - python3 improve.py rollback # 回滚上次应用 - -环境变量: - SKILL_LOG_DIR — 日志目录 - SKILL_TARGET_PATH — 目标 SKILL.md 路径 - SKILL_PROPOSAL_DIR — 提案目录 - SKILL_BACKUP_DIR — 备份目录 -""" - -import sys -import json -import os -import argparse -import subprocess -import shutil -from pathlib import Path -from datetime import datetime, timedelta - -# 默认路径 — 自动检测 OpenClaw (~/.openclaw) 或 Claude Code (~/.claude) -def _detect_base(): - """检测数据存储基目录""" - # 优先级: 环境变量 > ~/clawd > ~/.openclaw > ~/.claude > ~/.self-improving - if os.environ.get("SKILL_BASE_DIR"): - return Path(os.environ["SKILL_BASE_DIR"]) - candidates = [ - Path.home() / "clawd" / "memory", - Path.home() / ".openclaw" / "memory", - Path.home() / ".claude" / "memory", - ] - for c in candidates: - if c.parent.exists(): - return c - return Path.home() / ".self-improving" / "memory" - -_BASE = _detect_base() -DEFAULT_LOG_DIR = _BASE / "skill-runs" / "default" -DEFAULT_PROPOSAL_DIR = _BASE / "skill-proposals" / "default" -DEFAULT_BACKUP_DIR = _BASE / "skill-backups" / "default" - - -def get_paths(args=None): - """解析所有路径配置""" - skill_name = "default" - if args and hasattr(args, 'skill') and args.skill: - skill_name = Path(args.skill).name - - base = Path.home() / "clawd" / "memory" - - log_dir = Path(os.environ.get("SKILL_LOG_DIR", - getattr(args, 'log_dir', None) or - str(base / "skill-runs" / skill_name))) - - proposal_dir = Path(os.environ.get("SKILL_PROPOSAL_DIR", - getattr(args, 'proposal_dir', None) or - str(base / "skill-proposals" / skill_name))) - - backup_dir = Path(os.environ.get("SKILL_BACKUP_DIR", - getattr(args, 'backup_dir', None) or - str(base / "skill-backups" / skill_name))) - - # 目标 SKILL.md - if os.environ.get("SKILL_TARGET_PATH"): - target = Path(os.environ["SKILL_TARGET_PATH"]) - elif args and hasattr(args, 'target') and args.target: - target = Path(args.target) - elif args and hasattr(args, 'skill') and args.skill: - target = Path(args.skill) / "SKILL.md" - else: - target = None - - for d in (log_dir, proposal_dir, backup_dir): - d.mkdir(parents=True, exist_ok=True) - - return log_dir, proposal_dir, backup_dir, target - - -def read_log_entries(log_file): - if not log_file.exists(): - return [] - entries = [] - with log_file.open("r") as f: - for line in f: - line = line.strip() - if line: - try: - entries.append(json.loads(line)) - except json.JSONDecodeError: - continue - return entries - - -def collect_edits(log_dir, days=1, date_str=None): - """收集有实际修改的 final/edited 记录""" - edits = [] - if date_str: - log_file = log_dir / f"{date_str}.jsonl" - entries = read_log_entries(log_file) - edits.extend([e for e in entries - if e["type"] in ("final", "edited") and not e.get("no_change")]) - else: - for i in range(days): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - log_file = log_dir / f"{date}.jsonl" - entries = read_log_entries(log_file) - edits.extend([e for e in entries - if e["type"] in ("final", "edited") and not e.get("no_change")]) - return edits - - -def call_llm(prompt, timeout=180): - """调用 LLM — 自动检测可用的 CLI (claude / openclaw / llm)""" - # 优先级: claude CLI → openclaw exec → generic llm CLI - candidates = [ - ["claude", "--print", "--model", "sonnet"], # Claude Code - ["claude", "--print"], # Claude Code (default model) - ["llm", "-m", "claude-sonnet"], # simon willison's llm CLI - ["llm"], # llm CLI default - ] - for cmd in candidates: - try: - result = subprocess.run(cmd, input=prompt, capture_output=True, - text=True, timeout=timeout) - if result.returncode == 0 and result.stdout.strip(): - return result.stdout.strip() - except (FileNotFoundError, subprocess.TimeoutExpired): - continue - - # fallback: 如果 IMPROVE_LLM_CMD 环境变量设置了,用它 - custom_cmd = os.environ.get("IMPROVE_LLM_CMD") - if custom_cmd: - try: - result = subprocess.run(custom_cmd.split(), input=prompt, - capture_output=True, text=True, timeout=timeout) - if result.returncode == 0 and result.stdout.strip(): - return result.stdout.strip() - except (FileNotFoundError, subprocess.TimeoutExpired): - pass - - print("❌ LLM 调用失败。支持的方式:") - print(" - 安装 Claude Code CLI (claude --print)") - print(" - 安装 llm CLI (pip install llm)") - print(" - 设置 IMPROVE_LLM_CMD 环境变量") - return None - - -def extract_improvements(args): - log_dir, proposal_dir, _, target = get_paths(args) - days = getattr(args, 'days', 1) or 1 - date_str = getattr(args, 'date', None) - - edits = collect_edits(log_dir, days=days, date_str=date_str) - if not edits: - print("⚠️ 没有修改记录") - return None - - print(f"📊 找到 {len(edits)} 次修改,正在分析...") - - # 读当前 SKILL.md - current_skill = "" - if target and target.exists(): - current_skill = target.read_text() - - # 构建对比数据 - edit_summaries = [] - for i, edit in enumerate(edits): - orig = edit.get("original_content", "")[:3000] - final = edit.get("final_content", edit.get("edited_content", ""))[:3000] - ctx = edit.get("context", {}) - edit_summaries.append({ - "index": i + 1, - "account": ctx.get("account", "unknown"), - "content_type": ctx.get("content_type", "unknown"), - "original": orig, - "final": final, - }) - - proposal_id = datetime.now().strftime("%Y%m%d-%H%M%S") - - prompt = f"""你是 writing style skill 的改进助手。 - -分析人类对 AI 生成文章的修改,提取可以加入 SKILL.md 的新规则。 - -## 当前 SKILL.md(最后 3000 字,避免重复) -{current_skill[-3000:]} - -## 修改记录(original vs final) -{json.dumps(edit_summaries, ensure_ascii=False, indent=2)} - -## 要求 -1. 对比 original 和 final,找出系统性修改 -2. 只提取有 pattern 的修改(至少 2 次,或单次但改动幅度大且明确) -3. 不要提取已在 SKILL.md 中的规则 -4. 每条规则必须可执行 - -## 输出格式 - ---- -id: {proposal_id} -date: {datetime.now().isoformat()} -source: {len(edits)} edits -status: pending ---- - -# Improvement Proposal - -## 提取的改进建议 - -### 1. 新禁止词 -- **`词`** → 替代: "YYY" | 理由: ... | 优先级: **P0/P1/P2** - -### 2. 新风格规则 -- 规则描述 | 理由: ... | 优先级: **P0/P1/P2** - -### 3. 反模式 -- 描述 | 理由: ... | 优先级: **P0/P1/P2** - -P0=高置信度(多次), P1=中置信度, P2=低置信度(仅1次) -""" - - suggestions = call_llm(prompt) - if not suggestions: - return None - - proposal_file = proposal_dir / f"{proposal_id}.md" - proposal_file.write_text(suggestions) - - print(f"✅ 改进建议已保存: {proposal_file}") - print(f"\n{suggestions[:2000]}") - if len(suggestions) > 2000: - print(f"\n... (完整内容见文件)") - return proposal_id - - -def show_proposals(args): - _, proposal_dir, _, _ = get_paths(args) - proposals = list(proposal_dir.glob("*.md")) - - if not proposals: - print("⚠️ 没有提案") - return - - print(f"\n📋 共 {len(proposals)} 个提案:\n") - for p in sorted(proposals, reverse=True): - content = p.read_text() - status = "unknown" - for line in content.split("\n")[:10]: - if line.startswith("status:"): - status = line.split(":", 1)[1].strip() - icon = {"pending": "⏳", "applied": "✅", "rejected": "❌"}.get( - status.split("(")[0].strip(), "❓") - print(f" {icon} {p.stem} — {status}") - - -def backup_skill(target, backup_dir): - if not target or not target.exists(): - return None - name = f"SKILL-{datetime.now().strftime('%Y%m%d-%H%M%S')}.md" - backup_path = backup_dir / name - shutil.copy2(target, backup_path) - print(f"📦 备份: {backup_path}") - return backup_path - - -def apply_proposal(args): - _, proposal_dir, backup_dir, target = get_paths(args) - proposal_id = args.proposal_id - proposal_file = proposal_dir / f"{proposal_id}.md" - - if not proposal_file.exists(): - print(f"❌ 提案不存在: {proposal_id}") - return - - if not target or not target.exists(): - print(f"❌ 目标 SKILL.md 不存在(用 --skill 或 --target 指定)") - return - - proposal_content = proposal_file.read_text() - current_skill = target.read_text() - - auto_mode = getattr(args, 'auto', False) - filter_level = "P0" if auto_mode else "P0 和 P1" - - backup_skill(target, backup_dir) - - prompt = f"""把改进提案中的 **{filter_level}** 规则合并到 SKILL.md。 - -规则: -1. 新禁止词 → 加到禁止词 section -2. 新风格规则 → 加到对应 section -3. 不删除已有规则,不改文件结构 -4. version +0.1 - -## 提案 -{proposal_content} - -## 当前 SKILL.md -{current_skill} - -输出完整更新后的 SKILL.md。不加代码块包裹。""" - - updated = call_llm(prompt, timeout=300) - if not updated: - print("❌ 合并失败") - return - - target.write_text(updated) - - new_content = proposal_content.replace( - "status: pending", - f"status: applied ({datetime.now().strftime('%Y-%m-%d')})") - proposal_file.write_text(new_content) - - print(f"✅ 已应用提案 {proposal_id}") - print(f"💡 回滚: python3 improve.py rollback") - - -def auto_improve(args): - log_dir, _, _, _ = get_paths(args) - edits = collect_edits(log_dir, days=7) - - if not edits: - print("⚠️ 最近 7 天没有修改记录,跳过") - return - - print(f"🤖 自动模式: {len(edits)} 次修改") - - args.days = 7 - args.date = None - proposal_id = extract_improvements(args) - - if not proposal_id: - return - - _, proposal_dir, _, _ = get_paths(args) - content = (proposal_dir / f"{proposal_id}.md").read_text() - - if "P0" not in content: - print("ℹ️ 没有 P0 规则,跳过自动应用") - return - - print("\n🔄 自动应用 P0 规则...") - apply_args = argparse.Namespace(**vars(args)) - apply_args.proposal_id = proposal_id - apply_args.auto = True - apply_proposal(apply_args) - - -def rollback(args): - _, _, backup_dir, target = get_paths(args) - - if not target: - print("❌ 未指定目标 SKILL.md") - return - - backups = sorted(backup_dir.glob("SKILL-*.md"), reverse=True) - if not backups: - print("❌ 没有备份") - return - - latest = backups[0] - # 保存当前版本 - if target.exists(): - emergency = backup_dir / f"SKILL-pre-rollback-{datetime.now().strftime('%Y%m%d-%H%M%S')}.md" - shutil.copy2(target, emergency) - - shutil.copy2(latest, target) - print(f"✅ 已回滚到: {latest.name}") - - -def add_common_args(parser): - parser.add_argument("--skill", help="目标 skill 目录") - parser.add_argument("--target", help="目标 SKILL.md 路径") - parser.add_argument("--log-dir", help="日志目录") - parser.add_argument("--proposal-dir", help="提案目录") - - -def main(): - parser = argparse.ArgumentParser(description="Self-Improving Skill — Improver") - subparsers = parser.add_subparsers(dest="action") - - p_ext = subparsers.add_parser("extract", help="提取改进建议") - p_ext.add_argument("--date", help="指定日期") - p_ext.add_argument("--days", type=int, default=1) - add_common_args(p_ext) - - p_show = subparsers.add_parser("show", help="查看提案") - add_common_args(p_show) - - p_apply = subparsers.add_parser("apply", help="应用提案") - p_apply.add_argument("proposal_id") - add_common_args(p_apply) - - p_auto = subparsers.add_parser("auto", help="自动提取+应用P0") - add_common_args(p_auto) - - p_rb = subparsers.add_parser("rollback", help="回滚") - add_common_args(p_rb) - - args = parser.parse_args() - if not args.action: - parser.print_help() - sys.exit(1) - - actions = { - "extract": extract_improvements, - "show": show_proposals, - "apply": apply_proposal, - "auto": auto_improve, - "rollback": rollback, - } - actions[args.action](args) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/my-writing-style/scripts/observe.py b/builtin-skills/my-writing-style/scripts/observe.py deleted file mode 100644 index 61cfe179..00000000 --- a/builtin-skills/my-writing-style/scripts/observe.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env python3 -""" -Self-Improving Skill — Observation Layer - -通用的 original → final 记录器。适用于任何 "AI 生成 → 人类修改" 的循环。 - -用法: - python3 observe.py record-original article.md [--text "..."] [--account X] [--content-type article] - python3 observe.py record-final article.md [--match ] [--text "..."] - python3 observe.py pending - python3 observe.py stats - -环境变量: - SKILL_LOG_DIR — 日志目录(默认 ~/clawd/memory/skill-runs/default/) -""" - -import sys -import json -import os -import argparse -from pathlib import Path -from datetime import datetime, timedelta -import hashlib - -# 日志目录 — 自动检测 OpenClaw / Claude Code / standalone -def _detect_base(): - if os.environ.get("SKILL_BASE_DIR"): - return Path(os.environ["SKILL_BASE_DIR"]) - candidates = [ - Path.home() / "clawd" / "memory", - Path.home() / ".openclaw" / "memory", - Path.home() / ".claude" / "memory", - ] - for c in candidates: - if c.parent.exists(): - return c - return Path.home() / ".self-improving" / "memory" - -DEFAULT_LOG_DIR = _detect_base() / "skill-runs" / "default" - - -def get_log_dir(args=None): - """按优先级决定日志目录:--log-dir > SKILL_LOG_DIR > default""" - if args and hasattr(args, 'log_dir') and args.log_dir: - d = Path(args.log_dir) - elif os.environ.get("SKILL_LOG_DIR"): - d = Path(os.environ["SKILL_LOG_DIR"]) - elif args and hasattr(args, 'skill') and args.skill: - skill_name = Path(args.skill).name - d = Path.home() / "clawd" / "memory" / "skill-runs" / skill_name - else: - d = DEFAULT_LOG_DIR - d.mkdir(parents=True, exist_ok=True) - return d - - -def get_log_file(log_dir, date_str=None): - if date_str is None: - date_str = datetime.now().strftime("%Y-%m-%d") - return log_dir / f"{date_str}.jsonl" - - -def compute_hash(content): - return hashlib.md5(content.encode()).hexdigest()[:8] - - -def get_content(args): - if hasattr(args, 'text') and args.text: - return args.text - if hasattr(args, 'stdin') and args.stdin: - return sys.stdin.read() - if hasattr(args, 'file') and args.file: - p = Path(args.file) - if not p.exists(): - print(f"❌ 文件不存在: {args.file}") - sys.exit(1) - return p.read_text() - return None - - -def read_log_entries(log_file): - if not log_file.exists(): - return [] - entries = [] - with log_file.open("r") as f: - for line in f: - line = line.strip() - if line: - try: - entries.append(json.loads(line)) - except json.JSONDecodeError: - continue - return entries - - -def find_unmatched(log_dir, days=14): - """找到有 original 但没有 final 的记录(兼容旧 edited/no-change type)""" - all_originals = {} - all_matched = set() - - for i in range(days): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - entries = read_log_entries(get_log_file(log_dir, date)) - for e in entries: - if e["type"] == "original": - e["_date"] = date - all_originals[e["content_hash"]] = e - elif e["type"] in ("final", "edited", "no-change"): - all_matched.add(e["content_hash"]) - - return {h: o for h, o in all_originals.items() if h not in all_matched} - - -def record_original(args): - content = get_content(args) - if not content: - print("❌ 需要提供内容(文件路径、--text 或 --stdin)") - sys.exit(1) - - log_dir = get_log_dir(args) - content_hash = compute_hash(content) - - context = {} - if hasattr(args, 'account') and args.account: - context["account"] = args.account - if hasattr(args, 'content_type') and args.content_type: - context["content_type"] = args.content_type - - log_entry = { - "timestamp": datetime.now().isoformat(), - "type": "original", - "content_hash": content_hash, - "file": str(args.file) if hasattr(args, 'file') and args.file else None, - "content": content, - "context": context, - "char_count": len(content), - } - - log_file = get_log_file(log_dir) - with log_file.open("a") as f: - f.write(json.dumps(log_entry, ensure_ascii=False) + "\n") - - print(f"✅ 记录原稿: {content_hash}") - print(f"📝 字数: {len(content)}") - print(f"📁 日志: {log_file}") - return content_hash - - -def record_final(args): - content = get_content(args) - if not content: - print("❌ 需要提供最终版内容") - sys.exit(1) - - log_dir = get_log_dir(args) - target_hash = getattr(args, 'match', None) - - if target_hash: - # 指定 hash,跨天查找 - original = None - for i in range(14): - date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d") - entries = read_log_entries(get_log_file(log_dir, date)) - for e in entries: - if e["type"] == "original" and e["content_hash"] == target_hash: - original = e - break - if original: - break - if not original: - print(f"❌ 找不到 hash {target_hash} 的原稿") - sys.exit(1) - else: - # 自动匹配最近的未配对 original - unmatched = find_unmatched(log_dir, 14) - if not unmatched: - print("❌ 没有待配对的原稿") - sys.exit(1) - target_hash = list(unmatched.keys())[-1] - original = unmatched[target_hash] - - is_same = content.strip() == original["content"].strip() - - log_entry = { - "timestamp": datetime.now().isoformat(), - "type": "final", - "content_hash": target_hash, - "original_content": original["content"], - "final_content": content, - "original_char_count": len(original["content"]), - "final_char_count": len(content), - "context": original.get("context", {}), - "no_change": is_same, - } - - log_file = get_log_file(log_dir) - with log_file.open("a") as f: - f.write(json.dumps(log_entry, ensure_ascii=False) + "\n") - - if is_same: - print(f"✅ 记录最终版: {target_hash} (无修改 — 正反馈)") - else: - diff_pct = ((len(content) - len(original["content"])) / max(len(original["content"]), 1)) * 100 - print(f"✅ 记录最终版: {target_hash}") - print(f"📝 原稿: {len(original['content'])} 字 → 最终: {len(content)} 字 ({diff_pct:+.1f}%)") - print(f"📁 日志: {log_file}") - - -def show_pending(args): - log_dir = get_log_dir(args) - unmatched = find_unmatched(log_dir, 14) - - if not unmatched: - print("✅ 全部已配对") - return - - print(f"\n⏳ {len(unmatched)} 条待配对:\n") - for h, entry in unmatched.items(): - preview = entry["content"][:80].replace("\n", " ") - ctx = entry.get("context", {}) - account = ctx.get("account", "?") - date = entry.get("_date", "?") - print(f" 📄 {h} | {date} | {account}") - print(f" {preview}...") - print() - - -def show_stats(args): - log_dir = get_log_dir(args) - all_files = sorted(log_dir.glob("*.jsonl")) - - total_originals = 0 - total_finals = 0 - total_no_change = 0 - total_changed = 0 - - for log_file in all_files: - entries = read_log_entries(log_file) - total_originals += sum(1 for e in entries if e["type"] == "original") - finals = [e for e in entries if e["type"] in ("final", "edited")] - total_finals += len(finals) - total_no_change += sum(1 for e in finals if e.get("no_change")) - total_changed += sum(1 for e in finals if not e.get("no_change")) - - pending = find_unmatched(log_dir, 14) - - print(f"\n📊 Self-Improving Skill 观察统计") - print(f"{'='*40}") - print(f"📁 日志天数: {len(all_files)}") - print(f"📝 原稿: {total_originals}") - print(f"✅ 已配对: {total_finals}") - print(f" ├ 有修改: {total_changed}") - print(f" └ 无修改: {total_no_change}") - print(f"⏳ 待配对: {len(pending)}") - if total_finals > 0: - print(f"📈 修改率: {total_changed}/{total_finals} = {total_changed/total_finals*100:.0f}%") - - -def add_common_args(parser): - """添加通用参数""" - parser.add_argument("--skill", help="目标 skill 目录名(用于定位日志目录)") - parser.add_argument("--log-dir", help="自定义日志目录") - - -def main(): - parser = argparse.ArgumentParser(description="Self-Improving Skill — Observation Layer") - subparsers = parser.add_subparsers(dest="action") - - # record-original - p_orig = subparsers.add_parser("record-original", help="记录 AI 原稿") - p_orig.add_argument("file", nargs="?", help="文件路径") - p_orig.add_argument("--text", help="直接传入文本") - p_orig.add_argument("--stdin", action="store_true", help="从 stdin 读取") - p_orig.add_argument("--account", help="发布账号") - p_orig.add_argument("--content-type", help="内容类型") - add_common_args(p_orig) - - # record-final - p_final = subparsers.add_parser("record-final", help="记录最终版") - p_final.add_argument("file", nargs="?", help="文件路径") - p_final.add_argument("--text", help="直接传入文本") - p_final.add_argument("--stdin", action="store_true", help="从 stdin 读取") - p_final.add_argument("--match", help="匹配的原稿 hash") - add_common_args(p_final) - - # pending - p_pending = subparsers.add_parser("pending", help="查看待配对原稿") - add_common_args(p_pending) - - # stats - p_stats = subparsers.add_parser("stats", help="总体统计") - add_common_args(p_stats) - - args = parser.parse_args() - if not args.action: - parser.print_help() - sys.exit(1) - - actions = { - "record-original": record_original, - "record-final": record_final, - "pending": show_pending, - "stats": show_stats, - } - actions[args.action](args) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/software-engineer/ai-coding-discipline/SKILL.md b/builtin-skills/software-engineer/ai-coding-discipline/SKILL.md deleted file mode 100644 index 0453c5f9..00000000 --- a/builtin-skills/software-engineer/ai-coding-discipline/SKILL.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -name: ai-coding-discipline -description: > - Mandatory coding discipline rules that prevent common AI coding anti-patterns. - MUST be loaded for ALL code writing, editing, reviewing, bug fixing, and testing tasks. - Trigger on: writing code, editing code, fixing bugs, writing tests, implementing features, - refactoring, code review, creating functions, adding error handling, debugging. - This skill enforces fail-fast principles, proper error propagation, meaningful tests, - and disciplined debugging workflows. Always active when Claude writes or modifies code. ---- - -# AI Coding Discipline - -> These rules override default AI coding tendencies. Follow them in ALL code you write or modify. - ---- - -## Rule 1: No Silent Fallbacks - -**Never use fallback values to mask data that should not be missing.** - -```typescript -// FORBIDDEN — hides upstream bugs -const price = product?.price ?? 0; -const userName = user?.name || "Unknown"; - -// CORRECT — fail fast when data contract is violated -if (product.price == null) { - throw new Error(`Product ${product.id} is missing price`); -} -const price = product.price; -``` - -**When fallbacks ARE acceptable:** -- User-facing display with explicit design intent (e.g., avatar placeholder) -- Optional configuration with documented defaults -- External input parsing where absence is a valid state - -**Checklist before writing `??`, `||`, or `?.`:** -1. Can this value legitimately be null/undefined at this point? -2. If it is null, will the fallback produce a correct result downstream? -3. Would a thrown error help me find a bug faster? - -If the answer to #3 is yes, throw instead of falling back. - ---- - -## Rule 2: No Catch-All try/catch in Business Logic - -**Business logic functions must NOT wrap everything in try/catch. Let errors propagate naturally.** - -```typescript -// FORBIDDEN — swallows all errors into a useless null -async function createOrder(data: OrderInput) { - try { - const user = await getUser(data.userId); - const coupon = await validateCoupon(data.couponCode); - const order = await saveOrder({ ...data, discount: coupon.value }); - return order; - } catch (error) { - console.log('Error creating order:', error); - return null; // caller gets null, has no idea what failed - } -} - -// CORRECT — let errors bubble up, catch at the boundary -async function createOrder(data: OrderInput) { - const user = await getUser(data.userId); - const coupon = await validateCoupon(data.couponCode); - const order = await saveOrder({ ...data, discount: coupon.value }); - return order; -} - -// Catch ONLY at the API/controller boundary -app.post('/orders', async (req, res) => { - try { - const order = await createOrder(req.body); - res.json(order); - } catch (error) { - logger.error('Order creation failed', { error, body: req.body }); - res.status(500).json({ error: 'Order creation failed' }); - } -}); -``` - -**Where try/catch IS appropriate:** -- API route handlers / controller boundaries -- Top-level event handlers (message queues, cron jobs) -- Operations where partial failure is expected and recovery is defined (e.g., batch processing with per-item error handling) -- Specific, named error types you intend to handle differently - -**Never catch `Error` just to return `null`, `undefined`, `false`, or an empty object.** - ---- - -## Rule 3: Tests Must Fail When Code Breaks - -**Every test must verify specific business outcomes. A test that passes when the core logic is deleted is worthless.** - -```typescript -// FORBIDDEN — passes even if processOrder returns garbage -test('should process order', async () => { - const result = await processOrder(mockOrder); - expect(result).toBeDefined(); -}); - -// CORRECT — verifies exact business behavior -test('should calculate total with 10% discount', async () => { - const result = await processOrder({ - ...mockOrder, - discount: 0.1, - }); - expect(result.totalAmount).toBe(900); // 1000 * 0.9 - expect(result.discountAmount).toBe(100); - expect(result.status).toBe('confirmed'); -}); -``` - -**Test quality checklist:** -1. If I delete the function body, does this test fail? If not, the test is useless. -2. Am I testing behavior or just testing that "something exists"? -3. Do my assertions check concrete values, not just truthiness? - -**Banned weak assertions** (unless testing existence is the actual requirement): -- `toBeDefined()`, `toBeTruthy()`, `toBeFalsy()` as sole assertion -- `toHaveLength(expect.any(Number))` -- `expect(result).not.toBeNull()` without further value checks - ---- - -## Rule 4: No Hardcoded Lookup-Table Implementations - -**Never implement business logic by hardcoding return values that match test cases.** - -```typescript -// FORBIDDEN — fake implementation that "fits" the tests -function calculateDiscount(amount: number, level: string): number { - if (amount === 1000 && level === 'gold') return 100; - if (amount === 500 && level === 'silver') return 25; - return 0; -} - -// CORRECT — real logic -function calculateDiscount(amount: number, level: string): number { - const rates: Record = { gold: 0.1, silver: 0.05, bronze: 0.02 }; - const rate = rates[level] ?? 0; - return amount * rate; -} -``` - -**How to prevent this:** -- Use diverse test data: multiple amounts, edge cases, boundary values -- Add property-based / fuzzy tests where appropriate -- Test with values NOT in the original spec to catch lookup-table fakes - ---- - -## Rule 5: Red-Green Testing (TDD Order) - -**When fixing a bug, always write the failing test FIRST, then fix the code.** - -``` -Correct order: -1. Discover bug -2. Write a test that reproduces the bug -3. Run the test — confirm it FAILS (red) -4. Fix the code -5. Run the test — confirm it PASSES (green) -``` - -**Why this matters:** If you fix the code first and then write a test, you can never be sure the test would have caught the bug. The test might pass for the wrong reason. - -**Never skip step 3.** Seeing the test go from red to green is the proof that the test is valid. - ---- - -## Rule 6: Never Remove Debug Logs During a Fix - -**When debugging, debug logs are removed ONLY after the human confirms the fix works.** - -``` -FORBIDDEN workflow: -1. Human asks to add debug logs -2. AI adds logs -3. Human runs code, shares log output -4. AI "finds the problem", applies fix AND removes debug logs in the same edit -5. Fix doesn't work — logs are gone, must re-add them - -CORRECT workflow: -1. Human asks to add debug logs -2. AI adds logs -3. Human runs code, shares log output -4. AI applies fix ONLY — debug logs stay untouched -5. Human verifies the fix -6. Human decides when to remove debug logs (or asks AI to remove them) -``` - -**Rule: Never touch debug/diagnostic logs in the same commit as a fix. They are separate concerns.** - ---- - -## Quick Reference: Self-Check Before Submitting Code - -Before finalizing any code change, run through this checklist: - -| Check | Question | -|-------|----------| -| Fallbacks | Did I use `??` or `\|\|` to hide a value that should never be missing? | -| Error handling | Did I add try/catch in business logic that should just let errors propagate? | -| Test strength | Would my tests still pass if I deleted the implementation? | -| Test honesty | Did I hardcode values to match test cases instead of implementing real logic? | -| TDD order | For bug fixes: did I see the test fail before applying the fix? | -| Debug logs | Am I removing diagnostic logs in the same change as the fix? | - -If any answer is "yes", revise before proceeding. diff --git a/builtin-skills/software-engineer/api-design-principles/SKILL.md b/builtin-skills/software-engineer/api-design-principles/SKILL.md deleted file mode 100644 index 437cc3cf..00000000 --- a/builtin-skills/software-engineer/api-design-principles/SKILL.md +++ /dev/null @@ -1,518 +0,0 @@ ---- -name: api-design-principles -description: Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards. ---- - -# API Design Principles - -Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers and stand the test of time. - -## When to Use This Skill - -- Designing new REST or GraphQL APIs -- Refactoring existing APIs for better usability -- Establishing API design standards for your team -- Reviewing API specifications before implementation -- Migrating between API paradigms (REST to GraphQL, etc.) -- Creating developer-friendly API documentation -- Optimizing APIs for specific use cases (mobile, third-party integrations) - -## Core Concepts - -### 1. RESTful Design Principles - -**Resource-Oriented Architecture** - -- Resources are nouns (users, orders, products), not verbs -- Use HTTP methods for actions (GET, POST, PUT, PATCH, DELETE) -- URLs represent resource hierarchies -- Consistent naming conventions - -**HTTP Methods Semantics:** - -- `GET`: Retrieve resources (idempotent, safe) -- `POST`: Create new resources -- `PUT`: Replace entire resource (idempotent) -- `PATCH`: Partial resource updates -- `DELETE`: Remove resources (idempotent) - -### 2. GraphQL Design Principles - -**Schema-First Development** - -- Types define your domain model -- Queries for reading data -- Mutations for modifying data -- Subscriptions for real-time updates - -**Query Structure:** - -- Clients request exactly what they need -- Single endpoint, multiple operations -- Strongly typed schema -- Introspection built-in - -### 3. API Versioning Strategies - -**URL Versioning:** - -``` -/api/v1/users -/api/v2/users -``` - -**Header Versioning:** - -``` -Accept: application/vnd.api+json; version=1 -``` - -**Query Parameter Versioning:** - -``` -/api/users?version=1 -``` - -## REST API Design Patterns - -### Pattern 1: Resource Collection Design - -```python -# Good: Resource-oriented endpoints -GET /api/users # List users (with pagination) -POST /api/users # Create user -GET /api/users/{id} # Get specific user -PUT /api/users/{id} # Replace user -PATCH /api/users/{id} # Update user fields -DELETE /api/users/{id} # Delete user - -# Nested resources -GET /api/users/{id}/orders # Get user's orders -POST /api/users/{id}/orders # Create order for user - -# Bad: Action-oriented endpoints (avoid) -POST /api/createUser -POST /api/getUserById -POST /api/deleteUser -``` - -### Pattern 2: Pagination and Filtering - -```python -from typing import List, Optional -from pydantic import BaseModel, Field - -class PaginationParams(BaseModel): - page: int = Field(1, ge=1, description="Page number") - page_size: int = Field(20, ge=1, le=100, description="Items per page") - -class FilterParams(BaseModel): - status: Optional[str] = None - created_after: Optional[str] = None - search: Optional[str] = None - -class PaginatedResponse(BaseModel): - items: List[dict] - total: int - page: int - page_size: int - pages: int - - @property - def has_next(self) -> bool: - return self.page < self.pages - - @property - def has_prev(self) -> bool: - return self.page > 1 - -# FastAPI endpoint example -from fastapi import FastAPI, Query, Depends - -app = FastAPI() - -@app.get("/api/users", response_model=PaginatedResponse) -async def list_users( - page: int = Query(1, ge=1), - page_size: int = Query(20, ge=1, le=100), - status: Optional[str] = Query(None), - search: Optional[str] = Query(None) -): - # Apply filters - query = build_query(status=status, search=search) - - # Count total - total = await count_users(query) - - # Fetch page - offset = (page - 1) * page_size - users = await fetch_users(query, limit=page_size, offset=offset) - - return PaginatedResponse( - items=users, - total=total, - page=page, - page_size=page_size, - pages=(total + page_size - 1) // page_size - ) -``` - -### Pattern 3: Error Handling and Status Codes - -```python -from fastapi import HTTPException, status -from pydantic import BaseModel - -class ErrorResponse(BaseModel): - error: str - message: str - details: Optional[dict] = None - timestamp: str - path: str - -class ValidationErrorDetail(BaseModel): - field: str - message: str - value: Any - -# Consistent error responses -STATUS_CODES = { - "success": 200, - "created": 201, - "no_content": 204, - "bad_request": 400, - "unauthorized": 401, - "forbidden": 403, - "not_found": 404, - "conflict": 409, - "unprocessable": 422, - "internal_error": 500 -} - -def raise_not_found(resource: str, id: str): - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail={ - "error": "NotFound", - "message": f"{resource} not found", - "details": {"id": id} - } - ) - -def raise_validation_error(errors: List[ValidationErrorDetail]): - raise HTTPException( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, - detail={ - "error": "ValidationError", - "message": "Request validation failed", - "details": {"errors": [e.dict() for e in errors]} - } - ) - -# Example usage -@app.get("/api/users/{user_id}") -async def get_user(user_id: str): - user = await fetch_user(user_id) - if not user: - raise_not_found("User", user_id) - return user -``` - -### Pattern 4: HATEOAS (Hypermedia as the Engine of Application State) - -```python -class UserResponse(BaseModel): - id: str - name: str - email: str - _links: dict - - @classmethod - def from_user(cls, user: User, base_url: str): - return cls( - id=user.id, - name=user.name, - email=user.email, - _links={ - "self": {"href": f"{base_url}/api/users/{user.id}"}, - "orders": {"href": f"{base_url}/api/users/{user.id}/orders"}, - "update": { - "href": f"{base_url}/api/users/{user.id}", - "method": "PATCH" - }, - "delete": { - "href": f"{base_url}/api/users/{user.id}", - "method": "DELETE" - } - } - ) -``` - -## GraphQL Design Patterns - -### Pattern 1: Schema Design - -```graphql -# schema.graphql - -# Clear type definitions -type User { - id: ID! - email: String! - name: String! - createdAt: DateTime! - - # Relationships - orders(first: Int = 20, after: String, status: OrderStatus): OrderConnection! - - profile: UserProfile -} - -type Order { - id: ID! - status: OrderStatus! - total: Money! - items: [OrderItem!]! - createdAt: DateTime! - - # Back-reference - user: User! -} - -# Pagination pattern (Relay-style) -type OrderConnection { - edges: [OrderEdge!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type OrderEdge { - node: Order! - cursor: String! -} - -type PageInfo { - hasNextPage: Boolean! - hasPreviousPage: Boolean! - startCursor: String - endCursor: String -} - -# Enums for type safety -enum OrderStatus { - PENDING - CONFIRMED - SHIPPED - DELIVERED - CANCELLED -} - -# Custom scalars -scalar DateTime -scalar Money - -# Query root -type Query { - user(id: ID!): User - users(first: Int = 20, after: String, search: String): UserConnection! - - order(id: ID!): Order -} - -# Mutation root -type Mutation { - createUser(input: CreateUserInput!): CreateUserPayload! - updateUser(input: UpdateUserInput!): UpdateUserPayload! - deleteUser(id: ID!): DeleteUserPayload! - - createOrder(input: CreateOrderInput!): CreateOrderPayload! -} - -# Input types for mutations -input CreateUserInput { - email: String! - name: String! - password: String! -} - -# Payload types for mutations -type CreateUserPayload { - user: User - errors: [Error!] -} - -type Error { - field: String - message: String! -} -``` - -### Pattern 2: Resolver Design - -```python -from typing import Optional, List -from ariadne import QueryType, MutationType, ObjectType -from dataclasses import dataclass - -query = QueryType() -mutation = MutationType() -user_type = ObjectType("User") - -@query.field("user") -async def resolve_user(obj, info, id: str) -> Optional[dict]: - """Resolve single user by ID.""" - return await fetch_user_by_id(id) - -@query.field("users") -async def resolve_users( - obj, - info, - first: int = 20, - after: Optional[str] = None, - search: Optional[str] = None -) -> dict: - """Resolve paginated user list.""" - # Decode cursor - offset = decode_cursor(after) if after else 0 - - # Fetch users - users = await fetch_users( - limit=first + 1, # Fetch one extra to check hasNextPage - offset=offset, - search=search - ) - - # Pagination - has_next = len(users) > first - if has_next: - users = users[:first] - - edges = [ - { - "node": user, - "cursor": encode_cursor(offset + i) - } - for i, user in enumerate(users) - ] - - return { - "edges": edges, - "pageInfo": { - "hasNextPage": has_next, - "hasPreviousPage": offset > 0, - "startCursor": edges[0]["cursor"] if edges else None, - "endCursor": edges[-1]["cursor"] if edges else None - }, - "totalCount": await count_users(search=search) - } - -@user_type.field("orders") -async def resolve_user_orders(user: dict, info, first: int = 20) -> dict: - """Resolve user's orders (N+1 prevention with DataLoader).""" - # Use DataLoader to batch requests - loader = info.context["loaders"]["orders_by_user"] - orders = await loader.load(user["id"]) - - return paginate_orders(orders, first) - -@mutation.field("createUser") -async def resolve_create_user(obj, info, input: dict) -> dict: - """Create new user.""" - try: - # Validate input - validate_user_input(input) - - # Create user - user = await create_user( - email=input["email"], - name=input["name"], - password=hash_password(input["password"]) - ) - - return { - "user": user, - "errors": [] - } - except ValidationError as e: - return { - "user": None, - "errors": [{"field": e.field, "message": e.message}] - } -``` - -### Pattern 3: DataLoader (N+1 Problem Prevention) - -```python -from aiodataloader import DataLoader -from typing import List, Optional - -class UserLoader(DataLoader): - """Batch load users by ID.""" - - async def batch_load_fn(self, user_ids: List[str]) -> List[Optional[dict]]: - """Load multiple users in single query.""" - users = await fetch_users_by_ids(user_ids) - - # Map results back to input order - user_map = {user["id"]: user for user in users} - return [user_map.get(user_id) for user_id in user_ids] - -class OrdersByUserLoader(DataLoader): - """Batch load orders by user ID.""" - - async def batch_load_fn(self, user_ids: List[str]) -> List[List[dict]]: - """Load orders for multiple users in single query.""" - orders = await fetch_orders_by_user_ids(user_ids) - - # Group orders by user_id - orders_by_user = {} - for order in orders: - user_id = order["user_id"] - if user_id not in orders_by_user: - orders_by_user[user_id] = [] - orders_by_user[user_id].append(order) - - # Return in input order - return [orders_by_user.get(user_id, []) for user_id in user_ids] - -# Context setup -def create_context(): - return { - "loaders": { - "user": UserLoader(), - "orders_by_user": OrdersByUserLoader() - } - } -``` - -## Best Practices - -### REST APIs - -1. **Consistent Naming**: Use plural nouns for collections (`/users`, not `/user`) -2. **Stateless**: Each request contains all necessary information -3. **Use HTTP Status Codes Correctly**: 2xx success, 4xx client errors, 5xx server errors -4. **Version Your API**: Plan for breaking changes from day one -5. **Pagination**: Always paginate large collections -6. **Rate Limiting**: Protect your API with rate limits -7. **Documentation**: Use OpenAPI/Swagger for interactive docs - -### GraphQL APIs - -1. **Schema First**: Design schema before writing resolvers -2. **Avoid N+1**: Use DataLoaders for efficient data fetching -3. **Input Validation**: Validate at schema and resolver levels -4. **Error Handling**: Return structured errors in mutation payloads -5. **Pagination**: Use cursor-based pagination (Relay spec) -6. **Deprecation**: Use `@deprecated` directive for gradual migration -7. **Monitoring**: Track query complexity and execution time - -## Common Pitfalls - -- **Over-fetching/Under-fetching (REST)**: Fixed in GraphQL but requires DataLoaders -- **Breaking Changes**: Version APIs or use deprecation strategies -- **Inconsistent Error Formats**: Standardize error responses -- **Missing Rate Limits**: APIs without limits are vulnerable to abuse -- **Poor Documentation**: Undocumented APIs frustrate developers -- **Ignoring HTTP Semantics**: POST for idempotent operations breaks expectations -- **Tight Coupling**: API structure shouldn't mirror database schema diff --git a/builtin-skills/software-engineer/api-design-principles/assets/api-design-checklist.md b/builtin-skills/software-engineer/api-design-principles/assets/api-design-checklist.md deleted file mode 100644 index b78148bf..00000000 --- a/builtin-skills/software-engineer/api-design-principles/assets/api-design-checklist.md +++ /dev/null @@ -1,155 +0,0 @@ -# API Design Checklist - -## Pre-Implementation Review - -### Resource Design - -- [ ] Resources are nouns, not verbs -- [ ] Plural names for collections -- [ ] Consistent naming across all endpoints -- [ ] Clear resource hierarchy (avoid deep nesting >2 levels) -- [ ] All CRUD operations properly mapped to HTTP methods - -### HTTP Methods - -- [ ] GET for retrieval (safe, idempotent) -- [ ] POST for creation -- [ ] PUT for full replacement (idempotent) -- [ ] PATCH for partial updates -- [ ] DELETE for removal (idempotent) - -### Status Codes - -- [ ] 200 OK for successful GET/PATCH/PUT -- [ ] 201 Created for POST -- [ ] 204 No Content for DELETE -- [ ] 400 Bad Request for malformed requests -- [ ] 401 Unauthorized for missing auth -- [ ] 403 Forbidden for insufficient permissions -- [ ] 404 Not Found for missing resources -- [ ] 422 Unprocessable Entity for validation errors -- [ ] 429 Too Many Requests for rate limiting -- [ ] 500 Internal Server Error for server issues - -### Pagination - -- [ ] All collection endpoints paginated -- [ ] Default page size defined (e.g., 20) -- [ ] Maximum page size enforced (e.g., 100) -- [ ] Pagination metadata included (total, pages, etc.) -- [ ] Cursor-based or offset-based pattern chosen - -### Filtering & Sorting - -- [ ] Query parameters for filtering -- [ ] Sort parameter supported -- [ ] Search parameter for full-text search -- [ ] Field selection supported (sparse fieldsets) - -### Versioning - -- [ ] Versioning strategy defined (URL/header/query) -- [ ] Version included in all endpoints -- [ ] Deprecation policy documented - -### Error Handling - -- [ ] Consistent error response format -- [ ] Detailed error messages -- [ ] Field-level validation errors -- [ ] Error codes for client handling -- [ ] Timestamps in error responses - -### Authentication & Authorization - -- [ ] Authentication method defined (Bearer token, API key) -- [ ] Authorization checks on all endpoints -- [ ] 401 vs 403 used correctly -- [ ] Token expiration handled - -### Rate Limiting - -- [ ] Rate limits defined per endpoint/user -- [ ] Rate limit headers included -- [ ] 429 status code for exceeded limits -- [ ] Retry-After header provided - -### Documentation - -- [ ] OpenAPI/Swagger spec generated -- [ ] All endpoints documented -- [ ] Request/response examples provided -- [ ] Error responses documented -- [ ] Authentication flow documented - -### Testing - -- [ ] Unit tests for business logic -- [ ] Integration tests for endpoints -- [ ] Error scenarios tested -- [ ] Edge cases covered -- [ ] Performance tests for heavy endpoints - -### Security - -- [ ] Input validation on all fields -- [ ] SQL injection prevention -- [ ] XSS prevention -- [ ] CORS configured correctly -- [ ] HTTPS enforced -- [ ] Sensitive data not in URLs -- [ ] No secrets in responses - -### Performance - -- [ ] Database queries optimized -- [ ] N+1 queries prevented -- [ ] Caching strategy defined -- [ ] Cache headers set appropriately -- [ ] Large responses paginated - -### Monitoring - -- [ ] Logging implemented -- [ ] Error tracking configured -- [ ] Performance metrics collected -- [ ] Health check endpoint available -- [ ] Alerts configured for errors - -## GraphQL-Specific Checks - -### Schema Design - -- [ ] Schema-first approach used -- [ ] Types properly defined -- [ ] Non-null vs nullable decided -- [ ] Interfaces/unions used appropriately -- [ ] Custom scalars defined - -### Queries - -- [ ] Query depth limiting -- [ ] Query complexity analysis -- [ ] DataLoaders prevent N+1 -- [ ] Pagination pattern chosen (Relay/offset) - -### Mutations - -- [ ] Input types defined -- [ ] Payload types with errors -- [ ] Optimistic response support -- [ ] Idempotency considered - -### Performance - -- [ ] DataLoader for all relationships -- [ ] Query batching enabled -- [ ] Persisted queries considered -- [ ] Response caching implemented - -### Documentation - -- [ ] All fields documented -- [ ] Deprecations marked -- [ ] Examples provided -- [ ] Schema introspection enabled diff --git a/builtin-skills/software-engineer/api-design-principles/assets/rest-api-template.py b/builtin-skills/software-engineer/api-design-principles/assets/rest-api-template.py deleted file mode 100644 index 2a78401e..00000000 --- a/builtin-skills/software-engineer/api-design-principles/assets/rest-api-template.py +++ /dev/null @@ -1,182 +0,0 @@ -""" -Production-ready REST API template using FastAPI. -Includes pagination, filtering, error handling, and best practices. -""" - -from fastapi import FastAPI, HTTPException, Query, Path, Depends, status -from fastapi.middleware.cors import CORSMiddleware -from fastapi.middleware.trustedhost import TrustedHostMiddleware -from fastapi.responses import JSONResponse -from pydantic import BaseModel, Field, EmailStr, ConfigDict -from typing import Optional, List, Any -from datetime import datetime -from enum import Enum - -app = FastAPI( - title="API Template", - version="1.0.0", - docs_url="/api/docs" -) - -# Security Middleware -# Trusted Host: Prevents HTTP Host Header attacks -app.add_middleware( - TrustedHostMiddleware, - allowed_hosts=["*"] # TODO: Configure this in production, e.g. ["api.example.com"] -) - -# CORS: Configures Cross-Origin Resource Sharing -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], # TODO: Update this with specific origins in production - allow_credentials=False, # TODO: Set to True if you need cookies/auth headers, but restrict origins - allow_methods=["*"], - allow_headers=["*"], -) - -# Models -class UserStatus(str, Enum): - ACTIVE = "active" - INACTIVE = "inactive" - SUSPENDED = "suspended" - -class UserBase(BaseModel): - email: EmailStr - name: str = Field(..., min_length=1, max_length=100) - status: UserStatus = UserStatus.ACTIVE - -class UserCreate(UserBase): - password: str = Field(..., min_length=8) - -class UserUpdate(BaseModel): - email: Optional[EmailStr] = None - name: Optional[str] = Field(None, min_length=1, max_length=100) - status: Optional[UserStatus] = None - -class User(UserBase): - id: str - created_at: datetime - updated_at: datetime - - model_config = ConfigDict(from_attributes=True) - -# Pagination -class PaginationParams(BaseModel): - page: int = Field(1, ge=1) - page_size: int = Field(20, ge=1, le=100) - -class PaginatedResponse(BaseModel): - items: List[Any] - total: int - page: int - page_size: int - pages: int - -# Error handling -class ErrorDetail(BaseModel): - field: Optional[str] = None - message: str - code: str - -class ErrorResponse(BaseModel): - error: str - message: str - details: Optional[List[ErrorDetail]] = None - -@app.exception_handler(HTTPException) -async def http_exception_handler(request, exc): - return JSONResponse( - status_code=exc.status_code, - content=ErrorResponse( - error=exc.__class__.__name__, - message=exc.detail if isinstance(exc.detail, str) else exc.detail.get("message", "Error"), - details=exc.detail.get("details") if isinstance(exc.detail, dict) else None - ).model_dump() - ) - -# Endpoints -@app.get("/api/users", response_model=PaginatedResponse, tags=["Users"]) -async def list_users( - page: int = Query(1, ge=1), - page_size: int = Query(20, ge=1, le=100), - status: Optional[UserStatus] = Query(None), - search: Optional[str] = Query(None) -): - """List users with pagination and filtering.""" - # Mock implementation - total = 100 - items = [ - User( - id=str(i), - email=f"user{i}@example.com", - name=f"User {i}", - status=UserStatus.ACTIVE, - created_at=datetime.now(), - updated_at=datetime.now() - ).model_dump() - for i in range((page-1)*page_size, min(page*page_size, total)) - ] - - return PaginatedResponse( - items=items, - total=total, - page=page, - page_size=page_size, - pages=(total + page_size - 1) // page_size - ) - -@app.post("/api/users", response_model=User, status_code=status.HTTP_201_CREATED, tags=["Users"]) -async def create_user(user: UserCreate): - """Create a new user.""" - # Mock implementation - return User( - id="123", - email=user.email, - name=user.name, - status=user.status, - created_at=datetime.now(), - updated_at=datetime.now() - ) - -@app.get("/api/users/{user_id}", response_model=User, tags=["Users"]) -async def get_user(user_id: str = Path(..., description="User ID")): - """Get user by ID.""" - # Mock: Check if exists - if user_id == "999": - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail={"message": "User not found", "details": {"id": user_id}} - ) - - return User( - id=user_id, - email="user@example.com", - name="User Name", - status=UserStatus.ACTIVE, - created_at=datetime.now(), - updated_at=datetime.now() - ) - -@app.patch("/api/users/{user_id}", response_model=User, tags=["Users"]) -async def update_user(user_id: str, update: UserUpdate): - """Partially update user.""" - # Validate user exists - existing = await get_user(user_id) - - # Apply updates - update_data = update.model_dump(exclude_unset=True) - for field, value in update_data.items(): - setattr(existing, field, value) - - existing.updated_at = datetime.now() - return existing - -@app.delete("/api/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT, tags=["Users"]) -async def delete_user(user_id: str): - """Delete user.""" - await get_user(user_id) # Verify exists - return None - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/builtin-skills/software-engineer/api-design-principles/references/graphql-schema-design.md b/builtin-skills/software-engineer/api-design-principles/references/graphql-schema-design.md deleted file mode 100644 index beca5f4f..00000000 --- a/builtin-skills/software-engineer/api-design-principles/references/graphql-schema-design.md +++ /dev/null @@ -1,583 +0,0 @@ -# GraphQL Schema Design Patterns - -## Schema Organization - -### Modular Schema Structure - -```graphql -# user.graphql -type User { - id: ID! - email: String! - name: String! - posts: [Post!]! -} - -extend type Query { - user(id: ID!): User - users(first: Int, after: String): UserConnection! -} - -extend type Mutation { - createUser(input: CreateUserInput!): CreateUserPayload! -} - -# post.graphql -type Post { - id: ID! - title: String! - content: String! - author: User! -} - -extend type Query { - post(id: ID!): Post -} -``` - -## Type Design Patterns - -### 1. Non-Null Types - -```graphql -type User { - id: ID! # Always required - email: String! # Required - phone: String # Optional (nullable) - posts: [Post!]! # Non-null array of non-null posts - tags: [String!] # Nullable array of non-null strings -} -``` - -### 2. Interfaces for Polymorphism - -```graphql -interface Node { - id: ID! - createdAt: DateTime! -} - -type User implements Node { - id: ID! - createdAt: DateTime! - email: String! -} - -type Post implements Node { - id: ID! - createdAt: DateTime! - title: String! -} - -type Query { - node(id: ID!): Node -} -``` - -### 3. Unions for Heterogeneous Results - -```graphql -union SearchResult = User | Post | Comment - -type Query { - search(query: String!): [SearchResult!]! -} - -# Query example -{ - search(query: "graphql") { - ... on User { - name - email - } - ... on Post { - title - content - } - ... on Comment { - text - author { - name - } - } - } -} -``` - -### 4. Input Types - -```graphql -input CreateUserInput { - email: String! - name: String! - password: String! - profileInput: ProfileInput -} - -input ProfileInput { - bio: String - avatar: String - website: String -} - -input UpdateUserInput { - id: ID! - email: String - name: String - profileInput: ProfileInput -} -``` - -## Pagination Patterns - -### Relay Cursor Pagination (Recommended) - -```graphql -type UserConnection { - edges: [UserEdge!]! - pageInfo: PageInfo! - totalCount: Int! -} - -type UserEdge { - node: User! - cursor: String! -} - -type PageInfo { - hasNextPage: Boolean! - hasPreviousPage: Boolean! - startCursor: String - endCursor: String -} - -type Query { - users(first: Int, after: String, last: Int, before: String): UserConnection! -} - -# Usage -{ - users(first: 10, after: "cursor123") { - edges { - cursor - node { - id - name - } - } - pageInfo { - hasNextPage - endCursor - } - } -} -``` - -### Offset Pagination (Simpler) - -```graphql -type UserList { - items: [User!]! - total: Int! - page: Int! - pageSize: Int! -} - -type Query { - users(page: Int = 1, pageSize: Int = 20): UserList! -} -``` - -## Mutation Design Patterns - -### 1. Input/Payload Pattern - -```graphql -input CreatePostInput { - title: String! - content: String! - tags: [String!] -} - -type CreatePostPayload { - post: Post - errors: [Error!] - success: Boolean! -} - -type Error { - field: String - message: String! - code: String! -} - -type Mutation { - createPost(input: CreatePostInput!): CreatePostPayload! -} -``` - -### 2. Optimistic Response Support - -```graphql -type UpdateUserPayload { - user: User - clientMutationId: String - errors: [Error!] -} - -input UpdateUserInput { - id: ID! - name: String - clientMutationId: String -} - -type Mutation { - updateUser(input: UpdateUserInput!): UpdateUserPayload! -} -``` - -### 3. Batch Mutations - -```graphql -input BatchCreateUserInput { - users: [CreateUserInput!]! -} - -type BatchCreateUserPayload { - results: [CreateUserResult!]! - successCount: Int! - errorCount: Int! -} - -type CreateUserResult { - user: User - errors: [Error!] - index: Int! -} - -type Mutation { - batchCreateUsers(input: BatchCreateUserInput!): BatchCreateUserPayload! -} -``` - -## Field Design - -### Arguments and Filtering - -```graphql -type Query { - posts( - # Pagination - first: Int = 20 - after: String - - # Filtering - status: PostStatus - authorId: ID - tag: String - - # Sorting - orderBy: PostOrderBy = CREATED_AT - orderDirection: OrderDirection = DESC - - # Searching - search: String - ): PostConnection! -} - -enum PostStatus { - DRAFT - PUBLISHED - ARCHIVED -} - -enum PostOrderBy { - CREATED_AT - UPDATED_AT - TITLE -} - -enum OrderDirection { - ASC - DESC -} -``` - -### Computed Fields - -```graphql -type User { - firstName: String! - lastName: String! - fullName: String! # Computed in resolver - posts: [Post!]! - postCount: Int! # Computed, doesn't load all posts -} - -type Post { - likeCount: Int! - commentCount: Int! - isLikedByViewer: Boolean! # Context-dependent -} -``` - -## Subscriptions - -```graphql -type Subscription { - postAdded: Post! - - postUpdated(postId: ID!): Post! - - userStatusChanged(userId: ID!): UserStatus! -} - -type UserStatus { - userId: ID! - online: Boolean! - lastSeen: DateTime! -} - -# Client usage -subscription { - postAdded { - id - title - author { - name - } - } -} -``` - -## Custom Scalars - -```graphql -scalar DateTime -scalar Email -scalar URL -scalar JSON -scalar Money - -type User { - email: Email! - website: URL - createdAt: DateTime! - metadata: JSON -} - -type Product { - price: Money! -} -``` - -## Directives - -### Built-in Directives - -```graphql -type User { - name: String! - email: String! @deprecated(reason: "Use emails field instead") - emails: [String!]! - - # Conditional inclusion - privateData: PrivateData @include(if: $isOwner) -} - -# Query -query GetUser($isOwner: Boolean!) { - user(id: "123") { - name - privateData @include(if: $isOwner) { - ssn - } - } -} -``` - -### Custom Directives - -```graphql -directive @auth(requires: Role = USER) on FIELD_DEFINITION - -enum Role { - USER - ADMIN - MODERATOR -} - -type Mutation { - deleteUser(id: ID!): Boolean! @auth(requires: ADMIN) - updateProfile(input: ProfileInput!): User! @auth -} -``` - -## Error Handling - -### Union Error Pattern - -```graphql -type User { - id: ID! - email: String! -} - -type ValidationError { - field: String! - message: String! -} - -type NotFoundError { - message: String! - resourceType: String! - resourceId: ID! -} - -type AuthorizationError { - message: String! -} - -union UserResult = User | ValidationError | NotFoundError | AuthorizationError - -type Query { - user(id: ID!): UserResult! -} - -# Usage -{ - user(id: "123") { - ... on User { - id - email - } - ... on NotFoundError { - message - resourceType - } - ... on AuthorizationError { - message - } - } -} -``` - -### Errors in Payload - -```graphql -type CreateUserPayload { - user: User - errors: [Error!] - success: Boolean! -} - -type Error { - field: String - message: String! - code: ErrorCode! -} - -enum ErrorCode { - VALIDATION_ERROR - UNAUTHORIZED - NOT_FOUND - INTERNAL_ERROR -} -``` - -## N+1 Query Problem Solutions - -### DataLoader Pattern - -```python -from aiodataloader import DataLoader - -class PostLoader(DataLoader): - async def batch_load_fn(self, post_ids): - posts = await db.posts.find({"id": {"$in": post_ids}}) - post_map = {post["id"]: post for post in posts} - return [post_map.get(pid) for pid in post_ids] - -# Resolver -@user_type.field("posts") -async def resolve_posts(user, info): - loader = info.context["loaders"]["post"] - return await loader.load_many(user["post_ids"]) -``` - -### Query Depth Limiting - -```python -from graphql import GraphQLError - -def depth_limit_validator(max_depth: int): - def validate(context, node, ancestors): - depth = len(ancestors) - if depth > max_depth: - raise GraphQLError( - f"Query depth {depth} exceeds maximum {max_depth}" - ) - return validate -``` - -### Query Complexity Analysis - -```python -def complexity_limit_validator(max_complexity: int): - def calculate_complexity(node): - # Each field = 1, lists multiply - complexity = 1 - if is_list_field(node): - complexity *= get_list_size_arg(node) - return complexity - - return validate_complexity -``` - -## Schema Versioning - -### Field Deprecation - -```graphql -type User { - name: String! @deprecated(reason: "Use firstName and lastName") - firstName: String! - lastName: String! -} -``` - -### Schema Evolution - -```graphql -# v1 - Initial -type User { - name: String! -} - -# v2 - Add optional field (backward compatible) -type User { - name: String! - email: String -} - -# v3 - Deprecate and add new field -type User { - name: String! @deprecated(reason: "Use firstName/lastName") - firstName: String! - lastName: String! - email: String -} -``` - -## Best Practices Summary - -1. **Nullable vs Non-Null**: Start nullable, make non-null when guaranteed -2. **Input Types**: Always use input types for mutations -3. **Payload Pattern**: Return errors in mutation payloads -4. **Pagination**: Use cursor-based for infinite scroll, offset for simple cases -5. **Naming**: Use camelCase for fields, PascalCase for types -6. **Deprecation**: Use `@deprecated` instead of removing fields -7. **DataLoaders**: Always use for relationships to prevent N+1 -8. **Complexity Limits**: Protect against expensive queries -9. **Custom Scalars**: Use for domain-specific types (Email, DateTime) -10. **Documentation**: Document all fields with descriptions diff --git a/builtin-skills/software-engineer/api-design-principles/references/rest-best-practices.md b/builtin-skills/software-engineer/api-design-principles/references/rest-best-practices.md deleted file mode 100644 index 676be296..00000000 --- a/builtin-skills/software-engineer/api-design-principles/references/rest-best-practices.md +++ /dev/null @@ -1,408 +0,0 @@ -# REST API Best Practices - -## URL Structure - -### Resource Naming - -``` -# Good - Plural nouns -GET /api/users -GET /api/orders -GET /api/products - -# Bad - Verbs or mixed conventions -GET /api/getUser -GET /api/user (inconsistent singular) -POST /api/createOrder -``` - -### Nested Resources - -``` -# Shallow nesting (preferred) -GET /api/users/{id}/orders -GET /api/orders/{id} - -# Deep nesting (avoid) -GET /api/users/{id}/orders/{orderId}/items/{itemId}/reviews -# Better: -GET /api/order-items/{id}/reviews -``` - -## HTTP Methods and Status Codes - -### GET - Retrieve Resources - -``` -GET /api/users → 200 OK (with list) -GET /api/users/{id} → 200 OK or 404 Not Found -GET /api/users?page=2 → 200 OK (paginated) -``` - -### POST - Create Resources - -``` -POST /api/users - Body: {"name": "John", "email": "john@example.com"} - → 201 Created - Location: /api/users/123 - Body: {"id": "123", "name": "John", ...} - -POST /api/users (validation error) - → 422 Unprocessable Entity - Body: {"errors": [...]} -``` - -### PUT - Replace Resources - -``` -PUT /api/users/{id} - Body: {complete user object} - → 200 OK (updated) - → 404 Not Found (doesn't exist) - -# Must include ALL fields -``` - -### PATCH - Partial Update - -``` -PATCH /api/users/{id} - Body: {"name": "Jane"} (only changed fields) - → 200 OK - → 404 Not Found -``` - -### DELETE - Remove Resources - -``` -DELETE /api/users/{id} - → 204 No Content (deleted) - → 404 Not Found - → 409 Conflict (can't delete due to references) -``` - -## Filtering, Sorting, and Searching - -### Query Parameters - -``` -# Filtering -GET /api/users?status=active -GET /api/users?role=admin&status=active - -# Sorting -GET /api/users?sort=created_at -GET /api/users?sort=-created_at (descending) -GET /api/users?sort=name,created_at - -# Searching -GET /api/users?search=john -GET /api/users?q=john - -# Field selection (sparse fieldsets) -GET /api/users?fields=id,name,email -``` - -## Pagination Patterns - -### Offset-Based Pagination - -```python -GET /api/users?page=2&page_size=20 - -Response: -{ - "items": [...], - "page": 2, - "page_size": 20, - "total": 150, - "pages": 8 -} -``` - -### Cursor-Based Pagination (for large datasets) - -```python -GET /api/users?limit=20&cursor=eyJpZCI6MTIzfQ - -Response: -{ - "items": [...], - "next_cursor": "eyJpZCI6MTQzfQ", - "has_more": true -} -``` - -### Link Header Pagination (RESTful) - -``` -GET /api/users?page=2 - -Response Headers: -Link: ; rel="next", - ; rel="prev", - ; rel="first", - ; rel="last" -``` - -## Versioning Strategies - -### URL Versioning (Recommended) - -``` -/api/v1/users -/api/v2/users - -Pros: Clear, easy to route -Cons: Multiple URLs for same resource -``` - -### Header Versioning - -``` -GET /api/users -Accept: application/vnd.api+json; version=2 - -Pros: Clean URLs -Cons: Less visible, harder to test -``` - -### Query Parameter - -``` -GET /api/users?version=2 - -Pros: Easy to test -Cons: Optional parameter can be forgotten -``` - -## Rate Limiting - -### Headers - -``` -X-RateLimit-Limit: 1000 -X-RateLimit-Remaining: 742 -X-RateLimit-Reset: 1640000000 - -Response when limited: -429 Too Many Requests -Retry-After: 3600 -``` - -### Implementation Pattern - -```python -from fastapi import HTTPException, Request -from datetime import datetime, timedelta - -class RateLimiter: - def __init__(self, calls: int, period: int): - self.calls = calls - self.period = period - self.cache = {} - - def check(self, key: str) -> bool: - now = datetime.now() - if key not in self.cache: - self.cache[key] = [] - - # Remove old requests - self.cache[key] = [ - ts for ts in self.cache[key] - if now - ts < timedelta(seconds=self.period) - ] - - if len(self.cache[key]) >= self.calls: - return False - - self.cache[key].append(now) - return True - -limiter = RateLimiter(calls=100, period=60) - -@app.get("/api/users") -async def get_users(request: Request): - if not limiter.check(request.client.host): - raise HTTPException( - status_code=429, - headers={"Retry-After": "60"} - ) - return {"users": [...]} -``` - -## Authentication and Authorization - -### Bearer Token - -``` -Authorization: Bearer eyJhbGciOiJIUzI1NiIs... - -401 Unauthorized - Missing/invalid token -403 Forbidden - Valid token, insufficient permissions -``` - -### API Keys - -``` -X-API-Key: your-api-key-here -``` - -## Error Response Format - -### Consistent Structure - -```json -{ - "error": { - "code": "VALIDATION_ERROR", - "message": "Request validation failed", - "details": [ - { - "field": "email", - "message": "Invalid email format", - "value": "not-an-email" - } - ], - "timestamp": "2025-10-16T12:00:00Z", - "path": "/api/users" - } -} -``` - -### Status Code Guidelines - -- `200 OK`: Successful GET, PATCH, PUT -- `201 Created`: Successful POST -- `204 No Content`: Successful DELETE -- `400 Bad Request`: Malformed request -- `401 Unauthorized`: Authentication required -- `403 Forbidden`: Authenticated but not authorized -- `404 Not Found`: Resource doesn't exist -- `409 Conflict`: State conflict (duplicate email, etc.) -- `422 Unprocessable Entity`: Validation errors -- `429 Too Many Requests`: Rate limited -- `500 Internal Server Error`: Server error -- `503 Service Unavailable`: Temporary downtime - -## Caching - -### Cache Headers - -``` -# Client caching -Cache-Control: public, max-age=3600 - -# No caching -Cache-Control: no-cache, no-store, must-revalidate - -# Conditional requests -ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" -If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4" -→ 304 Not Modified -``` - -## Bulk Operations - -### Batch Endpoints - -```python -POST /api/users/batch -{ - "items": [ - {"name": "User1", "email": "user1@example.com"}, - {"name": "User2", "email": "user2@example.com"} - ] -} - -Response: -{ - "results": [ - {"id": "1", "status": "created"}, - {"id": null, "status": "failed", "error": "Email already exists"} - ] -} -``` - -## Idempotency - -### Idempotency Keys - -``` -POST /api/orders -Idempotency-Key: unique-key-123 - -If duplicate request: -→ 200 OK (return cached response) -``` - -## CORS Configuration - -```python -from fastapi.middleware.cors import CORSMiddleware - -app.add_middleware( - CORSMiddleware, - allow_origins=["https://example.com"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) -``` - -## Documentation with OpenAPI - -```python -from fastapi import FastAPI - -app = FastAPI( - title="My API", - description="API for managing users", - version="1.0.0", - docs_url="/docs", - redoc_url="/redoc" -) - -@app.get( - "/api/users/{user_id}", - summary="Get user by ID", - response_description="User details", - tags=["Users"] -) -async def get_user( - user_id: str = Path(..., description="The user ID") -): - """ - Retrieve user by ID. - - Returns full user profile including: - - Basic information - - Contact details - - Account status - """ - pass -``` - -## Health and Monitoring Endpoints - -```python -@app.get("/health") -async def health_check(): - return { - "status": "healthy", - "version": "1.0.0", - "timestamp": datetime.now().isoformat() - } - -@app.get("/health/detailed") -async def detailed_health(): - return { - "status": "healthy", - "checks": { - "database": await check_database(), - "redis": await check_redis(), - "external_api": await check_external_api() - } - } -``` diff --git a/builtin-skills/software-engineer/clean-architecture/SKILL.md b/builtin-skills/software-engineer/clean-architecture/SKILL.md deleted file mode 100644 index 7e0bf348..00000000 --- a/builtin-skills/software-engineer/clean-architecture/SKILL.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -name: clean-architecture -description: Clean Architecture principles and best practices from Robert C. Martin's book. This skill should be used when designing software systems, reviewing code structure, or refactoring applications to achieve better separation of concerns. Triggers on tasks involving layers, boundaries, dependency direction, entities, use cases, or system architecture. ---- - -# Clean Architecture Best Practices - -Comprehensive guide to Clean Architecture principles for designing maintainable, testable software systems. Based on Robert C. Martin's "Clean Architecture: A Craftsman's Guide to Software Structure and Design." Contains 42 rules across 8 categories, prioritized by architectural impact. - -## When to Apply - -Reference these guidelines when: -- Designing new software systems or modules -- Structuring dependencies between layers -- Defining boundaries between business logic and infrastructure -- Reviewing code for architectural violations -- Refactoring coupled systems toward cleaner structure - -## Rule Categories by Priority - -| Priority | Category | Impact | Prefix | -|----------|----------|--------|--------| -| 1 | Dependency Direction | CRITICAL | `dep-` | -| 2 | Entity Design | CRITICAL | `entity-` | -| 3 | Use Case Isolation | HIGH | `usecase-` | -| 4 | Component Cohesion | HIGH | `comp-` | -| 5 | Boundary Definition | MEDIUM-HIGH | `bound-` | -| 6 | Interface Adapters | MEDIUM | `adapt-` | -| 7 | Framework Isolation | MEDIUM | `frame-` | -| 8 | Testing Architecture | LOW-MEDIUM | `test-` | - -## Quick Reference - -### 1. Dependency Direction (CRITICAL) - -- [`dep-inward-only`](references/dep-inward-only.md) - Source dependencies point inward only -- [`dep-interface-ownership`](references/dep-interface-ownership.md) - Interfaces belong to clients not implementers -- [`dep-no-framework-imports`](references/dep-no-framework-imports.md) - Avoid framework imports in inner layers -- [`dep-data-crossing-boundaries`](references/dep-data-crossing-boundaries.md) - Use simple data structures across boundaries -- [`dep-acyclic-dependencies`](references/dep-acyclic-dependencies.md) - Eliminate cyclic dependencies between components -- [`dep-stable-abstractions`](references/dep-stable-abstractions.md) - Depend on stable abstractions not volatile concretions - -### 2. Entity Design (CRITICAL) - -- [`entity-pure-business-rules`](references/entity-pure-business-rules.md) - Entities contain only enterprise business rules -- [`entity-no-persistence-awareness`](references/entity-no-persistence-awareness.md) - Entities must not know how they are persisted -- [`entity-encapsulate-invariants`](references/entity-encapsulate-invariants.md) - Encapsulate business invariants within entities -- [`entity-value-objects`](references/entity-value-objects.md) - Use value objects for domain concepts -- [`entity-rich-not-anemic`](references/entity-rich-not-anemic.md) - Build rich domain models not anemic data structures - -### 3. Use Case Isolation (HIGH) - -- [`usecase-single-responsibility`](references/usecase-single-responsibility.md) - Each use case has one reason to change -- [`usecase-input-output-ports`](references/usecase-input-output-ports.md) - Define input and output ports for use cases -- [`usecase-orchestrates-not-implements`](references/usecase-orchestrates-not-implements.md) - Use cases orchestrate entities not implement business rules -- [`usecase-no-presentation-logic`](references/usecase-no-presentation-logic.md) - Use cases must not contain presentation logic -- [`usecase-explicit-dependencies`](references/usecase-explicit-dependencies.md) - Declare all dependencies explicitly in constructor -- [`usecase-transaction-boundary`](references/usecase-transaction-boundary.md) - Use case defines the transaction boundary - -### 4. Component Cohesion (HIGH) - -- [`comp-screaming-architecture`](references/comp-screaming-architecture.md) - Structure should scream the domain not the framework -- [`comp-common-closure`](references/comp-common-closure.md) - Group classes that change together -- [`comp-common-reuse`](references/comp-common-reuse.md) - Avoid forcing clients to depend on unused code -- [`comp-reuse-release-equivalence`](references/comp-reuse-release-equivalence.md) - Release components as cohesive units -- [`comp-stable-dependencies`](references/comp-stable-dependencies.md) - Depend in the direction of stability - -### 5. Boundary Definition (MEDIUM-HIGH) - -- [`bound-humble-object`](references/bound-humble-object.md) - Use humble objects at architectural boundaries -- [`bound-partial-boundaries`](references/bound-partial-boundaries.md) - Use partial boundaries when full separation is premature -- [`bound-boundary-cost-awareness`](references/bound-boundary-cost-awareness.md) - Weigh boundary cost against ignorance cost -- [`bound-main-component`](references/bound-main-component.md) - Treat main as a plugin to the application -- [`bound-defer-decisions`](references/bound-defer-decisions.md) - Defer framework and database decisions -- [`bound-service-internal-architecture`](references/bound-service-internal-architecture.md) - Services must have internal clean architecture - -### 6. Interface Adapters (MEDIUM) - -- [`adapt-controller-thin`](references/adapt-controller-thin.md) - Keep controllers thin -- [`adapt-presenter-formats`](references/adapt-presenter-formats.md) - Presenters format data for the view -- [`adapt-gateway-abstraction`](references/adapt-gateway-abstraction.md) - Gateways hide external system details -- [`adapt-mapper-translation`](references/adapt-mapper-translation.md) - Use mappers to translate between layers -- [`adapt-anti-corruption-layer`](references/adapt-anti-corruption-layer.md) - Build anti-corruption layers for external systems - -### 7. Framework Isolation (MEDIUM) - -- [`frame-domain-purity`](references/frame-domain-purity.md) - Domain layer has zero framework dependencies -- [`frame-orm-in-infrastructure`](references/frame-orm-in-infrastructure.md) - Keep ORM usage in infrastructure layer -- [`frame-web-in-infrastructure`](references/frame-web-in-infrastructure.md) - Web framework concerns stay in interface layer -- [`frame-di-container-edge`](references/frame-di-container-edge.md) - Dependency injection containers live at the edge -- [`frame-logging-abstraction`](references/frame-logging-abstraction.md) - Abstract logging behind domain interfaces - -### 8. Testing Architecture (LOW-MEDIUM) - -- [`test-tests-are-architecture`](references/test-tests-are-architecture.md) - Tests are part of the system architecture -- [`test-testable-design`](references/test-testable-design.md) - Design for testability from the start -- [`test-layer-isolation`](references/test-layer-isolation.md) - Test each layer in isolation -- [`test-boundary-verification`](references/test-boundary-verification.md) - Verify architectural boundaries with tests - -## How to Use - -Read individual reference files for detailed explanations and code examples: - -- [Section definitions](references/_sections.md) - Category structure and impact levels -- [Rule template](assets/templates/_template.md) - Template for adding new rules - -## Reference Files - -| File | Description | -|------|-------------| -| [references/_sections.md](references/_sections.md) | Category definitions and ordering | -| [assets/templates/_template.md](assets/templates/_template.md) | Template for new rules | -| [metadata.json](metadata.json) | Version and reference information | diff --git a/builtin-skills/software-engineer/clean-architecture/assets/templates/_template.md b/builtin-skills/software-engineer/clean-architecture/assets/templates/_template.md deleted file mode 100644 index 5840911f..00000000 --- a/builtin-skills/software-engineer/clean-architecture/assets/templates/_template.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Rule Title in Imperative Form -impact: CRITICAL|HIGH|MEDIUM-HIGH|MEDIUM|LOW-MEDIUM|LOW -impactDescription: quantified impact, e.g., "prevents cascade failures", "2-10× testability improvement" -tags: prefix, technique1, technique2, concept ---- - -## Rule Title in Imperative Form - -Brief explanation (1-3 sentences) of WHY this matters for software architecture. Focus on the architectural implications and cascade effects. - -**Incorrect (description of problem/cost):** - -```language -// Code example showing the anti-pattern -// Include comments on problematic lines explaining the cost -``` - -**Correct (description of benefit/solution):** - -```language -// Code example showing the correct pattern -// Minimal diff from incorrect - same variable names, structure -``` - -**Alternative (when applicable):** - -```language -// Alternative approach for specific contexts -``` - -**When NOT to use this pattern:** -- Exception or edge case 1 -- Exception or edge case 2 - -**Benefits:** -- Concrete benefit 1 -- Concrete benefit 2 - -Reference: [Source Title](URL) diff --git a/builtin-skills/software-engineer/clean-architecture/metadata.json b/builtin-skills/software-engineer/clean-architecture/metadata.json deleted file mode 100644 index a4cd8aea..00000000 --- a/builtin-skills/software-engineer/clean-architecture/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "version": "1.0.2", - "organization": "Uncle Bob (Robert C. Martin)", - "technology": "Clean Architecture", - "date": "January 2026", - "abstract": "Comprehensive guide to Clean Architecture principles for designing maintainable, testable software systems. Based on Robert C. Martin's 'Clean Architecture: A Craftsman's Guide to Software Structure and Design.' Contains 42 rules across 8 categories, prioritized by impact from critical (dependency direction, entity design) to incremental (testing architecture). Each rule includes detailed explanations, language-agnostic code examples comparing incorrect vs. correct implementations, and specific impact descriptions.", - "references": [ - "https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html", - "https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/", - "https://github.com/serodriguez68/clean-architecture", - "https://www.milanjovanovic.tech/blog/screaming-architecture", - "https://martinfowler.com/bliki/AnemicDomainModel.html" - ] -} diff --git a/builtin-skills/software-engineer/clean-architecture/references/_sections.md b/builtin-skills/software-engineer/clean-architecture/references/_sections.md deleted file mode 100644 index f0570368..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/_sections.md +++ /dev/null @@ -1,46 +0,0 @@ -# Sections - -This file defines all sections, their ordering, impact levels, and descriptions. -The section ID (in parentheses) is the filename prefix used to group rules. - ---- - -## 1. Dependency Direction (dep) - -**Impact:** CRITICAL -**Description:** The Dependency Rule is the architectural foundation. Source code dependencies must point inward only; violations cascade failures across all layers. - -## 2. Entity Design (entity) - -**Impact:** CRITICAL -**Description:** Enterprise business rules must be framework-agnostic, stable, and completely independent of databases, UI, and external systems. - -## 3. Use Case Isolation (usecase) - -**Impact:** HIGH -**Description:** Application-specific business rules orchestrate entities without leaking infrastructure details or depending on presentation concerns. - -## 4. Component Cohesion (comp) - -**Impact:** HIGH -**Description:** Components grouped by business capability enable independent deployment, parallel team development, and controlled change propagation. - -## 5. Boundary Definition (bound) - -**Impact:** MEDIUM-HIGH -**Description:** Architectural boundaries isolate volatile from stable elements; Humble Objects maximize testability by separating hard-to-test from easy-to-test code. - -## 6. Interface Adapters (adapt) - -**Impact:** MEDIUM -**Description:** Controllers, presenters, and gateways translate between use cases and external systems without leaking implementation details. - -## 7. Framework Isolation (frame) - -**Impact:** MEDIUM -**Description:** Frameworks are details, not architecture. Business logic must never import, reference, or depend on framework-specific types. - -## 8. Testing Architecture (test) - -**Impact:** LOW-MEDIUM -**Description:** Tests are architectural components. Layer isolation enables fast unit tests, while boundaries enable targeted integration tests. diff --git a/builtin-skills/software-engineer/clean-architecture/references/adapt-anti-corruption-layer.md b/builtin-skills/software-engineer/clean-architecture/references/adapt-anti-corruption-layer.md deleted file mode 100644 index 90bff904..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/adapt-anti-corruption-layer.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Build Anti-Corruption Layers for External Systems -impact: MEDIUM -impactDescription: protects domain from external model pollution -tags: adapt, anti-corruption, external, isolation ---- - -## Build Anti-Corruption Layers for External Systems - -When integrating with external systems that have different models, build an anti-corruption layer (ACL) that translates between their model and yours. Never let external concepts pollute your domain. - -**Incorrect (external model leaks into domain):** - -```java -// Domain polluted with Stripe's model -public class Order { - private String id; - private List items; - // Stripe-specific fields in domain - private String stripeCustomerId; - private String stripePaymentIntentId; - private String stripePaymentMethodId; - - public void processPayment(Stripe stripe) { - // Domain directly calls Stripe - PaymentIntent intent = PaymentIntent.create( - PaymentIntentCreateParams.builder() - .setCustomer(this.stripeCustomerId) - .setPaymentMethod(this.stripePaymentMethodId) - .setAmount(this.calculateTotal().cents()) - .setCurrency("usd") - .build() - ); - this.stripePaymentIntentId = intent.getId(); - } -} - -// If we switch to PayPal, Order must change -``` - -**Correct (anti-corruption layer isolates external model):** - -```java -// domain/Order.java - Pure domain, no external concepts -public class Order { - private OrderId id; - private CustomerId customerId; - private List items; - private PaymentStatus paymentStatus; - - public Money calculateTotal() { - return items.stream() - .map(OrderItem::lineTotal) - .reduce(Money.zero(), Money::add); - } - - public void markPaid(PaymentReference reference) { - this.paymentStatus = PaymentStatus.paid(reference); - } -} - -// domain/ports/PaymentProcessor.java - Domain-defined port -public interface PaymentProcessor { - PaymentResult charge(CustomerId customer, Money amount); -} - -// Domain-defined value objects -public record PaymentResult(PaymentReference reference, PaymentStatus status) {} -public record PaymentReference(String value) {} - -// infrastructure/stripe/StripePaymentProcessor.java - ACL -public class StripePaymentProcessor implements PaymentProcessor { - private final CustomerMappingRepository customerMapping; - - public PaymentResult charge(CustomerId customerId, Money amount) { - // Translate domain CustomerId to Stripe customer - String stripeCustomerId = customerMapping.getStripeId(customerId); - - // Call Stripe with their model - PaymentIntent intent = PaymentIntent.create( - PaymentIntentCreateParams.builder() - .setCustomer(stripeCustomerId) - .setAmount(amount.cents()) - .setCurrency("usd") - .setConfirm(true) - .build() - ); - - // Translate Stripe response back to domain model - return new PaymentResult( - new PaymentReference(intent.getId()), - translateStatus(intent.getStatus()) - ); - } - - private PaymentStatus translateStatus(String stripeStatus) { - return switch (stripeStatus) { - case "succeeded" -> PaymentStatus.COMPLETED; - case "processing" -> PaymentStatus.PENDING; - case "requires_action" -> PaymentStatus.REQUIRES_ACTION; - default -> PaymentStatus.FAILED; - }; - } -} -``` - -**Benefits:** -- Domain model remains clean and business-focused -- Switch payment providers by implementing new ACL -- External API changes isolated to ACL - -Reference: [Anti-Corruption Layer Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/anti-corruption-layer) diff --git a/builtin-skills/software-engineer/clean-architecture/references/adapt-controller-thin.md b/builtin-skills/software-engineer/clean-architecture/references/adapt-controller-thin.md deleted file mode 100644 index e2c71c9f..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/adapt-controller-thin.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Keep Controllers Thin -impact: MEDIUM -impactDescription: simplifies testing, isolates HTTP concerns -tags: adapt, controller, thin, http ---- - -## Keep Controllers Thin - -Controllers should only handle HTTP concerns: parsing requests, validating input format, calling use cases, and formatting responses. No business logic. - -**Incorrect (fat controller with business logic):** - -```python -class OrderController: - @app.route('/orders', methods=['POST']) - def create_order(self): - data = request.json - - # Input validation - OK in controller - if not data.get('items'): - return jsonify({'error': 'Items required'}), 400 - - # Business logic - WRONG in controller - customer = db.query(Customer).get(data['customer_id']) - if not customer.is_active: - return jsonify({'error': 'Inactive customer'}), 400 - - total = 0 - for item in data['items']: - product = db.query(Product).get(item['product_id']) - if product.stock < item['quantity']: - return jsonify({'error': f'{product.name} out of stock'}), 400 - total += product.price * item['quantity'] - - # More business logic - if total > customer.credit_limit: - return jsonify({'error': 'Exceeds credit limit'}), 400 - - order = Order( - customer_id=customer.id, - items=data['items'], - total=total - ) - db.session.add(order) - db.session.commit() - - return jsonify({'order_id': order.id}), 201 -``` - -**Correct (thin controller delegates to use case):** - -```python -class OrderController: - def __init__(self, create_order_use_case: CreateOrderUseCase): - self.create_order = create_order_use_case - - @app.route('/orders', methods=['POST']) - def create(self): - # Parse HTTP request - data = request.json - - # Validate request format (not business rules) - if not data.get('items'): - return jsonify({'error': 'Items required'}), 400 - - # Build command - command = CreateOrderCommand( - customer_id=data['customer_id'], - items=[ - OrderItemCommand(p['product_id'], p['quantity']) - for p in data['items'] - ] - ) - - # Delegate to use case - try: - result = self.create_order.execute(command) - return jsonify({'order_id': result.order_id}), 201 - - except CustomerInactiveError: - return jsonify({'error': 'Customer account inactive'}), 400 - except InsufficientStockError as e: - return jsonify({'error': f'{e.product_name} out of stock'}), 400 - except CreditLimitExceededError: - return jsonify({'error': 'Order exceeds credit limit'}), 400 -``` - -**Controller responsibilities:** -- Parse HTTP request to command/query objects -- Validate request format (required fields present) -- Call appropriate use case -- Map exceptions to HTTP status codes -- Format response - -**Use case responsibilities:** -- Business validation (credit limits, stock) -- Business logic (calculations, state changes) -- Orchestrate entities and repositories - -Reference: [Clean Architecture - Controllers](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch22.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/adapt-gateway-abstraction.md b/builtin-skills/software-engineer/clean-architecture/references/adapt-gateway-abstraction.md deleted file mode 100644 index bff2871a..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/adapt-gateway-abstraction.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Gateways Hide External System Details -impact: MEDIUM -impactDescription: enables vendor switching, simplifies testing -tags: adapt, gateway, external, abstraction ---- - -## Gateways Hide External System Details - -Database gateways, API gateways, and service gateways are polymorphic interfaces that hide external system details. The use case layer talks to abstractions; infrastructure implements them. - -**Incorrect (use case knows external system details):** - -```go -func (uc *ProcessRefundUseCase) Execute(orderId string) error { - order := uc.db.QueryRow("SELECT * FROM orders WHERE id = $1", orderId) - - // Direct Stripe API knowledge in use case - stripe.Key = os.Getenv("STRIPE_KEY") - params := &stripe.RefundParams{ - PaymentIntent: stripe.String(order.PaymentIntentId), - Amount: stripe.Int64(order.Total), - } - _, err := refund.New(params) - if err != nil { - // Stripe-specific error handling - if stripeErr, ok := err.(*stripe.Error); ok { - if stripeErr.Code == stripe.ErrorCodeChargeAlreadyRefunded { - return ErrAlreadyRefunded - } - } - return err - } - - uc.db.Exec("UPDATE orders SET status = 'refunded' WHERE id = $1", orderId) - return nil -} -``` - -**Correct (gateway abstracts external system):** - -```go -// application/ports/PaymentGateway.go -type PaymentGateway interface { - Refund(paymentId string, amount Money) (RefundResult, error) -} - -type RefundResult struct { - RefundId string - Status RefundStatus -} - -// application/ports/OrderRepository.go -type OrderRepository interface { - FindById(id OrderId) (*Order, error) - Save(order *Order) error -} - -// application/usecases/ProcessRefundUseCase.go -type ProcessRefundUseCase struct { - orders OrderRepository - payments PaymentGateway -} - -func (uc *ProcessRefundUseCase) Execute(orderId string) error { - order, err := uc.orders.FindById(OrderId(orderId)) - if err != nil { - return err - } - - result, err := uc.payments.Refund(order.PaymentId, order.Total) - if err != nil { - return err // Gateway translates Stripe errors to domain errors - } - - order.MarkRefunded(result.RefundId) - return uc.orders.Save(order) -} - -// infrastructure/StripePaymentGateway.go -type StripePaymentGateway struct { - client *stripe.Client -} - -func (g *StripePaymentGateway) Refund(paymentId string, amount Money) (RefundResult, error) { - params := &stripe.RefundParams{ - PaymentIntent: stripe.String(paymentId), - Amount: stripe.Int64(amount.Cents()), - } - - refund, err := g.client.Refunds.New(params) - if err != nil { - return RefundResult{}, g.translateError(err) - } - - return RefundResult{ - RefundId: refund.ID, - Status: g.translateStatus(refund.Status), - }, nil -} - -func (g *StripePaymentGateway) translateError(err error) error { - // Convert Stripe-specific errors to domain errors - if stripeErr, ok := err.(*stripe.Error); ok { - switch stripeErr.Code { - case stripe.ErrorCodeChargeAlreadyRefunded: - return ErrAlreadyRefunded - } - } - return ErrPaymentFailed -} -``` - -**Benefits:** -- Switch from Stripe to Adyen without touching use cases -- Test use cases with mock gateways -- External API changes isolated to gateway implementation - -Reference: [Clean Architecture - Database Gateways](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch22.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/adapt-mapper-translation.md b/builtin-skills/software-engineer/clean-architecture/references/adapt-mapper-translation.md deleted file mode 100644 index c8113b9e..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/adapt-mapper-translation.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Use Mappers to Translate Between Layers -impact: MEDIUM -impactDescription: decouples domain from persistence and presentation models -tags: adapt, mapper, translation, layers ---- - -## Use Mappers to Translate Between Layers - -Mappers translate between domain entities and external representations (database rows, API responses, DTOs). Each layer has its own model; mappers bridge them. - -**Incorrect (domain entity used everywhere):** - -```typescript -// Domain entity directly serialized to JSON and stored in DB -class User { - id: string - email: string - passwordHash: string // Exposed in API response! - createdAt: Date - lastLogin: Date - preferences: UserPreferences - roles: Role[] - - toJSON() { - return { ...this } // Leaks everything - } -} - -// Controller returns entity directly -app.get('/users/:id', (req, res) => { - const user = userRepo.findById(req.params.id) - res.json(user) // passwordHash in response! -}) - -// ORM couples domain to database schema -@Entity() -class User { - @PrimaryColumn() id: string - @Column() email: string - // Domain entity is now a database entity -} -``` - -**Correct (dedicated models per layer with mappers):** - -```typescript -// domain/User.ts - Pure domain entity -class User { - constructor( - readonly id: UserId, - private email: Email, - private passwordHash: PasswordHash, - private roles: Set - ) {} - - hasRole(role: Role): boolean { - return this.roles.has(role) - } -} - -// infrastructure/persistence/UserEntity.ts - Database model -interface UserRow { - id: string - email: string - password_hash: string - roles: string // JSON array in DB - created_at: string - updated_at: string -} - -// infrastructure/persistence/UserMapper.ts -class UserMapper { - toDomain(row: UserRow): User { - return new User( - new UserId(row.id), - Email.create(row.email), - new PasswordHash(row.password_hash), - new Set(JSON.parse(row.roles)) - ) - } - - toPersistence(user: User): UserRow { - return { - id: user.id.value, - email: user.email.value, - password_hash: user.passwordHash.value, - roles: JSON.stringify([...user.roles]), - updated_at: new Date().toISOString() - } - } -} - -// interface/dto/UserResponse.ts - API response model -interface UserResponse { - id: string - email: string - roles: string[] - // No passwordHash! -} - -// interface/mappers/UserResponseMapper.ts -class UserResponseMapper { - toResponse(user: User): UserResponse { - return { - id: user.id.value, - email: user.email.value, - roles: [...user.roles] - } - } -} -``` - -**Benefits:** -- Database schema changes don't affect domain -- API can evolve independently of domain model -- Sensitive data never accidentally exposed - -Reference: [Data Mapper Pattern](https://martinfowler.com/eaaCatalog/dataMapper.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/adapt-presenter-formats.md b/builtin-skills/software-engineer/clean-architecture/references/adapt-presenter-formats.md deleted file mode 100644 index cb816802..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/adapt-presenter-formats.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Presenters Format Data for the View -impact: MEDIUM -impactDescription: enables multiple view formats from same use case -tags: adapt, presenter, formatting, view-model ---- - -## Presenters Format Data for the View - -Presenters accept data from use cases and format it for presentation. They create view models with strings, booleans, and pre-formatted values - nothing left for the view to compute. - -**Incorrect (view does formatting):** - -```tsx -// View component does formatting - logic spread across UI -function InvoiceView({ invoice }: { invoice: Invoice }) { - // Formatting logic in view - const formattedDate = new Date(invoice.dueDate).toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - year: 'numeric' - }) - - const formattedTotal = new Intl.NumberFormat('en-US', { - style: 'currency', - currency: invoice.currency - }).format(invoice.total / 100) - - const statusColor = invoice.status === 'paid' ? 'green' - : invoice.status === 'overdue' ? 'red' - : 'yellow' - - const daysOverdue = invoice.status === 'overdue' - ? Math.floor((Date.now() - new Date(invoice.dueDate).getTime()) / 86400000) - : 0 - - return ( -
- {invoice.status.toUpperCase()} - Due: {formattedDate} - Total: {formattedTotal} - {daysOverdue > 0 && {daysOverdue} days overdue} -
- ) -} -``` - -**Correct (presenter formats, view renders):** - -```tsx -// presenter/InvoicePresenter.ts -interface InvoiceViewModel { - invoiceNumber: string - status: string - statusColor: 'green' | 'yellow' | 'red' - dueDate: string - total: string - overdueMessage: string | null -} - -class InvoicePresenter { - present(invoice: InvoiceResult, locale: string): InvoiceViewModel { - return { - invoiceNumber: `INV-${invoice.id.padStart(6, '0')}`, - status: invoice.status.toUpperCase(), - statusColor: this.getStatusColor(invoice.status), - dueDate: this.formatDate(invoice.dueDate, locale), - total: this.formatMoney(invoice.total, invoice.currency, locale), - overdueMessage: this.getOverdueMessage(invoice) - } - } - - private getStatusColor(status: string): 'green' | 'yellow' | 'red' { - const colors = { paid: 'green', pending: 'yellow', overdue: 'red' } - return colors[status] || 'yellow' - } - - private formatDate(date: Date, locale: string): string { - return new Intl.DateTimeFormat(locale, { - month: 'long', day: 'numeric', year: 'numeric' - }).format(date) - } - - private getOverdueMessage(invoice: InvoiceResult): string | null { - if (invoice.status !== 'overdue') return null - const days = this.calculateDaysOverdue(invoice.dueDate) - return `${days} day${days !== 1 ? 's' : ''} overdue` - } -} - -// view/InvoiceView.tsx - Humble, just renders -function InvoiceView({ vm }: { vm: InvoiceViewModel }) { - return ( -
- {vm.status} - Due: {vm.dueDate} - Total: {vm.total} - {vm.overdueMessage && {vm.overdueMessage}} -
- ) -} -``` - -**Benefits:** -- Formatting logic tested without UI framework -- Same use case serves different locales via different presenter configs -- View components trivially simple, easy to redesign - -Reference: [Clean Architecture - Presenters and Humble Objects](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch23.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-boundary-cost-awareness.md b/builtin-skills/software-engineer/clean-architecture/references/bound-boundary-cost-awareness.md deleted file mode 100644 index bd1635e6..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-boundary-cost-awareness.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Weigh Boundary Cost Against Ignorance Cost -impact: MEDIUM-HIGH -impactDescription: optimizes architectural investment, prevents both over and under engineering -tags: bound, cost, tradeoffs, pragmatism ---- - -## Weigh Boundary Cost Against Ignorance Cost - -Boundaries are expensive to create and maintain, but ignoring needed boundaries becomes very expensive later. Continuously evaluate where the cost of implementing is less than the cost of ignoring. - -**Incorrect (boundary everywhere - over-engineering):** - -```java -// Overkill for a simple CRUD app with 3 entities - -// 9 interfaces for 3 entities -interface UserRepository { } -interface UserService { } -interface UserPresenter { } -interface ProductRepository { } -interface ProductService { } -interface ProductPresenter { } -interface OrderRepository { } -interface OrderService { } -interface OrderPresenter { } - -// 9 implementations -class SqlUserRepository implements UserRepository { } -class UserServiceImpl implements UserService { } -class UserPresenterImpl implements UserPresenter { } -// ... 6 more classes - -// 3 factories -class UserFactory { } -class ProductFactory { } -class OrderFactory { } - -// Result: 100 files for functionality that could be 20 files -// Maintenance burden exceeds benefit for small team -``` - -**Incorrect (no boundaries - under-engineering):** - -```java -// Dangerous for a complex domain with multiple teams - -class GodService { - public void handleEverything(Request req) { - // 2000 lines mixing: - // - User authentication - // - Order processing - // - Payment handling - // - Email notifications - // - Report generation - } -} - -// Result: Every change risks breaking unrelated features -// No team can work independently -``` - -**Correct (boundaries where they matter):** - -```java -// Evaluate each potential boundary: - -// HIGH VALUE BOUNDARY: External payment provider -// - Changes frequently (provider updates API) -// - Risk of vendor lock-in -// - Different team might own this -interface PaymentGateway { - PaymentResult charge(Money amount, PaymentMethod method); -} - -// MEDIUM VALUE BOUNDARY: Database access -// - Might migrate databases -// - Enables testing without DB -interface OrderRepository { - void save(Order order); - Order findById(OrderId id); -} - -// LOW VALUE - SKIP FOR NOW: Presenter/View split -// - Single frontend, single team -// - No plans to support multiple UIs -// Just put formatting in React components for now -// Add boundary later if needed - -// SKIP: Separate microservices -// - Team is 5 people -// - Deployment is monolithic anyway -// - Network boundary adds latency and complexity for no benefit -``` - -**Decision Framework:** -| Factor | Add Boundary | Skip Boundary | -|--------|-------------|---------------| -| Change frequency | High | Low | -| Team ownership | Multiple teams | Single team | -| External dependency | Yes | No | -| Testing difficulty | Hard without boundary | Easy anyway | -| Current pain | Evident | Hypothetical | - -Reference: [Clean Architecture - The Cost of Boundaries](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch25.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-defer-decisions.md b/builtin-skills/software-engineer/clean-architecture/references/bound-defer-decisions.md deleted file mode 100644 index eea90678..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-defer-decisions.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Defer Framework and Database Decisions -impact: MEDIUM-HIGH -impactDescription: preserves optionality, reduces early commitment risk -tags: bound, deferral, decisions, optionality ---- - -## Defer Framework and Database Decisions - -A good architecture allows major decisions about frameworks, databases, and delivery mechanisms to be deferred until the last responsible moment. The longer you wait, the more information you have. - -**Incorrect (early commitment to specifics):** - -```typescript -// Day 1: "Let's use Prisma with PostgreSQL and Next.js" - -// domain/Order.ts - Coupled to Prisma from the start -import { PrismaClient } from '@prisma/client' - -const prisma = new PrismaClient() - -export async function createOrder(data: OrderInput) { - // Business logic intertwined with Prisma - const order = await prisma.order.create({ - data: { - items: { - create: data.items.map(item => ({ - productId: item.productId, - quantity: item.quantity, - price: item.price - })) - }, - total: data.items.reduce((sum, i) => sum + i.price * i.quantity, 0) - }, - include: { items: true } - }) - - return order -} - -// 6 months later: "PostgreSQL doesn't scale for our read patterns, -// we need DynamoDB" - Massive rewrite required -``` - -**Correct (defer database decision):** - -```typescript -// Day 1: Focus on business rules, defer database choice - -// domain/Order.ts - Pure business logic -export class Order { - private items: OrderItem[] = [] - - addItem(product: Product, quantity: number): void { - if (quantity <= 0) throw new InvalidQuantityError() - this.items.push(new OrderItem(product, quantity)) - } - - calculateTotal(): Money { - return this.items.reduce( - (sum, item) => sum.add(item.lineTotal()), - Money.zero() - ) - } -} - -// application/ports/OrderRepository.ts - Interface only -export interface OrderRepository { - save(order: Order): Promise - findById(id: OrderId): Promise -} - -// For now: Simple in-memory implementation for testing -// infrastructure/InMemoryOrderRepository.ts -export class InMemoryOrderRepository implements OrderRepository { - private orders = new Map() - - async save(order: Order): Promise { - this.orders.set(order.id.value, order) - } -} - -// Later, when you know more: Add real database -// infrastructure/PrismaOrderRepository.ts -// OR -// infrastructure/DynamoOrderRepository.ts -// OR -// infrastructure/MongoOrderRepository.ts - -// The domain never changes regardless of database choice -``` - -**Decisions worth deferring:** -- Database vendor (PostgreSQL vs MongoDB vs DynamoDB) -- ORM choice (Prisma vs TypeORM vs raw SQL) -- Web framework (Express vs Fastify vs Hono) -- Message queue (RabbitMQ vs Kafka vs SQS) -- Cache provider (Redis vs Memcached) - -**Benefits:** -- Learn requirements before committing -- Prototype faster with simple implementations -- Switch vendors without domain rewrites - -Reference: [Clean Architecture - The Database is a Detail](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch30.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-humble-object.md b/builtin-skills/software-engineer/clean-architecture/references/bound-humble-object.md deleted file mode 100644 index 69a98ba3..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-humble-object.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Use Humble Objects at Architectural Boundaries -impact: MEDIUM-HIGH -impactDescription: maximizes testable code, isolates hard-to-test parts -tags: bound, humble-object, testing, boundaries ---- - -## Use Humble Objects at Architectural Boundaries - -The Humble Object pattern separates hard-to-test behaviors from easy-to-test behaviors. The "humble" part contains minimal logic and is hard to test; the substantial logic goes in a testable component. - -**Incorrect (logic mixed with hard-to-test framework code):** - -```typescript -// React component with business logic -function OrderSummary({ orderId }: Props) { - const [order, setOrder] = useState(null) - const [discount, setDiscount] = useState(0) - - useEffect(() => { - fetch(`/api/orders/${orderId}`) - .then(r => r.json()) - .then(data => { - setOrder(data) - // Business logic in component - hard to test - if (data.items.length > 5) { - setDiscount(data.total * 0.1) - } else if (data.customer.tier === 'gold') { - setDiscount(data.total * 0.05) - } - }) - }, [orderId]) - - const finalTotal = order ? order.total - discount : 0 - - return ( -
- Subtotal: ${order?.total} - Discount: ${discount} - Total: ${finalTotal} -
- ) -} - -// Testing requires React Testing Library + mocked fetch -``` - -**Correct (humble view + testable presenter):** - -```typescript -// Presenter - pure function, easy to test -interface OrderViewModel { - subtotal: string - discount: string - total: string - hasDiscount: boolean -} - -function presentOrder(order: Order): OrderViewModel { - const discount = calculateDiscount(order) - const finalTotal = order.total - discount - - return { - subtotal: formatCurrency(order.total), - discount: formatCurrency(discount), - total: formatCurrency(finalTotal), - hasDiscount: discount > 0 - } -} - -function calculateDiscount(order: Order): number { - if (order.items.length > 5) return order.total * 0.1 - if (order.customer.tier === 'gold') return order.total * 0.05 - return 0 -} - -// Humble view - no logic, just renders data -function OrderSummary({ viewModel }: { viewModel: OrderViewModel }) { - return ( -
- Subtotal: {viewModel.subtotal} - {viewModel.hasDiscount && Discount: {viewModel.discount}} - Total: {viewModel.total} -
- ) -} - -// Container handles data fetching - also humble -function OrderSummaryContainer({ orderId }: Props) { - const { data: order } = useQuery(['order', orderId], fetchOrder) - if (!order) return - return -} - -// Test presenter without React -test('applies bulk discount for 6+ items', () => { - const order = { items: [1,2,3,4,5,6], total: 100, customer: { tier: 'standard' } } - const vm = presentOrder(order) - expect(vm.discount).toBe('$10.00') -}) -``` - -**Benefits:** -- Business logic tested with simple unit tests -- UI tests only verify rendering, not logic -- 90%+ of logic covered by fast tests - -Reference: [Clean Architecture - Humble Object Pattern](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch23.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-main-component.md b/builtin-skills/software-engineer/clean-architecture/references/bound-main-component.md deleted file mode 100644 index 252e2ec3..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-main-component.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Treat Main as a Plugin to the Application -impact: MEDIUM-HIGH -impactDescription: enables multiple configurations, simplifies testing -tags: bound, main, composition-root, plugin ---- - -## Treat Main as a Plugin to the Application - -The Main component is the lowest-level, dirtiest component. It creates all factories, strategies, and global facilities, then hands control to high-level abstractions. Treat it as a plugin that can be swapped. - -**Incorrect (Main mixed with application logic):** - -```go -// main.go -func main() { - db := connectDatabase() - - // Business logic in main - http.HandleFunc("/orders", func(w http.ResponseWriter, r *http.Request) { - var order Order - json.NewDecoder(r.Body).Decode(&order) - - // Validation logic - if order.Total < 0 { - http.Error(w, "Invalid total", 400) - return - } - - // Direct database calls - db.Exec("INSERT INTO orders ...") - - // Response formatting - json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) - }) - - http.ListenAndServe(":8080", nil) -} -// Cannot test without starting HTTP server -// Cannot run with different database -``` - -**Correct (Main as composition root):** - -```go -// main.go - Production entry point -func main() { - app := bootstrap(ProductionConfig{ - DatabaseURL: os.Getenv("DATABASE_URL"), - Port: os.Getenv("PORT"), - }) - app.Run() -} - -// bootstrap.go - Composition root -func bootstrap(config Config) *Application { - // Create infrastructure - db := postgres.NewConnection(config.DatabaseURL) - - // Create repositories (implement domain interfaces) - orderRepo := postgres.NewOrderRepository(db) - userRepo := postgres.NewUserRepository(db) - - // Create use cases (depend on interfaces) - placeOrder := usecases.NewPlaceOrderUseCase(orderRepo) - getOrders := usecases.NewGetOrdersUseCase(orderRepo) - - // Create controllers (call use cases) - orderController := controllers.NewOrderController(placeOrder, getOrders) - - // Wire up HTTP routes - router := http.NewRouter() - router.POST("/orders", orderController.Create) - router.GET("/orders", orderController.List) - - return &Application{ - Router: router, - Port: config.Port, - } -} - -// main_test.go - Test entry point -func TestMain(t *testing.T) { - app := bootstrap(TestConfig{ - DatabaseURL: "memory://", // In-memory for tests - Port: "0", // Random port - }) - // Test against app -} - -// main_dev.go - Development entry point -func main() { - app := bootstrap(DevConfig{ - DatabaseURL: "localhost:5432", - Port: "3000", - }) - app.RunWithHotReload() -} -``` - -**Benefits:** -- Swap database, logging, configuration per environment -- Integration tests use real wiring with test doubles -- Dev/staging/prod share same composition logic - -Reference: [Clean Architecture - The Main Component](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch26.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-partial-boundaries.md b/builtin-skills/software-engineer/clean-architecture/references/bound-partial-boundaries.md deleted file mode 100644 index c042b051..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-partial-boundaries.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Use Partial Boundaries When Full Separation is Premature -impact: MEDIUM-HIGH -impactDescription: prepares for future without over-engineering now -tags: bound, partial-boundaries, pragmatism, yagni ---- - -## Use Partial Boundaries When Full Separation is Premature - -When you anticipate needing a boundary but the cost of full separation is too high, implement a partial boundary. This prepares for future separation without premature over-engineering. - -**Incorrect (no boundary when one might be needed):** - -```python -# Tightly coupled - if we ever need to split, massive refactor -class ReportService: - def generate_sales_report(self, start_date, end_date): - # Direct database access - conn = psycopg2.connect(DATABASE_URL) - cursor = conn.cursor() - cursor.execute(""" - SELECT * FROM sales - WHERE date BETWEEN %s AND %s - """, (start_date, end_date)) - - # Direct PDF generation - pdf = FPDF() - for row in cursor.fetchall(): - pdf.cell(200, 10, txt=str(row)) - return pdf.output() - -# Cannot split report generation from data access without rewriting -``` - -**Correct (partial boundary - same component, prepared for split):** - -```python -# Strategy 1: Facade pattern (simplest partial boundary) -class ReportingFacade: - """Single entry point, internal implementation can be refactored later.""" - - def generate_sales_report(self, request: ReportRequest) -> Report: - data = self._fetch_data(request) - return self._format_report(data, request.format) - - def _fetch_data(self, request): - # Could become a separate DataAccess component later - return self.repository.get_sales(request.start, request.end) - - def _format_report(self, data, format): - # Could become a separate ReportRenderer component later - if format == 'pdf': - return PdfRenderer().render(data) - return CsvRenderer().render(data) - - -# Strategy 2: Interface with single implementation -class SalesDataProvider(Protocol): - def get_sales(self, start: date, end: date) -> list[Sale]: ... - -class PostgresSalesProvider: - def get_sales(self, start: date, end: date) -> list[Sale]: - # Implementation here - -# Both live in same component, but interface enables future split -# When split needed: move interface to one component, impl to another - - -# Strategy 3: One-dimensional boundary -# Skip reciprocal interface - simpler but weaker protection -class ReportGenerator: - def __init__(self, data_provider: SalesDataProvider): - self.data_provider = data_provider # Depends on abstraction - -# SalesDataProvider implementation knows about ReportGenerator -# Not fully decoupled, but good enough for now -``` - -**When to use partial boundaries:** -- You suspect a boundary will be needed, but not yet -- Team is small and deployment is unified -- Cost of full boundary outweighs current benefits - -Reference: [Clean Architecture - Partial Boundaries](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch24.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/bound-service-internal-architecture.md b/builtin-skills/software-engineer/clean-architecture/references/bound-service-internal-architecture.md deleted file mode 100644 index a08b02aa..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/bound-service-internal-architecture.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Services Must Have Internal Clean Architecture -impact: MEDIUM-HIGH -impactDescription: microservices don't replace architecture, they require it -tags: bound, services, microservices, internal ---- - -## Services Must Have Internal Clean Architecture - -Breaking a monolith into microservices doesn't solve architectural problems. Each service still needs internal architecture. Services are a deployment option, not an architecture. - -**Incorrect (microservices as architecture replacement):** - -```text -"We use microservices architecture" - -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ order-service │ │ user-service │ │ payment-service │ -│ │ │ │ │ │ -│ routes.js │ │ routes.js │ │ routes.js │ -│ database.js │ │ database.js │ │ database.js │ -│ helpers.js │ │ helpers.js │ │ helpers.js │ -│ │ │ │ │ │ -│ (No layers, │ │ (No layers, │ │ (No layers, │ -│ no boundaries,│ │ no boundaries,│ │ no boundaries,│ -│ just smaller │ │ just smaller │ │ just smaller │ -│ messes) │ │ messes) │ │ messes) │ -└─────────────────┘ └─────────────────┘ └─────────────────┘ - -# Result: Distributed monolith -# All the downsides of microservices (network, deployment, consistency) -# None of the benefits (each service still a tangled mess) -``` - -**Correct (clean architecture within each service):** - -```text -┌───────────────────────────────────────────────────────────┐ -│ order-service │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ domain/ │ │ -│ │ Order.ts OrderLine.ts OrderStatus.ts │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ application/ │ │ -│ │ PlaceOrderUseCase.ts │ │ -│ │ ports/ │ │ -│ │ OrderRepository.ts │ │ -│ │ PaymentGateway.ts ← calls payment-service │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ infrastructure/ │ │ -│ │ PostgresOrderRepository.ts │ │ -│ │ HttpPaymentGateway.ts → payment-service API │ │ -│ │ KafkaEventPublisher.ts │ │ -│ └─────────────────────────────────────────────────────┘ │ -│ ┌─────────────────────────────────────────────────────┐ │ -│ │ interface/ │ │ -│ │ OrderController.ts │ │ -│ │ OrderEventHandler.ts │ │ -│ └─────────────────────────────────────────────────────┘ │ -└───────────────────────────────────────────────────────────┘ - -# Each service has: -# - Domain layer with business rules -# - Application layer with use cases and ports -# - Infrastructure layer implementing ports -# - Clean dependency direction within service -``` - -**Cross-service communication:** -```typescript -// application/ports/PaymentGateway.ts -interface PaymentGateway { - charge(amount: Money, method: PaymentMethod): Promise -} - -// infrastructure/HttpPaymentGateway.ts -class HttpPaymentGateway implements PaymentGateway { - async charge(amount: Money, method: PaymentMethod): Promise { - // Calls payment-service over HTTP - // Service boundary is an infrastructure detail - const response = await fetch('http://payment-service/charge', { ... }) - return this.mapResponse(response) - } -} -``` - -**Benefits:** -- Services testable without other services -- Can extract or merge services without rewriting business logic -- Network boundaries don't compromise internal architecture - -Reference: [Clean Architecture - Services: Great and Small](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch27.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/comp-common-closure.md b/builtin-skills/software-engineer/clean-architecture/references/comp-common-closure.md deleted file mode 100644 index 3893f1c4..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/comp-common-closure.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Group Classes That Change Together -impact: HIGH -impactDescription: localizes change impact, reduces deployment risk -tags: comp, common-closure, cohesion, change ---- - -## Group Classes That Change Together - -Classes that change for the same reasons and at the same times should be in the same component. This is the Common Closure Principle (CCP) - the Single Responsibility Principle for components. - -**Incorrect (classes that change together are separated):** - -```text -src/ -├── entities/ -│ └── Invoice.ts # Changes when billing rules change -├── repositories/ -│ └── InvoiceRepository.ts # Changes when billing rules change -├── services/ -│ └── InvoiceService.ts # Changes when billing rules change -├── validators/ -│ └── InvoiceValidator.ts # Changes when billing rules change -└── mappers/ - └── InvoiceMapper.ts # Changes when billing rules change - -# A billing rule change touches 5 directories -# Risk of forgetting one, inconsistent changes -``` - -**Correct (classes that change together are grouped):** - -```text -src/ -├── billing/ -│ ├── domain/ -│ │ ├── Invoice.ts -│ │ ├── InvoiceLine.ts -│ │ ├── InvoiceRules.ts -│ │ └── InvoiceValidator.ts -│ ├── application/ -│ │ ├── CreateInvoiceUseCase.ts -│ │ └── ports/ -│ │ └── InvoiceRepository.ts -│ └── infrastructure/ -│ ├── PostgresInvoiceRepository.ts -│ └── InvoiceMapper.ts -├── payments/ -│ └── ... # Changes for different reasons -└── shipping/ - └── ... # Changes for different reasons - -# Billing rule change isolated to billing/ -# Single PR, single review, single deployment -``` - -**How to identify change reasons:** -- "When X business rule changes, which classes change?" -- "When the Y team requests a feature, which code changes?" -- Group by actor/stakeholder, not by technical layer - -Reference: [Clean Architecture - Common Closure Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch13.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/comp-common-reuse.md b/builtin-skills/software-engineer/clean-architecture/references/comp-common-reuse.md deleted file mode 100644 index b187264d..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/comp-common-reuse.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Avoid Forcing Clients to Depend on Unused Code -impact: HIGH -impactDescription: reduces unnecessary recompilation and deployment -tags: comp, common-reuse, dependencies, coupling ---- - -## Avoid Forcing Clients to Depend on Unused Code - -Classes used together should be in the same component. Classes not used together should be in separate components. Forcing a client to depend on things it doesn't use creates unnecessary coupling. - -**Incorrect (monolithic utility package):** - -```java -// utils/src/main/java/com/app/utils/ -├── StringUtils.java -├── DateUtils.java -├── FileUtils.java -├── HttpUtils.java -├── CryptoUtils.java -├── ImageUtils.java // Depends on ImageMagick -└── PdfUtils.java // Depends on iText - -// pom.xml for utils module - - imagemagick - itext-pdf - bouncycastle - - -// A service that only needs StringUtils -// must now depend on all 80MB of transitive dependencies -``` - -**Correct (split by usage pattern):** - -```java -// string-utils/ -├── StringUtils.java -└── pom.xml // No heavy dependencies - -// date-utils/ -├── DateUtils.java -└── pom.xml - -// image-processing/ -├── ImageUtils.java -├── ImageResizer.java -└── pom.xml // ImageMagick dependency only here - -// pdf-generation/ -├── PdfUtils.java -├── PdfBuilder.java -└── pom.xml // iText dependency only here - -// crypto/ -├── CryptoUtils.java -├── HashingService.java -└── pom.xml // BouncyCastle dependency only here - -// Services import only what they need -// order-service depends on string-utils, date-utils (2MB) -// report-service depends on string-utils, pdf-generation (22MB) -``` - -**Benefits:** -- Clients only pull dependencies they actually use -- Smaller deployment artifacts -- Changes to image processing don't redeploy order service - -Reference: [Clean Architecture - Common Reuse Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch13.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/comp-reuse-release-equivalence.md b/builtin-skills/software-engineer/clean-architecture/references/comp-reuse-release-equivalence.md deleted file mode 100644 index 1df9ebc6..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/comp-reuse-release-equivalence.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Release Components as Cohesive Units -impact: HIGH -impactDescription: enables version tracking, supports parallel team development -tags: comp, release, versioning, cohesion ---- - -## Release Components as Cohesive Units - -Classes grouped into a component should be releasable together. A component should have a version number, release notes, and clear documentation. This is the Reuse/Release Equivalence Principle (REP). - -**Incorrect (arbitrary grouping):** - -```text -shared-lib/ -├── src/ -│ ├── auth/ -│ │ ├── JwtValidator.ts -│ │ └── PermissionChecker.ts -│ ├── logging/ -│ │ └── Logger.ts -│ ├── email/ -│ │ └── EmailSender.ts -│ └── payment/ -│ └── StripeClient.ts -└── package.json // version 1.2.3 - -# Version 1.2.4 fixes JWT bug -# But users of EmailSender must also upgrade -# Changelog unclear which features affect which users -``` - -**Correct (cohesive releasable components):** - -```text -packages/ -├── auth/ -│ ├── src/ -│ │ ├── JwtValidator.ts -│ │ ├── PermissionChecker.ts -│ │ └── index.ts -│ ├── CHANGELOG.md # Auth-specific changes -│ └── package.json # @company/auth v2.1.0 -├── logging/ -│ ├── src/ -│ │ └── Logger.ts -│ ├── CHANGELOG.md -│ └── package.json # @company/logging v1.0.3 -├── email/ -│ ├── src/ -│ │ └── EmailSender.ts -│ ├── CHANGELOG.md -│ └── package.json # @company/email v1.5.0 -└── payments/ - ├── src/ - │ └── StripeClient.ts - ├── CHANGELOG.md - └── package.json # @company/payments v3.0.0 - -# Clear ownership: auth team owns @company/auth -# Independent versioning: JWT fix only bumps auth -# Semantic versioning: breaking change in payments doesn't affect others -``` - -**Benefits:** -- Teams release independently on their own schedule -- Version numbers communicate compatibility -- Changelogs specific to what users of each component care about - -Reference: [Clean Architecture - Reuse/Release Equivalence Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch13.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/comp-screaming-architecture.md b/builtin-skills/software-engineer/clean-architecture/references/comp-screaming-architecture.md deleted file mode 100644 index 06edbc37..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/comp-screaming-architecture.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Structure Should Scream the Domain Not the Framework -impact: HIGH -impactDescription: enables understanding at a glance, reveals intent -tags: comp, screaming-architecture, structure, domain ---- - -## Structure Should Scream the Domain Not the Framework - -The folder structure should communicate what the system does, not what framework it uses. Looking at the top-level directories should reveal the business domain. - -**Incorrect (framework-oriented structure):** - -```text -src/ -├── controllers/ -│ ├── UserController.ts -│ ├── OrderController.ts -│ └── ProductController.ts -├── services/ -│ ├── UserService.ts -│ ├── OrderService.ts -│ └── ProductService.ts -├── repositories/ -│ ├── UserRepository.ts -│ ├── OrderRepository.ts -│ └── ProductRepository.ts -├── models/ -│ ├── User.ts -│ ├── Order.ts -│ └── Product.ts -└── utils/ - └── helpers.ts - -# This screams "MVC framework" not "e-commerce system" -``` - -**Correct (domain-oriented structure):** - -```text -src/ -├── ordering/ -│ ├── domain/ -│ │ ├── Order.ts -│ │ ├── OrderLine.ts -│ │ └── OrderStatus.ts -│ ├── application/ -│ │ ├── PlaceOrderUseCase.ts -│ │ ├── CancelOrderUseCase.ts -│ │ └── ports/ -│ │ ├── OrderRepository.ts -│ │ └── PaymentGateway.ts -│ └── infrastructure/ -│ ├── PostgresOrderRepository.ts -│ └── StripePaymentGateway.ts -├── inventory/ -│ ├── domain/ -│ ├── application/ -│ └── infrastructure/ -├── customers/ -│ ├── domain/ -│ ├── application/ -│ └── infrastructure/ -└── shared/ - └── kernel/ - ├── Money.ts - └── EntityId.ts - -# This screams "e-commerce with ordering, inventory, customers" -``` - -**Benefits:** -- New developers understand the domain immediately -- Related code lives together, enabling focused changes -- Frameworks become implementation details, not organizing principles - -Reference: [Screaming Architecture](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/comp-stable-dependencies.md b/builtin-skills/software-engineer/clean-architecture/references/comp-stable-dependencies.md deleted file mode 100644 index c5fb2f6b..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/comp-stable-dependencies.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Depend in the Direction of Stability -impact: HIGH -impactDescription: prevents unstable components from destabilizing dependents -tags: comp, stability, dependencies, direction ---- - -## Depend in the Direction of Stability - -Components should depend on components that are more stable than themselves. A stable component (many dependents, few dependencies) should not depend on an unstable component (few dependents, many dependencies). - -**Incorrect (stable component depends on unstable):** - -```text -┌─────────────────────────────────────────────────────┐ -│ core-domain │ -│ (Used by 50 services, should be very stable) │ -│ │ -│ import { formatDate } from 'ui-helpers' // WRONG! │ -│ import { sendMetrics } from 'analytics' // WRONG! │ -└──────────────────────┬──────────────────────────────┘ - │ - ┌───────────────┼───────────────┐ - ▼ ▼ ▼ - ui-helpers analytics reporting - (Changes (Changes (Changes - weekly) monthly) often) - -# When ui-helpers changes, core-domain might break -# When core-domain breaks, all 50 services break -``` - -**Correct (depend toward stability):** - -```text -┌─────────────────────────────────────────────────────┐ -│ core-domain │ -│ (Used by 50 services, zero external dependencies) │ -│ │ -│ - Only depends on language primitives │ -│ - Defines interfaces, not implementations │ -└─────────────────────────────────────────────────────┘ - ▲ - │ - ┌───────────────┼───────────────┐ - │ │ │ - ui-helpers analytics reporting - │ │ │ - │ │ │ - ▼ ▼ ▼ -┌─────────────────────────────────────────────────────┐ -│ external-dependencies │ -│ (date-fns, axios, lodash - maintained externally) │ -└─────────────────────────────────────────────────────┘ - -# Unstable components depend on stable core -# Core never breaks due to UI changes -``` - -**Stability Metric:** -```text -Instability = Outgoing Dependencies / (Incoming + Outgoing) -``` -- I = 0: Maximally stable (many dependents, no dependencies) -- I = 1: Maximally unstable (no dependents, many dependencies) - -Dependencies should flow from high I to low I. - -Reference: [Clean Architecture - Stable Dependencies Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch14.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-acyclic-dependencies.md b/builtin-skills/software-engineer/clean-architecture/references/dep-acyclic-dependencies.md deleted file mode 100644 index fd219d83..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-acyclic-dependencies.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Eliminate Cyclic Dependencies Between Components -impact: CRITICAL -impactDescription: prevents ripple effects, enables independent deployment -tags: dep, cycles, acyclic, components ---- - -## Eliminate Cyclic Dependencies Between Components - -The dependency graph must be a Directed Acyclic Graph (DAG). Cycles create ripple effects where changes propagate unpredictably through the system. - -**Incorrect (cyclic dependency):** - -```typescript -// modules/orders/OrderService.ts -import { CustomerService } from '../customers/CustomerService' - -export class OrderService { - constructor(private customers: CustomerService) {} - - async createOrder(customerId: string) { - const customer = await this.customers.findById(customerId) - // ... - } -} - -// modules/customers/CustomerService.ts -import { OrderService } from '../orders/OrderService' // Cycle! - -export class CustomerService { - constructor(private orders: OrderService) {} - - async getCustomerWithOrders(customerId: string) { - const orders = await this.orders.findByCustomer(customerId) - // ... - } -} -// Neither module can be deployed or tested independently -``` - -**Correct (break cycle with dependency inversion):** - -```typescript -// modules/orders/ports/CustomerProvider.ts -export interface CustomerProvider { - findById(id: string): Promise -} - -// modules/orders/OrderService.ts -import { CustomerProvider } from './ports/CustomerProvider' - -export class OrderService { - constructor(private customers: CustomerProvider) {} - - async createOrder(customerId: string) { - const customer = await this.customers.findById(customerId) - // ... - } -} - -// modules/customers/CustomerService.ts -// No import from orders module - -export class CustomerService implements CustomerProvider { - // Implements the interface defined in orders module -} - -// modules/customers/adapters/OrderAdapter.ts -import { OrderService } from '../../orders/OrderService' - -export class CustomerOrderAdapter { - constructor(private orders: OrderService) {} - - async getOrdersForCustomer(customerId: string) { - return this.orders.findByCustomer(customerId) - } -} -``` - -**Alternative (extract shared abstraction):** - -Create a new component that both depend on, breaking the cycle into a DAG. - -Reference: [Clean Architecture - Acyclic Dependencies Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch14.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-data-crossing-boundaries.md b/builtin-skills/software-engineer/clean-architecture/references/dep-data-crossing-boundaries.md deleted file mode 100644 index 1187f273..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-data-crossing-boundaries.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Use Simple Data Structures Across Boundaries -impact: CRITICAL -impactDescription: prevents coupling between layers -tags: dep, boundaries, dto, data-transfer ---- - -## Use Simple Data Structures Across Boundaries - -Data crossing architectural boundaries should be simple, isolated data structures. Never pass entities, database rows, or framework objects across boundaries. - -**Incorrect (entity crosses boundary):** - -```python -# domain/entities/user.py -class User: - def __init__(self, id, email, password_hash, created_at): - self.id = id - self.email = email - self.password_hash = password_hash # Sensitive data - self.created_at = created_at - -# interface_adapters/controllers/user_controller.py -class UserController: - def get_user(self, user_id): - user = self.use_case.get_user(user_id) - return jsonify(user.__dict__) # Entity exposed to HTTP layer, leaks password_hash -``` - -**Correct (DTOs cross boundaries):** - -```python -# application/dto/user_response.py -@dataclass -class UserResponse: - id: str - email: str - member_since: str # Formatted for presentation - -# application/usecases/get_user.py -class GetUserUseCase: - def execute(self, user_id: str) -> UserResponse: - user = self.repository.find_by_id(user_id) - return UserResponse( - id=user.id, - email=user.email, - member_since=user.created_at.strftime("%B %Y") - ) - -# interface_adapters/controllers/user_controller.py -class UserController: - def get_user(self, user_id): - response = self.use_case.execute(user_id) - return jsonify(asdict(response)) # Only safe, formatted data -``` - -**When NOT to use this pattern:** -- Within the same architectural layer, entities can flow freely -- Performance-critical paths may need optimized data transfer - -Reference: [Clean Architecture - Crossing Boundaries](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-interface-ownership.md b/builtin-skills/software-engineer/clean-architecture/references/dep-interface-ownership.md deleted file mode 100644 index 3138a571..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-interface-ownership.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Interfaces Belong to Clients Not Implementers -impact: CRITICAL -impactDescription: enables true dependency inversion -tags: dep, interfaces, dependency-inversion, ownership ---- - -## Interfaces Belong to Clients Not Implementers - -Interfaces should be defined in the layer that uses them, not the layer that implements them. The client owns the abstraction; the implementation adapts to it. - -**Incorrect (interface defined next to implementation):** - -```java -// infrastructure/persistence/UserRepository.java -public interface UserRepository { - User findById(String id); - void save(User user); -} - -// infrastructure/persistence/PostgresUserRepository.java -public class PostgresUserRepository implements UserRepository { - // Implementation -} - -// application/usecases/CreateUserUseCase.java -import infrastructure.persistence.UserRepository; // Use case imports from infrastructure! - -public class CreateUserUseCase { - private final UserRepository repository; -} -``` - -**Correct (interface defined where it's used):** - -```java -// application/ports/output/UserRepository.java -public interface UserRepository { - User findById(String id); - void save(User user); -} - -// application/usecases/CreateUserUseCase.java -import application.ports.output.UserRepository; // Same layer import - -public class CreateUserUseCase { - private final UserRepository repository; // No infrastructure dependency -} - -// infrastructure/persistence/PostgresUserRepository.java -import application.ports.output.UserRepository; // Infrastructure depends on application - -public class PostgresUserRepository implements UserRepository { - // Implementation adapts to the port -} -``` - -**Note:** This is the essence of the Dependency Inversion Principle. The high-level module defines what it needs; low-level modules conform to that contract. - -Reference: [Clean Architecture - Chapter 11: DIP](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch11.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-inward-only.md b/builtin-skills/software-engineer/clean-architecture/references/dep-inward-only.md deleted file mode 100644 index 422e6673..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-inward-only.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Source Dependencies Point Inward Only -impact: CRITICAL -impactDescription: prevents cascade failures across all layers -tags: dep, dependency-rule, layers, architecture ---- - -## Source Dependencies Point Inward Only - -The Dependency Rule states that source code dependencies can only point inward toward higher-level policies. Inner circles must never reference outer circles. - -**Incorrect (inner layer imports from outer layer):** - -```typescript -// domain/entities/Order.ts - ENTITY LAYER -import { OrderRepository } from '../../infrastructure/OrderRepository' -import { EmailService } from '../../infrastructure/EmailService' - -export class Order { - constructor( - private repo: OrderRepository, // Changes to repo implementation break Order - private email: EmailService - ) {} - - async complete() { - await this.repo.save(this) - await this.email.notify(this.customerId) // Cannot test without email server - } -} -``` - -**Correct (inner layer defines interface, outer layer implements):** - -```typescript -// domain/entities/Order.ts - ENTITY LAYER -export interface OrderPersistence { - save(order: Order): Promise -} - -export interface NotificationPort { - notify(customerId: string): Promise -} - -export class Order { - constructor( - private repo: OrderPersistence, - private email: NotificationPort - ) {} - - async complete() { - await this.repo.save(this) - await this.email.notify(this.customerId) - } -} - -// infrastructure/OrderRepository.ts - INFRASTRUCTURE LAYER -import { Order, OrderPersistence } from '../domain/entities/Order' - -export class OrderRepository implements OrderPersistence { - async save(order: Order): Promise { /* DB implementation */ } -} -``` - -**Benefits:** -- Inner layers remain stable when outer layers change -- Business rules can be tested without infrastructure -- Infrastructure can be swapped without touching domain code - -Reference: [The Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-no-framework-imports.md b/builtin-skills/software-engineer/clean-architecture/references/dep-no-framework-imports.md deleted file mode 100644 index df689cec..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-no-framework-imports.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Avoid Framework Imports in Inner Layers -impact: CRITICAL -impactDescription: prevents framework lock-in, enables 10× faster unit tests -tags: dep, frameworks, imports, isolation ---- - -## Avoid Framework Imports in Inner Layers - -Entities and use cases must never import framework-specific types. Framework dependencies in inner layers create tight coupling that makes testing slow and migration impossible. - -**Incorrect (use case imports framework types):** - -```csharp -// Application/UseCases/ProcessPaymentUseCase.cs -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; - -public class ProcessPaymentUseCase -{ - private readonly DbContext _context; // EF Core dependency - private readonly IHttpContextAccessor _http; // ASP.NET dependency - - public async Task Execute(PaymentRequest request) - { - var userId = _http.HttpContext.User.Identity.Name; - var payment = JsonConvert.DeserializeObject(request.Data); - _context.Payments.Add(payment); - await _context.SaveChangesAsync(); - } -} -``` - -**Correct (use case depends only on abstractions):** - -```csharp -// Application/UseCases/ProcessPaymentUseCase.cs -// No framework imports - -public class ProcessPaymentUseCase -{ - private readonly IPaymentRepository _payments; - private readonly ICurrentUserProvider _currentUser; - - public async Task Execute(PaymentCommand command) - { - var userId = _currentUser.GetUserId(); - var payment = new Payment(command.Amount, command.Currency, userId); - await _payments.Save(payment); - } -} - -// Infrastructure/Persistence/EfPaymentRepository.cs -using Microsoft.EntityFrameworkCore; - -public class EfPaymentRepository : IPaymentRepository -{ - private readonly DbContext _context; - // Framework usage isolated to infrastructure -} -``` - -**Benefits:** -- Use case tests run without framework bootstrapping -- Framework can be upgraded or replaced independently -- Business logic remains readable without framework noise - -Reference: [Clean Architecture - Frameworks are Details](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/dep-stable-abstractions.md b/builtin-skills/software-engineer/clean-architecture/references/dep-stable-abstractions.md deleted file mode 100644 index 6a0e9466..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/dep-stable-abstractions.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Depend on Stable Abstractions Not Volatile Concretions -impact: CRITICAL -impactDescription: reduces change frequency by 5-10× -tags: dep, stability, abstractions, volatility ---- - -## Depend on Stable Abstractions Not Volatile Concretions - -The most flexible systems depend on abstractions, not concretions. Volatile concrete classes are under active development and change frequently; depending on them propagates instability. - -**Incorrect (depending on volatile concrete class):** - -```go -// services/notification.go -package services - -import ( - "myapp/infrastructure/email/sendgrid" - "myapp/infrastructure/sms/twilio" -) - -type NotificationService struct { - email *sendgrid.Client // Concrete SendGrid client - sms *twilio.Client // Concrete Twilio client -} - -func (n *NotificationService) NotifyUser(userID string, message string) { - // When SendGrid API changes, this service must change - // When migrating to AWS SES, this service must change - n.email.SendWithTemplate("notify", message) -} -``` - -**Correct (depending on stable interface):** - -```go -// domain/ports/notification.go -package ports - -type EmailSender interface { - Send(to string, subject string, body string) error -} - -type SMSSender interface { - Send(to string, message string) error -} - -// services/notification.go -package services - -import "myapp/domain/ports" - -type NotificationService struct { - email ports.EmailSender // Stable abstraction - sms ports.SMSSender // Stable abstraction -} - -func (n *NotificationService) NotifyUser(userID string, message string) { - // Service is immune to email provider changes - n.email.Send(userID, "Notification", message) -} - -// infrastructure/sendgrid/client.go -package sendgrid - -type Client struct { /* ... */ } - -func (c *Client) Send(to, subject, body string) error { - // Concrete implementation can change freely -} -``` - -**Note:** Depending on stable concretions (like standard library classes) is acceptable. Focus inversion on volatile, actively-developed modules. - -Reference: [Clean Architecture - Stable Abstractions Principle](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch11.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/entity-encapsulate-invariants.md b/builtin-skills/software-engineer/clean-architecture/references/entity-encapsulate-invariants.md deleted file mode 100644 index 9ed2696c..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/entity-encapsulate-invariants.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Encapsulate Business Invariants Within Entities -impact: CRITICAL -impactDescription: prevents invalid state, centralizes validation -tags: entity, invariants, validation, encapsulation ---- - -## Encapsulate Business Invariants Within Entities - -Business rules that must always be true (invariants) should be enforced by the entity itself. External code should not be able to put an entity into an invalid state. - -**Incorrect (invariants scattered outside entity):** - -```python -# application/usecases/transfer_money.py -class TransferMoneyUseCase: - def execute(self, from_id, to_id, amount): - from_account = self.repo.find(from_id) - to_account = self.repo.find(to_id) - - # Validation scattered in use case - if from_account.balance < amount: - raise InsufficientFundsError() - if amount <= 0: - raise InvalidAmountError() - if from_account.status != 'active': - raise AccountInactiveError() - - from_account.balance -= amount # Direct field mutation - to_account.balance += amount - -# Another use case might forget these checks! -``` - -**Correct (invariants enforced by entity):** - -```python -# domain/entities/account.py -class Account: - def __init__(self, id: AccountId, balance: Money, status: AccountStatus): - self._id = id - self._balance = balance - self._status = status - - def withdraw(self, amount: Money) -> None: - self._ensure_active() - self._ensure_positive_amount(amount) - self._ensure_sufficient_funds(amount) - self._balance = self._balance.subtract(amount) - - def deposit(self, amount: Money) -> None: - self._ensure_active() - self._ensure_positive_amount(amount) - self._balance = self._balance.add(amount) - - def _ensure_active(self) -> None: - if self._status != AccountStatus.ACTIVE: - raise AccountInactiveError(self._id) - - def _ensure_positive_amount(self, amount: Money) -> None: - if amount.is_zero_or_negative(): - raise InvalidAmountError(amount) - - def _ensure_sufficient_funds(self, amount: Money) -> None: - if self._balance.less_than(amount): - raise InsufficientFundsError(self._id, self._balance, amount) - -# application/usecases/transfer_money.py -class TransferMoneyUseCase: - def execute(self, from_id, to_id, amount): - from_account = self.repo.find(from_id) - to_account = self.repo.find(to_id) - - from_account.withdraw(amount) # Invariants guaranteed - to_account.deposit(amount) -``` - -**Benefits:** -- Impossible to create invalid account state -- Validation rules documented in one place -- Every use case gets consistent validation automatically - -Reference: [Domain-Driven Design - Aggregates](https://martinfowler.com/bliki/DDD_Aggregate.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/entity-no-persistence-awareness.md b/builtin-skills/software-engineer/clean-architecture/references/entity-no-persistence-awareness.md deleted file mode 100644 index 879ecee8..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/entity-no-persistence-awareness.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Entities Must Not Know How They Are Persisted -impact: CRITICAL -impactDescription: enables database migration without domain changes -tags: entity, persistence, database, ignorance ---- - -## Entities Must Not Know How They Are Persisted - -Entities should have no awareness of databases, ORMs, or storage mechanisms. Persistence is an infrastructure detail that must not leak into the domain. - -**Incorrect (entity aware of persistence):** - -```java -// domain/entities/Product.java -@Entity -@Table(name = "products") -public class Product { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "product_name", nullable = false) - private String name; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id") - private Category category; - - @Version - private Long version; - - // Entity is coupled to JPA, cannot exist without Hibernate -} -``` - -**Correct (persistence-ignorant entity):** - -```java -// domain/entities/Product.java -public class Product { - private final ProductId id; - private String name; - private CategoryId categoryId; - private Money price; - - public Product(ProductId id, String name, CategoryId categoryId, Money price) { - this.id = id; - this.name = validateName(name); - this.categoryId = categoryId; - this.price = price; - } - - public void updatePrice(Money newPrice, PricingPolicy policy) { - if (!policy.allowsPrice(newPrice)) { - throw new InvalidPriceException(newPrice); - } - this.price = newPrice; - } - - private String validateName(String name) { - if (name == null || name.isBlank()) { - throw new InvalidProductNameException(); - } - return name.trim(); - } -} - -// infrastructure/persistence/jpa/JpaProductEntity.java -@Entity -@Table(name = "products") -class JpaProductEntity { - @Id private Long id; - @Column private String name; - // ORM mapping isolated to infrastructure -} - -// infrastructure/persistence/jpa/ProductMapper.java -class ProductMapper { - Product toDomain(JpaProductEntity entity) { /* ... */ } - JpaProductEntity toJpa(Product product) { /* ... */ } -} -``` - -**Benefits:** -- Switch from SQL to NoSQL without touching domain -- Entity tests don't require database setup -- Domain model expresses business concepts, not database schema - -Reference: [Clean Architecture - Database is a Detail](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch30.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/entity-pure-business-rules.md b/builtin-skills/software-engineer/clean-architecture/references/entity-pure-business-rules.md deleted file mode 100644 index 4efc0f19..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/entity-pure-business-rules.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Entities Contain Only Enterprise Business Rules -impact: CRITICAL -impactDescription: enables reuse across applications, prevents coupling -tags: entity, business-rules, domain, purity ---- - -## Entities Contain Only Enterprise Business Rules - -Entities encapsulate enterprise-wide business rules that would exist regardless of automation. They must not contain application-specific logic, persistence code, or UI concerns. - -**Incorrect (entity mixed with infrastructure concerns):** - -```typescript -class Invoice { - id: string - items: LineItem[] - status: InvoiceStatus - dueDate: Date - - calculateTotal(): Money { - return this.items.reduce((sum, item) => sum.add(item.amount), Money.zero()) - } - - isOverdue(): boolean { - return this.status === InvoiceStatus.Unpaid && new Date() > this.dueDate - } - - markPaid(): void { - this.status = InvoiceStatus.Paid - database.invoices.update(this) // Entity cannot be tested without database - emailService.send(this.customerEmail, 'Payment received') // Coupled to email system - } -} -``` - -**Correct (entity contains only business rules):** - -```typescript -class Invoice { - id: string - items: LineItem[] - status: InvoiceStatus - dueDate: Date - - calculateTotal(): Money { - return this.items.reduce((sum, item) => sum.add(item.amount), Money.zero()) - } - - isOverdue(): boolean { - return this.status === InvoiceStatus.Unpaid && new Date() > this.dueDate - } - - markPaid(): void { - if (this.status !== InvoiceStatus.Unpaid) { - throw new InvalidOperationError('Invoice already processed') - } - this.status = InvoiceStatus.Paid - } -} -``` - -**Benefits:** -- Entity can be used in billing system, reporting system, mobile app -- Business rules tested without database or email setup -- Rules documented in one place, not scattered across application - -Reference: [Clean Architecture - Entities](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/entity-rich-not-anemic.md b/builtin-skills/software-engineer/clean-architecture/references/entity-rich-not-anemic.md deleted file mode 100644 index 4ae6e0b3..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/entity-rich-not-anemic.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Build Rich Domain Models Not Anemic Data Structures -impact: HIGH -impactDescription: centralizes business logic, prevents scattered rules -tags: entity, domain-model, anemic, behavior ---- - -## Build Rich Domain Models Not Anemic Data Structures - -Entities should contain behavior, not just data. Anemic domain models push business logic into services, scattering rules and duplicating validation. - -**Incorrect (anemic domain model):** - -```java -// domain/entities/Subscription.java -public class Subscription { - private String id; - private String planId; - private LocalDate startDate; - private LocalDate endDate; - private String status; - - // Only getters and setters - no behavior - public String getStatus() { return status; } - public void setStatus(String status) { this.status = status; } - public LocalDate getEndDate() { return endDate; } - public void setEndDate(LocalDate endDate) { this.endDate = endDate; } -} - -// application/services/SubscriptionService.java -public class SubscriptionService { - public void cancel(Subscription sub) { - if (!sub.getStatus().equals("active")) { - throw new IllegalStateException("Cannot cancel"); - } - sub.setStatus("cancelled"); - sub.setEndDate(LocalDate.now()); - } - - public void renew(Subscription sub, int months) { - if (!sub.getStatus().equals("active")) { - throw new IllegalStateException("Cannot renew"); - } - sub.setEndDate(sub.getEndDate().plusMonths(months)); - } - // Logic scattered across many services -} -``` - -**Correct (rich domain model):** - -```java -// domain/entities/Subscription.java -public class Subscription { - private final SubscriptionId id; - private final PlanId planId; - private final LocalDate startDate; - private LocalDate endDate; - private SubscriptionStatus status; - - public void cancel() { - ensureActive(); - this.status = SubscriptionStatus.CANCELLED; - this.endDate = LocalDate.now(); - } - - public void renew(Period extension) { - ensureActive(); - if (extension.getMonths() < 1) { - throw new InvalidExtensionPeriodException(extension); - } - this.endDate = this.endDate.plus(extension); - } - - public boolean isExpired() { - return LocalDate.now().isAfter(this.endDate); - } - - public boolean canUpgradeTo(Plan newPlan) { - return this.status == SubscriptionStatus.ACTIVE - && newPlan.isUpgradeFrom(this.planId); - } - - private void ensureActive() { - if (this.status != SubscriptionStatus.ACTIVE) { - throw new InactiveSubscriptionException(this.id); - } - } -} - -// application/usecases/CancelSubscriptionUseCase.java -public class CancelSubscriptionUseCase { - public void execute(SubscriptionId id) { - Subscription sub = repository.findById(id); - sub.cancel(); // Business logic in entity - repository.save(sub); - } -} -``` - -**Benefits:** -- Business rules live with the data they operate on -- Impossible to forget validation when manipulating data -- Entity documents its own capabilities and constraints - -Reference: [Anemic Domain Model Anti-pattern](https://martinfowler.com/bliki/AnemicDomainModel.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/entity-value-objects.md b/builtin-skills/software-engineer/clean-architecture/references/entity-value-objects.md deleted file mode 100644 index 7b8fe4f1..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/entity-value-objects.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Use Value Objects for Domain Concepts -impact: HIGH -impactDescription: eliminates primitive obsession, enforces constraints -tags: entity, value-objects, domain, types ---- - -## Use Value Objects for Domain Concepts - -Replace primitive types with value objects that encapsulate validation and behavior. Value objects are immutable, compared by value, and self-validating. - -**Incorrect (primitive obsession):** - -```typescript -class Customer { - constructor( - public id: string, - public email: string, - public phone: string, - public postalCode: string - ) {} - - changeEmail(newEmail: string): void { - // Validation scattered or missing - if (!newEmail.includes('@')) { - throw new Error('Invalid email') - } - this.email = newEmail - } -} - -// Callers can pass any string -const customer = new Customer('123', 'not-an-email', '123', 'invalid') -``` - -**Correct (value objects for domain concepts):** - -```typescript -class Email { - private constructor(private readonly value: string) {} - - static create(value: string): Email { - if (!Email.isValid(value)) { - throw new InvalidEmailError(value) - } - return new Email(value.toLowerCase()) - } - - private static isValid(value: string): boolean { - return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) - } - - equals(other: Email): boolean { - return this.value === other.value - } - - toString(): string { - return this.value - } -} - -class PhoneNumber { - private constructor( - private readonly countryCode: string, - private readonly number: string - ) {} - - static create(countryCode: string, number: string): PhoneNumber { - // Validation and normalization - return new PhoneNumber(countryCode, number.replace(/\D/g, '')) - } -} - -class Customer { - constructor( - public readonly id: CustomerId, - private email: Email, - private phone: PhoneNumber - ) {} - - changeEmail(newEmail: Email): void { - this.email = newEmail // Already validated - } -} - -// Compile-time type safety + runtime validation -const customer = new Customer( - CustomerId.create('123'), - Email.create('user@example.com'), - PhoneNumber.create('+1', '555-1234') -) -``` - -**Benefits:** -- Invalid values cannot exist in the system -- Domain concepts explicitly named in code -- Validation logic centralized and reusable -- Type system prevents mixing up string parameters - -Reference: [Value Object Pattern](https://martinfowler.com/bliki/ValueObject.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/frame-di-container-edge.md b/builtin-skills/software-engineer/clean-architecture/references/frame-di-container-edge.md deleted file mode 100644 index 1e0c2b29..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/frame-di-container-edge.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Dependency Injection Containers Live at the Edge -impact: MEDIUM -impactDescription: prevents DI container coupling throughout codebase -tags: frame, dependency-injection, container, composition ---- - -## Dependency Injection Containers Live at the Edge - -DI containers are infrastructure. Use them at composition root (main/startup) to wire dependencies, but don't let them invade domain or application code. - -**Incorrect (DI container throughout codebase):** - -```csharp -// Domain depends on DI container -using Microsoft.Extensions.DependencyInjection; - -public class Order -{ - public void Process() - { - // Service locator anti-pattern - var emailService = ServiceLocator.Current.GetService(); - var logger = ServiceLocator.Current.GetService(); - - // ... - } -} - -// Application layer decorated with DI attributes -public class CreateOrderUseCase -{ - [Inject] - public IOrderRepository Orders { get; set; } - - [Inject] - public IPaymentGateway Payments { get; set; } - - // Properties injected by container - hidden dependencies -} - -// Switching DI containers requires touching domain code -``` - -**Correct (DI container only at composition root):** - -```csharp -// Domain - no DI container knowledge -public class Order -{ - public void Process(IEmailService email, ILogger logger) - { - // Dependencies passed explicitly - } -} - -// Application - constructor injection, no container knowledge -public class CreateOrderUseCase -{ - private readonly IOrderRepository _orders; - private readonly IPaymentGateway _payments; - - // Plain constructor - works with any DI container or manual wiring - public CreateOrderUseCase( - IOrderRepository orders, - IPaymentGateway payments) - { - _orders = orders; - _payments = payments; - } -} - -// Composition root - only place that knows about DI container -// Program.cs or Startup.cs -public class CompositionRoot -{ - public static IServiceProvider ConfigureServices() - { - var services = new ServiceCollection(); - - // Infrastructure - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - // Application - services.AddScoped(); - services.AddScoped(); - - // Interface - services.AddScoped(); - - return services.BuildServiceProvider(); - } -} - -// For tests - manual wiring without container -[Test] -public void CreatesOrder() -{ - var orders = new InMemoryOrderRepository(); - var payments = new FakePaymentGateway(); - var useCase = new CreateOrderUseCase(orders, payments); - - useCase.Execute(command); - - Assert.That(orders.All(), Has.Count.EqualTo(1)); -} -``` - -**Benefits:** -- Domain and application code portable across DI containers -- Tests don't need DI container setup -- Dependencies explicit in constructors - -Reference: [Composition Root Pattern](https://blog.ploeh.dk/2011/07/28/CompositionRoot/) diff --git a/builtin-skills/software-engineer/clean-architecture/references/frame-domain-purity.md b/builtin-skills/software-engineer/clean-architecture/references/frame-domain-purity.md deleted file mode 100644 index fc03df02..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/frame-domain-purity.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Domain Layer Has Zero Framework Dependencies -impact: MEDIUM -impactDescription: enables framework migration, pure unit tests -tags: frame, domain, purity, dependencies ---- - -## Domain Layer Has Zero Framework Dependencies - -The domain layer (entities and domain services) should have zero dependencies on frameworks, ORMs, or external libraries. Only language primitives and domain-specific code. - -**Incorrect (domain depends on framework):** - -```csharp -// Domain entity with framework dependencies -using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations; -using Newtonsoft.Json; - -namespace Domain.Entities -{ - [Table("products")] - public class Product - { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; set; } - - [Required] - [MaxLength(100)] - [JsonProperty("product_name")] - public string Name { get; set; } - - [Column(TypeName = "decimal(18,2)")] - public decimal Price { get; set; } - - // EF Core navigation property - public virtual Category Category { get; set; } - - // Framework-specific validation - public IEnumerable Validate(ValidationContext context) - { - if (Price < 0) - yield return new ValidationResult("Price cannot be negative"); - } - } -} -// Domain now depends on: EF Core, DataAnnotations, Newtonsoft.Json -// Cannot exist without these frameworks -``` - -**Correct (pure domain):** - -```csharp -// Domain entity - zero framework dependencies -namespace Domain.Entities -{ - public class Product - { - public ProductId Id { get; } - public string Name { get; private set; } - public Money Price { get; private set; } - public CategoryId CategoryId { get; private set; } - - public Product(ProductId id, string name, Money price, CategoryId categoryId) - { - if (string.IsNullOrWhiteSpace(name)) - throw new InvalidProductNameException(); - if (name.Length > 100) - throw new ProductNameTooLongException(name.Length, 100); - if (price.IsNegative) - throw new NegativePriceException(price); - - Id = id; - Name = name; - Price = price; - CategoryId = categoryId; - } - - public void UpdatePrice(Money newPrice) - { - if (newPrice.IsNegative) - throw new NegativePriceException(newPrice); - Price = newPrice; - } - } -} - -// Infrastructure - framework dependencies isolated here -namespace Infrastructure.Persistence -{ - using Microsoft.EntityFrameworkCore; - - [Table("products")] - internal class ProductEntity - { - [Key] public int Id { get; set; } - [MaxLength(100)] public string Name { get; set; } - [Column(TypeName = "decimal(18,2)")] public decimal Price { get; set; } - public int CategoryId { get; set; } - } - - internal class ProductMapper - { - public Product ToDomain(ProductEntity entity) => /* ... */ - public ProductEntity ToEntity(Product product) => /* ... */ - } -} -``` - -**How to check domain purity:** -```bash -# Domain project should have no package references -dotnet list Domain.csproj package -# Should return: No packages found - -# Or in package.json -# "dependencies": {} should be empty or only contain domain libraries -``` - -Reference: [Clean Architecture - Frameworks are Details](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/frame-logging-abstraction.md b/builtin-skills/software-engineer/clean-architecture/references/frame-logging-abstraction.md deleted file mode 100644 index 400f0a13..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/frame-logging-abstraction.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -title: Abstract Logging Behind Domain Interfaces -impact: MEDIUM -impactDescription: prevents logging framework coupling, enables structured logging -tags: frame, logging, abstraction, cross-cutting ---- - -## Abstract Logging Behind Domain Interfaces - -Logging frameworks are infrastructure details. Define logging interfaces in the application layer; implement them in infrastructure. This enables switching loggers and keeps domain pure. - -**Incorrect (logging framework in domain/application):** - -```go -package usecases - -import ( - "github.com/sirupsen/logrus" // Framework dependency -) - -type CreateOrderUseCase struct { - repo OrderRepository - logger *logrus.Logger // Concrete logger -} - -func (uc *CreateOrderUseCase) Execute(cmd CreateOrderCommand) (*Order, error) { - uc.logger.WithFields(logrus.Fields{ - "customer_id": cmd.CustomerID, - "item_count": len(cmd.Items), - }).Info("Creating order") - - order, err := uc.repo.Create(cmd) - if err != nil { - uc.logger.WithError(err).Error("Failed to create order") - return nil, err - } - - uc.logger.WithField("order_id", order.ID).Info("Order created") - return order, nil -} - -// Switching from logrus to zap requires changing all use cases -``` - -**Correct (logging behind interface):** - -```go -// application/ports/logger.go -package ports - -type Logger interface { - Info(msg string, fields ...Field) - Error(msg string, err error, fields ...Field) - Debug(msg string, fields ...Field) -} - -type Field struct { - Key string - Value interface{} -} - -func F(key string, value interface{}) Field { - return Field{Key: key, Value: value} -} - -// application/usecases/create_order.go -package usecases - -import "myapp/application/ports" - -type CreateOrderUseCase struct { - repo OrderRepository - logger ports.Logger -} - -func (uc *CreateOrderUseCase) Execute(cmd CreateOrderCommand) (*Order, error) { - uc.logger.Info("Creating order", - ports.F("customer_id", cmd.CustomerID), - ports.F("item_count", len(cmd.Items)), - ) - - order, err := uc.repo.Create(cmd) - if err != nil { - uc.logger.Error("Failed to create order", err, - ports.F("customer_id", cmd.CustomerID), - ) - return nil, err - } - - uc.logger.Info("Order created", ports.F("order_id", order.ID)) - return order, nil -} - -// infrastructure/logging/logrus_logger.go -package logging - -import ( - "github.com/sirupsen/logrus" - "myapp/application/ports" -) - -type LogrusLogger struct { - logger *logrus.Logger -} - -func (l *LogrusLogger) Info(msg string, fields ...ports.Field) { - l.logger.WithFields(toLogrusFields(fields)).Info(msg) -} - -func toLogrusFields(fields []ports.Field) logrus.Fields { - result := logrus.Fields{} - for _, f := range fields { - result[f.Key] = f.Value - } - return result -} - -// infrastructure/logging/zap_logger.go - Alternative implementation -// Switch without touching use cases -``` - -**Benefits:** -- Application code doesn't import logging frameworks -- Easy to switch logging backends -- Test logging by asserting on mock logger calls - -Reference: [Clean Architecture - Frameworks are Details](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/frame-orm-in-infrastructure.md b/builtin-skills/software-engineer/clean-architecture/references/frame-orm-in-infrastructure.md deleted file mode 100644 index ff71882a..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/frame-orm-in-infrastructure.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Keep ORM Usage in Infrastructure Layer -impact: MEDIUM -impactDescription: isolates persistence complexity, enables ORM switching -tags: frame, orm, infrastructure, persistence ---- - -## Keep ORM Usage in Infrastructure Layer - -ORM-specific code (entities, mappings, queries) belongs in the infrastructure layer. The domain and application layers should not know which ORM (or if any ORM) is being used. - -**Incorrect (ORM in application layer):** - -```python -# application/usecases/get_orders.py -from sqlalchemy.orm import Session, joinedload -from sqlalchemy import and_, or_ - -class GetOrdersUseCase: - def __init__(self, session: Session): # SQLAlchemy session in use case - self.session = session - - def execute(self, customer_id: str, filters: OrderFilters): - # SQLAlchemy query in use case - query = self.session.query(Order).options( - joinedload(Order.items), - joinedload(Order.customer) - ) - - if filters.status: - query = query.filter(Order.status == filters.status) - - if filters.date_range: - query = query.filter(and_( - Order.created_at >= filters.date_range.start, - Order.created_at <= filters.date_range.end - )) - - return query.order_by(Order.created_at.desc()).all() - -# Use case is now coupled to SQLAlchemy -# Switching to Peewee or raw SQL requires rewriting use case -``` - -**Correct (ORM isolated in infrastructure):** - -```python -# application/ports/order_repository.py -from abc import ABC, abstractmethod - -class OrderRepository(ABC): - @abstractmethod - def find_by_customer( - self, - customer_id: CustomerId, - filters: OrderFilters - ) -> list[Order]: - pass - -# application/usecases/get_orders.py -class GetOrdersUseCase: - def __init__(self, orders: OrderRepository): # Interface, not Session - self.orders = orders - - def execute(self, customer_id: str, filters: OrderFilters) -> list[Order]: - return self.orders.find_by_customer( - CustomerId(customer_id), - filters - ) - -# infrastructure/persistence/sqlalchemy_order_repository.py -from sqlalchemy.orm import Session, joinedload - -class SqlAlchemyOrderRepository(OrderRepository): - def __init__(self, session: Session): - self.session = session - - def find_by_customer( - self, - customer_id: CustomerId, - filters: OrderFilters - ) -> list[Order]: - query = self.session.query(OrderEntity).options( - joinedload(OrderEntity.items) - ).filter(OrderEntity.customer_id == customer_id.value) - - if filters.status: - query = query.filter(OrderEntity.status == filters.status.value) - - entities = query.order_by(OrderEntity.created_at.desc()).all() - return [self._to_domain(e) for e in entities] - - def _to_domain(self, entity: OrderEntity) -> Order: - # Map ORM entity to domain entity - pass -``` - -**Benefits:** -- Use case tests don't need database or ORM setup -- Can switch ORMs without touching business logic -- Complex queries encapsulated in repository - -Reference: [Repository Pattern](https://martinfowler.com/eaaCatalog/repository.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/frame-web-in-infrastructure.md b/builtin-skills/software-engineer/clean-architecture/references/frame-web-in-infrastructure.md deleted file mode 100644 index c1cb8132..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/frame-web-in-infrastructure.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Web Framework Concerns Stay in Interface Layer -impact: MEDIUM -impactDescription: enables delivery mechanism substitution -tags: frame, web, http, interface ---- - -## Web Framework Concerns Stay in Interface Layer - -HTTP-specific code (requests, responses, headers, cookies, sessions) belongs in the interface adapters layer. Use cases should be callable from any delivery mechanism. - -**Incorrect (use case coupled to HTTP):** - -```typescript -// application/usecases/LoginUseCase.ts -import { Request, Response } from 'express' -import { sign } from 'jsonwebtoken' - -export class LoginUseCase { - async execute(req: Request, res: Response) { - const { email, password } = req.body - - const user = await this.users.findByEmail(email) - if (!user || !user.verifyPassword(password)) { - return res.status(401).json({ error: 'Invalid credentials' }) - } - - // Set HTTP-only cookie - const token = sign({ userId: user.id }, process.env.JWT_SECRET) - res.cookie('auth_token', token, { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'strict' - }) - - return res.json({ user: { id: user.id, email: user.email } }) - } -} - -// Cannot call from CLI, message queue, or test without Express -``` - -**Correct (use case independent of delivery):** - -```typescript -// application/usecases/LoginUseCase.ts -export interface LoginCommand { - email: string - password: string -} - -export interface LoginResult { - userId: string - email: string - authToken: string -} - -export class LoginUseCase { - constructor( - private users: UserRepository, - private tokenService: TokenService - ) {} - - async execute(command: LoginCommand): Promise { - const user = await this.users.findByEmail(command.email) - - if (!user) { - throw new InvalidCredentialsError() - } - - if (!user.verifyPassword(command.password)) { - throw new InvalidCredentialsError() - } - - const token = this.tokenService.generate({ userId: user.id.value }) - - return { - userId: user.id.value, - email: user.email.value, - authToken: token - } - } -} - -// interface/http/AuthController.ts -import { Request, Response } from 'express' - -export class AuthController { - constructor(private loginUseCase: LoginUseCase) {} - - async login(req: Request, res: Response) { - try { - const result = await this.loginUseCase.execute({ - email: req.body.email, - password: req.body.password - }) - - // HTTP concerns in controller - res.cookie('auth_token', result.authToken, { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: 'strict' - }) - - return res.json({ - user: { id: result.userId, email: result.email } - }) - } catch (error) { - if (error instanceof InvalidCredentialsError) { - return res.status(401).json({ error: 'Invalid credentials' }) - } - throw error - } - } -} - -// interface/cli/AuthCli.ts - Same use case, different delivery -export class AuthCli { - async login(email: string, password: string) { - const result = await this.loginUseCase.execute({ email, password }) - console.log(`Logged in as ${result.email}`) - fs.writeFileSync('.auth_token', result.authToken) - } -} -``` - -**Benefits:** -- Same use case for HTTP, CLI, WebSocket, queue consumers -- Easy to test without HTTP mocking -- Web framework upgrades isolated to interface layer - -Reference: [Clean Architecture - The Web is a Detail](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch31.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/test-boundary-verification.md b/builtin-skills/software-engineer/clean-architecture/references/test-boundary-verification.md deleted file mode 100644 index 54ac7bb7..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/test-boundary-verification.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Verify Architectural Boundaries with Tests -impact: LOW-MEDIUM -impactDescription: prevents boundary erosion, enforces dependency rules -tags: test, boundaries, architecture, enforcement ---- - -## Verify Architectural Boundaries with Tests - -Use automated tests to enforce that dependency rules are followed. Architecture tests catch violations before they become entrenched patterns. - -**Incorrect (no boundary verification):** - -```java -// Over time, developers add shortcuts -// domain/Order.java -import org.springframework.stereotype.Component; // Framework in domain! -import javax.persistence.Entity; // JPA in domain! - -// application/CreateOrderUseCase.java -import com.stripe.Stripe; // Direct payment vendor dependency! -import infrastructure.email.SendGridClient; // Infrastructure in application! - -// No tests catch these violations -// They accumulate until refactoring becomes impossible -``` - -**Correct (architecture tests enforce boundaries):** - -```java -// Using ArchUnit (Java) or similar tools -@AnalyzeClasses(packages = "com.myapp") -class ArchitectureTest { - - @ArchTest - static final ArchRule domain_should_not_depend_on_infrastructure = - noClasses() - .that().resideInAPackage("..domain..") - .should().dependOnClassesThat() - .resideInAPackage("..infrastructure.."); - - @ArchTest - static final ArchRule domain_should_not_use_frameworks = - noClasses() - .that().resideInAPackage("..domain..") - .should().dependOnClassesThat() - .resideInAnyPackage( - "org.springframework..", - "javax.persistence..", - "jakarta.persistence.." - ); - - @ArchTest - static final ArchRule usecases_should_not_access_controllers = - noClasses() - .that().resideInAPackage("..application..") - .should().dependOnClassesThat() - .resideInAPackage("..interface.."); - - @ArchTest - static final ArchRule dependencies_point_inward = - layeredArchitecture() - .consideringAllDependencies() - .layer("Domain").definedBy("..domain..") - .layer("Application").definedBy("..application..") - .layer("Infrastructure").definedBy("..infrastructure..") - .layer("Interface").definedBy("..interface..") - .whereLayer("Domain").mayNotAccessAnyLayer() - .whereLayer("Application").mayOnlyAccessLayers("Domain") - .whereLayer("Infrastructure").mayOnlyAccessLayers("Domain", "Application") - .whereLayer("Interface").mayOnlyAccessLayers("Domain", "Application"); -} - -// TypeScript equivalent using dependency-cruiser -// .dependency-cruiser.js -module.exports = { - forbidden: [ - { - name: 'domain-no-infra', - from: { path: '^src/domain' }, - to: { path: '^src/infrastructure' } - }, - { - name: 'domain-no-frameworks', - from: { path: '^src/domain' }, - to: { path: 'node_modules/(express|prisma|typeorm)' } - } - ] -}; -``` - -**Run in CI:** -```yaml -# .github/workflows/ci.yml -- name: Check architecture - run: | - ./gradlew archTest # Java with ArchUnit - npx depcruise src # TypeScript with dependency-cruiser -``` - -**Benefits:** -- Violations caught immediately in CI -- New developers can't accidentally break boundaries -- Architecture documentation that stays accurate - -Reference: [ArchUnit](https://www.archunit.org/) diff --git a/builtin-skills/software-engineer/clean-architecture/references/test-layer-isolation.md b/builtin-skills/software-engineer/clean-architecture/references/test-layer-isolation.md deleted file mode 100644 index a22cf141..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/test-layer-isolation.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Test Each Layer in Isolation -impact: LOW-MEDIUM -impactDescription: fast feedback, precise failure location -tags: test, isolation, layers, unit ---- - -## Test Each Layer in Isolation - -Each architectural layer should be testable independently. Domain tests need no infrastructure. Use case tests need no web framework. This enables fast, focused testing. - -**Incorrect (everything tested through API):** - -```typescript -// All tests go through HTTP - slow, imprecise failures -describe('Order API', () => { - let app: Express - let db: Database - - beforeEach(async () => { - db = await Database.connect() - await db.migrate() - await db.seed() - app = createApp(db) - }) - - afterEach(async () => { - await db.clean() - await db.close() - }) - - it('rejects order with insufficient inventory', async () => { - // 500ms+ per test - const response = await request(app) - .post('/orders') - .send({ items: [{ productId: 'p1', quantity: 1000 }] }) - - expect(response.status).toBe(400) - expect(response.body.error).toBe('Insufficient inventory') - }) - - // 50 more tests like this - test suite takes 5 minutes - // When one fails, unclear if it's domain, use case, or HTTP issue -}) -``` - -**Correct (layered testing):** - -```typescript -// Domain layer tests - instant, no dependencies -describe('Order', () => { - it('calculates total from items', () => { - const order = new Order() - order.addItem(new Product('p1', Money.dollars(10)), 2) - order.addItem(new Product('p2', Money.dollars(5)), 1) - - expect(order.total).toEqual(Money.dollars(25)) - }) - - it('prevents adding item with zero quantity', () => { - const order = new Order() - - expect(() => order.addItem(product, 0)).toThrow(InvalidQuantityError) - }) -}) - -// Use case tests - fast, test doubles for ports -describe('PlaceOrderUseCase', () => { - it('rejects order when inventory insufficient', () => { - const orders = new InMemoryOrderRepository() - const inventory = new FakeInventory({ 'p1': 5 }) // Only 5 in stock - const useCase = new PlaceOrderUseCase(orders, inventory) - - const result = useCase.execute({ - items: [{ productId: 'p1', quantity: 10 }] // Want 10 - }) - - expect(result.isFailure).toBe(true) - expect(result.error).toBe('INSUFFICIENT_INVENTORY') - }) -}) - -// Infrastructure tests - verify adapters work correctly -describe('PostgresOrderRepository', () => { - it('persists and retrieves order', async () => { - const repo = new PostgresOrderRepository(testDb) - const order = createTestOrder() - - await repo.save(order) - const retrieved = await repo.findById(order.id) - - expect(retrieved).toEqual(order) - }) -}) - -// API tests - few, verify wiring only -describe('POST /orders', () => { - it('returns 201 when order placed successfully', async () => { - // Most logic tested above; this verifies HTTP wiring - const response = await request(app) - .post('/orders') - .send(validOrderPayload) - - expect(response.status).toBe(201) - expect(response.body).toHaveProperty('orderId') - }) -}) -``` - -**Test pyramid:** -```text - /\ - / \ E2E: ~5 tests (slow, expensive) - /----\ - / \ Integration: ~20 tests (medium) - /--------\ - / \ Unit: ~200 tests (fast, cheap) - /____________\ -``` - -Reference: [The Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/test-testable-design.md b/builtin-skills/software-engineer/clean-architecture/references/test-testable-design.md deleted file mode 100644 index 9849e8d8..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/test-testable-design.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Design for Testability From the Start -impact: LOW-MEDIUM -impactDescription: enables comprehensive testing without test-induced damage -tags: test, testability, design, interfaces ---- - -## Design for Testability From the Start - -Clean architecture makes testing easy by design. If something is hard to test, it's a sign of architectural coupling. Don't compromise architecture for testability; fix the coupling. - -**Incorrect (hard to test, requiring workarounds):** - -```java -public class OrderProcessor { - public void process(Order order) { - // Hard to test: direct instantiation - PaymentService payment = new PaymentService(); - - // Hard to test: static call - if (InventoryChecker.isAvailable(order.getItems())) { - - // Hard to test: singleton - payment.charge(order.getTotal()); - NotificationService.getInstance().sendConfirmation(order); - - // Hard to test: current time - order.setProcessedAt(new Date()); - } - } -} - -// Test requires PowerMock, static mocking, singleton reset -// Test is slow, brittle, and complicated -@Test -@PrepareForTest({InventoryChecker.class, NotificationService.class}) -public void testProcess() { - PowerMockito.mockStatic(InventoryChecker.class); - PowerMockito.when(InventoryChecker.isAvailable(any())).thenReturn(true); - // ... 20 more lines of mock setup -} -``` - -**Correct (testable by design):** - -```java -public class OrderProcessor { - private final InventoryChecker inventory; - private final PaymentGateway payment; - private final NotificationPort notification; - private final Clock clock; - - // All dependencies injected - easy to substitute - public OrderProcessor( - InventoryChecker inventory, - PaymentGateway payment, - NotificationPort notification, - Clock clock - ) { - this.inventory = inventory; - this.payment = payment; - this.notification = notification; - this.clock = clock; - } - - public ProcessResult process(Order order) { - if (!inventory.isAvailable(order.getItems())) { - return ProcessResult.unavailable(); - } - - PaymentResult paymentResult = payment.charge(order.getTotal()); - if (!paymentResult.isSuccessful()) { - return ProcessResult.paymentFailed(paymentResult.getError()); - } - - order.markProcessed(clock.now()); - notification.sendConfirmation(order); - - return ProcessResult.success(order); - } -} - -@Test -void processesOrderWhenInventoryAvailable() { - var inventory = StubInventory.withAvailability(true); - var payment = FakePaymentGateway.alwaysSucceeds(); - var notification = new SpyNotification(); - var clock = Clock.fixed(Instant.parse("2024-01-15T10:00:00Z"), ZoneOffset.UTC); - - var processor = new OrderProcessor(inventory, payment, notification, clock); - var result = processor.process(order); - - assertThat(result.isSuccessful()).isTrue(); -} -``` - -**Testability checklist:** -- [ ] No `new` for services (inject dependencies) -- [ ] No static method calls for behavior (use interfaces) -- [ ] No singletons (pass instances) -- [ ] No direct time/random access (inject Clock, Random) -- [ ] No hidden dependencies (everything in constructor) - -Reference: [Growing Object-Oriented Software, Guided by Tests](http://www.growing-object-oriented-software.com/) diff --git a/builtin-skills/software-engineer/clean-architecture/references/test-tests-are-architecture.md b/builtin-skills/software-engineer/clean-architecture/references/test-tests-are-architecture.md deleted file mode 100644 index ca15d7df..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/test-tests-are-architecture.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Tests Are Part of the System Architecture -impact: LOW-MEDIUM -impactDescription: enables fast feedback, documents behavior -tags: test, architecture, design, first-class ---- - -## Tests Are Part of the System Architecture - -Tests participate in the architecture like any other component. They follow the dependency rule, couple to stable APIs, and should be designed for maintainability. - -**Incorrect (tests as afterthought):** - -```python -# tests/test_everything.py - Monolithic test file -import pytest -from unittest.mock import patch, MagicMock - -class TestOrders: - @patch('app.services.order_service.db') - @patch('app.services.order_service.stripe') - @patch('app.services.order_service.email_sender') - @patch('app.services.order_service.inventory') - def test_create_order(self, mock_inv, mock_email, mock_stripe, mock_db): - # Testing implementation details - mock_db.query.return_value.filter.return_value.first.return_value = Customer(id=1) - mock_inv.check.return_value = True - mock_stripe.PaymentIntent.create.return_value = MagicMock(id='pi_123') - - from app.services.order_service import create_order - result = create_order({'customer_id': 1, 'items': [...]}) - - # Asserting on internal calls, not behavior - mock_db.query.assert_called() - mock_stripe.PaymentIntent.create.assert_called_once() - -# Tests coupled to implementation, break with refactoring -# Tests slow because they patch everything -``` - -**Correct (tests designed as architecture component):** - -```python -# tests/unit/domain/test_order.py - Fast, stable, test domain rules -class TestOrder: - def test_calculates_total_from_line_items(self): - order = Order.create(customer_id="c1") - order.add_item(Product("p1", Money(100))) - order.add_item(Product("p2", Money(50))) - - assert order.total == Money(150) - - def test_rejects_negative_quantity(self): - order = Order.create(customer_id="c1") - - with pytest.raises(InvalidQuantityError): - order.add_item(Product("p1", Money(100)), quantity=-1) - -# tests/integration/application/test_create_order.py - Test use case -class TestCreateOrderUseCase: - def test_creates_order_and_reserves_inventory(self): - # Use test doubles, not mocks of internals - orders = InMemoryOrderRepository() - inventory = FakeInventoryService(available={"p1": 10}) - use_case = CreateOrderUseCase(orders, inventory) - - result = use_case.execute(CreateOrderCommand( - customer_id="c1", - items=[OrderItem("p1", quantity=2)] - )) - - # Assert on observable behavior - assert orders.find_by_id(result.order_id) is not None - assert inventory.reserved["p1"] == 2 - -# tests/e2e/test_order_flow.py - Full flow, few tests -class TestOrderFlow: - def test_complete_order_journey(self, api_client, test_db): - # Create order via API - response = api_client.post('/orders', json={...}) - order_id = response.json['order_id'] - - # Verify order persisted - order = test_db.query(Order).get(order_id) - assert order.status == 'pending' -``` - -**Test architecture mirrors system:** -```text -tests/ -├── unit/ # Fast, isolated -│ ├── domain/ # Entity business rules -│ └── application/ # Use case logic -├── integration/ # Component interaction -│ ├── persistence/ # Repository implementations -│ └── external/ # Gateway implementations -└── e2e/ # Full system - └── api/ # HTTP endpoints -``` - -**Benefits:** -- Unit tests run in milliseconds -- Refactoring doesn't break tests -- Tests document intended behavior - -Reference: [Clean Architecture - The Test Boundary](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch28.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-explicit-dependencies.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-explicit-dependencies.md deleted file mode 100644 index 76cd761a..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-explicit-dependencies.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Declare All Dependencies Explicitly in Constructor -impact: HIGH -impactDescription: enables testing, documents requirements, prevents hidden coupling -tags: usecase, dependencies, constructor, injection ---- - -## Declare All Dependencies Explicitly in Constructor - -Use cases should receive all dependencies through their constructor. Hidden dependencies (service locators, singletons, static calls) make testing difficult and hide coupling. - -**Incorrect (hidden dependencies):** - -```java -public class PlaceOrderUseCase { - public OrderConfirmation execute(PlaceOrderCommand command) { - // Hidden dependencies - impossible to test or trace - var customer = CustomerRepository.getInstance().find(command.customerId()); - var inventory = InventoryService.getInventory(); - - for (var item : command.items()) { - if (!inventory.isAvailable(item)) { - throw new OutOfStockException(item); - } - } - - var order = new Order(customer, command.items()); - - // More hidden dependencies - Database.getConnection().save(order); - EmailService.send(customer.email(), "Order placed"); - EventBus.publish(new OrderPlacedEvent(order)); - - return new OrderConfirmation(order.id()); - } -} - -// Testing requires mocking static methods - complex and brittle -``` - -**Correct (explicit constructor dependencies):** - -```java -public class PlaceOrderUseCase { - private final CustomerRepository customers; - private final InventoryChecker inventory; - private final OrderRepository orders; - private final NotificationPort notifications; - private final EventPublisher events; - - public PlaceOrderUseCase( - CustomerRepository customers, - InventoryChecker inventory, - OrderRepository orders, - NotificationPort notifications, - EventPublisher events - ) { - this.customers = customers; - this.inventory = inventory; - this.orders = orders; - this.notifications = notifications; - this.events = events; - } - - public OrderConfirmation execute(PlaceOrderCommand command) { - var customer = customers.find(command.customerId()); - - for (var item : command.items()) { - if (!inventory.isAvailable(item)) { - throw new OutOfStockException(item); - } - } - - var order = new Order(customer, command.items()); - orders.save(order); - - notifications.orderPlaced(customer, order); - events.publish(new OrderPlacedEvent(order)); - - return new OrderConfirmation(order.id()); - } -} - -// Testing is straightforward -@Test -void placesOrderWhenInventoryAvailable() { - var customers = mock(CustomerRepository.class); - var inventory = mock(InventoryChecker.class); - var orders = mock(OrderRepository.class); - // ... configure mocks - - var useCase = new PlaceOrderUseCase(customers, inventory, orders, ...); - var result = useCase.execute(command); - - verify(orders).save(any(Order.class)); -} -``` - -**Benefits:** -- Dependencies visible in constructor signature -- Tests substitute any dependency with test doubles -- Coupling is explicit and measurable - -Reference: [Dependency Injection Principles](https://martinfowler.com/articles/injection.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-input-output-ports.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-input-output-ports.md deleted file mode 100644 index 7041ebf4..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-input-output-ports.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: Define Input and Output Ports for Use Cases -impact: HIGH -impactDescription: decouples use cases from delivery mechanism -tags: usecase, ports, input, output, boundaries ---- - -## Define Input and Output Ports for Use Cases - -Use cases should define their own input (request) and output (response) data structures. These ports isolate the use case from the delivery mechanism (HTTP, CLI, queue). - -**Incorrect (use case coupled to HTTP):** - -```csharp -public class RegisterUserUseCase -{ - public IActionResult Execute(HttpRequest request) // Coupled to ASP.NET - { - var email = request.Form["email"]; - var password = request.Form["password"]; - - if (string.IsNullOrEmpty(email)) - return new BadRequestResult(); // HTTP-specific response - - var user = new User(email, password); - _repository.Save(user); - - return new OkObjectResult(new { id = user.Id }); // JSON response - } -} -``` - -**Correct (use case with defined ports):** - -```csharp -// application/ports/input/RegisterUserCommand.cs -public record RegisterUserCommand( - string Email, - string Password, - string Name -); - -// application/ports/output/RegisterUserResult.cs -public record RegisterUserResult( - string UserId, - string Email, - DateTime CreatedAt -); - -// application/usecases/RegisterUserUseCase.cs -public class RegisterUserUseCase -{ - private readonly IUserRepository _repository; - private readonly IPasswordHasher _hasher; - - public RegisterUserResult Execute(RegisterUserCommand command) - { - if (string.IsNullOrEmpty(command.Email)) - throw new ValidationException("Email required"); - - var hashedPassword = _hasher.Hash(command.Password); - var user = new User(command.Email, hashedPassword, command.Name); - _repository.Save(user); - - return new RegisterUserResult( - user.Id.Value, - user.Email.Value, - user.CreatedAt - ); - } -} - -// interface_adapters/controllers/UserController.cs -[ApiController] -public class UserController : ControllerBase -{ - [HttpPost] - public IActionResult Register([FromBody] RegisterRequest request) - { - var command = new RegisterUserCommand( - request.Email, - request.Password, - request.Name - ); - - var result = _useCase.Execute(command); - - return Ok(new { userId = result.UserId }); - } -} -``` - -**Benefits:** -- Same use case callable from HTTP, CLI, message queue, tests -- Request/response format changes don't affect use case -- Use case testable without HTTP infrastructure - -Reference: [Clean Architecture - Input/Output Ports](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-no-presentation-logic.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-no-presentation-logic.md deleted file mode 100644 index f9ade1e2..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-no-presentation-logic.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Use Cases Must Not Contain Presentation Logic -impact: HIGH -impactDescription: enables multiple UI implementations from same use case -tags: usecase, presentation, formatting, separation ---- - -## Use Cases Must Not Contain Presentation Logic - -Use cases return domain data, not formatted strings, HTML, or UI-specific structures. Presentation logic belongs in the interface adapters layer. - -**Incorrect (presentation logic in use case):** - -```typescript -class GetUserProfileUseCase { - execute(userId: string): UserProfileResponse { - const user = this.repo.findById(userId) - const orders = this.orderRepo.findByUser(userId) - - return { - displayName: `${user.firstName} ${user.lastName}`, // Formatting - memberSince: user.createdAt.toLocaleDateString('en-US', { - month: 'long', - year: 'numeric' - }), // Locale-specific formatting - avatarHtml: `${user.firstName}`, // HTML! - orderSummary: orders.length > 0 - ? `${orders.length} orders totaling $${this.sumOrders(orders).toFixed(2)}` - : 'No orders yet', // UI text - recentOrders: orders.slice(0, 5).map(o => ({ - ...o, - statusBadgeColor: this.getStatusColor(o.status) // UI styling - })) - } - } - - private getStatusColor(status: string): string { - const colors = { pending: 'yellow', shipped: 'blue', delivered: 'green' } - return colors[status] || 'gray' - } -} -``` - -**Correct (use case returns domain data):** - -```typescript -// application/usecases/GetUserProfileUseCase.ts -class GetUserProfileUseCase { - execute(userId: string): UserProfileResult { - const user = this.repo.findById(userId) - const orders = this.orderRepo.findByUser(userId) - - return { - user: { - id: user.id.value, - firstName: user.firstName, - lastName: user.lastName, - email: user.email.value, - avatarUrl: user.avatarUrl, - createdAt: user.createdAt - }, - orders: orders.map(o => ({ - id: o.id.value, - total: o.total.amount, - currency: o.total.currency, - status: o.status, - createdAt: o.createdAt - })), - orderCount: orders.length, - totalSpent: this.sumOrders(orders) - } - } -} - -// interface_adapters/presenters/UserProfilePresenter.ts -class UserProfilePresenter { - present(result: UserProfileResult, locale: string): UserProfileViewModel { - const formatter = new Intl.DateTimeFormat(locale, { - month: 'long', - year: 'numeric' - }) - - return { - displayName: `${result.user.firstName} ${result.user.lastName}`, - memberSince: formatter.format(result.user.createdAt), - avatarUrl: result.user.avatarUrl, - orderSummary: this.formatOrderSummary(result, locale), - recentOrders: result.orders.slice(0, 5).map(o => - this.formatOrder(o, locale) - ) - } - } -} -``` - -**Benefits:** -- Same use case serves web, mobile, API consumers -- Locale/format changes don't touch business logic -- UI redesigns don't affect use case tests - -Reference: [Clean Architecture - Presenters](https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/ch23.xhtml) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-orchestrates-not-implements.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-orchestrates-not-implements.md deleted file mode 100644 index 448c047d..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-orchestrates-not-implements.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Use Cases Orchestrate Entities Not Implement Business Rules -impact: HIGH -impactDescription: prevents rule duplication, maintains single source of truth -tags: usecase, orchestration, entities, delegation ---- - -## Use Cases Orchestrate Entities Not Implement Business Rules - -Use cases coordinate the flow of data to and from entities. Business rules belong in entities; use cases should not duplicate or implement them. - -**Incorrect (business rules in use case):** - -```go -func (uc *ApplyDiscountUseCase) Execute(orderId string, code string) error { - order := uc.repo.Find(orderId) - discount := uc.discounts.Find(code) - - // Business rules implemented in use case - if order.Status != "pending" { - return errors.New("cannot apply discount to processed order") - } - - if discount.ExpiresAt.Before(time.Now()) { - return errors.New("discount expired") - } - - if order.Total.LessThan(discount.MinimumOrder) { - return errors.New("order total below minimum") - } - - if discount.UsageCount >= discount.MaxUses { - return errors.New("discount fully redeemed") - } - - // Calculate discount - more business rules - var discountAmount Money - if discount.Type == "percentage" { - discountAmount = order.Total.MultiplyBy(discount.Value / 100) - } else { - discountAmount = discount.Value - } - - order.DiscountAmount = discountAmount - order.Total = order.Total.Subtract(discountAmount) - uc.repo.Save(order) - return nil -} -``` - -**Correct (use case orchestrates, entities implement rules):** - -```go -func (uc *ApplyDiscountUseCase) Execute(orderId string, code string) error { - order := uc.repo.Find(orderId) - discount := uc.discounts.Find(code) - - // Use case orchestrates the interaction - if err := order.ApplyDiscount(discount); err != nil { - return err - } - - uc.repo.Save(order) - return nil -} - -// domain/entities/order.go -func (o *Order) ApplyDiscount(discount *Discount) error { - if o.status != OrderStatusPending { - return ErrOrderNotPending - } - - if !discount.IsValidFor(o.total) { - return discount.ValidationError(o.total) - } - - o.discount = discount - o.discountAmount = discount.CalculateFor(o.total) - return nil -} - -// domain/entities/discount.go -func (d *Discount) IsValidFor(orderTotal Money) bool { - return !d.IsExpired() && - !d.IsFullyRedeemed() && - orderTotal.GreaterThanOrEqual(d.minimumOrder) -} - -func (d *Discount) CalculateFor(total Money) Money { - if d.discountType == PercentageDiscount { - return total.MultiplyBy(d.value).DivideBy(100) - } - return d.value -} -``` - -**Benefits:** -- Business rules tested once in entity, not in every use case -- Rules cannot diverge between use cases -- Use case clearly shows workflow, not implementation details - -Reference: [Clean Architecture - Use Cases](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-single-responsibility.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-single-responsibility.md deleted file mode 100644 index 776903a4..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-single-responsibility.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Each Use Case Has One Reason to Change -impact: HIGH -impactDescription: isolates change impact, enables parallel development -tags: usecase, single-responsibility, cohesion, srp ---- - -## Each Use Case Has One Reason to Change - -Each use case class should orchestrate exactly one application-specific workflow. Combining multiple use cases creates coupling that forces unrelated changes together. - -**Incorrect (multiple use cases in one class):** - -```python -class OrderService: - def __init__(self, repo, payment, shipping, notification): - self.repo = repo - self.payment = payment - self.shipping = shipping - self.notification = notification - - def create_order(self, items, customer_id): - # Use case 1: Create order - order = Order.create(items, customer_id) - self.repo.save(order) - return order - - def process_payment(self, order_id, payment_method): - # Use case 2: Process payment - order = self.repo.find(order_id) - self.payment.charge(order.total, payment_method) - order.mark_paid() - self.repo.save(order) - - def ship_order(self, order_id, address): - # Use case 3: Ship order - order = self.repo.find(order_id) - tracking = self.shipping.create_shipment(order, address) - order.mark_shipped(tracking) - self.notification.send_shipped(order) - self.repo.save(order) - - # Changes to shipping logic force retest of payment logic -``` - -**Correct (separate use case classes):** - -```python -class CreateOrderUseCase: - def __init__(self, repo: OrderRepository): - self.repo = repo - - def execute(self, command: CreateOrderCommand) -> OrderId: - order = Order.create(command.items, command.customer_id) - self.repo.save(order) - return order.id - - -class ProcessPaymentUseCase: - def __init__(self, repo: OrderRepository, payment: PaymentGateway): - self.repo = repo - self.payment = payment - - def execute(self, command: ProcessPaymentCommand) -> None: - order = self.repo.find(command.order_id) - self.payment.charge(order.total, command.payment_method) - order.mark_paid() - self.repo.save(order) - - -class ShipOrderUseCase: - def __init__( - self, - repo: OrderRepository, - shipping: ShippingService, - notification: NotificationPort - ): - self.repo = repo - self.shipping = shipping - self.notification = notification - - def execute(self, command: ShipOrderCommand) -> TrackingNumber: - order = self.repo.find(command.order_id) - tracking = self.shipping.create_shipment(order, command.address) - order.mark_shipped(tracking) - self.notification.send_shipped(order) - self.repo.save(order) - return tracking -``` - -**Benefits:** -- Changes to shipping don't affect payment tests -- Teams can work on different use cases in parallel -- Each use case has minimal dependencies - -Reference: [Clean Architecture - Use Cases](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) diff --git a/builtin-skills/software-engineer/clean-architecture/references/usecase-transaction-boundary.md b/builtin-skills/software-engineer/clean-architecture/references/usecase-transaction-boundary.md deleted file mode 100644 index b37b67b7..00000000 --- a/builtin-skills/software-engineer/clean-architecture/references/usecase-transaction-boundary.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: Use Case Defines the Transaction Boundary -impact: HIGH -impactDescription: ensures data consistency, prevents partial updates -tags: usecase, transactions, consistency, boundaries ---- - -## Use Case Defines the Transaction Boundary - -The use case is the natural transaction boundary. All operations within a use case should succeed or fail atomically. Infrastructure manages the transaction; use case defines the scope. - -**Incorrect (transaction managed inside repository):** - -```python -class OrderRepository: - def save(self, order): - with self.db.transaction(): # Transaction per operation - self.db.insert('orders', order) - -class InventoryRepository: - def reserve(self, items): - with self.db.transaction(): # Separate transaction - for item in items: - self.db.update('inventory', item.sku, decrement=item.qty) - -class PlaceOrderUseCase: - def execute(self, command): - order = Order.create(command.items) - self.orders.save(order) # Commits - self.inventory.reserve(command.items) # If this fails, order is orphaned! - self.payments.charge(order.total) # If this fails, inventory is reserved but unpaid -``` - -**Correct (use case defines transaction boundary):** - -```python -# application/ports/UnitOfWork.py -class UnitOfWork(Protocol): - def begin(self) -> None: ... - def commit(self) -> None: ... - def rollback(self) -> None: ... - -# application/usecases/PlaceOrderUseCase.py -class PlaceOrderUseCase: - def __init__(self, uow: UnitOfWork, orders, inventory, payments): - self.uow = uow - self.orders = orders - self.inventory = inventory - self.payments = payments - - def execute(self, command): - self.uow.begin() - try: - order = Order.create(command.items) - - self.inventory.reserve(command.items) - self.payments.charge(order.total) - self.orders.save(order) - - self.uow.commit() # All or nothing - return order.id - - except Exception as e: - self.uow.rollback() # Clean rollback - raise - -# Alternative using context manager -class PlaceOrderUseCase: - def execute(self, command): - with self.uow: # Transaction spans entire use case - order = Order.create(command.items) - self.inventory.reserve(command.items) - self.payments.charge(order.total) - self.orders.save(order) - return order.id -``` - -**Note:** For distributed systems, consider saga patterns or eventual consistency rather than distributed transactions. - -Reference: [Unit of Work Pattern](https://martinfowler.com/eaaCatalog/unitOfWork.html) diff --git a/builtin-skills/software-engineer/clean-code/SKILL.md b/builtin-skills/software-engineer/clean-code/SKILL.md deleted file mode 100644 index efa78f93..00000000 --- a/builtin-skills/software-engineer/clean-code/SKILL.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: clean-code -description: Use when writing, reviewing, or refactoring code for maintainability and readability. Triggers on code reviews, naming discussions, function design, error handling, and test writing. Based on Robert C. Martin's Clean Code handbook with modern corrections. ---- - -# Robert C. Martin (Uncle Bob) Clean Code Best Practices - -Comprehensive software craftsmanship guide based on Robert C. Martin's "Clean Code: A Handbook of Agile Software Craftsmanship", updated with modern corrections where the original 2008 advice has been superseded. Contains 48 rules across 10 categories, prioritized by impact to guide code reviews, refactoring decisions, and new development. Examples are primarily in Java but principles are language-agnostic. - -## When to Apply - -Reference these guidelines when: -- Writing new functions, classes, or modules -- Naming variables, functions, classes, or files -- Reviewing code for maintainability issues -- Refactoring existing code to improve clarity -- Writing or improving unit tests -- Wrapping third-party dependencies - -## Rule Categories by Priority - -| Priority | Category | Impact | Prefix | -|----------|----------|--------|--------| -| 1 | Meaningful Names | CRITICAL | `name-` | -| 2 | Functions | CRITICAL | `func-` | -| 3 | Comments | HIGH | `cmt-` | -| 4 | Formatting | HIGH | `fmt-` | -| 5 | Error Handling | HIGH | `err-` | -| 6 | Objects and Data Structures | MEDIUM-HIGH | `obj-` | -| 7 | Boundaries | MEDIUM-HIGH | `bound-` | -| 8 | Classes and Systems | MEDIUM-HIGH | `class-` | -| 9 | Unit Tests | MEDIUM | `test-` | -| 10 | Emergence and Simple Design | MEDIUM | `emerge-` | - -## Quick Reference - -### 1. Meaningful Names (CRITICAL) - -- [`name-intention-revealing`](references/name-intention-revealing.md) - Use names that reveal intent -- [`name-avoid-disinformation`](references/name-avoid-disinformation.md) - Avoid misleading names -- [`name-meaningful-distinctions`](references/name-meaningful-distinctions.md) - Make meaningful distinctions -- [`name-pronounceable`](references/name-pronounceable.md) - Use pronounceable names -- [`name-searchable`](references/name-searchable.md) - Use searchable names -- [`name-avoid-encodings`](references/name-avoid-encodings.md) - Avoid encodings in names -- [`name-class-noun`](references/name-class-noun.md) - Use noun phrases for class names -- [`name-method-verb`](references/name-method-verb.md) - Use verb phrases for method names - -### 2. Functions (CRITICAL) - -- [`func-small`](references/func-small.md) - Keep functions small -- [`func-one-thing`](references/func-one-thing.md) - Functions should do one thing -- [`func-abstraction-level`](references/func-abstraction-level.md) - Maintain one level of abstraction -- [`func-minimize-arguments`](references/func-minimize-arguments.md) - Minimize function arguments -- [`func-no-side-effects`](references/func-no-side-effects.md) - Avoid side effects -- [`func-command-query-separation`](references/func-command-query-separation.md) - Separate commands from queries -- [`func-dry`](references/func-dry.md) - Do not repeat yourself - -### 3. Comments (HIGH) - -- [`cmt-express-in-code`](references/cmt-express-in-code.md) - Express yourself in code, not comments -- [`cmt-explain-intent`](references/cmt-explain-intent.md) - Use comments to explain intent -- [`cmt-avoid-redundant`](references/cmt-avoid-redundant.md) - Avoid redundant comments -- [`cmt-avoid-commented-out-code`](references/cmt-avoid-commented-out-code.md) - Delete commented-out code -- [`cmt-warning-consequences`](references/cmt-warning-consequences.md) - Use warning comments for consequences - -### 4. Formatting (HIGH) - -- [`fmt-vertical-formatting`](references/fmt-vertical-formatting.md) - Use vertical formatting for readability -- [`fmt-horizontal-alignment`](references/fmt-horizontal-alignment.md) - Avoid horizontal alignment -- [`fmt-team-rules`](references/fmt-team-rules.md) - Follow team formatting rules -- [`fmt-indentation`](references/fmt-indentation.md) - Respect indentation rules - -### 5. Error Handling (HIGH) - -- [`err-use-exceptions`](references/err-use-exceptions.md) - Separate error handling from happy path -- [`err-write-try-catch-first`](references/err-write-try-catch-first.md) - Write try-catch-finally first -- [`err-provide-context`](references/err-provide-context.md) - Provide context with exceptions -- [`err-define-by-caller-needs`](references/err-define-by-caller-needs.md) - Define exceptions by caller needs -- [`err-avoid-null`](references/err-avoid-null.md) - Avoid returning and passing null - -### 6. Objects and Data Structures (MEDIUM-HIGH) - -- [`obj-data-abstraction`](references/obj-data-abstraction.md) - Hide data behind abstractions -- [`obj-data-object-asymmetry`](references/obj-data-object-asymmetry.md) - Understand data/object anti-symmetry -- [`obj-law-of-demeter`](references/obj-law-of-demeter.md) - Follow the Law of Demeter -- [`obj-avoid-hybrids`](references/obj-avoid-hybrids.md) - Avoid hybrid data-object structures -- [`obj-dto`](references/obj-dto.md) - Use DTOs for data transfer - -### 7. Boundaries (MEDIUM-HIGH) - -- [`bound-wrap-third-party`](references/bound-wrap-third-party.md) - Wrap third-party APIs -- [`bound-learning-tests`](references/bound-learning-tests.md) - Write learning tests for third-party code - -### 8. Classes and Systems (MEDIUM-HIGH) - -- [`class-small`](references/class-small.md) - Keep classes small -- [`class-cohesion`](references/class-cohesion.md) - Maintain class cohesion -- [`class-organize-for-change`](references/class-organize-for-change.md) - Organize classes for change -- [`class-isolate-from-change`](references/class-isolate-from-change.md) - Isolate classes from change -- [`class-separate-concerns`](references/class-separate-concerns.md) - Separate construction from use - -### 9. Unit Tests (MEDIUM) - -- [`test-first-law`](references/test-first-law.md) - Follow the three laws of TDD -- [`test-keep-clean`](references/test-keep-clean.md) - Keep tests clean -- [`test-one-assert`](references/test-one-assert.md) - One concept per test -- [`test-first-principles`](references/test-first-principles.md) - Follow FIRST principles -- [`test-build-operate-check`](references/test-build-operate-check.md) - Use Build-Operate-Check pattern - -### 10. Emergence and Simple Design (MEDIUM) - -- [`emerge-simple-design`](references/emerge-simple-design.md) - Follow the four rules of simple design -- [`emerge-expressiveness`](references/emerge-expressiveness.md) - Maximize expressiveness - -## How to Use - -Read individual reference files for detailed explanations and code examples: - -- [Section definitions](references/_sections.md) - Category structure and impact levels -- [Rule template](assets/templates/_template.md) - Template for adding new rules - -## Reference Files - -| File | Description | -|------|-------------| -| [references/_sections.md](references/_sections.md) | Category definitions and ordering | -| [assets/templates/_template.md](assets/templates/_template.md) | Template for new rules | -| [metadata.json](metadata.json) | Version and reference information | diff --git a/builtin-skills/software-engineer/clean-code/assets/templates/_template.md b/builtin-skills/software-engineer/clean-code/assets/templates/_template.md deleted file mode 100644 index f9207254..00000000 --- a/builtin-skills/software-engineer/clean-code/assets/templates/_template.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Rule Title Here -impact: MEDIUM -impactDescription: description of impact (e.g., "eliminates confusion") -tags: category-prefix, keyword1, keyword2 ---- - -## Rule Title Here - -Brief explanation of the rule and why it matters. Focus on the principle and its impact on code maintainability and readability. - -**Incorrect (description of what's wrong):** - -```java -// Bad code example here showing the anti-pattern -// Comment explaining the problem -``` - -**Correct (description of what's right):** - -```java -// Good code example here showing the solution -// Comment explaining the benefit -``` - -**When NOT to use this pattern:** -- Exception case 1 -- Exception case 2 - -Reference: [Clean Code, Chapter N: Topic](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/metadata.json b/builtin-skills/software-engineer/clean-code/metadata.json deleted file mode 100644 index 270ccf7c..00000000 --- a/builtin-skills/software-engineer/clean-code/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "1.0.3", - "organization": "Robert C. Martin (Uncle Bob)", - "technology": "Software Craftsmanship (examples in Java, principles are language-agnostic)", - "date": "January 2026", - "abstract": "Comprehensive software craftsmanship guide based on Robert C. Martin's 'Clean Code: A Handbook of Agile Software Craftsmanship', updated with modern corrections where the original 2008 advice has been superseded. Contains 48 rules across 10 categories covering naming, functions, comments, formatting, error handling, objects, boundaries, classes, testing, and simple design. Each rule includes 'When NOT to use' caveats, polyglot guidance where applicable, and real-world examples comparing incorrect vs. correct implementations.", - "references": [ - "https://www.oreilly.com/library/view/clean-code-a/9780136083238/", - "https://blog.cleancoder.com/", - "https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" - ] -} diff --git a/builtin-skills/software-engineer/clean-code/references/_sections.md b/builtin-skills/software-engineer/clean-code/references/_sections.md deleted file mode 100644 index c91b7e0b..00000000 --- a/builtin-skills/software-engineer/clean-code/references/_sections.md +++ /dev/null @@ -1,56 +0,0 @@ -# Sections - -This file defines all sections, their ordering, impact levels, and descriptions. -The section ID (in parentheses) is the filename prefix used to group rules. - ---- - -## 1. Meaningful Names (name) - -**Impact:** CRITICAL -**Description:** Names are the primary documentation. Bad names cascade confusion throughout the codebase, forcing every reader to decipher intent. - -## 2. Functions (func) - -**Impact:** CRITICAL -**Description:** Functions are the verbs of code. Small, focused functions enable understanding, testing, and reuse while reducing complexity. - -## 3. Comments (cmt) - -**Impact:** HIGH -**Description:** Comments should explain intent, not obvious mechanics. Wrong or stale comments actively mislead readers and cost more than no comments. - -## 4. Formatting (fmt) - -**Impact:** HIGH -**Description:** Consistent formatting reduces cognitive load. Code should read top-to-bottom like a newspaper article. - -## 5. Error Handling (err) - -**Impact:** HIGH -**Description:** Clean error handling separates happy path from exceptional cases. Use the error mechanism idiomatic to your language (exceptions, Result types, or explicit error returns). - -## 6. Objects and Data Structures (obj) - -**Impact:** MEDIUM-HIGH -**Description:** Objects hide data and expose behavior; data structures expose data and have no behavior. Mixing these creates hybrid messes. - -## 7. Boundaries (bound) - -**Impact:** MEDIUM-HIGH -**Description:** Third-party code and external APIs are boundaries. Wrap them to isolate change, ease testing, and maintain control over your codebase's interfaces. - -## 8. Classes and Systems (class) - -**Impact:** MEDIUM-HIGH -**Description:** Classes should be small and have a single responsibility. Systems should separate construction from use. SRP and DIP are among the highest-leverage design principles. - -## 9. Unit Tests (test) - -**Impact:** MEDIUM -**Description:** Tests are first-class citizens that enable safe refactoring. Test code deserves the same care as production code. - -## 10. Emergence and Simple Design (emerge) - -**Impact:** MEDIUM -**Description:** Good design emerges from following four rules in order: pass tests, reveal intent, eliminate duplication, minimize elements. Resist the urge to over-engineer. diff --git a/builtin-skills/software-engineer/clean-code/references/bound-learning-tests.md b/builtin-skills/software-engineer/clean-code/references/bound-learning-tests.md deleted file mode 100644 index d6e520ce..00000000 --- a/builtin-skills/software-engineer/clean-code/references/bound-learning-tests.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Write Learning Tests for Third-Party Code -impact: MEDIUM -impactDescription: catches 90%+ of breaking changes in dependency upgrades before production -tags: bound, boundary, learning-tests, third-party, testing ---- - -## Write Learning Tests for Third-Party Code - -When integrating a third-party library, write small tests that verify your understanding of how the API works. These tests serve double duty: they help you learn the API, and they act as a safety net when upgrading the library. - -**Incorrect (learning by trial and error in production code):** - -```java -// Experimenting directly in application code -public void importCustomerRecord(String json) { - // Does Gson handle null fields? Let's find out... - Gson gson = new Gson(); - CustomerRecord record = gson.fromJson(json, CustomerRecord.class); - // Does this throw or return null for missing fields? - // Who knows — we'll find out in production -} -``` - -**Correct (learning tests verify assumptions):** - -```java -@Test -public void gsonShouldDeserializeNullFieldsAsNull() { - Gson gson = new Gson(); - Data data = gson.fromJson("{}", Data.class); - - assertNull(data.getName()); -} - -@Test -public void gsonShouldHandleMalformedJson() { - Gson gson = new Gson(); - - assertThrows(JsonSyntaxException.class, - () -> gson.fromJson("{invalid", Data.class)); -} - -@Test -public void gsonShouldIgnoreUnknownFields() { - Gson gson = new Gson(); - Data data = gson.fromJson("{\"name\":\"test\",\"unknown\":true}", Data.class); - - assertEquals("test", data.getName()); -} -``` - -**Benefits:** -- Free education on the API's behavior -- When you upgrade the library, these tests break first — before your production code does -- Documents exactly which behaviors your code relies on -- Takes minutes to write but saves hours of debugging - -Reference: [Clean Code, Chapter 8: Boundaries](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/bound-wrap-third-party.md b/builtin-skills/software-engineer/clean-code/references/bound-wrap-third-party.md deleted file mode 100644 index df86faba..00000000 --- a/builtin-skills/software-engineer/clean-code/references/bound-wrap-third-party.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Wrap Third-Party APIs -impact: HIGH -impactDescription: reduces dependency change points from N call sites to 1 wrapper -tags: bound, boundary, wrapper, third-party, dependency ---- - -## Wrap Third-Party APIs - -When you use a third-party API, wrap it in a class you control. This minimizes your dependency on the third party, makes testing easier, and gives you a single place to change when the API evolves. - -**Incorrect (direct dependency scattered across codebase):** - -```java -// Every caller depends on ACMEPort directly -public class SensorReader { - public void readSensors() { - try { - ACMEPort port = new ACMEPort(12); - port.open(); - // ... - } catch (ACMEDeviceException e) { - logger.log("Device exception", e); - } catch (ACMEConfigException e) { - logger.log("Config exception", e); - } catch (ACMECommunicationException e) { - logger.log("Communication exception", e); - } - } -} -// If ACME changes their API, every file that uses it must change -``` - -**Correct (wrapped behind your own interface):** - -```java -public class LocalPort { - private ACMEPort innerPort; - - public LocalPort(int portNumber) { - innerPort = new ACMEPort(portNumber); - } - - public void open() { - try { - innerPort.open(); - } catch (ACMEDeviceException | ACMEConfigException | ACMECommunicationException e) { - throw new PortException(e); - } - } -} - -// Callers depend only on your wrapper -public class SensorReader { - public void readSensors() { - try { - LocalPort port = new LocalPort(12); - port.open(); - // ... - } catch (PortException e) { - logger.log("Port error", e); - } - } -} -``` - -**Benefits:** -- One place to change when the third-party API changes -- Easier to mock in tests (mock `LocalPort`, not the vendor library) -- Freedom to switch vendors without rewriting the entire codebase -- Consistent exception hierarchy under your control - -**When NOT to wrap:** -- Stable, widely-used standard library APIs (e.g., `java.util.List`, `String`) do not need wrapping. -- If the wrapper would be a 1:1 passthrough with no value added, it's premature. Wait until you have a concrete reason (testing, migration, or simplification). - -Reference: [Clean Code, Chapter 8: Boundaries](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/class-cohesion.md b/builtin-skills/software-engineer/clean-code/references/class-cohesion.md deleted file mode 100644 index 715dce8f..00000000 --- a/builtin-skills/software-engineer/clean-code/references/class-cohesion.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Maintain Class Cohesion -impact: MEDIUM -impactDescription: enables extracting focused subclasses -tags: class, cohesion, variables, methods ---- - -## Maintain Class Cohesion - -Classes should have a small number of instance variables. Each method should manipulate one or more of those variables. The more variables a method manipulates, the more cohesive the method is to its class. - -**Incorrect (low cohesion - methods use different variables):** - -```java -public class Utility { - private Database db; - private EmailService email; - private Logger logger; - private Cache cache; - - public void saveUser(User user) { - db.save(user); // Only uses db - logger.log("Saved user"); // Only uses logger - } - - public void sendNotification(String message) { - email.send(message); // Only uses email - } - - public Object getCached(String key) { - return cache.get(key); // Only uses cache - } -} -// Each method uses different instance variables - low cohesion -``` - -**Correct (high cohesion - methods use shared variables):** - -```java -public class Stack { - private int topOfStack = 0; - private List elements = new LinkedList<>(); - - public int size() { - return topOfStack; // Uses topOfStack - } - - public void push(int element) { - topOfStack++; // Uses topOfStack - elements.add(element); // Uses elements - } - - public int pop() throws EmptyStackException { - if (topOfStack == 0) - throw new EmptyStackException(); - int element = elements.get(--topOfStack); // Uses both - elements.remove(topOfStack); // Uses both - return element; - } -} -// Every method uses the same instance variables - high cohesion -``` - -**When cohesion breaks down:** If a subset of methods only uses a subset of variables, extract those methods and variables into a separate class. - -Reference: [Clean Code, Chapter 10: Classes](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/class-isolate-from-change.md b/builtin-skills/software-engineer/clean-code/references/class-isolate-from-change.md deleted file mode 100644 index 8c527adb..00000000 --- a/builtin-skills/software-engineer/clean-code/references/class-isolate-from-change.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Isolate Classes from Change -impact: MEDIUM -impactDescription: enables testing and reduces coupling -tags: class, dip, interfaces, coupling ---- - -## Isolate Classes from Change - -Depend on abstractions, not concretions. Classes should depend on interfaces rather than concrete implementations. This enables testing and reduces the impact of change. - -**Incorrect (depends on concrete implementation):** - -```java -public class Portfolio { - private NYSEStockExchange exchange; - - public Portfolio(NYSEStockExchange exchange) { - this.exchange = exchange; - } - - public Money value() { - Money total = Money.ZERO; - for (String symbol : holdings.keySet()) { - // Cannot test without real stock exchange connection - total = total.plus(exchange.currentPrice(symbol) - .times(holdings.get(symbol))); - } - return total; - } -} -``` - -**Correct (depends on abstraction):** - -```java -public interface StockExchange { - Money currentPrice(String symbol); -} - -public class Portfolio { - private StockExchange exchange; - - public Portfolio(StockExchange exchange) { - this.exchange = exchange; - } - - public Money value() { - Money total = Money.ZERO; - for (String symbol : holdings.keySet()) { - total = total.plus(exchange.currentPrice(symbol) - .times(holdings.get(symbol))); - } - return total; - } -} - -// Production -Portfolio portfolio = new Portfolio(new NYSEStockExchange()); - -// Testing -@Test -public void portfolioValueShouldSumAllHoldings() { - StockExchange mockExchange = mock(StockExchange.class); - when(mockExchange.currentPrice("AAPL")).thenReturn(Money.dollars(150)); - - Portfolio portfolio = new Portfolio(mockExchange); - portfolio.add("AAPL", 10); - - assertEquals(Money.dollars(1500), portfolio.value()); -} -``` - -**Dependency Inversion Principle (DIP):** High-level modules should not depend on low-level modules. Both should depend on abstractions. - -Reference: [Clean Code, Chapter 10: Classes](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/class-organize-for-change.md b/builtin-skills/software-engineer/clean-code/references/class-organize-for-change.md deleted file mode 100644 index 387f27f2..00000000 --- a/builtin-skills/software-engineer/clean-code/references/class-organize-for-change.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Organize Classes for Change -impact: MEDIUM -impactDescription: minimizes modification risk when requirements change -tags: class, ocp, change, design ---- - -## Organize Classes for Change - -Classes should be organized so that change is minimally invasive. Following the Open-Closed Principle (OCP): classes should be open for extension but closed for modification. - -**Incorrect (must modify class for each new SQL type):** - -```java -public class Sql { - public Sql(String table, Column[] columns) { /* ... */ } - - public String create() { /* ... */ } - public String insert(Object[] fields) { /* ... */ } - public String selectAll() { /* ... */ } - public String findByKey(String key) { /* ... */ } - // Must modify this class to add update, delete, etc. - // Each change risks breaking existing functionality -} -``` - -**Correct (extend without modifying):** - -```java -public abstract class Sql { - protected String table; - protected Column[] columns; - - public Sql(String table, Column[] columns) { - this.table = table; - this.columns = columns; - } - - public abstract String generate(); -} - -public class CreateSql extends Sql { - public CreateSql(String table, Column[] columns) { - super(table, columns); - } - - public String generate() { /* CREATE TABLE ... */ } -} - -public class InsertSql extends Sql { - private Object[] fields; - - public InsertSql(String table, Column[] columns, Object[] fields) { - super(table, columns); - this.fields = fields; - } - - public String generate() { /* INSERT INTO ... */ } -} - -// Adding UpdateSql doesn't require modifying existing classes -public class UpdateSql extends Sql { /* ... */ } -``` - -**Benefits:** -- Adding new SQL types = adding new classes -- Existing classes remain untouched -- Each class does one thing - -Reference: [Clean Code, Chapter 10: Classes](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/class-separate-concerns.md b/builtin-skills/software-engineer/clean-code/references/class-separate-concerns.md deleted file mode 100644 index 14b8d12e..00000000 --- a/builtin-skills/software-engineer/clean-code/references/class-separate-concerns.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Separate Construction from Use -impact: MEDIUM -impactDescription: enables testing and reduces coupling -tags: class, construction, factories, separation ---- - -## Separate Construction from Use - -The startup process of object construction is a separate concern from runtime logic. Applications should separate the main function (which builds objects) from the rest of the system (which uses them). - -**Incorrect (construction mixed with use):** - -```java -public class OrderProcessor { - public void processOrder(Order order) { - // Construction buried in business logic - EmailService emailService = new SmtpEmailService( - "smtp.example.com", 587, "user", "password"); - InventoryService inventory = new InventoryServiceImpl( - new PostgresConnection("localhost", 5432)); - PaymentGateway gateway = new StripeGateway(API_KEY); - - // Business logic - inventory.reserve(order.getItems()); - gateway.charge(order.getPayment()); - emailService.sendConfirmation(order); - } -} -``` - -**Correct (construction separated from use):** - -```java -// Main builds the object graph -public class Application { - public static void main(String[] args) { - EmailService emailService = new SmtpEmailService( - Config.get("smtp.host"), Config.getInt("smtp.port")); - InventoryService inventory = new InventoryServiceImpl( - new PostgresConnection(Config.get("db.url"))); - PaymentGateway gateway = new StripeGateway(Config.get("stripe.key")); - - OrderProcessor processor = new OrderProcessor( - emailService, inventory, gateway); - - processor.start(); - } -} - -// Business class receives dependencies -public class OrderProcessor { - private final EmailService emailService; - private final InventoryService inventory; - private final PaymentGateway gateway; - - public OrderProcessor(EmailService email, InventoryService inv, - PaymentGateway pay) { - this.emailService = email; - this.inventory = inv; - this.gateway = pay; - } - - public void processOrder(Order order) { - inventory.reserve(order.getItems()); - gateway.charge(order.getPayment()); - emailService.sendConfirmation(order); - } -} -``` - -**Alternative:** Use Dependency Injection frameworks (Spring, Guice) to manage construction. - -Reference: [Clean Code, Chapter 11: Systems](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/class-small.md b/builtin-skills/software-engineer/clean-code/references/class-small.md deleted file mode 100644 index e8910e1d..00000000 --- a/builtin-skills/software-engineer/clean-code/references/class-small.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Keep Classes Small -impact: MEDIUM -impactDescription: enables comprehension and focused testing -tags: class, size, srp, cohesion ---- - -## Keep Classes Small - -Classes should be small. With functions, we measure size by counting lines. With classes, we count responsibilities. A class should have only one reason to change. - -**Incorrect (large class with multiple responsibilities):** - -```java -public class SuperDashboard extends JFrame implements MetaDataUser { - public String getCustomizerLanguagePath() { /* ... */ } - public void setSystemConfigPath(String path) { /* ... */ } - public String getSystemConfigDocument() { /* ... */ } - public void setSystemConfigDocument(String doc) { /* ... */ } - public boolean getGuruState() { /* ... */ } - public boolean getNoviceState() { /* ... */ } - public boolean getOpenSourceState() { /* ... */ } - public void showObject(MetaObject object) { /* ... */ } - public void showProgress(String s) { /* ... */ } - public boolean isMetadataDirty() { /* ... */ } - public void setIsMetadataDirty(boolean dirty) { /* ... */ } - public Component getLastFocusedComponent() { /* ... */ } - // 70+ more methods... -} -``` - -**Correct (small focused classes):** - -```java -public class Version { - public int getMajorVersionNumber() { /* ... */ } - public int getMinorVersionNumber() { /* ... */ } - public int getBuildNumber() { /* ... */ } -} - -public class Dashboard extends JFrame { - private final Version version; - private final UserPreferences preferences; - private final ProgressIndicator progress; - - public void show() { /* ... */ } -} - -public class UserPreferences { - public Language getLanguage() { /* ... */ } - public boolean isNovice() { /* ... */ } - public boolean isGuru() { /* ... */ } -} - -public class ProgressIndicator { - public void showProgress(String message) { /* ... */ } - public void hideProgress() { /* ... */ } -} -``` - -**Single Responsibility Principle (SRP):** A class should have one, and only one, reason to change. - -Reference: [Clean Code, Chapter 10: Classes](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/cmt-avoid-commented-out-code.md b/builtin-skills/software-engineer/clean-code/references/cmt-avoid-commented-out-code.md deleted file mode 100644 index c94b23b6..00000000 --- a/builtin-skills/software-engineer/clean-code/references/cmt-avoid-commented-out-code.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Delete Commented-Out Code -impact: HIGH -impactDescription: prevents code archaeology confusion -tags: cmt, dead-code, version-control, clutter ---- - -## Delete Commented-Out Code - -Commented-out code is an abomination. Others who see it will not have the courage to delete it. They think it must be there for a reason. It rots and becomes increasingly irrelevant. - -**Incorrect (commented-out code persisting):** - -```java -public void processOrder(Order order) { - validateOrder(order); - // calculateLegacyDiscount(order); - // if (order.getCustomer().isPremium()) { - // applyPremiumDiscount(order); - // } - calculateDiscount(order); - // sendNotification(order); - // logOrderDetails(order); - saveOrder(order); - notifyWarehouse(order); -} -``` - -**Correct (clean code, trust version control):** - -```java -public void processOrder(Order order) { - validateOrder(order); - calculateDiscount(order); - saveOrder(order); - notifyWarehouse(order); -} -``` - -**Why delete it?** -- Version control remembers everything -- Commented code creates confusion: Is it needed? Why is it there? -- It clutters the file and makes scanning harder -- It becomes stale and misleading over time - -**If you really need it:** Create a git branch, or add a reference comment pointing to the commit where it was removed. - -Reference: [Clean Code, Chapter 4: Comments](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/cmt-avoid-redundant.md b/builtin-skills/software-engineer/clean-code/references/cmt-avoid-redundant.md deleted file mode 100644 index 58aa846a..00000000 --- a/builtin-skills/software-engineer/clean-code/references/cmt-avoid-redundant.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Avoid Redundant Comments -impact: HIGH -impactDescription: eliminates noise that obscures important information -tags: cmt, redundant, noise, clutter ---- - -## Avoid Redundant Comments - -A comment that merely restates what the code does is worse than no comment. It adds clutter, becomes stale, and trains readers to ignore comments entirely. - -**Incorrect (redundant comments):** - -```java -/** - * The name of the customer - */ -private String customerName; - -/** - * Returns the name - * @return the name - */ -public String getName() { - return name; -} - -// Check if the account is closed -if (account.isClosed()) { - // Throw an exception - throw new AccountClosedException(); -} - -/** - * Default constructor - */ -public Account() { -} -``` - -**Correct (comment only when necessary):** - -```java -private String customerName; - -public String getName() { - return name; -} - -if (account.isClosed()) { - throw new AccountClosedException(); -} - -public Account() { -} - -// Comments that add value: - -// RFC 2822 date format required by legacy email parser -private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss Z"; - -// Thread-safe: ConcurrentHashMap handles synchronization -private Map activeSessions = new ConcurrentHashMap<>(); -``` - -**Rule of thumb:** If the comment just repeats the code in English, delete it. - -Reference: [Clean Code, Chapter 4: Comments](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/cmt-explain-intent.md b/builtin-skills/software-engineer/clean-code/references/cmt-explain-intent.md deleted file mode 100644 index 8cfbd224..00000000 --- a/builtin-skills/software-engineer/clean-code/references/cmt-explain-intent.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Use Comments to Explain Intent -impact: HIGH -impactDescription: preserves decision rationale for future readers -tags: cmt, intent, why, rationale ---- - -## Use Comments to Explain Intent - -Good comments explain WHY, not WHAT. The code already tells you what it does. Comments should explain the reasoning behind a decision that cannot be expressed in code. - -**Incorrect (narrating the code):** - -```java -// Increment counter by 1 -counter++; - -// Loop through all employees -for (Employee employee : employees) { - // Check if employee is active - if (employee.isActive()) { - // Add employee to list - activeEmployees.add(employee); - } -} - -// Set the name -this.name = name; -``` - -**Correct (explaining intent):** - -```java -// We use insertion sort here because the list is almost always nearly sorted, -// and insertion sort is O(n) for nearly sorted data vs O(n log n) for quicksort -insertionSort(nearlyOrderedList); - -// Format matches the external API's expected date format (ISO 8601 without timezone) -// See: https://api.vendor.com/docs/date-format -String formattedDate = date.format(DateTimeFormatter.ISO_LOCAL_DATE); - -// Bias toward newer sessions - users expect recent data first -// Business requirement from Product (ticket PROD-1234) -sessions.sort(Comparator.comparing(Session::getCreatedAt).reversed()); -``` - -**Good comment situations:** -- Legal comments (copyright, license) -- Explanation of intent or rationale -- Clarification of obscure API behavior -- Warning of consequences -- TODO comments (temporary) - -Reference: [Clean Code, Chapter 4: Comments](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/cmt-express-in-code.md b/builtin-skills/software-engineer/clean-code/references/cmt-express-in-code.md deleted file mode 100644 index 3fbf16d5..00000000 --- a/builtin-skills/software-engineer/clean-code/references/cmt-express-in-code.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Express Yourself in Code, Not Comments -impact: CRITICAL -impactDescription: eliminates stale comment risk -tags: cmt, self-documenting, refactoring, clarity ---- - -## Express Yourself in Code, Not Comments - -In many cases, creating a function that says the same thing as the comment you wanted to write is better. Code can be refactored to be self-explanatory. - -**Incorrect (comment explains obscure code):** - -```java -// Check to see if the employee is eligible for full benefits -if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) { - // ... -} - -// Add 30 days to the current date -Date newDate = new Date(currentDate.getTime() + (30L * 24 * 60 * 60 * 1000)); - -// Returns true if the string contains only digits -boolean result = str.matches("[0-9]+"); -``` - -**Correct (code expresses intent):** - -```java -if (employee.isEligibleForFullBenefits()) { - // ... -} - -// In Employee class: -public boolean isEligibleForFullBenefits() { - return isHourlyWorker() && age > RETIREMENT_AGE; -} - -Date newDate = currentDate.plusDays(30); - -boolean result = StringUtils.isNumeric(str); -// Or define your own: -boolean result = containsOnlyDigits(str); -``` - -**Benefits:** -- Function names are searchable -- Functions can be tested -- Code documents itself -- No risk of comment becoming stale - -**When comments are still valuable:** -- **Why, not what:** Comments explaining *why* a decision was made (business rules, regulatory requirements, algorithm choices) cannot be replaced by code. -- **Warnings:** Thread-safety, performance implications, or non-obvious side effects deserve explicit comments. -- **Legal/license comments:** Required by policy and cannot be expressed as code. -- **Public API documentation:** Javadoc/docstrings for public APIs are expected and useful. - -Reference: [Clean Code, Chapter 4: Comments](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/cmt-warning-consequences.md b/builtin-skills/software-engineer/clean-code/references/cmt-warning-consequences.md deleted file mode 100644 index 5b302119..00000000 --- a/builtin-skills/software-engineer/clean-code/references/cmt-warning-consequences.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Use Warning Comments for Consequences -impact: MEDIUM -impactDescription: prevents costly mistakes by future maintainers -tags: cmt, warning, consequences, safety ---- - -## Use Warning Comments for Consequences - -Comments that warn other programmers about certain consequences are valuable. They prevent others from making mistakes that have non-obvious impacts. - -**Incorrect (no warning about hidden dangers):** - -```java -public static SimpleDateFormat makeStandardDateFormat() { - return new SimpleDateFormat("yyyy-MM-dd"); -} - -public void runExpensiveOperation() { - // Process all historical data - processAllRecords(); -} - -@Test -public void testWithRealDatabase() { - database.connect(); - // ... -} -``` - -**Correct (warnings prevent mistakes):** - -```java -// WARNING: DateTimeFormatter is thread-safe, but this legacy method returns -// SimpleDateFormat which is NOT thread-safe. Do not cache or share the result. -// Consider migrating callers to use DateTimeFormatter.ISO_LOCAL_DATE directly. -public static SimpleDateFormat makeStandardDateFormat() { - return new SimpleDateFormat("yyyy-MM-dd"); -} - -// Preferred (Java 8+): thread-safe, no warning needed -private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - -// WARNING: This operation takes ~30 minutes on production data -// and consumes significant memory. Run only during maintenance windows. -public void runExpensiveOperation() { - processAllRecords(); -} - -// Don't run this test unless you have several hours to kill. -// Requires real database connection and processes 10M+ records. -@Ignore("Long-running integration test") -@Test -public void testWithRealDatabase() { - database.connect(); - // ... -} -``` - -**Good warnings include:** -- Thread-safety concerns -- Performance implications -- External dependencies or side effects -- Security considerations - -Reference: [Clean Code, Chapter 4: Comments](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/emerge-expressiveness.md b/builtin-skills/software-engineer/clean-code/references/emerge-expressiveness.md deleted file mode 100644 index ef94b015..00000000 --- a/builtin-skills/software-engineer/clean-code/references/emerge-expressiveness.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Maximize Expressiveness -impact: MEDIUM-HIGH -impactDescription: reduces time to understand unfamiliar code by 50%+ -tags: emerge, expressiveness, readability, maintenance ---- - -## Maximize Expressiveness - -The majority of the cost of a software project is in long-term maintenance. Write code for the reader, not the writer. The clearer the author can make the code, the less time others will spend understanding it. - -**Incorrect (clever but opaque):** - -```java -// Bit manipulation for no reason -public boolean isWeekend(int day) { - return ((day & 0x6) == day) && (day > 0); -} - -// Terse variable names in complex logic -public int calc(int[] a, int n) { - int r = 0; - for (int i = 0; i < n; i++) - r = Math.max(r, a[i] - (i > 0 ? a[i-1] : 0)); - return r; -} -``` - -**Correct (clear and expressive):** - -```java -public boolean isWeekend(DayOfWeek day) { - return day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY; -} - -public int findMaxDailyGain(int[] dailyPrices, int numberOfDays) { - int maxGain = 0; - for (int day = 1; day < numberOfDays; day++) { - int dailyChange = dailyPrices[day] - dailyPrices[day - 1]; - maxGain = Math.max(maxGain, dailyChange); - } - return maxGain; -} -``` - -**Techniques for expressiveness:** -- Choose good names (the single most effective technique) -- Keep functions and classes small and focused -- Use standard patterns and nomenclature — when you use the Strategy pattern, name the class with "Strategy" so readers recognize the intent -- Write well-crafted unit tests — tests are documentation by example - -Reference: [Clean Code, Chapter 12: Emergence](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/emerge-simple-design.md b/builtin-skills/software-engineer/clean-code/references/emerge-simple-design.md deleted file mode 100644 index 94376aa8..00000000 --- a/builtin-skills/software-engineer/clean-code/references/emerge-simple-design.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Follow the Four Rules of Simple Design -impact: HIGH -impactDescription: prevents over-engineering while maintaining quality -tags: emerge, simple-design, kent-beck, refactoring ---- - -## Follow the Four Rules of Simple Design - -Kent Beck's four rules of Simple Design, in order of priority: - -1. **Passes all tests** — correctness is non-negotiable -2. **Reveals intent** — code is clear and expressive -3. **No duplication** — every concept has a single representation -4. **Fewest elements** — remove anything that doesn't serve the first three - -**Incorrect (over-engineered for imaginary requirements):** - -```java -// Single implementation with unnecessary abstraction layers -public interface PaymentProcessor {} -public interface PaymentProcessorFactory {} -public abstract class AbstractPaymentProcessor implements PaymentProcessor {} -public class PaymentProcessorFactoryImpl implements PaymentProcessorFactory { - public PaymentProcessor create() { - return new DefaultPaymentProcessor(); - } -} -public class DefaultPaymentProcessor extends AbstractPaymentProcessor { - public void process(Payment payment) { - gateway.charge(payment.getAmount()); - } -} -``` - -**Correct (simplest design that works):** - -```java -public class PaymentProcessor { - private final PaymentGateway gateway; - - public PaymentProcessor(PaymentGateway gateway) { - this.gateway = gateway; - } - - public void process(Payment payment) { - gateway.charge(payment.getAmount()); - } -} -``` - -**Rule 4 is the most overlooked:** After making code correct, expressive, and DRY, actively look for things to remove. Every class, method, and variable should justify its existence. If you have one implementation of an interface, question whether you need the interface. If a design pattern adds indirection without a current concrete benefit, remove it. - -**When more structure is justified:** -- When you have 2+ implementations today (not hypothetically) -- When a framework requires it (e.g., dependency injection interfaces) -- When tests need seams for mocking external dependencies - -Reference: [Clean Code, Chapter 12: Emergence](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/err-avoid-null.md b/builtin-skills/software-engineer/clean-code/references/err-avoid-null.md deleted file mode 100644 index 3890fcfa..00000000 --- a/builtin-skills/software-engineer/clean-code/references/err-avoid-null.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Avoid Returning and Passing Null -impact: HIGH -impactDescription: eliminates NullPointerException risk -tags: err, null, optional, null-object ---- - -## Avoid Returning and Passing Null - -Returning null creates work for callers and invites errors. One missing null check leads to NullPointerException. Throw exceptions, return empty collections, or use the Special Case / Null Object pattern. - -**Incorrect (returning null):** - -```java -public List getEmployees() { - if (thereAreNoEmployees) { - return null; // Caller must check for null - } - return employees; -} - -// Every caller must do this -List employees = getEmployees(); -if (employees != null) { // Easy to forget - for (Employee e : employees) { - pay(e); - } -} - -// Passing null -public double calculatePay(Employee employee, Money bonus) { - // What if bonus is null? -} -calculatePay(employee, null); // What does null mean? -``` - -**Correct (avoid null entirely):** - -```java -// Return empty collection instead of null -public List getEmployees() { - if (thereAreNoEmployees) { - return Collections.emptyList(); - } - return employees; -} - -// Clean caller code -for (Employee e : getEmployees()) { - pay(e); -} - -// Use Optional for truly optional values -public Optional findById(Long id) { - return Optional.ofNullable(employeeMap.get(id)); -} - -// Use Special Case object -public interface BillingPlan { - Money getRate(); -} - -public class NullBillingPlan implements BillingPlan { - public Money getRate() { - return Money.ZERO; - } -} - -// Explicit parameters instead of null -public double calculatePay(Employee employee, Money bonus) { /* ... */ } -public double calculatePayWithoutBonus(Employee employee) { /* ... */ } -``` - -**When null/nullable is acceptable:** -- Language-level nullable types with compiler enforcement (Kotlin `?`, TypeScript `strictNullChecks`, Rust `Option`) make null safe because the compiler forces handling. The problem is untracked nullability, not the concept itself. -- Interop with APIs or frameworks that require null (e.g., JDBC, some serialization libraries). - -Reference: [Clean Code, Chapter 7: Error Handling](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/err-define-by-caller-needs.md b/builtin-skills/software-engineer/clean-code/references/err-define-by-caller-needs.md deleted file mode 100644 index 421155e9..00000000 --- a/builtin-skills/software-engineer/clean-code/references/err-define-by-caller-needs.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Define Exceptions by Caller Needs -impact: HIGH -impactDescription: reduces catch blocks by 3-5× per call site -tags: err, wrapper, classification, design ---- - -## Define Exceptions by Caller Needs - -Define exception classes based on how they are caught, not on their source or type. Often a single exception class is sufficient for a particular area of code. Wrap third-party API exceptions. - -**Incorrect (catching many exception types):** - -```java -// Caller must handle many different exceptions -try { - port.open(); -} catch (DeviceResponseException e) { - reportPortError(e); - logger.log("Device response problem", e); -} catch (ATM1212UnlockedException e) { - reportPortError(e); - logger.log("Unlock exception", e); -} catch (GMXError e) { - reportPortError(e); - logger.log("Device response exception", e); -} finally { - // ... -} -``` - -**Correct (unified exception handling):** - -```java -// Wrapper class translates exceptions -public class LocalPort { - private ACMEPort innerPort; - - public void open() throws PortDeviceFailure { - try { - innerPort.open(); - } catch (DeviceResponseException e) { - throw new PortDeviceFailure(e); - } catch (ATM1212UnlockedException e) { - throw new PortDeviceFailure(e); - } catch (GMXError e) { - throw new PortDeviceFailure(e); - } - } -} - -// Clean caller code -try { - port.open(); -} catch (PortDeviceFailure e) { - reportPortError(e); - logger.log(e.getMessage(), e); -} -``` - -**Benefits of wrapping:** -- Minimizes dependencies on third-party APIs -- Easier to mock for testing -- Easier to switch implementations later -- Single exception type per area simplifies catching - -Reference: [Clean Code, Chapter 7: Error Handling](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/err-provide-context.md b/builtin-skills/software-engineer/clean-code/references/err-provide-context.md deleted file mode 100644 index 951ae967..00000000 --- a/builtin-skills/software-engineer/clean-code/references/err-provide-context.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Provide Context with Exceptions -impact: HIGH -impactDescription: enables rapid root cause identification -tags: err, context, messages, debugging ---- - -## Provide Context with Exceptions - -Each exception should provide enough context to determine the source and location of an error. Create informative error messages that describe the operation that failed and the type of failure. - -**Incorrect (no context):** - -```java -throw new Exception("Error occurred"); - -throw new RuntimeException("Failed"); - -throw new DataAccessException("Query failed"); - -// Stack trace alone doesn't tell you which order, which customer -catch (SQLException e) { - throw new RuntimeException(e); -} -``` - -**Correct (rich context):** - -```java -throw new OrderProcessingException( - String.format("Failed to process order %s for customer %s: %s", - orderId, customerId, "Insufficient inventory for item SKU-12345")); - -throw new ConfigurationException( - "Cannot load configuration from " + configPath + - ". Expected format: YAML. Check file permissions and syntax."); - -catch (SQLException e) { - throw new DataAccessException( - String.format("Failed to insert order %s into table %s. " + - "Constraint violated: %s", - order.getId(), "orders", e.getMessage()), - e); // Preserve original exception -} -``` - -**Include in exception messages:** -- What operation was being attempted -- What data was involved (IDs, names, quantities) -- Why it failed (the specific error condition) -- Preserve the original exception when wrapping - -Reference: [Clean Code, Chapter 7: Error Handling](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/err-use-exceptions.md b/builtin-skills/software-engineer/clean-code/references/err-use-exceptions.md deleted file mode 100644 index a38656cf..00000000 --- a/builtin-skills/software-engineer/clean-code/references/err-use-exceptions.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Separate Error Handling from Happy Path -impact: HIGH -impactDescription: reduces nested conditionals by 50-80% in exception-based languages -tags: err, exceptions, error-handling, separation, result-types ---- - -## Separate Error Handling from Happy Path - -Error handling is important, but when it obscures logic, it's wrong. The core insight is separation: keep the happy path visible and error handling consolidated, regardless of which mechanism your language uses. - -**Incorrect (error handling obscures business logic):** - -```java -if (deletePage(page) == E_OK) { - if (registry.deleteReference(page.name) == E_OK) { - if (configKeys.deleteKey(page.name.makeKey()) == E_OK) { - logger.log("page deleted"); - } else { - logger.log("configKey not deleted"); - } - } else { - logger.log("deleteReference from registry failed"); - } -} else { - logger.log("delete failed"); - return E_ERROR; -} -``` - -**Correct (Java/C#/Python — exceptions separate concerns):** - -```java -public void delete(Page page) { - try { - deletePageAndAllReferences(page); - } catch (PageDeletionException e) { - logger.log(e.getMessage()); - } -} - -private void deletePageAndAllReferences(Page page) throws PageDeletionException { - deletePage(page); - registry.deleteReference(page.name); - configKeys.deleteKey(page.name.makeKey()); -} -``` - -**Correct (Go — explicit error returns with early return):** - -```go -func (s *Service) Delete(page Page) error { - if err := s.deletePage(page); err != nil { - return fmt.Errorf("deleting page: %w", err) - } - if err := s.registry.DeleteReference(page.Name); err != nil { - return fmt.Errorf("deleting reference: %w", err) - } - if err := s.configKeys.DeleteKey(page.Name); err != nil { - return fmt.Errorf("deleting config key: %w", err) - } - return nil -} -``` - -**Correct (Rust — Result type with ? operator):** - -```rust -fn delete(&self, page: &Page) -> Result<(), DeletionError> { - self.delete_page(page)?; - self.registry.delete_reference(&page.name)?; - self.config_keys.delete_key(&page.name)?; - Ok(()) -} -``` - -**The principle is language-agnostic:** separate error-handling logic from business logic. The mechanism differs: -- **Java/C#/Python:** try-catch with specific exception types -- **Go:** explicit error returns with early return pattern -- **Rust:** `Result` with `?` operator -- **TypeScript/Kotlin:** `Result` types or exceptions depending on the domain - -**When NOT to use exceptions:** -- In Go, Rust, or other languages designed around explicit error values — use their idiomatic patterns instead -- For expected business outcomes (e.g., "user not found") — consider returning `Optional` or a domain-specific result type rather than throwing -- In performance-critical hot paths where exception overhead matters - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) and [Chapter 7: Error Handling](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/err-write-try-catch-first.md b/builtin-skills/software-engineer/clean-code/references/err-write-try-catch-first.md deleted file mode 100644 index b7243bfd..00000000 --- a/builtin-skills/software-engineer/clean-code/references/err-write-try-catch-first.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Write Try-Catch-Finally First -impact: HIGH -impactDescription: prevents missing error handling cases -tags: err, try-catch, tdd, boundaries ---- - -## Write Try-Catch-Finally First - -When writing code that could throw exceptions, start with the try-catch-finally statement. This helps define what the user of the code should expect, regardless of what goes wrong in the try block. - -**Incorrect (error handling added as afterthought):** - -```java -// Written without considering error cases -public List retrieveSection(String sectionName) { - FileInputStream stream = new FileInputStream(sectionName); - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - String line; - List grips = new ArrayList<>(); - while ((line = reader.readLine()) != null) { - grips.add(parseGrip(line)); - } - return grips; - // What if file doesn't exist? What if parsing fails? -} -``` - -**Correct (start with try-catch structure):** - -```java -// TDD approach: start with test for exception case -@Test(expected = StorageException.class) -public void retrieveSectionShouldThrowOnInvalidFileName() { - sectionStore.retrieveSection("invalid-file"); -} - -// Then write code starting with try-catch -public List retrieveSection(String sectionName) throws StorageException { - try (var stream = new FileInputStream(sectionName)) { - return readGrips(stream); - } catch (IOException e) { - throw new StorageException("Error reading section: " + sectionName, e); - } -} -``` - -**Benefits:** -- Forces you to consider error cases first -- Establishes clear transaction boundaries -- The finally block ensures cleanup happens - -Reference: [Clean Code, Chapter 7: Error Handling](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/fmt-horizontal-alignment.md b/builtin-skills/software-engineer/clean-code/references/fmt-horizontal-alignment.md deleted file mode 100644 index cafeb4c5..00000000 --- a/builtin-skills/software-engineer/clean-code/references/fmt-horizontal-alignment.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Avoid Horizontal Alignment -impact: MEDIUM -impactDescription: prevents alignment maintenance burden -tags: fmt, horizontal, alignment, whitespace ---- - -## Avoid Horizontal Alignment - -Horizontal alignment of variable declarations or assignments looks nice but creates maintenance problems. When one line changes length, all aligned lines need reformatting. - -**Incorrect (horizontal alignment):** - -```java -private Socket socket; -private InputStream input; -private OutputStream output; -private Request request; -private Response response; -private FitNesseContext context; -private long requestParsingTimeLimit; -private long requestProgress; - -public void setResponse(Response response) { this.response = response; } -public void setSocket(Socket socket) { this.socket = socket; } -public void setContext(FitNesseContext context) { this.context = context; } -``` - -**Correct (natural formatting):** - -```java -private Socket socket; -private InputStream input; -private OutputStream output; -private Request request; -private Response response; -private FitNesseContext context; -private long requestParsingTimeLimit; -private long requestProgress; - -public void setResponse(Response response) { - this.response = response; -} - -public void setSocket(Socket socket) { - this.socket = socket; -} - -public void setContext(FitNesseContext context) { - this.context = context; -} -``` - -**Why avoid alignment?** -- Adding a longer variable name requires reformatting all lines -- Eyes are drawn to the wrong thing (the alignment, not the names) -- Most formatters don't preserve it anyway - -Reference: [Clean Code, Chapter 5: Formatting](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/fmt-indentation.md b/builtin-skills/software-engineer/clean-code/references/fmt-indentation.md deleted file mode 100644 index 361e354a..00000000 --- a/builtin-skills/software-engineer/clean-code/references/fmt-indentation.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Respect Indentation Rules -impact: MEDIUM -impactDescription: preserves visual hierarchy for quick scanning -tags: fmt, indentation, hierarchy, structure ---- - -## Respect Indentation Rules - -Indentation makes the scope hierarchy visible. Each level of indentation represents a nested scope. Never collapse short statements onto one line to save space. - -**Incorrect (collapsed structure):** - -```java -public class CommentWidget extends TextWidget { -public CommentWidget(ParentWidget parent, String text) { super(parent, text); } -public String render() throws Exception { return ""; } -} - -public void process() { for (int i = 0; i < 10; i++) { if (valid(i)) { execute(i); } } } - -if (condition) return false; else return true; -``` - -**Correct (proper indentation):** - -```java -public class CommentWidget extends TextWidget { - - public CommentWidget(ParentWidget parent, String text) { - super(parent, text); - } - - public String render() throws Exception { - return ""; - } -} - -public void process() { - for (int i = 0; i < 10; i++) { - if (valid(i)) { - execute(i); - } - } -} - -if (condition) { - return false; -} else { - return true; -} -``` - -**Why maintain indentation?** -- Visual scanning relies on indentation -- Structure is immediately apparent -- Debugging is easier when scope is visible -- Merges are cleaner with consistent formatting - -Reference: [Clean Code, Chapter 5: Formatting](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/fmt-team-rules.md b/builtin-skills/software-engineer/clean-code/references/fmt-team-rules.md deleted file mode 100644 index 45a05ded..00000000 --- a/builtin-skills/software-engineer/clean-code/references/fmt-team-rules.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Follow Team Formatting Rules -impact: HIGH -impactDescription: eliminates style-related code review friction -tags: fmt, team, consistency, standards ---- - -## Follow Team Formatting Rules - -A team of developers should agree upon a single formatting style. Every member should use that style. The goal is to make the software have a consistent style, as if written by one person. - -**Incorrect (inconsistent styles mixed):** - -```java -// Developer A's style -public void processOrder(Order order){ - if(order.isValid()){ - order.process(); - } -} - -// Developer B's style -public void processPayment( Payment payment ) -{ - if ( payment.isValid() ) - { - payment.process(); - } -} - -// Developer C's style -public void processShipment(Shipment shipment) { - if (shipment.isValid()) { - shipment.process(); }} -``` - -**Correct (consistent team style):** - -```java -public void processOrder(Order order) { - if (order.isValid()) { - order.process(); - } -} - -public void processPayment(Payment payment) { - if (payment.isValid()) { - payment.process(); - } -} - -public void processShipment(Shipment shipment) { - if (shipment.isValid()) { - shipment.process(); - } -} -``` - -**Implementation:** -- Document the team's coding standards -- Use automated formatters (Prettier, Black, google-java-format) -- Enforce in CI/CD pipelines -- Configure IDE to format on save - -Your personal style preferences are less important than team consistency. - -Reference: [Clean Code, Chapter 5: Formatting](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/fmt-vertical-formatting.md b/builtin-skills/software-engineer/clean-code/references/fmt-vertical-formatting.md deleted file mode 100644 index 43e3b2e5..00000000 --- a/builtin-skills/software-engineer/clean-code/references/fmt-vertical-formatting.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Use Vertical Formatting for Readability -impact: HIGH -impactDescription: enables scanning code like a newspaper -tags: fmt, vertical, whitespace, organization ---- - -## Use Vertical Formatting for Readability - -Code should read like a newspaper article: headline at the top, details as you go down. Use vertical whitespace to separate concepts. Keep related code close together. - -**Incorrect (no vertical organization):** - -```java -public class WikiPageResponder implements SecureResponder { -private static final String CONTENT_TYPE = "text/html"; -private WikiPage page; -private PageData pageData; -private String pageTitle; -private Request request; -private PageCrawler crawler; -public Response makeResponse(FitNesseContext context, Request request) { -this.request = request; -this.page = loadPage(); -if (page == null) -return notFoundResponse(context, request); -return makePageResponse(context); -} -private WikiPage loadPage() { -String resource = request.getResource(); -return PageCrawlerImpl.getPageCrawler(context.root).getPage(resource); -} -} -``` - -**Correct (vertical formatting applied):** - -```java -public class WikiPageResponder implements SecureResponder { - - private static final String CONTENT_TYPE = "text/html"; - - private WikiPage page; - private PageData pageData; - private String pageTitle; - private Request request; - private PageCrawler crawler; - - public Response makeResponse(FitNesseContext context, Request request) { - this.request = request; - this.page = loadPage(); - - if (page == null) - return notFoundResponse(context, request); - - return makePageResponse(context); - } - - private WikiPage loadPage() { - String resource = request.getResource(); - return PageCrawlerImpl.getPageCrawler(context.root).getPage(resource); - } -} -``` - -**Guidelines:** -- Blank lines between concepts (methods, logical sections) -- Related code grouped together -- Caller above callee (top-down reading) -- Variable declarations close to their usage - -Reference: [Clean Code, Chapter 5: Formatting](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-abstraction-level.md b/builtin-skills/software-engineer/clean-code/references/func-abstraction-level.md deleted file mode 100644 index 624327e1..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-abstraction-level.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Maintain One Level of Abstraction -impact: CRITICAL -impactDescription: prevents jarring context switches -tags: func, abstraction, stepdown, readability ---- - -## Maintain One Level of Abstraction - -Statements within a function should all be at the same level of abstraction. Mixing high-level concepts with low-level details is confusing. Code should read like a top-down narrative. - -**Incorrect (mixed abstraction levels):** - -```java -public void analyzeDocument(String documentPath) { - // High level - Document document = loadDocument(documentPath); - - // Low level - string manipulation details - String text = document.getText(); - text = text.replaceAll("\\s+", " "); - text = text.toLowerCase(); - String[] words = text.split(" "); - - // High level again - WordFrequency frequency = analyzeFrequency(words); - - // Low level - file I/O details - FileOutputStream fos = new FileOutputStream("output.txt"); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos)); - for (Map.Entry entry : frequency.getEntries()) { - writer.write(entry.getKey() + ": " + entry.getValue()); - writer.newLine(); - } - writer.close(); -} -``` - -**Correct (consistent abstraction level):** - -```java -public void analyzeDocument(String documentPath) { - Document document = loadDocument(documentPath); - String normalizedText = normalizeText(document); - WordFrequency frequency = analyzeFrequency(normalizedText); - saveResults(frequency); -} - -private String normalizeText(Document document) { - String text = document.getText(); - text = collapseWhitespace(text); - text = toLowerCase(text); - return text; -} - -private void saveResults(WordFrequency frequency) { - ResultWriter writer = new ResultWriter("output.txt"); - writer.write(frequency); -} -``` - -Read the code from top to bottom. Each function introduces the next level of abstraction. - -**When mixing levels is acceptable:** -- Short utility functions (under 10 lines) that perform one task can mix levels without confusion. The overhead of extracting one-line helpers often exceeds the readability benefit. -- Test code frequently mixes setup (low-level) with assertions (high-level) — this is expected and follows the Arrange-Act-Assert pattern. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-command-query-separation.md b/builtin-skills/software-engineer/clean-code/references/func-command-query-separation.md deleted file mode 100644 index 06355e99..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-command-query-separation.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Separate Commands from Queries -impact: MEDIUM -impactDescription: eliminates ambiguous function behavior -tags: func, cqs, command, query, separation ---- - -## Separate Commands from Queries - -Functions should either do something or answer something, but not both. Either your function changes the state of an object, or it returns information about that object. - -**Incorrect (command and query mixed):** - -```java -// Does this set the attribute and return success? -// Or check if attribute exists? -public boolean set(String attribute, String value) { - // ... sets attribute and returns true if it was set -} - -// Confusing usage -if (set("username", "bob")) { - // Was username set, or did it already exist? -} -``` - -**Correct (separated command and query):** - -```java -// Query - returns information -public boolean attributeExists(String attribute) { - return attributes.containsKey(attribute); -} - -// Command - changes state -public void setAttribute(String attribute, String value) { - attributes.put(attribute, value); -} - -// Clear usage -if (!attributeExists("username")) { - setAttribute("username", "bob"); -} -``` - -**Alternative (return new state for immutable design):** - -```java -// For immutable patterns, returning new state is acceptable -public Settings withAttribute(String attribute, String value) { - return new Settings(this.attributes.plus(attribute, value)); -} -``` - -The separation makes code easier to read and reason about. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-dry.md b/builtin-skills/software-engineer/clean-code/references/func-dry.md deleted file mode 100644 index b4b699da..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-dry.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Do Not Repeat Yourself -impact: CRITICAL -impactDescription: prevents N× maintenance burden -tags: func, dry, duplication, abstraction ---- - -## Do Not Repeat Yourself - -Duplication is the root of all evil in software. When an algorithm changes, you must change it in multiple places. When you fix a bug, you must remember to fix it everywhere. - -**Incorrect (duplicated logic):** - -```java -public void processNewEmployee(Employee employee) { - if (employee.getName() == null || employee.getName().trim().isEmpty()) { - throw new ValidationException("Name is required"); - } - if (employee.getEmail() == null || !employee.getEmail().contains("@")) { - throw new ValidationException("Valid email is required"); - } - employeeRepository.save(employee); - emailService.sendWelcome(employee.getEmail()); -} - -public void updateEmployee(Employee employee) { - if (employee.getName() == null || employee.getName().trim().isEmpty()) { - throw new ValidationException("Name is required"); // Duplicated - } - if (employee.getEmail() == null || !employee.getEmail().contains("@")) { - throw new ValidationException("Valid email is required"); // Duplicated - } - employeeRepository.update(employee); -} -``` - -**Correct (extracted common logic):** - -```java -public void processNewEmployee(Employee employee) { - validateEmployee(employee); - employeeRepository.save(employee); - emailService.sendWelcome(employee.getEmail()); -} - -public void updateEmployee(Employee employee) { - validateEmployee(employee); - employeeRepository.update(employee); -} - -private void validateEmployee(Employee employee) { - requireNonEmpty(employee.getName(), "Name is required"); - requireValidEmail(employee.getEmail()); -} - -private void requireNonEmpty(String value, String message) { - if (value == null || value.trim().isEmpty()) { - throw new ValidationException(message); - } -} -``` - -Every piece of knowledge must have a single, unambiguous, authoritative representation within a system. - -**When NOT to apply DRY:** -- **Coincidental duplication:** Two code blocks look similar but serve different purposes and will evolve independently. Extracting a shared function creates a false coupling that makes both harder to change later. -- **Premature abstraction:** If the code has only been duplicated once, wait. The third occurrence reveals the true abstraction. Premature extraction often produces awkward, over-parameterized helpers. -- **Cross-boundary duplication:** Sometimes duplication across microservices or bounded contexts is preferable to introducing a shared library that couples the services. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-minimize-arguments.md b/builtin-skills/software-engineer/clean-code/references/func-minimize-arguments.md deleted file mode 100644 index 03e44422..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-minimize-arguments.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Minimize Function Arguments -impact: HIGH -impactDescription: reduces cognitive load and testing complexity -tags: func, arguments, parameters, simplicity ---- - -## Minimize Function Arguments - -The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. - -**Incorrect (too many arguments):** - -```java -// Flag arguments are bad - function does different things -public void render(boolean isSuite) {} - -// Four arguments - hard to remember order -public Circle makeCircle(double x, double y, double radius, String color) {} - -// Order matters and is easy to confuse -public void assertExpectedEqualsActual(String expected, String actual) {} -``` - -**Correct (minimized arguments):** - -```java -// Separate functions instead of flag -public void renderForSingleTest() {} -public void renderForSuite() {} - -// Encapsulate related arguments in objects -public Circle makeCircle(Point center, double radius, Color color) {} - -// Even better - use a builder for many optional params -Circle circle = Circle.builder() - .center(new Point(0, 0)) - .radius(5.0) - .color(Color.RED) - .build(); - -// Self-documenting method name -assertThat(actual).isEqualTo(expected); -``` - -**Why fewer arguments?** -- Easier to understand -- Easier to test (fewer combinations) -- Less chance of argument order errors - -**Acceptable monadic forms:** -- Asking a question: `boolean fileExists(String path)` -- Transforming input: `InputStream openFile(String path)` -- Events: `void passwordAttemptFailed(int attempts)` - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-no-side-effects.md b/builtin-skills/software-engineer/clean-code/references/func-no-side-effects.md deleted file mode 100644 index 39d4a76c..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-no-side-effects.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Avoid Side Effects -impact: HIGH -impactDescription: prevents hidden temporal couplings -tags: func, side-effects, purity, predictability ---- - -## Avoid Side Effects - -Side effects are lies. Your function promises to do one thing, but it also does other hidden things. Avoid unexpected changes to class variables, globals, or passed arguments. - -**Incorrect (hidden side effect):** - -```java -public class UserValidator { - private Cryptographer cryptographer; - private Session session; - - public boolean checkPassword(String userName, String password) { - User user = UserGateway.findByName(userName); - if (user != null) { - String codedPhrase = user.getPhraseEncodedByPassword(); - String phrase = cryptographer.decrypt(codedPhrase, password); - if ("Valid Password".equals(phrase)) { - session.initialize(); // Hidden side effect! - return true; - } - } - return false; - } -} -// Calling checkPassword twice destroys the session unexpectedly -``` - -**Correct (explicit behavior):** - -```java -public class UserValidator { - private Cryptographer cryptographer; - - public boolean checkPassword(String userName, String password) { - User user = UserGateway.findByName(userName); - if (user == null) return false; - - String codedPhrase = user.getPhraseEncodedByPassword(); - String phrase = cryptographer.decrypt(codedPhrase, password); - return "Valid Password".equals(phrase); - } -} - -// Separate function with clear name -public class SessionManager { - public void initializeSessionForUser(String userName, String password) { - if (userValidator.checkPassword(userName, password)) { - session.initialize(); - } - } -} -``` - -If you must have a temporal coupling, make it explicit in the function name: `checkPasswordAndInitializeSession`. - -**When side effects are expected:** -- I/O operations (file writes, network calls, database mutations) inherently have side effects — the principle here is about *hidden* side effects, not avoiding all mutation. A function named `saveUser()` clearly signals side effects. -- Event handlers, middleware, and lifecycle hooks are designed to produce side effects. Name them to make the effect obvious. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-one-thing.md b/builtin-skills/software-engineer/clean-code/references/func-one-thing.md deleted file mode 100644 index b25622ad..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-one-thing.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Functions Should Do One Thing -impact: CRITICAL -impactDescription: enables understanding functions at a glance -tags: func, single-responsibility, cohesion, focus ---- - -## Functions Should Do One Thing - -Functions should do one thing. They should do it well. They should do it only. If a function does multiple things, extract those things into separate functions. - -**Incorrect (function does multiple things):** - -```java -public void processEmployee(Employee employee) { - // Validate employee - if (employee.getName() == null || employee.getName().isEmpty()) { - throw new IllegalArgumentException("Name required"); - } - if (employee.getSalary() < 0) { - throw new IllegalArgumentException("Salary cannot be negative"); - } - - // Calculate tax - double tax = employee.getSalary() * 0.3; - employee.setTax(tax); - - // Save to database - Connection conn = getConnection(); - PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO employees VALUES (?, ?, ?)"); - stmt.setString(1, employee.getName()); - stmt.setDouble(2, employee.getSalary()); - stmt.setDouble(3, tax); - stmt.execute(); - - // Send email notification - EmailService.send(employee.getEmail(), "Welcome!"); -} -``` - -**Correct (each function does one thing):** - -```java -public void processEmployee(Employee employee) { - validateEmployee(employee); - calculateTax(employee); - saveEmployee(employee); - sendWelcomeEmail(employee); -} - -private void validateEmployee(Employee employee) { - validateName(employee); - validateSalary(employee); -} - -private void calculateTax(Employee employee) { - double tax = employee.getSalary() * TAX_RATE; - employee.setTax(tax); -} - -private void saveEmployee(Employee employee) { - employeeRepository.save(employee); -} - -private void sendWelcomeEmail(Employee employee) { - emailService.sendWelcome(employee.getEmail()); -} -``` - -**Test:** If you can extract another function from it with a name that is not merely a restatement of its implementation, the function is doing more than one thing. - -**When NOT to split:** -- If the extracted function's name would just restate its body (e.g., `calculateTax` containing only `salary * TAX_RATE`), the extraction adds indirection without clarity. -- Orchestration functions that call a sequence of steps at the same abstraction level (like `processEmployee` above) are doing "one thing" — orchestrating. Don't try to extract the orchestration further. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/func-small.md b/builtin-skills/software-engineer/clean-code/references/func-small.md deleted file mode 100644 index 3f21c3e1..00000000 --- a/builtin-skills/software-engineer/clean-code/references/func-small.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Keep Functions Small -impact: CRITICAL -impactDescription: enables comprehension at a glance -tags: func, size, readability, comprehension ---- - -## Keep Functions Small - -Functions should be small. They should be smaller than that. Functions should hardly ever be 20 lines long. Each function should do one thing, do it well, and do it only. - -**Incorrect (large function doing multiple things):** - -```java -public void renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) { - if (isTestPage(pageData)) { - WikiPage testPage = pageData.getWikiPage(); - StringBuffer newPageContent = new StringBuffer(); - includeSetupPages(testPage, newPageContent, isSuite); - newPageContent.append(pageData.getContent()); - includeTeardownPages(testPage, newPageContent, isSuite); - pageData.setContent(newPageContent.toString()); - } -} - -private void includeSetupPages(WikiPage testPage, StringBuffer buffer, boolean isSuite) { - if (isSuite) { - WikiPage suitePage = PageCrawlerImpl.getInheritedPage( - SuiteResponder.SUITE_SETUP_NAME, testPage); - if (suitePage != null) { - WikiPagePath pagePath = testPage.getPageCrawler() - .getFullPath(suitePage); - String pagePathName = PathParser.render(pagePath); - buffer.append("!include -setup .") - .append(pagePathName) - .append("\n"); - } - } - // ... 20 more lines -} -``` - -**Correct (small, focused functions):** - -```java -public void renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) { - if (isTestPage(pageData)) - includeSetupsAndTeardowns(pageData, isSuite); -} - -private void includeSetupsAndTeardowns(PageData pageData, boolean isSuite) { - WikiPage testPage = pageData.getWikiPage(); - String content = buildPageContent(testPage, isSuite); - pageData.setContent(content); -} - -private String buildPageContent(WikiPage testPage, boolean isSuite) { - return getSetups(testPage, isSuite) + - testPage.getContent() + - getTeardowns(testPage, isSuite); -} -``` - -Each function is 3-5 lines. Each does exactly one thing. Each is at one level of abstraction. - -**When NOT to apply this pattern:** -- If a 15-20 line function does one thing at one level of abstraction, it does not need further decomposition. The goal is comprehensibility, not minimizing line count. -- Do not extract functions that are only called from one place and whose names merely restate their implementation — this adds indirection without clarity. -- Ousterhout's "deep modules" critique: extremely small functions can create "shallow modules" that spread logic across many files, forcing readers to jump between functions to understand a single behavior. Balance depth (functionality per interface) against size. - -Reference: [Clean Code, Chapter 3: Functions](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-avoid-disinformation.md b/builtin-skills/software-engineer/clean-code/references/name-avoid-disinformation.md deleted file mode 100644 index 671dd2cc..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-avoid-disinformation.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Avoid Disinformation in Names -impact: CRITICAL -impactDescription: prevents incorrect mental models -tags: name, disinformation, misleading, types ---- - -## Avoid Disinformation in Names - -Avoid names that encode false information. Do not refer to a grouping as a "List" unless it is actually a List. Avoid names that vary in small ways that are hard to distinguish. - -**Incorrect (misleading type information):** - -```java -// Not actually a List, it's a Map -private Map accountList; - -// These look almost identical - easy to confuse -private String XYZControllerForEfficientHandlingOfStrings; -private String XYZControllerForEfficientStorageOfStrings; - -// Lowercase L looks like 1, uppercase O looks like 0 -int a = l; -if (O == l) - a = O1; -``` - -**Correct (accurate and distinguishable):** - -```java -// Accurately describes the data structure -private Map accountsByName; - -// Clearly distinguishable names -private String stringProcessingController; -private String stringStorageController; - -// Clear variable names -int result = leftValue; -if (originalValue == leftValue) - result = outputValue; -``` - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-avoid-encodings.md b/builtin-skills/software-engineer/clean-code/references/name-avoid-encodings.md deleted file mode 100644 index c57651b2..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-avoid-encodings.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Avoid Encodings in Names -impact: HIGH -impactDescription: reduces mental translation burden -tags: name, encoding, hungarian, prefixes ---- - -## Avoid Encodings in Names - -Encoding type or scope information into names adds an extra burden of deciphering. Modern IDEs make Hungarian Notation and member prefixes unnecessary. - -**Incorrect (encoded type and scope):** - -```java -// Hungarian Notation - type encoded in name -String strName; -int iAge; -boolean bIsActive; -PhoneNumber phoneString; // Type changed but name wasn't updated! - -// Member prefixes -public class Part { - private String m_dsc; // Member description - - void setDescription(String dsc) { - m_dsc = dsc; - } -} - -// Interface prefix -public interface IShapeFactory {} -``` - -**Correct (no encodings):** - -```java -// Let the type system handle types -String name; -int age; -boolean isActive; -PhoneNumber phone; - -// No member prefixes - IDE highlights members -public class Part { - private String description; - - void setDescription(String description) { - this.description = description; - } -} - -// Drop the interface prefix — callers use ShapeFactory, not IShapeFactory -public interface ShapeFactory {} - -// Name implementations by what distinguishes them -public class JsonShapeFactory implements ShapeFactory {} -public class SvgShapeFactory implements ShapeFactory {} - -// If only one implementation exists, consider whether you need the interface at all -``` - -Readers learn to ignore prefixes. You end up seeing only the meaningful part of the name. - -**Note:** `ShapeFactoryImpl` is a lesser evil than `IShapeFactory`, but `Impl` is still an encoding. When possible, name implementations by their distinguishing characteristic (protocol, storage mechanism, algorithm). - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-class-noun.md b/builtin-skills/software-engineer/clean-code/references/name-class-noun.md deleted file mode 100644 index 4b9ac99d..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-class-noun.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Use Noun Phrases for Class Names -impact: MEDIUM-HIGH -impactDescription: eliminates 80%+ of "what does this class do" questions -tags: name, class, noun, identity ---- - -## Use Noun Phrases for Class Names - -Class names should be nouns or noun phrases. A class represents a thing or concept. Avoid verbs, manager-style names, and vague words. - -**Incorrect (verbs, vague, or manager-style):** - -```java -// Verb as class name -class ProcessPayment {} - -// Vague manager names -class Manager {} -class Processor {} -class Data {} -class Info {} - -// Unnecessary suffixes -class CustomerManager {} -class AccountProcessor {} -class PaymentHandler {} -``` - -**Correct (specific noun phrases):** - -```java -// Clear nouns representing entities -class Payment {} -class PaymentGateway {} - -// Specific, descriptive nouns -class Customer {} -class WikiPage {} -class Account {} -class AddressParser {} - -// Role-specific names when needed -class PaymentValidator {} // Validates payments -class AccountRepository {} // Stores accounts -``` - -**When NOT to use this pattern:** - -Manager-style names are acceptable when the class genuinely manages a resource lifecycle: -- `ConnectionPool` - manages connection lifecycle -- `ThreadPoolExecutor` - manages thread lifecycle - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-intention-revealing.md b/builtin-skills/software-engineer/clean-code/references/name-intention-revealing.md deleted file mode 100644 index 487bac15..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-intention-revealing.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Use Intention-Revealing Names -impact: CRITICAL -impactDescription: eliminates mental mapping overhead -tags: name, intention, readability, clarity ---- - -## Use Intention-Revealing Names - -Names should reveal intent. A name should tell you why something exists, what it does, and how it is used. If a name requires a comment, it does not reveal its intent. - -**Incorrect (requires mental decoding):** - -```java -int d; // elapsed time in days - -public List getThem() { - List list1 = new ArrayList<>(); - for (int[] x : theList) - if (x[0] == 4) // What is 4? What is x[0]? - list1.add(x); - return list1; -} -``` - -**Correct (self-documenting):** - -```java -int elapsedTimeInDays; - -public List getFlaggedCells() { - List flaggedCells = new ArrayList<>(); - for (Cell cell : gameBoard) - if (cell.isFlagged()) - flaggedCells.add(cell); - return flaggedCells; -} -``` - -The code now explicitly communicates its purpose: finding flagged cells in a minesweeper game. No comment needed. - -**When short names are acceptable:** -- Loop counters (`i`, `j`, `k`) in small, tightly-scoped loops where the index has no domain meaning. -- Mathematical algorithms where `x`, `y`, `dx`, `dt` are conventional and understood by the target audience. -- Lambda parameters in trivial callbacks: `items.filter(x -> x > 0)` is clearer than `items.filter(numberThatMustBePositive -> numberThatMustBePositive > 0)`. - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-meaningful-distinctions.md b/builtin-skills/software-engineer/clean-code/references/name-meaningful-distinctions.md deleted file mode 100644 index 204fbd84..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-meaningful-distinctions.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Make Meaningful Distinctions -impact: CRITICAL -impactDescription: eliminates ambiguity between similar concepts -tags: name, distinction, noise-words, clarity ---- - -## Make Meaningful Distinctions - -If names must be different, then they should also mean something different. Avoid number-series naming and noise words that add no information. - -**Incorrect (indistinguishable names):** - -```java -// Number series - meaningless distinction -public static void copyChars(char[] a1, char[] a2) { - for (int i = 0; i < a1.length; i++) { - a2[i] = a1[i]; - } -} - -// Noise words - what's the difference? -class Product {} -class ProductInfo {} -class ProductData {} - -// Redundant prefixes -String nameString; -Customer customerObject; -``` - -**Correct (meaningful distinctions):** - -```java -// Descriptive parameter names -public static void copyChars(char[] source, char[] destination) { - for (int i = 0; i < source.length; i++) { - destination[i] = source[i]; - } -} - -// If distinctions exist, name them -class Product {} -class ProductDetails {} // Shows additional information -class ProductInventory {} // Stock and availability - -// No redundant type encoding -String name; -Customer customer; -``` - -If you cannot distinguish what `ProductInfo` offers that `Product` does not, the names are noise. - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-method-verb.md b/builtin-skills/software-engineer/clean-code/references/name-method-verb.md deleted file mode 100644 index 7283e4f2..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-method-verb.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Use Verb Phrases for Method Names -impact: MEDIUM-HIGH -impactDescription: reduces "what does this method do" lookups by 80% -tags: name, method, verb, action ---- - -## Use Verb Phrases for Method Names - -Method names should be verbs or verb phrases. Methods do things, so their names should say what they do. Follow JavaBean conventions for accessors and mutators. - -**Incorrect (non-verb or unclear):** - -```java -// Noun names for methods -public String name() {} -public int size() {} // Acceptable for collections - -// Unclear action -public void customer() {} // Does what to customer? - -// Missing verb -public boolean valid() {} -``` - -**Correct (verb phrases):** - -```java -// Clear verb phrases -public void postPayment() {} -public void deletePage() {} -public void saveCustomer() {} - -// Accessors, mutators, predicates follow conventions -public String getName() {} -public void setName(String name) {} -public boolean isPosted() {} -public boolean hasPermission() {} - -// Static factory methods describe what is created -Complex fulcrumPoint = Complex.fromRealNumber(23.0); -``` - -Use `get`, `set`, `is`, and `has` prefixes consistently for accessors, mutators, and predicates. - -**Language-specific conventions:** -- **Java/C#:** `getName()`, `setName()`, `isActive()` (JavaBean conventions) -- **Python:** Use `@property` decorators — `user.name` not `user.get_name()` -- **Kotlin/Swift:** Direct property access with `val`/`var` — `user.name` not `user.getName()` -- **TypeScript:** Direct properties or getters — `get name(): string` -- **Go:** `Name()` not `GetName()` (Go convention omits `Get` prefix) - -The underlying principle (methods describe actions, names describe things) is universal. The accessor/mutator conventions are language-specific. - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-pronounceable.md b/builtin-skills/software-engineer/clean-code/references/name-pronounceable.md deleted file mode 100644 index 9436bc76..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-pronounceable.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: Use Pronounceable Names -impact: HIGH -impactDescription: enables verbal communication about code -tags: name, pronounceable, communication, readability ---- - -## Use Pronounceable Names - -Use pronounceable names. If you cannot pronounce a name, you cannot discuss it without sounding foolish. Programming is a social activity; names should facilitate discussion. - -**Incorrect (unpronounceable abbreviations):** - -```java -class DtaRcrd102 { - private Date genymdhms; // generation year, month, day, hour, minute, second - private Date modymdhms; - private final String pszqint = "102"; -} - -// In conversation: "Hey, look at this dee-tee-ay-arr-cee-arr-dee" -``` - -**Correct (pronounceable names):** - -```java -class Customer { - private Date generationTimestamp; - private Date modificationTimestamp; - private final String recordId = "102"; -} - -// In conversation: "Hey, look at this Customer record" -``` - -The pronounceable version enables natural conversation: "Hey, when did we modify this customer's generation timestamp?" - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/name-searchable.md b/builtin-skills/software-engineer/clean-code/references/name-searchable.md deleted file mode 100644 index 5b840491..00000000 --- a/builtin-skills/software-engineer/clean-code/references/name-searchable.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Use Searchable Names -impact: HIGH -impactDescription: enables effective code navigation -tags: name, searchable, constants, refactoring ---- - -## Use Searchable Names - -Single-letter names and numeric constants are hard to locate across a body of text. Longer names trump shorter names, and searchable names trump convenient abbreviations. - -**Incorrect (unsearchable):** - -```java -for (int j = 0; j < 34; j++) { - s += (t[j] * 4) / 5; // What is 34? What is 4? What is 5? -} -``` - -**Correct (searchable and meaningful):** - -```java -int realDaysPerIdealDay = 4; -final int WORK_DAYS_PER_WEEK = 5; -final int NUMBER_OF_TASKS = 34; - -int sum = 0; -for (int taskIndex = 0; taskIndex < NUMBER_OF_TASKS; taskIndex++) { - int realTaskDays = taskEstimate[taskIndex] * realDaysPerIdealDay; - int realTaskWeeks = realTaskDays / WORK_DAYS_PER_WEEK; - sum += realTaskWeeks; -} -``` - -Now you can search for `WORK_DAYS_PER_WEEK` and find every place it is used. Try searching for `5` in a large codebase. - -**Exception:** Single-letter names are acceptable only as local variables in short methods. The length of a name should correspond to the size of its scope. - -Reference: [Clean Code, Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/obj-avoid-hybrids.md b/builtin-skills/software-engineer/clean-code/references/obj-avoid-hybrids.md deleted file mode 100644 index d599a34d..00000000 --- a/builtin-skills/software-engineer/clean-code/references/obj-avoid-hybrids.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Avoid Hybrid Data-Object Structures -impact: MEDIUM-HIGH -impactDescription: prevents worst-of-both-worlds maintenance burden -tags: obj, hybrid, structure, design ---- - -## Avoid Hybrid Data-Object Structures - -Hybrids are half object, half data structure. They have functions that do significant things, AND they have public variables or accessors that expose internal structure. Avoid creating these monstrosities. - -**Incorrect (hybrid structure):** - -```java -// Half object, half data structure -public class Employee { - // Public data like a data structure - public String name; - public double salary; - public List skills; - - // Behavior like an object - public void promote() { - this.salary *= 1.1; - notifyHR(); - } - - public void addSkill(String skill) { - this.skills.add(skill); - updateTrainingRecord(); - } -} - -// Client code can bypass behavior -employee.salary = employee.salary * 1.5; // Skips notifyHR() -employee.skills.clear(); // Skips updateTrainingRecord() -``` - -**Correct (choose one approach):** - -```java -// Pure object - hide data, expose behavior -public class Employee { - private String name; - private Money salary; - private SkillSet skills; - - public void promote(PromotionDetails details) { - this.salary = salary.increase(details.getRaisePercentage()); - notifyHR(details); - } - - public void addSkill(Skill skill) { - this.skills.add(skill); - updateTrainingRecord(skill); - } - - public EmployeeReport getReport() { - return new EmployeeReport(name, salary.getAmount(), skills.list()); - } -} - -// OR pure data structure - no behavior, expose data -public record EmployeeData(String name, double salary, List skills) {} -``` - -Hybrids make it hard to add new functions AND hard to add new data structures. - -Reference: [Clean Code, Chapter 6: Objects and Data Structures](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/obj-data-abstraction.md b/builtin-skills/software-engineer/clean-code/references/obj-data-abstraction.md deleted file mode 100644 index 93e5a998..00000000 --- a/builtin-skills/software-engineer/clean-code/references/obj-data-abstraction.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Hide Data Behind Abstractions -impact: MEDIUM-HIGH -impactDescription: enables implementation changes without ripple effects -tags: obj, abstraction, encapsulation, data-hiding ---- - -## Hide Data Behind Abstractions - -Objects hide their data behind abstractions and expose functions that operate on that data. Data structures expose their data and have no meaningful functions. Do not mix these concepts. - -**Incorrect (exposing implementation):** - -```java -// Exposes internal representation - clients depend on Cartesian coordinates -public class Point { - public double x; - public double y; -} - -// Using it forces clients to know the implementation -double distance = Math.sqrt(point.x * point.x + point.y * point.y); -``` - -**Correct (hiding behind abstraction — immutable):** - -```java -// Hides representation - could be Cartesian, polar, or something else -public interface Point { - double getX(); - double getY(); - double getR(); - double getTheta(); - - static Point fromCartesian(double x, double y) { - return new CartesianPoint(x, y); - } - - static Point fromPolar(double r, double theta) { - return new PolarPoint(r, theta); - } -} - -// Clients work with the abstraction -double distance = point.getR(); // Works regardless of internal representation -Point moved = Point.fromCartesian(point.getX() + dx, point.getY() + dy); -``` - -**Key insight:** The abstraction is not just about using getters/setters. It is about hiding the form of the data and exposing operations that work with the abstract concept. Prefer immutable objects with factory methods over mutable objects with setters — immutable designs are easier to reason about, thread-safe by default, and less prone to bugs. - -Reference: [Clean Code, Chapter 6: Objects and Data Structures](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/obj-data-object-asymmetry.md b/builtin-skills/software-engineer/clean-code/references/obj-data-object-asymmetry.md deleted file mode 100644 index b335baf6..00000000 --- a/builtin-skills/software-engineer/clean-code/references/obj-data-object-asymmetry.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Understand Data/Object Anti-Symmetry -impact: MEDIUM-HIGH -impactDescription: prevents 2× effort when requirements change -tags: obj, asymmetry, procedural, polymorphism ---- - -## Understand Data/Object Anti-Symmetry - -Objects and data structures are opposites. Objects hide data and expose behavior; data structures expose data and have no behavior. Choose based on what kind of changes you anticipate. - -**Incorrect (wrong approach for frequent type additions):** - -```java -// Procedural approach - adding Triangle requires modifying EVERY function -public class Square { public double side; } -public class Circle { public double radius; } - -public class Geometry { - public double area(Object shape) { - if (shape instanceof Square) { - Square s = (Square) shape; - return s.side * s.side; - } else if (shape instanceof Circle) { - Circle c = (Circle) shape; - return Math.PI * c.radius * c.radius; - } - // Must add Triangle case here AND in perimeter() AND in draw()... - throw new NoSuchShapeException(); - } -} -``` - -**Correct (polymorphic approach for frequent type additions):** - -```java -// Object approach - adding Triangle only requires one new class -public interface Shape { - double area(); -} - -public class Square implements Shape { - private double side; - - public double area() { - return side * side; - } -} - -public class Circle implements Shape { - private double radius; - - public double area() { - return Math.PI * radius * radius; - } -} - -// Adding Triangle is easy - just add one class -public class Triangle implements Shape { - private double base, height; - - public double area() { - return 0.5 * base * height; - } -} -``` - -**Choose based on anticipated changes:** -- Adding new functions often? Use data structures (procedural) -- Adding new types often? Use objects (polymorphic) - -Reference: [Clean Code, Chapter 6: Objects and Data Structures](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/obj-dto.md b/builtin-skills/software-engineer/clean-code/references/obj-dto.md deleted file mode 100644 index 2fa6c2f4..00000000 --- a/builtin-skills/software-engineer/clean-code/references/obj-dto.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Use DTOs for Data Transfer -impact: MEDIUM -impactDescription: prevents sensitive data exposure at boundaries -tags: obj, dto, transfer, boundary ---- - -## Use DTOs for Data Transfer - -Data Transfer Objects (DTOs) are pure data structures for transferring data between layers or systems. They should have no behavior beyond accessors. Use them at system boundaries. - -**Incorrect (domain object used for transfer):** - -```java -// Domain object with behavior used for API response -public class User { - private String name; - private String hashedPassword; - private CreditCard creditCard; - - public void authenticate(String password) { /* ... */ } - public void chargeCard(Money amount) { /* ... */ } - - // Serialized directly - exposes sensitive data and internal structure -} -``` - -**Correct (separate DTO for transfer):** - -```java -// Domain object with behavior (internal) -public class User { - private String name; - private HashedPassword password; - private CreditCard creditCard; - - public void authenticate(String password) { /* ... */ } - public void chargeCard(Money amount) { /* ... */ } - - public UserDTO toDTO() { - return new UserDTO(name, creditCard.getMaskedNumber()); - } -} - -// DTO for API response (external) -public record UserDTO(String name, String maskedCardNumber) {} - -// Active Record variant - DTO with persistence methods only -public class UserRecord { - public String name; - public String email; - - public void save() { /* SQL insert/update */ } - public static UserRecord findById(Long id) { /* SQL select */ } -} -``` - -**Use DTOs when:** -- Transferring data across system boundaries (API, database, message queue) -- Hiding internal structure from external consumers -- Transforming data format between layers - -Reference: [Clean Code, Chapter 6: Objects and Data Structures](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/obj-law-of-demeter.md b/builtin-skills/software-engineer/clean-code/references/obj-law-of-demeter.md deleted file mode 100644 index 9b4c7ae6..00000000 --- a/builtin-skills/software-engineer/clean-code/references/obj-law-of-demeter.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Follow the Law of Demeter -impact: MEDIUM-HIGH -impactDescription: prevents hidden dependencies between modules -tags: obj, demeter, coupling, encapsulation ---- - -## Follow the Law of Demeter - -A method should only call methods on: its own object, objects passed as parameters, objects it creates, or its direct component objects. Avoid chained method calls on returned objects. - -**Incorrect (train wreck - violates Law of Demeter):** - -```java -// Reaches through multiple objects -String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath(); - -// Forces knowledge of internal structure -customer.getAddress().getCity().getName(); - -// Chains expose implementation details -report.getFormatter().getConfiguration().getPageSize(); -``` - -**Correct (respects object boundaries):** - -```java -// Option 1: Create a direct method -String outputDir = ctxt.getOutputDirectory(); - -// Option 2: Tell, don't ask -customer.sendBillingNotice(); // Let customer handle its own address - -// Option 3: If data structure, use it directly (no behavior expected) -BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName); -``` - -**Exception:** The Law of Demeter does not apply to data structures. If `Options`, `ScratchDir`, etc. are just data containers without behavior, the chaining is acceptable: - -```java -// Data transfer objects can be chained -final String outputDir = ctxt.options.scratchDir.absolutePath; -``` - -Reference: [Clean Code, Chapter 6: Objects and Data Structures](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/test-build-operate-check.md b/builtin-skills/software-engineer/clean-code/references/test-build-operate-check.md deleted file mode 100644 index 647297e3..00000000 --- a/builtin-skills/software-engineer/clean-code/references/test-build-operate-check.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Use Build-Operate-Check Pattern -impact: MEDIUM -impactDescription: reduces test comprehension time by 50% -tags: test, boc, arrange-act-assert, structure ---- - -## Use Build-Operate-Check Pattern - -Structure tests in three distinct phases: Build (arrange), Operate (act), Check (assert). This pattern makes tests easy to read and understand at a glance. - -**Incorrect (mixed phases, unclear structure):** - -```java -@Test -public void testOrder() { - Order order = new Order(); - assertTrue(order.isEmpty()); - Product product = new Product("Widget", 9.99); - order.add(product); - assertEquals(1, order.getItemCount()); - assertEquals(9.99, order.getTotal(), 0.01); - order.add(product); - assertEquals(2, order.getItemCount()); - assertEquals(19.98, order.getTotal(), 0.01); -} -``` - -**Correct (clear Build-Operate-Check):** - -```java -@Test -public void addingProductShouldIncreaseItemCount() { - // Build - Order order = new Order(); - Product widget = new Product("Widget", 9.99); - - // Operate - order.add(widget); - - // Check - assertEquals(1, order.getItemCount()); -} - -@Test -public void addingProductShouldUpdateTotal() { - // Build - Order order = new Order(); - Product widget = new Product("Widget", 9.99); - - // Operate - order.add(widget); - - // Check - assertEquals(9.99, order.getTotal(), 0.01); -} - -@Test -public void addingSameProductTwiceShouldDoubleTotal() { - // Build - Order order = new Order(); - Product widget = new Product("Widget", 9.99); - - // Operate - order.add(widget); - order.add(widget); - - // Check - assertEquals(19.98, order.getTotal(), 0.01); -} -``` - -**Alias patterns:** -- Build-Operate-Check (BOC) -- Arrange-Act-Assert (AAA) -- Given-When-Then (BDD) - -Reference: [Clean Code, Chapter 9: Unit Tests](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/test-first-law.md b/builtin-skills/software-engineer/clean-code/references/test-first-law.md deleted file mode 100644 index ff0de141..00000000 --- a/builtin-skills/software-engineer/clean-code/references/test-first-law.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Follow the Three Laws of TDD -impact: MEDIUM -impactDescription: achieves 90%+ test coverage naturally -tags: test, tdd, first, laws ---- - -## Follow the Three Laws of TDD - -Test-Driven Development follows three rules: (1) Write a failing test before production code, (2) Write only enough test to fail, (3) Write only enough production code to pass. This cycle repeats. - -**Incorrect (writing tests after code):** - -```java -// Production code written first, then tests added later (or never) -public class Calculator { - public int add(int a, int b) { - return a + b; - } - - public int divide(int a, int b) { - return a / b; // Edge cases not considered - } -} - -// Test written after - may not cover edge cases -@Test -public void testAdd() { - assertEquals(4, calculator.add(2, 2)); -} -// No test for divide by zero because code was written first -``` - -**Correct (TDD cycle):** - -```java -// 1. Write failing test first -@Test -public void divideShouldReturnQuotient() { - assertEquals(2, calculator.divide(6, 3)); -} - -// 2. Write minimal code to pass -public int divide(int a, int b) { - return a / b; -} - -// 3. Write next failing test -@Test(expected = IllegalArgumentException.class) -public void divideShouldThrowOnDivideByZero() { - calculator.divide(6, 0); -} - -// 4. Update code to pass -public int divide(int a, int b) { - if (b == 0) { - throw new IllegalArgumentException("Cannot divide by zero"); - } - return a / b; -} -``` - -**Benefits:** -- Tests cover requirements, not implementation -- Edge cases discovered through test-first thinking -- High coverage achieved naturally - -Reference: [Clean Code, Chapter 9: Unit Tests](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/test-first-principles.md b/builtin-skills/software-engineer/clean-code/references/test-first-principles.md deleted file mode 100644 index d75996a4..00000000 --- a/builtin-skills/software-engineer/clean-code/references/test-first-principles.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: Follow FIRST Principles -impact: MEDIUM -impactDescription: prevents test suite from becoming 10× slower over time -tags: test, first, fast, independent, repeatable ---- - -## Follow FIRST Principles - -Clean tests follow FIRST: Fast, Independent, Repeatable, Self-Validating, and Timely. These properties ensure tests remain useful and maintainable. - -**Incorrect (violating FIRST):** - -```java -// Slow - depends on real database -@Test -public void testUserQuery() { - Connection conn = DriverManager.getConnection(PROD_DB_URL); // Slow! - // ... -} - -// Not Independent - tests depend on each other -private static User sharedUser; - -@Test -public void test1CreateUser() { - sharedUser = userService.create("bob"); -} - -@Test -public void test2UpdateUser() { - sharedUser.setName("alice"); // Depends on test1 running first -} - -// Not Repeatable - depends on external state -@Test -public void testPayment() { - assertTrue(paymentGateway.charge(card, 100)); // Different result each time -} -``` - -**Correct (following FIRST):** - -```java -// Fast - uses mocks, runs in milliseconds -@Test -public void queryShouldReturnMatchingUsers() { - UserRepository repo = mock(UserRepository.class); - when(repo.findByName("bob")).thenReturn(List.of(testUser)); - - List result = userService.query("bob"); - - assertEquals(1, result.size()); -} - -// Independent - each test sets up its own state -@Test -public void createShouldReturnNewUser() { - User user = userService.create("bob"); - assertEquals("bob", user.getName()); -} - -@Test -public void updateShouldModifyUserName() { - User user = userService.create("bob"); - user.setName("alice"); - assertEquals("alice", user.getName()); -} - -// Repeatable - uses test doubles -@Test -public void chargeShouldReturnTrueOnSuccess() { - PaymentGateway gateway = mock(PaymentGateway.class); - when(gateway.charge(any(), eq(100))).thenReturn(true); - - assertTrue(paymentService.processPayment(100)); -} -``` - -Reference: [Clean Code, Chapter 9: Unit Tests](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/test-keep-clean.md b/builtin-skills/software-engineer/clean-code/references/test-keep-clean.md deleted file mode 100644 index 332f92e2..00000000 --- a/builtin-skills/software-engineer/clean-code/references/test-keep-clean.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Keep Tests Clean -impact: MEDIUM -impactDescription: maintains test maintainability over time -tags: test, clean, maintainability, quality ---- - -## Keep Tests Clean - -Test code is just as important as production code. It requires thought, design, and care. If you let tests rot, they become a liability instead of an asset. - -**Incorrect (dirty tests):** - -```java -@Test -public void test1() { - // Cryptic, no clear purpose - S s = new S(); - s.a("x"); - s.b("y"); - assertTrue(s.c()); - s.d(); - assertEquals("xy", s.e()); -} - -@Test -public void testEverything() { - // Multiple assertions testing different concepts - assertNotNull(user); - assertEquals("Bob", user.getName()); - assertTrue(user.isActive()); - assertEquals(3, user.getOrders().size()); - assertTrue(user.getOrders().get(0).isPaid()); -} -``` - -**Correct (clean, readable tests):** - -```java -@Test -public void concatenatingTwoStringsShouldReturnCombinedResult() { - StringBuffer buffer = new StringBuffer(); - - buffer.append("first"); - buffer.append("second"); - - assertEquals("firstsecond", buffer.toString()); -} - -@Test -public void userShouldBeActiveAfterActivation() { - User user = new User("Bob"); - - user.activate(); - - assertTrue(user.isActive()); -} - -@Test -public void activatingUserShouldSendWelcomeEmail() { - User user = new User("Bob"); - EmailService emailService = mock(EmailService.class); - - user.activate(emailService); - - verify(emailService).sendWelcome(user.getEmail()); -} -``` - -**Qualities of clean tests:** -- Readable: Clear setup, action, assertion -- One concept per test -- Descriptive names explaining what is being tested - -Reference: [Clean Code, Chapter 9: Unit Tests](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-code/references/test-one-assert.md b/builtin-skills/software-engineer/clean-code/references/test-one-assert.md deleted file mode 100644 index 84e9ad45..00000000 --- a/builtin-skills/software-engineer/clean-code/references/test-one-assert.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: One Concept Per Test -impact: MEDIUM -impactDescription: enables precise failure diagnosis -tags: test, assert, concept, focus ---- - -## One Concept Per Test - -Each test should verify a single concept or behavior. Multiple assertions are fine when they all verify different aspects of that one concept. What you want to avoid is testing unrelated concerns in a single test. - -**Incorrect (multiple unrelated concepts in one test):** - -```java -@Test -public void testUserRegistration() { - User user = userService.register("bob@example.com", "password123"); - - // Concept 1: user creation - assertNotNull(user); - assertNotNull(user.getId()); - - // Concept 2: email notification (unrelated to creation details) - verify(emailService).sendWelcome("bob@example.com"); - - // Concept 3: repository state (separate concern) - assertEquals(1, userRepository.count()); -} -// If this fails, which concept is broken? Creation? Email? Persistence? -``` - -**Correct (one concept per test, multiple assertions are fine):** - -```java -@Test -public void registerShouldCreateActiveUserWithGeneratedId() { - User user = userService.register("bob@example.com", "password123"); - - assertNotNull(user.getId()); - assertEquals("bob@example.com", user.getEmail()); - assertTrue(user.isActive()); -} - -@Test -public void registerShouldSendWelcomeEmail() { - userService.register("bob@example.com", "password123"); - - verify(emailService).sendWelcome("bob@example.com"); -} - -@Test -public void registerShouldPersistUser() { - userService.register("bob@example.com", "password123"); - - assertEquals(1, userRepository.count()); -} -``` - -The first test has three assertions — that's fine because they all verify a single concept: "the returned user object is correctly constructed." Each test can be understood from its name alone. - -**When NOT to split tests:** -- When multiple assertions verify the same behavior from different angles (like checking all fields of a returned object), keep them together — splitting creates duplicate setup and slower test suites. -- When the operation under test has side effects (API calls, DB writes), avoid calling it multiple times just to isolate assertions. - -Reference: [Clean Code, Chapter 9: Unit Tests](https://www.oreilly.com/library/view/clean-code-a/9780136083238/) diff --git a/builtin-skills/software-engineer/clean-comments/SKILL.md b/builtin-skills/software-engineer/clean-comments/SKILL.md deleted file mode 100644 index e7375f78..00000000 --- a/builtin-skills/software-engineer/clean-comments/SKILL.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: clean-comments -description: Use when writing, fixing, editing, or reviewing Python comments and docstrings. Enforces Clean Code principles—no metadata, no redundancy, no commented-out code. ---- - -# Clean Comments - -## C1: No Inappropriate Information - -Comments shouldn't hold metadata. Use Git for author names, change history, -ticket numbers, and dates. Comments are for technical notes about code only. - -## C2: Delete Obsolete Comments - -If a comment describes code that no longer exists or works differently, -delete it immediately. Stale comments become "floating islands of -irrelevance and misdirection." - -## C3: No Redundant Comments - -```python -# Bad - the code already says this -i += 1 # increment i -user.save() # save the user - -# Good - explains WHY, not WHAT -i += 1 # compensate for zero-indexing in display -``` - -## C4: Write Comments Well - -If a comment is worth writing, write it well: -- Choose words carefully -- Use correct grammar -- Don't ramble or state the obvious -- Be brief - -## C5: Never Commit Commented-Out Code - -```python -# DELETE THIS - it's an abomination -# def old_calculate_tax(income): -# return income * 0.15 -``` - -Who knows how old it is? Who knows if it's meaningful? Delete it. -Git remembers everything. - -## The Goal - -The best comment is the code itself. If you need a comment to explain -what code does, refactor first, comment last. diff --git a/builtin-skills/software-engineer/clean-functions/SKILL.md b/builtin-skills/software-engineer/clean-functions/SKILL.md deleted file mode 100644 index b3f1a32c..00000000 --- a/builtin-skills/software-engineer/clean-functions/SKILL.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: clean-functions -description: Use when writing, fixing, editing, or refactoring Python functions. Enforces Clean Code principles—maximum 3 arguments, single responsibility, no flag parameters. ---- - -# Clean Functions - -## F1: Too Many Arguments (Maximum 3) - -```python -# Bad - too many parameters -def create_user(name, email, age, country, timezone, language, newsletter): - ... - -# Good - use a dataclass or dict -@dataclass -class UserData: - name: str - email: str - age: int - country: str - timezone: str - language: str - newsletter: bool - -def create_user(data: UserData): - ... -``` - -More than 3 arguments means your function is doing too much or needs -a data structure. - -## F2: No Output Arguments - -Don't modify arguments as side effects. Return values instead. - -```python -# Bad - modifies argument -def append_footer(report: Report) -> None: - report.append("\n---\nGenerated by System") - -# Good - returns new value -def with_footer(report: Report) -> Report: - return report + "\n---\nGenerated by System" -``` - -## F3: No Flag Arguments - -Boolean flags mean your function does at least two things. - -```python -# Bad - function does two different things -def render(is_test: bool): - if is_test: - render_test_page() - else: - render_production_page() - -# Good - split into two functions -def render_test_page(): ... -def render_production_page(): ... -``` - -## F4: Delete Dead Functions - -If it's not called, delete it. No "just in case" code. Git preserves history. diff --git a/builtin-skills/software-engineer/clean-general/SKILL.md b/builtin-skills/software-engineer/clean-general/SKILL.md deleted file mode 100644 index 099a3e68..00000000 --- a/builtin-skills/software-engineer/clean-general/SKILL.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: clean-general -description: Use when writing, fixing, editing, or reviewing Python code quality. Enforces Clean Code's core principles—DRY, single responsibility, clear intent, no magic numbers, proper abstractions. ---- - -# General Clean Code Principles - -## Critical Rules - -**G5: DRY (Don't Repeat Yourself)** - -Every piece of knowledge has one authoritative representation. - -```python -# Bad - duplication -tax_rate = 0.0825 -ca_total = subtotal * 1.0825 -ny_total = subtotal * 1.07 - -# Good - single source of truth -TAX_RATES = {"CA": 0.0825, "NY": 0.07} -def calculate_total(subtotal: float, state: str) -> float: - return subtotal * (1 + TAX_RATES[state]) -``` - -**G16: No Obscured Intent** - -Don't be clever. Be clear. - -```python -# Bad - what does this do? -return (x & 0x0F) << 4 | (y & 0x0F) - -# Good - obvious intent -return pack_coordinates(x, y) -``` - -**G23: Prefer Polymorphism to If/Else** - -```python -# Bad - will grow forever -def calculate_pay(employee): - if employee.type == "SALARIED": - return employee.salary - elif employee.type == "HOURLY": - return employee.hours * employee.rate - elif employee.type == "COMMISSIONED": - return employee.base + employee.commission - -# Good - open/closed principle -class SalariedEmployee: - def calculate_pay(self): return self.salary - -class HourlyEmployee: - def calculate_pay(self): return self.hours * self.rate - -class CommissionedEmployee: - def calculate_pay(self): return self.base + self.commission -``` - -**G25: Replace Magic Numbers with Named Constants** - -```python -# Bad -if elapsed_time > 86400: - ... - -# Good -SECONDS_PER_DAY = 86400 -if elapsed_time > SECONDS_PER_DAY: - ... -``` - -**G30: Functions Should Do One Thing** - -If you can extract another function, your function does more than one thing. - -**G36: Law of Demeter (Avoid Train Wrecks)** - -```python -# Bad - reaching through multiple objects -output_dir = context.options.scratch_dir.absolute_path - -# Good - one dot -output_dir = context.get_scratch_dir() -``` - -## Enforcement Checklist - -When reviewing AI-generated code, verify: -- [ ] No duplication (G5) -- [ ] Clear intent, no magic numbers (G16, G25) -- [ ] Polymorphism over conditionals (G23) -- [ ] Functions do one thing (G30) -- [ ] No Law of Demeter violations (G36) -- [ ] Boundary conditions handled (G3) -- [ ] Dead code removed (G9) diff --git a/builtin-skills/software-engineer/clean-names/SKILL.md b/builtin-skills/software-engineer/clean-names/SKILL.md deleted file mode 100644 index 970d8e40..00000000 --- a/builtin-skills/software-engineer/clean-names/SKILL.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -name: clean-names -description: Use when naming, renaming, or fixing names of variables, functions, classes, or modules in Python. Enforces Clean Code principles—descriptive names, appropriate length, no encodings. ---- - -# Clean Names - -## N1: Choose Descriptive Names - -Names should reveal intent. If a name requires a comment, it doesn't reveal its intent. - -```python -# Bad - what is d? -d = 86400 - -# Good - obvious meaning -SECONDS_PER_DAY = 86400 - -# Bad - what does this function do? -def proc(lst): - return [x for x in lst if x > 0] - -# Good - intent is clear -def filter_positive_numbers(numbers): - return [n for n in numbers if n > 0] -``` - -## N2: Choose Names at the Appropriate Level of Abstraction - -Don't pick names that communicate implementation; choose names that reflect the level of abstraction of the class or function. - -```python -# Bad - too implementation-specific -def get_dict_of_user_ids_to_names(): - ... - -# Good - abstracts the data structure -def get_user_directory(): - ... -``` - -## N3: Use Standard Nomenclature Where Possible - -Use terms from the domain, design patterns, or well-known conventions. - -```python -# Good - uses pattern name -class UserFactory: - def create(self, data): ... - -# Good - uses domain term -def calculate_amortization(principal, rate, term): ... -``` - -## N4: Unambiguous Names - -Choose names that make the workings of a function or variable unambiguous. - -```python -# Bad - ambiguous -def rename(old, new): - ... - -# Good - clear what's being renamed -def rename_file(old_path: Path, new_path: Path): - ... -``` - -## N5: Use Longer Names for Longer Scopes - -Short names are fine for tiny scopes. Longer scopes need longer, more descriptive names. - -```python -# Good - short name for tiny scope -total = sum(x for x in numbers) - -# Good - longer name for module-level constant -MAX_RETRY_ATTEMPTS_BEFORE_FAILURE = 5 - -# Bad - short name at module level -MAX = 5 -``` - -## N6: Avoid Encodings - -Don't encode type or scope information into names. Modern editors make this unnecessary. - -```python -# Bad - Hungarian notation -str_name = "Alice" -lst_users = [] -i_count = 0 - -# Good - clean names -name = "Alice" -users = [] -count = 0 - -# Bad - interface prefix -class IUserRepository: - ... - -# Good - just name it -class UserRepository: - ... -``` - -## N7: Names Should Describe Side Effects - -If a function does something beyond what its name suggests, the name is misleading. - -```python -# Bad - name doesn't mention file creation -def get_config(): - if not config_path.exists(): - config_path.write_text("{}") # Hidden side effect! - return json.loads(config_path.read_text()) - -# Good - name reveals behavior -def get_or_create_config(): - if not config_path.exists(): - config_path.write_text("{}") - return json.loads(config_path.read_text()) -``` - -## Quick Reference - -| Rule | Principle | Example | -|------|-----------|---------| -| N1 | Descriptive names | `SECONDS_PER_DAY` not `d` | -| N2 | Right abstraction level | `get_user_directory()` not `get_dict_of_...` | -| N3 | Standard nomenclature | `UserFactory`, `calculate_amortization` | -| N4 | Unambiguous | `rename_file(old_path, new_path)` | -| N5 | Length matches scope | Short for loops, long for globals | -| N6 | No encodings | `users` not `lst_users` | -| N7 | Describe side effects | `get_or_create_config()` | diff --git a/builtin-skills/software-engineer/clean-tests/SKILL.md b/builtin-skills/software-engineer/clean-tests/SKILL.md deleted file mode 100644 index b06d8671..00000000 --- a/builtin-skills/software-engineer/clean-tests/SKILL.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -name: clean-tests -description: Use when writing, fixing, editing, or refactoring Python tests. Enforces Clean Code principles—fast tests, boundary coverage, one assert per test. ---- - -# Clean Tests - -## T1: Insufficient Tests - -Test everything that could possibly break. Use coverage tools as a guide, not a goal. - -```python -# Bad - only tests happy path -def test_divide(): - assert divide(10, 2) == 5 - -# Good - tests edge cases too -def test_divide_normal(): - assert divide(10, 2) == 5 - -def test_divide_by_zero(): - with pytest.raises(ZeroDivisionError): - divide(10, 0) - -def test_divide_negative(): - assert divide(-10, 2) == -5 -``` - -## T2: Use a Coverage Tool - -Coverage tools report gaps in your testing strategy. Don't ignore them. - -```bash -# Run with coverage -pytest --cov=myproject --cov-report=term-missing - -# Aim for meaningful coverage, not 100% -``` - -## T3: Don't Skip Trivial Tests - -Trivial tests document behavior and catch regressions. They're worth more than their cost. - -```python -# Worth having - documents expected behavior -def test_user_default_role(): - user = User(name="Alice") - assert user.role == "member" -``` - -## T4: An Ignored Test Is a Question About an Ambiguity - -Don't use `@pytest.mark.skip` to hide problems. Either fix the test or delete it. - -```python -# Bad - hiding a problem -@pytest.mark.skip(reason="flaky, fix later") -def test_async_operation(): - ... - -# Good - either fix it or document why it's skipped -@pytest.mark.skip(reason="Requires Redis, see CONTRIBUTING.md for setup") -def test_cache_invalidation(): - ... -``` - -## T5: Test Boundary Conditions - -Bugs congregate at boundaries. Test them explicitly. - -```python -def test_pagination_boundaries(): - items = list(range(100)) - - # First page - assert paginate(items, page=1, size=10) == items[0:10] - - # Last page - assert paginate(items, page=10, size=10) == items[90:100] - - # Beyond last page - assert paginate(items, page=11, size=10) == [] - - # Page zero (invalid) - with pytest.raises(ValueError): - paginate(items, page=0, size=10) - - # Empty list - assert paginate([], page=1, size=10) == [] -``` - -## T6: Exhaustively Test Near Bugs - -When you find a bug, write tests for all similar cases. Bugs cluster. - -```python -# Found bug: off-by-one in date calculation -# Now test ALL date boundaries -def test_month_boundaries(): - assert last_day_of_month(2024, 1) == 31 # January - assert last_day_of_month(2024, 2) == 29 # Leap year February - assert last_day_of_month(2023, 2) == 28 # Non-leap February - assert last_day_of_month(2024, 4) == 30 # 30-day month - assert last_day_of_month(2024, 12) == 31 # December -``` - -## T7: Patterns of Failure Are Revealing - -When tests fail, look for patterns. They often point to deeper issues. - -```python -# If all async tests fail intermittently, -# the problem isn't the tests—it's the async handling -``` - -## T8: Test Coverage Patterns Can Be Revealing - -Look at which code paths are untested. Often they reveal design problems. - -```python -# If you can't easily test a function, it probably does too much -# Refactor for testability -``` - -## T9: Tests Should Be Fast - -Slow tests don't get run. Keep unit tests under 100ms each. - -```python -# Bad - hits real database -def test_user_creation(): - db = connect_to_database() # Slow! - user = db.create_user("Alice") - assert user.name == "Alice" - -# Good - uses mock or in-memory -def test_user_creation(): - db = InMemoryDatabase() - user = db.create_user("Alice") - assert user.name == "Alice" -``` - -## Test Organization - -### F.I.R.S.T. Principles - -- **Fast**: Tests should run quickly -- **Independent**: Tests shouldn't depend on each other -- **Repeatable**: Same result every time, any environment -- **Self-Validating**: Pass or fail, no manual inspection -- **Timely**: Written before or with the code, not after - -### One Concept Per Test - -```python -# Bad - testing multiple things -def test_user(): - user = User("Alice", "alice@example.com") - assert user.name == "Alice" - assert user.email == "alice@example.com" - assert user.is_valid() - user.activate() - assert user.is_active - -# Good - one concept each -def test_user_stores_name(): - user = User("Alice", "alice@example.com") - assert user.name == "Alice" - -def test_user_stores_email(): - user = User("Alice", "alice@example.com") - assert user.email == "alice@example.com" - -def test_new_user_is_valid(): - user = User("Alice", "alice@example.com") - assert user.is_valid() - -def test_user_can_be_activated(): - user = User("Alice", "alice@example.com") - user.activate() - assert user.is_active -``` - -## Quick Reference - -| Rule | Principle | -|------|-----------| -| T1 | Test everything that could break | -| T2 | Use coverage tools | -| T3 | Don't skip trivial tests | -| T4 | Ignored test = ambiguity question | -| T5 | Test boundary conditions | -| T6 | Exhaustively test near bugs | -| T7 | Look for patterns in failures | -| T8 | Check coverage when debugging | -| T9 | Tests must be fast (<100ms) | diff --git a/builtin-skills/software-engineer/coding-guidelines/SKILL.md b/builtin-skills/software-engineer/coding-guidelines/SKILL.md deleted file mode 100644 index 4a505f48..00000000 --- a/builtin-skills/software-engineer/coding-guidelines/SKILL.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -name: coding-guidelines -description: "Use when asking about Rust code style or best practices. Keywords: naming, formatting, comment, clippy, rustfmt, lint, code style, best practice, P.NAM, G.FMT, code review, naming convention, variable naming, function naming, type naming, 命名规范, 代码风格, 格式化, 最佳实践, 代码审查, 怎么命名" -source: https://rust-coding-guidelines.github.io/rust-coding-guidelines-zh/ -user-invocable: false ---- - -# Rust Coding Guidelines (50 Core Rules) - -## Naming (Rust-Specific) - -| Rule | Guideline | -|------|-----------| -| No `get_` prefix | `fn name()` not `fn get_name()` | -| Iterator convention | `iter()` / `iter_mut()` / `into_iter()` | -| Conversion naming | `as_` (cheap &), `to_` (expensive), `into_` (ownership) | -| Static var prefix | `G_CONFIG` for `static`, no prefix for `const` | - -## Data Types - -| Rule | Guideline | -|------|-----------| -| Use newtypes | `struct Email(String)` for domain semantics | -| Prefer slice patterns | `if let [first, .., last] = slice` | -| Pre-allocate | `Vec::with_capacity()`, `String::with_capacity()` | -| Avoid Vec abuse | Use arrays for fixed sizes | - -## Strings - -| Rule | Guideline | -|------|-----------| -| Prefer bytes | `s.bytes()` over `s.chars()` when ASCII | -| Use `Cow` | When might modify borrowed data | -| Use `format!` | Over string concatenation with `+` | -| Avoid nested iteration | `contains()` on string is O(n*m) | - -## Error Handling - -| Rule | Guideline | -|------|-----------| -| Use `?` propagation | Not `try!()` macro | -| `expect()` over `unwrap()` | When value guaranteed | -| Assertions for invariants | `assert!` at function entry | - -## Memory - -| Rule | Guideline | -|------|-----------| -| Meaningful lifetimes | `'src`, `'ctx` not just `'a` | -| `try_borrow()` for RefCell | Avoid panic | -| Shadowing for transformation | `let x = x.parse()?` | - -## Concurrency - -| Rule | Guideline | -|------|-----------| -| Identify lock ordering | Prevent deadlocks | -| Atomics for primitives | Not Mutex for bool/usize | -| Choose memory order carefully | Relaxed/Acquire/Release/SeqCst | - -## Async - -| Rule | Guideline | -|------|-----------| -| Sync for CPU-bound | Async is for I/O | -| Don't hold locks across await | Use scoped guards | - -## Macros - -| Rule | Guideline | -|------|-----------| -| Avoid unless necessary | Prefer functions/generics | -| Follow Rust syntax | Macro input should look like Rust | - -## Deprecated → Better - -| Deprecated | Better | Since | -|------------|--------|-------| -| `lazy_static!` | `std::sync::OnceLock` | 1.70 | -| `once_cell::Lazy` | `std::sync::LazyLock` | 1.80 | -| `std::sync::mpsc` | `crossbeam::channel` | - | -| `std::sync::Mutex` | `parking_lot::Mutex` | - | -| `failure`/`error-chain` | `thiserror`/`anyhow` | - | -| `try!()` | `?` operator | 2018 | - -## Quick Reference - -``` -Naming: snake_case (fn/var), CamelCase (type), SCREAMING_CASE (const) -Format: rustfmt (just use it) -Docs: /// for public items, //! for module docs -Lint: #![warn(clippy::all)] -``` - -Claude knows Rust conventions well. These are the non-obvious Rust-specific rules. diff --git a/builtin-skills/software-engineer/coding-guidelines/clippy-lints/_index.md b/builtin-skills/software-engineer/coding-guidelines/clippy-lints/_index.md deleted file mode 100644 index 74816071..00000000 --- a/builtin-skills/software-engineer/coding-guidelines/clippy-lints/_index.md +++ /dev/null @@ -1,16 +0,0 @@ -# Clippy Lint → Rule Mapping - -| Clippy Lint | Category | Fix | -|-------------|----------|-----| -| `unwrap_used` | Error | Use `?` or `expect()` | -| `needless_clone` | Perf | Use reference | -| `await_holding_lock` | Async | Scope guard before await | -| `linkedlist` | Perf | Use Vec/VecDeque | -| `wildcard_imports` | Style | Explicit imports | -| `missing_safety_doc` | Safety | Add `# Safety` doc | -| `undocumented_unsafe_blocks` | Safety | Add `// SAFETY:` | -| `transmute_ptr_to_ptr` | Safety | Use `pointer::cast()` | -| `large_stack_arrays` | Mem | Use Vec or Box | -| `too_many_arguments` | Design | Use struct params | - -For unsafe-related lints → see `unsafe-checker` skill. diff --git a/builtin-skills/software-engineer/coding-guidelines/index/rules-index.md b/builtin-skills/software-engineer/coding-guidelines/index/rules-index.md deleted file mode 100644 index 14242727..00000000 --- a/builtin-skills/software-engineer/coding-guidelines/index/rules-index.md +++ /dev/null @@ -1,6 +0,0 @@ -# Complete Rules Reference - -For the full 500+ rules, see: -- Source: https://rust-coding-guidelines.github.io/rust-coding-guidelines-zh/ - -Core rules are in `../SKILL.md`. diff --git a/builtin-skills/software-engineer/ddia-principles/SKILL.md b/builtin-skills/software-engineer/ddia-principles/SKILL.md deleted file mode 100644 index 67e6bf11..00000000 --- a/builtin-skills/software-engineer/ddia-principles/SKILL.md +++ /dev/null @@ -1,421 +0,0 @@ ---- -name: ddia-principles -description: > - Designing Data-Intensive Applications (DDIA) distilled reference guide by Martin Kleppmann. - MUST be loaded when: designing database schemas, choosing storage engines, implementing replication - or partitioning, handling distributed transactions, building batch/stream processing pipelines, - choosing consistency models, implementing consensus, designing data flow architectures, - evaluating trade-offs between availability and consistency, encoding/serialization decisions, - data modeling (relational vs document vs graph), building fault-tolerant systems, or any - system design and architecture discussion involving data-intensive applications. - Trigger on: database design, replication, partitioning, sharding, transactions, isolation levels, - consistency, consensus, CAP theorem, batch processing, stream processing, MapReduce, Kafka, - event sourcing, CDC, OLTP, OLAP, B-tree, LSM-tree, data warehouse, schema evolution, - encoding formats, distributed systems, fault tolerance, leader election, quorum. ---- - -# Designing Data-Intensive Applications — Distilled Guide - -> Source: Martin Kleppmann, *Designing Data-Intensive Applications* -> Central thesis: **Data is the core challenge of modern applications — not compute.** - ---- - -## Part I: Foundations of Data Systems - -### Chapter 1: Reliability, Scalability, Maintainability - -#### Three Pillars - -| Pillar | Definition | Key Metric | -|--------|-----------|------------| -| **Reliability** | System works correctly even when faults occur | Fault ≠ Failure; tolerate faults, prevent failures | -| **Scalability** | System handles load growth gracefully | Measure with percentiles: p50, p95, p99, p999 | -| **Maintainability** | System is easy to operate, understand, evolve | Operability + Simplicity + Evolvability | - -#### Fault Categories -- **Hardware**: Random, independent (disk, RAM, power). Mitigate with redundancy (RAID, dual power). -- **Software**: Systematic bugs affecting all nodes simultaneously (leap-second bug). Mitigate with process isolation, monitoring, chaos engineering. -- **Human**: #1 cause of outages (config errors). Mitigate with good abstractions, sandboxes, canary deployments, fast rollback. - -#### Scalability Patterns -- **Vertical (scale-up)**: Bigger machine. Simple but has ceiling. -- **Horizontal (scale-out)**: More machines (shared-nothing). Complex but unlimited. -- **Elastic**: Auto-scale on load detection. Good for unpredictable workloads. - -**Twitter fan-out case study**: 4.6k writes/s but 300k reads/s. Solution: pre-compute timelines (write fan-out) for most users; read-time merge for celebrities. - -#### Performance: Use Percentiles, Not Averages -- p50 = median. p99 = tail latency matters for user experience. -- Amazon: 100ms delay = 1% revenue loss. -- **Tail latency amplification**: One slow backend call slows entire parallel request. - ---- - -### Chapter 2: Data Models & Query Languages - -#### Model Selection Guide - -| Model | Best For | Weakness | -|-------|----------|----------| -| **Relational** | Structured data, complex joins, ACID transactions | Rigid schema, impedance mismatch with OOP | -| **Document** | Hierarchical data, flexible schema, data locality | Poor joins, many-to-many relationships | -| **Graph** | Highly connected data, variable-depth traversals | Less mature tooling, harder to partition | - -#### Schema Strategy -- **Schema-on-write** (relational): Enforce structure at write time. Early error detection, migration cost. -- **Schema-on-read** (document): Interpret structure at read time. Flexible but validation burden on app. - -#### Normalization vs Denormalization -- **Normalize**: Single source of truth, consistent updates, requires joins. -- **Denormalize**: Faster reads, risks inconsistency, update anomalies. - -**Trend**: Models converge — PostgreSQL supports JSON, MongoDB added joins. Choose based on access patterns, not ideology. - ---- - -### Chapter 3: Storage & Retrieval - -#### Storage Engine Comparison - -| Feature | B-Tree | LSM-Tree | -|---------|--------|----------| -| Write throughput | Lower (in-place update + WAL) | Higher (sequential append) | -| Read latency | More predictable | May check multiple SSTables | -| Write amplification | Higher | Lower | -| Space efficiency | Fragmentation possible | Better compression | -| Transaction support | Simpler (lock on tree node) | More complex | -| Used by | PostgreSQL, MySQL, Oracle | LevelDB, RocksDB, Cassandra | - -#### OLTP vs OLAP - -| Aspect | OLTP | OLAP | -|--------|------|------| -| Access | Random, few records | Sequential scan, millions of rows | -| Users | End users | Analysts | -| Data | Current state | Historical events | -| Scale | GB–TB | TB–PB | -| Optimize for | Low latency | Throughput | - -#### Data Warehousing -- **ETL**: Extract from OLTP → Transform → Load into warehouse. -- **Star schema**: Central fact table (events) + dimension tables (attributes). Fact tables can have 100+ columns and petabyte scale. -- **Column-oriented storage**: Store each column separately. Huge I/O savings when queries touch few columns. Enables bitmap encoding, run-length compression, vectorized processing. - ---- - -### Chapter 4: Encoding & Evolution - -#### Format Comparison - -| Format | Size (example) | Schema | Evolution | Cross-language | -|--------|---------------|--------|-----------|----------------| -| JSON | 81 bytes | Implicit | Manual | Excellent | -| Thrift | 59 bytes | Required | Field tags | Good | -| Protobuf | 33 bytes | Required | Field tags | Excellent | -| Avro | 32 bytes | Required | Name matching | Good | - -#### Compatibility Rules -- **Backward compatible**: New code reads old data. *(Always required)* -- **Forward compatible**: Old code reads new data. *(Required for rolling upgrades)* -- Rule: Only add/remove fields with default values. Never reuse deleted field tags. - -#### Data Flow Patterns -1. **Via databases**: Multiple code versions coexist during rolling deploys. Data outlives code. -2. **Via services (REST/RPC)**: Servers update before clients. Backward compat on requests, forward compat on responses. -3. **Via async messaging**: Decouples producers/consumers. Supports independent version evolution. - -**Avoid**: Language-specific serialization (Java Serializable, Python pickle) — vendor lock-in + security risk. - ---- - -## Part II: Distributed Data - -### Chapter 5: Replication - -#### Replication Models - -| Model | Writes | Conflict | Use Case | -|-------|--------|----------|----------| -| **Single-leader** | One node | None | Most common (PostgreSQL, MySQL) | -| **Multi-leader** | Multiple nodes | Must resolve | Multi-datacenter, offline clients | -| **Leaderless** | Any node | Must resolve | Cassandra, Riak, Voldemort | - -#### Sync vs Async Replication -- **Sync**: Durable, blocks on replica failure. -- **Async**: Fast, risks data loss on leader failure. -- **Semi-sync**: One replica sync, rest async. Practical compromise. - -#### Replication Lag Problems & Solutions - -| Problem | Symptom | Solution | -|---------|---------|----------| -| **Read-after-write** | User doesn't see own write | Read from leader for user's own data | -| **Monotonic reads** | Data goes backward in time | Stick user to one replica | -| **Consistent prefix reads** | Causal order violated | Write causally related data to same partition | - -#### Conflict Resolution -- **Last-Write-Wins (LWW)**: Simple but loses data. Only safe if keys are immutable. -- **Merge**: Union values, concatenate, CRDT data structures. -- **Application-level**: Return all versions ("siblings"), let app decide. -- **Version vectors**: Track causal dependencies per replica. - -#### Quorum: `w + r > n` -- w = write acknowledgments, r = read queries, n = total replicas. -- **Sloppy quorum**: Accept writes on non-home nodes during partitions (hinted handoff). Improves availability, weakens consistency. - ---- - -### Chapter 6: Partitioning (Sharding) - -#### Partitioning Strategies - -| Strategy | Pros | Cons | -|----------|------|------| -| **Key-range** | Efficient range queries | Hotspot risk on sequential keys | -| **Hash** | Even distribution | No range queries | -| **Compound** | First part hashed, rest sorted | More complex, best of both | - -#### Secondary Index Partitioning -- **Local (document-based)**: Each partition indexes its own data. Writes simple, reads scatter-gather. -- **Global (term-based)**: Index partitioned by term. Reads efficient, writes update multiple partitions. - -#### Rebalancing -- **Fixed partition count**: More partitions than nodes. Redistribute on node changes. (Riak, Elasticsearch) -- **Dynamic**: Split/merge based on size. (HBase, RethinkDB) -- **Proportional to nodes**: Fixed partitions per node. (Cassandra) - -#### Request Routing -- Round-robin to any node (node forwards if needed) -- Routing layer (partition-aware proxy) -- Client-aware (client knows partition map) -- **ZooKeeper**: Authoritative partition → node mapping. Used by HBase, Kafka. - ---- - -### Chapter 7: Transactions - -#### Isolation Levels (Weakest → Strongest) - -| Level | Prevents | Allows | Implementation | -|-------|----------|--------|----------------| -| **Read Committed** | Dirty reads, dirty writes | Non-repeatable reads, lost updates | Row locks + old value copy | -| **Snapshot Isolation** | + Non-repeatable reads | Write skew, phantoms | MVCC (multi-version) | -| **Serializable** | Everything | Nothing | 2PL, serial execution, or SSI | - -#### Concurrency Anomalies - -| Anomaly | Description | Example | -|---------|-------------|---------| -| **Dirty read** | See uncommitted data | Reading half-written transfer | -| **Dirty write** | Overwrite uncommitted data | Two buyers "winning" same item | -| **Lost update** | Read-modify-write race | Two concurrent counter increments | -| **Write skew** | Decision based on stale read | Two doctors both going off-call | -| **Phantom** | New rows change query result | Meeting room double-booking | - -#### Serializable Implementations -1. **Serial execution**: Single thread, in-memory. Fast but limited throughput. (VoltDB, Redis) -2. **Two-Phase Locking (2PL)**: Shared/exclusive locks held until commit. Strong but slow, deadlock-prone. -3. **SSI (Serializable Snapshot Isolation)**: Optimistic — execute freely, detect conflicts at commit. Best performance for read-heavy workloads. (PostgreSQL 9.1+) - ---- - -### Chapter 8: Troubles with Distributed Systems - -#### The Three Unreliabilities - -**Networks**: Async packet networks — no delivery guarantee, no timing guarantee. Cannot distinguish crash from network delay. Timeouts are the only failure detector, but no correct timeout value exists. - -**Clocks**: -- Wall clocks: Can jump backward (NTP correction). Never use for ordering events. -- Monotonic clocks: Safe for elapsed time, not cross-node comparison. -- Quartz drift: ~200ppm → 6ms error every 30 seconds. - -**Processes**: GC pauses, VM suspension, page faults — threads stop without warning. A paused node doesn't know time passed. - -#### Key Principles -- **Fault ≠ failure**: Design for partial failures. Some nodes work while others don't. -- **Truth is defined by majority**: Individual nodes cannot determine system state alone. Quorum votes decide. -- **Fencing tokens**: Monotonically increasing tokens prevent zombie processes from corrupting state. -- **Safety vs liveness**: Safety (bad things never happen) must hold always. Liveness (good things eventually happen) may have conditions. - ---- - -### Chapter 9: Consistency & Consensus - -#### Consistency Models (Strongest → Weakest) - -| Model | Guarantee | Cost | -|-------|-----------|------| -| **Linearizability** | Behaves as if one copy, all ops atomic | High latency, reduced availability during partition | -| **Causal consistency** | Respects cause-effect ordering | Better performance, partition-tolerant | -| **Eventual consistency** | Replicas converge eventually | Best performance, weakest guarantee | - -#### Linearizability Use Cases -- Leader election / distributed locks -- Uniqueness constraints (usernames, filenames) -- Cross-channel coordination (message queue + storage) - -#### Consensus Algorithms -- **2PC**: Coordinator-based, blocking on coordinator failure. Practical but fragile. -- **Paxos/Raft/Zab**: Epoch-based leader election + quorum voting. Non-blocking. Used by etcd, ZooKeeper, Consul. -- **FLP impossibility**: Consensus impossible in pure async systems with crashes. Practical algorithms use timeouts. - -#### Total Order Broadcast ≡ Consensus ≡ Linearizable CAS -These three problems are mathematically equivalent. Solving one solves all. - -#### ZooKeeper / etcd Pattern -- Small consensus cluster (3–5 nodes) for coordination. -- Linearizable atomic CAS operations. -- Failure detection via session heartbeats. -- Applications: leader election, partition assignment, distributed locks, service discovery. - ---- - -## Part III: Derived Data - -### Chapter 10: Batch Processing - -#### Unix Philosophy → MapReduce -- Each program does one thing well. -- Output of one program = input of another. -- Immutable inputs, deterministic processing. - -#### MapReduce Pipeline -`Input → Mapper (extract key-value) → Sort/Partition → Reducer (aggregate by key) → Output` - -#### Distributed Join Strategies - -| Join Type | When | How | -|-----------|------|-----| -| **Sort-merge** | Both inputs large | Sort by join key, merge in reducer | -| **Broadcast hash** | One input small (fits in RAM) | Load small side as hash table | -| **Partitioned hash** | Both inputs partitioned identically | Per-partition hash join | - -#### Beyond MapReduce: Dataflow Engines (Spark, Flink, Tez) -- Treat entire workflow as single job. -- Pipeline intermediate results (avoid full materialization to HDFS). -- Keep data in memory where possible. -- Track computation lineage for fault recovery (RDDs). -- Support iterative algorithms (graph processing via Pregel/BSP model). - ---- - -### Chapter 11: Stream Processing - -#### Message Broker Models - -| Model | Delivery | Ordering | Replay | Use Case | -|-------|----------|----------|--------|----------| -| **AMQP/JMS** | Per-message ack, delete after | No ordering guarantee | No | Task queues, async RPC | -| **Log-based (Kafka)** | Offset-based, retained | Per-partition ordering | Yes | Event streaming, CDC | - -#### Change Data Capture (CDC) -Extract database changes as event stream → keep derived systems (search indexes, caches, warehouses) in sync. **Source of truth stays in database; derived views are consumers.** - -#### Event Sourcing -Model state as append-only sequence of business events (not DB operations). Events are immutable facts. Current state = fold over event history. - -#### Stream Joins - -| Join | Input A | Input B | State | -|------|---------|---------|-------| -| **Stream-Stream** | Events | Events | Time-windowed buffer | -| **Stream-Table** | Events | DB snapshot (via CDC) | Local materialized table | -| **Table-Table** | CDC stream | CDC stream | Derived materialized view | - -#### Time & Windowing - -| Window | Description | -|--------|-------------| -| **Tumbling** | Fixed-size, non-overlapping (e.g., every 1 min) | -| **Hopping** | Fixed-size, overlapping (e.g., 1 min window every 30s) | -| **Sliding** | All events within time threshold of each other | -| **Session** | Grouped by activity gap (e.g., 30 min inactivity) | - -**Event time ≠ processing time.** Always use event time for correctness. Handle late events with watermarks or correction publishes. - -#### Processing Guarantees -- **Microbatching** (Spark Streaming): ~1s latency, atomic small batches. -- **Checkpointing** (Flink): Periodic snapshots with message barriers. -- **Idempotency**: Deduplicate using message offsets or unique IDs. -- End-to-end exactly-once requires idempotent output + deduplication. - ---- - -### Chapter 12: The Future of Data Systems - -#### Data Integration Pattern -No single database does everything. Use **event log as integration backbone**: -1. All writes go through authoritative event log. -2. Derived systems (indexes, caches, ML models) consume the log. -3. Deterministic, idempotent functions transform between layers. - -#### Unbundling Databases -Separate concerns: -- **Record system**: Captures authoritative writes. -- **Derived systems**: Indexes, caches, materialized views consume change streams. -- Enables gradual migration — run old and new systems in parallel. - -#### End-to-End Exactly-Once -Low-level guarantees (TCP, DB transactions) don't ensure application correctness. Require: -- **Operation identifiers**: UUID-based deduplication at application level. -- **Idempotent operations**: Same effect whether executed once or many times. -- **Unique constraint enforcement**: Via partitioned stream processing. - -#### Async Constraint Enforcement -Instead of distributed transactions: -1. Route requests by constraint field to partitioned log. -2. Stream processor sequences competing requests. -3. Reject violations, notify clients via output stream. -4. Some applications tolerate temporary violations with compensating transactions. - -#### Auditability -- Treat data like immutable event log — enables reconstruction and verification. -- Implement cryptographic audit trails (Merkle trees). -- Periodically test backup restoration and data reconstruction. - ---- - -## Decision Framework: Quick Reference - -### Choosing a Data Model -``` -Many-to-many relationships? → Relational or Graph -Hierarchical / nested data? → Document -Highly connected data? → Graph -Flexible / evolving schema? → Document (schema-on-read) -Strong consistency required? → Relational (ACID) -``` - -### Choosing a Storage Engine -``` -Write-heavy workload? → LSM-tree (RocksDB, Cassandra) -Read-heavy, predictable? → B-tree (PostgreSQL, MySQL) -Analytical queries? → Column store (ClickHouse, Redshift) -Full-text search? → Inverted index (Elasticsearch) -``` - -### Choosing a Replication Strategy -``` -Single datacenter? → Single-leader -Multi-datacenter? → Multi-leader -Offline-first clients? → Multi-leader or Leaderless -Maximum availability? → Leaderless with sloppy quorum -Strong consistency? → Single-leader with sync replication -``` - -### Choosing an Isolation Level -``` -Read-only analytics? → Snapshot isolation -General OLTP? → Read committed (default in most DBs) -Financial / critical? → Serializable (prefer SSI over 2PL) -High write contention? → Serial execution (if data fits in RAM) -``` - -### Choosing Batch vs Stream -``` -Historical data reprocessing? → Batch (Spark, Flink batch mode) -Real-time derived views? → Stream (Kafka + Flink/Spark Streaming) -Both needed? → Unified engine (Flink) over Lambda architecture -``` diff --git a/builtin-skills/software-engineer/devops-engineer/SKILL.md b/builtin-skills/software-engineer/devops-engineer/SKILL.md deleted file mode 100644 index d5dd170d..00000000 --- a/builtin-skills/software-engineer/devops-engineer/SKILL.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -name: devops-engineer -description: Creates Dockerfiles, configures CI/CD pipelines, writes Kubernetes manifests, and generates Terraform/Pulumi infrastructure templates. Handles deployment automation, GitOps configuration, incident response runbooks, and internal developer platform tooling. Use when setting up CI/CD pipelines, containerizing applications, managing infrastructure as code, deploying to Kubernetes clusters, configuring cloud platforms, automating releases, or responding to production incidents. Invoke for pipelines, Docker, Kubernetes, GitOps, Terraform, GitHub Actions, on-call, or platform engineering. -license: MIT -metadata: - author: https://github.com/Jeffallan - version: "1.1.1" - domain: devops - triggers: DevOps, CI/CD, deployment, Docker, Kubernetes, Terraform, GitHub Actions, infrastructure, platform engineering, incident response, on-call, self-service - role: engineer - scope: implementation - output-format: code - related-skills: terraform-engineer, kubernetes-specialist, sre-engineer, monitoring-expert, security-reviewer ---- - -# DevOps Engineer - -Senior DevOps engineer specializing in CI/CD pipelines, infrastructure as code, and deployment automation. - -## Role Definition - -You are a senior DevOps engineer with 10+ years of experience. You operate with three perspectives: -- **Build Hat**: Automating build, test, and packaging -- **Deploy Hat**: Orchestrating deployments across environments -- **Ops Hat**: Ensuring reliability, monitoring, and incident response - -## When to Use This Skill - -- Setting up CI/CD pipelines (GitHub Actions, GitLab CI, Jenkins) -- Containerizing applications (Docker, Docker Compose) -- Kubernetes deployments and configurations -- Infrastructure as code (Terraform, Pulumi) -- Cloud platform configuration (AWS, GCP, Azure) -- Deployment strategies (blue-green, canary, rolling) -- Building internal developer platforms and self-service tools -- Incident response, on-call, and production troubleshooting -- Release automation and artifact management - -## Core Workflow - -1. **Assess** - Understand application, environments, requirements -2. **Design** - Pipeline structure, deployment strategy -3. **Implement** - IaC, Dockerfiles, CI/CD configs -4. **Validate** - Run `terraform plan`, lint configs, execute unit/integration tests; confirm no destructive changes before proceeding -5. **Deploy** - Roll out with verification; run smoke tests post-deployment -6. **Monitor** - Set up observability, alerts; confirm rollback procedure is ready before going live - -## Reference Guide - -Load detailed guidance based on context: - -| Topic | Reference | Load When | -|-------|-----------|-----------| -| GitHub Actions | `references/github-actions.md` | Setting up CI/CD pipelines, GitHub workflows | -| Docker | `references/docker-patterns.md` | Containerizing applications, writing Dockerfiles | -| Kubernetes | `references/kubernetes.md` | K8s deployments, services, ingress, pods | -| Terraform | `references/terraform-iac.md` | Infrastructure as code, AWS/GCP provisioning | -| Deployment | `references/deployment-strategies.md` | Blue-green, canary, rolling updates, rollback | -| Platform | `references/platform-engineering.md` | Self-service infra, developer portals, golden paths, Backstage | -| Release | `references/release-automation.md` | Artifact management, feature flags, multi-platform CI/CD | -| Incidents | `references/incident-response.md` | Production outages, on-call, MTTR, postmortems, runbooks | - -## Constraints - -### MUST DO -- Use infrastructure as code (never manual changes) -- Implement health checks and readiness probes -- Store secrets in secret managers (not env files) -- Enable container scanning in CI/CD -- Document rollback procedures -- Use GitOps for Kubernetes (ArgoCD, Flux) - -### MUST NOT DO -- Deploy to production without explicit approval -- Store secrets in code or CI/CD variables -- Skip staging environment testing -- Ignore resource limits in containers -- Use `latest` tag in production -- Deploy on Fridays without monitoring - -## Output Templates - -Provide: CI/CD pipeline config, Dockerfile, K8s/Terraform files, deployment verification, rollback procedure - -### Minimal GitHub Actions Example - -```yaml -name: CI -on: - push: - branches: [main] -jobs: - build-test-push: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build image - run: docker build -t myapp:${{ github.sha }} . - - name: Run tests - run: docker run --rm myapp:${{ github.sha }} pytest - - name: Scan image - uses: aquasecurity/trivy-action@master - with: - image-ref: myapp:${{ github.sha }} - - name: Push to registry - run: | - docker tag myapp:${{ github.sha }} ghcr.io/org/myapp:${{ github.sha }} - docker push ghcr.io/org/myapp:${{ github.sha }} -``` - -### Minimal Dockerfile Example - -```dockerfile -FROM python:3.12-slim AS builder -WORKDIR /app -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -FROM python:3.12-slim -WORKDIR /app -COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages -COPY . . -USER nonroot -HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/health || exit 1 -CMD ["python", "main.py"] -``` - -### Rollback Procedure Example - -```bash -# Kubernetes: roll back to previous deployment revision -kubectl rollout undo deployment/myapp -n production -kubectl rollout status deployment/myapp -n production - -# Verify rollback succeeded -kubectl get pods -n production -l app=myapp -curl -f https://myapp.example.com/health -``` - -Always document the rollback command and verification step in the PR or change ticket before deploying. - -## Knowledge Reference - -GitHub Actions, GitLab CI, Jenkins, CircleCI, Docker, Kubernetes, Helm, ArgoCD, Flux, Terraform, Pulumi, Crossplane, AWS/GCP/Azure, Prometheus, Grafana, PagerDuty, Backstage, LaunchDarkly, Flagger diff --git a/builtin-skills/software-engineer/devops-engineer/references/deployment-strategies.md b/builtin-skills/software-engineer/devops-engineer/references/deployment-strategies.md deleted file mode 100644 index 795bdd94..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/deployment-strategies.md +++ /dev/null @@ -1,241 +0,0 @@ -# Deployment Strategies - -## Strategy Comparison - -| Strategy | Use When | Rollback | Risk | -|----------|----------|----------|------| -| **Rolling** | Standard updates, can tolerate mixed versions | Automatic via health checks | Low | -| **Blue-Green** | Zero downtime, instant rollback needed | Switch traffic to old env | Medium | -| **Canary** | Risk mitigation, gradual rollout | Scale down canary | Low | -| **Recreate** | Stateful apps, breaking changes | Redeploy previous version | High | - -## Rolling Deployment (Kubernetes) - -```yaml -apiVersion: apps/v1 -kind: Deployment -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 25% # Max pods above desired - maxUnavailable: 25% # Max pods unavailable -``` - -## Blue-Green with Ingress - -```yaml -# Blue deployment (current) -apiVersion: apps/v1 -kind: Deployment -metadata: - name: app-blue - labels: - version: blue ---- -# Green deployment (new) -apiVersion: apps/v1 -kind: Deployment -metadata: - name: app-green - labels: - version: green ---- -# Service pointing to active version -apiVersion: v1 -kind: Service -metadata: - name: app -spec: - selector: - version: blue # Switch to 'green' for cutover -``` - -## Canary with Istio - -```yaml -apiVersion: networking.istio.io/v1beta1 -kind: VirtualService -metadata: - name: app -spec: - hosts: - - app - http: - - match: - - headers: - canary: - exact: "true" - route: - - destination: - host: app-canary - - route: - - destination: - host: app-stable - weight: 90 - - destination: - host: app-canary - weight: 10 -``` - -## Rollback Procedures - -### Kubernetes Rollback -```bash -# View rollout history -kubectl rollout history deployment/app - -# Rollback to previous -kubectl rollout undo deployment/app - -# Rollback to specific revision -kubectl rollout undo deployment/app --to-revision=2 - -# Check status -kubectl rollout status deployment/app -``` - -### ArgoCD Rollback -```bash -argocd app rollback app-prod --revision=123 -``` - -### Terraform Rollback -```bash -# Identify previous state -terraform state list - -# Import previous configuration -git checkout HEAD~1 -- main.tf -terraform apply -``` - -## Pre-deployment Checklist - -- [ ] Database migrations are backward compatible -- [ ] Feature flags for new functionality -- [ ] Monitoring dashboards updated -- [ ] Alert thresholds reviewed -- [ ] Rollback procedure documented -- [ ] Staging tested and approved -- [ ] Team notified of deployment window - -## Post-deployment Verification - -```bash -# Check pod status -kubectl get pods -l app=app - -# Check logs for errors -kubectl logs -l app=app --tail=100 | grep -i error - -# Verify endpoints -curl -f https://app.example.com/health - -# Check metrics -# - Error rate < 1% -# - Latency p99 < 500ms -# - No memory/CPU spikes -``` - -## Deployment Metrics (DORA) - -Track four key metrics: -- **Deployment Frequency**: Target 10+/day -- **Lead Time for Changes**: Target <1 hour -- **Change Failure Rate**: Target <5% -- **MTTR**: Target <30 minutes - -```yaml -# Prometheus metrics for DORA tracking -- record: deployment:frequency:1d - expr: count_over_time(deployment_completed[1d]) - -- record: deployment:lead_time:p95 - expr: histogram_quantile(0.95, - rate(commit_to_deploy_seconds_bucket[1h])) - -- record: deployment:failure_rate - expr: | - sum(rate(deployment_failed[1h])) - / sum(rate(deployment_total[1h])) -``` - -## Advanced Canary with Automated Analysis - -```yaml -# Flagger: Automated canary with rollback -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: api -spec: - provider: istio - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: api - progressDeadlineSeconds: 60 - service: - port: 8080 - trafficPolicy: - tls: - mode: ISTIO_MUTUAL - analysis: - interval: 30s - threshold: 5 - maxWeight: 50 - stepWeight: 10 - metrics: - - name: error-rate - templateRef: - name: error-rate - thresholdRange: - max: 1 - - name: latency - templateRef: - name: latency - thresholdRange: - max: 500 - webhooks: - - name: acceptance-test - type: pre-rollout - url: http://test-runner/ - - name: load-test - url: http://loadtester/ - timeout: 5s - metadata: - type: bash - cmd: "hey -z 1m -q 10 http://api-canary:8080/" -``` - -## Shadow Deployment - -```yaml -# Mirror traffic to shadow deployment -apiVersion: networking.istio.io/v1beta1 -kind: VirtualService -metadata: - name: api -spec: - hosts: - - api - http: - - match: - - headers: - x-test-version: - exact: "v2" - route: - - destination: - host: api - subset: v2 - mirror: - host: api - subset: v2-shadow - mirrorPercentage: - value: 100 - - route: - - destination: - host: api - subset: v1 -``` diff --git a/builtin-skills/software-engineer/devops-engineer/references/docker-patterns.md b/builtin-skills/software-engineer/devops-engineer/references/docker-patterns.md deleted file mode 100644 index f5523e7f..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/docker-patterns.md +++ /dev/null @@ -1,113 +0,0 @@ -# Docker Patterns - -## Multi-stage Dockerfile (Node.js) - -```dockerfile -# Build stage -FROM node:20-alpine AS builder -WORKDIR /app -COPY package*.json ./ -RUN npm ci --only=production && npm cache clean --force -COPY . . -RUN npm run build - -# Production stage -FROM node:20-alpine AS runner -WORKDIR /app -ENV NODE_ENV=production -RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 -COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist -COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules -USER nodejs -EXPOSE 3000 -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \ - CMD wget -qO- http://localhost:3000/health || exit 1 -CMD ["node", "dist/main.js"] -``` - -## Multi-stage Dockerfile (Python) - -```dockerfile -FROM python:3.12-slim AS builder -WORKDIR /app -RUN pip install --no-cache-dir poetry -COPY pyproject.toml poetry.lock ./ -RUN poetry export -f requirements.txt --output requirements.txt -RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt - -FROM python:3.12-slim AS runner -WORKDIR /app -RUN useradd -m -u 1001 appuser -COPY --from=builder /wheels /wheels -RUN pip install --no-cache-dir /wheels/* -COPY --chown=appuser:appuser . . -USER appuser -EXPOSE 8000 -HEALTHCHECK --interval=30s --timeout=3s \ - CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] -``` - -## Docker Compose (Development) - -```yaml -version: '3.8' -services: - app: - build: - context: . - target: builder # Use dev stage - volumes: - - .:/app - - /app/node_modules - ports: - - "3000:3000" - environment: - - DATABASE_URL=postgres://user:pass@db:5432/app - depends_on: - db: - condition: service_healthy - - db: - image: postgres:16-alpine - environment: - POSTGRES_USER: user - POSTGRES_PASSWORD: pass - POSTGRES_DB: app - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d app"] - interval: 5s - timeout: 5s - retries: 5 - -volumes: - postgres_data: -``` - -## Security Best Practices - -| Practice | Implementation | -|----------|----------------| -| Non-root user | `USER nodejs` or `USER 1001` | -| Minimal base image | Use `-alpine` or `-slim` variants | -| No secrets in image | Use runtime env vars or secrets | -| Pin versions | `FROM node:20.10.0-alpine` not `latest` | -| Scan images | `docker scout`, `trivy`, `snyk` | -| Health checks | `HEALTHCHECK` instruction | -| .dockerignore | Exclude `node_modules`, `.git`, `.env` | - -## .dockerignore Template - -``` -node_modules -.git -.env* -*.md -Dockerfile* -docker-compose* -.dockerignore -coverage -.nyc_output -``` diff --git a/builtin-skills/software-engineer/devops-engineer/references/github-actions.md b/builtin-skills/software-engineer/devops-engineer/references/github-actions.md deleted file mode 100644 index 367c273d..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/github-actions.md +++ /dev/null @@ -1,139 +0,0 @@ -# GitHub Actions Pipelines - -## Complete CI/CD Pipeline - -```yaml -name: CI/CD Pipeline - -on: - push: - branches: [main, develop] - pull_request: - branches: [main] - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - run: npm ci - - run: npm test - - run: npm run lint - - build: - needs: test - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - outputs: - image-tag: ${{ steps.meta.outputs.tags }} - steps: - - uses: actions/checkout@v4 - - uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=sha,prefix= - type=ref,event=branch - - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - cache-from: type=gha - cache-to: type=gha,mode=max - - deploy-staging: - needs: build - if: github.ref == 'refs/heads/develop' - runs-on: ubuntu-latest - environment: staging - steps: - - uses: actions/checkout@v4 - - run: | - kubectl set image deployment/app app=${{ needs.build.outputs.image-tag }} - - deploy-production: - needs: build - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - environment: production - steps: - - uses: actions/checkout@v4 - - run: | - kubectl set image deployment/app app=${{ needs.build.outputs.image-tag }} -``` - -## Common Workflow Patterns - -### Matrix Builds (Multi-version testing) -```yaml -jobs: - test: - strategy: - matrix: - node-version: [18, 20, 22] - os: [ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} -``` - -### Reusable Workflows -```yaml -# .github/workflows/deploy.yml -on: - workflow_call: - inputs: - environment: - required: true - type: string - secrets: - DEPLOY_KEY: - required: true - -jobs: - deploy: - runs-on: ubuntu-latest - environment: ${{ inputs.environment }} - steps: - - run: echo "Deploying to ${{ inputs.environment }}" -``` - -### Caching Dependencies -```yaml -- uses: actions/cache@v4 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- -``` - -## Quick Reference - -| Action | Purpose | -|--------|---------| -| `actions/checkout@v4` | Clone repository | -| `actions/setup-node@v4` | Install Node.js | -| `docker/build-push-action@v5` | Build and push Docker image | -| `docker/metadata-action@v5` | Generate Docker tags | -| `actions/cache@v4` | Cache dependencies | diff --git a/builtin-skills/software-engineer/devops-engineer/references/incident-response.md b/builtin-skills/software-engineer/devops-engineer/references/incident-response.md deleted file mode 100644 index 1ff77317..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/incident-response.md +++ /dev/null @@ -1,331 +0,0 @@ -# Incident Response - -## Response Metrics - -- **MTTD** (Mean Time to Detect): Target < 5 minutes -- **MTTA** (Mean Time to Acknowledge): Target < 5 minutes -- **MTTR** (Mean Time to Resolve): Target < 30 minutes -- **MTBF** (Mean Time Between Failures): Maximize - -### Severity Levels - -| Level | Impact | Response | Example | -|-------|--------|----------|---------| -| SEV1 | Complete outage | Immediate | Database down, payment failed | -| SEV2 | Major degradation | 15 min | API latency >5s, 50% errors | -| SEV3 | Minor degradation | 1 hour | Non-critical feature broken | -| SEV4 | Low impact | Business hours | UI glitch, logging issues | - -## Runbook Template - -```markdown -# Runbook: High API Error Rate - -## Symptoms -- Alert: `api_error_rate > 0.05` -- Dashboard: https://grafana.example.com/d/api-errors - -## Impact -Users cannot complete purchases (~$X per minute) - -## Triage -1. Check dashboard for affected endpoints -2. Check recent deployments: `kubectl rollout history deployment/api` -3. Check dependencies: database, redis, external APIs - -## Resolution - -### Option 1: Rollback -kubectl rollout undo deployment/api -n production - -### Option 2: Scale Up -kubectl scale deployment/api --replicas=10 -n production - -### Option 3: Fix Config -kubectl set env deployment/api DB_POOL_SIZE=50 -n production - -## Verification -- [ ] Error rate <1% -- [ ] P95 latency <500ms -- [ ] Health checks passing - -## Communication -- Update status page -- Notify #incidents -- Post if user-facing -``` - -## Auto-Remediation Script - -```python -#!/usr/bin/env python3 -import kubernetes, prometheus_api_client - -class IncidentRemediator: - def check_high_error_rate(self): - query = 'rate(http_requests_total{status=~"5.."}[5m]) > 0.05' - result = self.prometheus.custom_query(query) - return len(result) > 0 - - def rollback_deployment(self, namespace, deployment): - body = {'spec': {'rollbackTo': {'revision': 0}}} - self.k8s.patch_namespaced_deployment(deployment, namespace, body) - - def remediate(self): - if self.check_high_error_rate(): - if self.rollback_deployment('production', 'api'): - time.sleep(120) - if not self.check_high_error_rate(): - return # Success - # Escalate if remediation fails - self.create_incident("Auto-remediation failed") -``` - -## Postmortem Template - -```markdown -# Postmortem: API Outage - 2024-01-15 - -**Date**: January 15, 2024 -**Duration**: 45 minutes (14:23 - 15:08 UTC) -**Severity**: SEV1 -**Impact**: Complete API outage, ~$25K revenue loss - -## Summary -API became unresponsive due to database connection pool exhaustion -from slow query in v2.3.1. - -## Timeline (UTC) -- 14:23 - Alert fired -- 14:27 - Incident declared SEV1 -- 14:30 - Rollback initiated -- 14:45 - Identified slow query -- 14:50 - Killed queries -- 15:08 - Resolved - -## Root Cause -New query missing index on `user_id`, causing full table scans that -exhausted connection pool under load. - -## Impact -- 100% API failure for 45 minutes -- 15,000 users affected -- $25K revenue loss -- 200+ support tickets - -## Action Items -| Action | Owner | Deadline | -|--------|-------|----------| -| Add index on user_id | DB team | 2024-01-16 | -| Add query perf testing | Platform | 2024-01-22 | -| Increase staging DB size | Infra | 2024-01-30 | - -## Lessons Learned -- Performance testing must use production-scale data -- Connection pool exhaustion needs active intervention -- Consider circuit breakers for DB operations -``` - -## PagerDuty Configuration - -```yaml -schedules: - - name: Primary On-Call - time_zone: America/New_York - layers: - - rotation_turn_length_seconds: 604800 # 1 week - users: [PXXXXXX, PXXXXXX, PXXXXXX] - -escalation_policies: - - name: Production - rules: - - escalation_delay_in_minutes: 0 - targets: [{type: schedule, id: primary}] - - escalation_delay_in_minutes: 15 - targets: [{type: schedule, id: secondary}] - - escalation_delay_in_minutes: 30 - targets: [{type: user, id: manager}] -``` - -## Chaos Engineering - -```yaml -# chaos-mesh: Pod failure test -apiVersion: chaos-mesh.org/v1alpha1 -kind: PodChaos -metadata: - name: pod-failure-test -spec: - action: pod-failure - mode: one - duration: "30s" - selector: - namespaces: [production] - labelSelectors: - app: api - scheduler: - cron: "@every 2h" -``` - -```bash -#!/bin/bash -# Game Day: Database failover drill - -echo "🎮 Game Day: Database failover" -slack-cli -d incidents "Starting failover drill" - -# Simulate failure -kubectl delete pod postgres-0 -n production - -# Monitor recovery -start=$(date +%s) -while ! kubectl get pod postgres-1 | grep Running; do - sleep 5 -done -duration=$(($(date +%s) - start)) - -echo "Failover: ${duration}s" >> results.md -curl -f https://api.example.com/health || echo "FAIL" -``` - -## Evidence Collection & Forensics - -```bash -#!/bin/bash -# collect-evidence.sh - Preserve incident evidence - -INCIDENT_ID=$1 -EVIDENCE_DIR="incidents/${INCIDENT_ID}/evidence" -mkdir -p $EVIDENCE_DIR - -# Preserve logs -kubectl logs -l app=api --all-containers --timestamps \ - --since=2h > $EVIDENCE_DIR/pod-logs.txt - -# Capture current state -kubectl get all -n production -o yaml > $EVIDENCE_DIR/k8s-state.yaml -kubectl describe pods -n production > $EVIDENCE_DIR/pod-details.txt - -# Network traces -kubectl exec -n production deploy/api -- \ - tcpdump -i any -w /tmp/capture.pcap -G 60 -W 5 & - -# Memory/CPU snapshot -kubectl top pods -n production > $EVIDENCE_DIR/resource-usage.txt - -# Git commit at time of incident -git log --since="2 hours ago" --oneline > $EVIDENCE_DIR/recent-commits.txt - -# Database queries -psql -c "SELECT * FROM pg_stat_activity" > $EVIDENCE_DIR/db-activity.txt - -# Create timeline -echo "$(date): Evidence collection completed" >> $EVIDENCE_DIR/timeline.txt -``` - -## Communication Templates - -```markdown -## SEV1 Initial Notification - -**INCIDENT ALERT - SEV1** - -**Status**: Investigating -**Impact**: Payment API unavailable (100% error rate) -**Started**: 2024-01-15 14:23 UTC -**Affected**: All users (~15K active sessions) -**Lead**: @oncall-engineer -**War Room**: https://zoom.us/incident-123 - -Updates every 15 minutes or on major change. - ---- - -## SEV1 Resolution Notification - -**INCIDENT RESOLVED** - -**Summary**: Payment API restored after database connection pool exhaustion -**Duration**: 45 minutes (14:23 - 15:08 UTC) -**Resolution**: Rollback to v2.3.0 + query optimization -**Impact**: 15K users, ~$25K revenue loss -**Next Steps**: Postmortem scheduled for Jan 16 10am - -Thanks to @oncall-team for rapid response. -``` - -## Incident Classification - -| Type | Examples | Response Team | Escalation | -|------|----------|---------------|------------| -| **Security** | Breach, data leak, unauthorized access | Security + DevOps | CISO, Legal | -| **Service** | Outage, degradation, errors | DevOps + SRE | Engineering VP | -| **Data** | Corruption, loss, sync issues | DBA + DevOps | CTO | -| **Compliance** | GDPR, SOC2, audit violations | Compliance + Legal | CEO | -| **Third-party** | Provider outage, API failures | DevOps + Product | Account manager | - -## Security Incident Specifics - -```bash -# Compromise investigation checklist -□ Isolate affected systems -□ Preserve logs and memory dumps -□ Identify attack vector -□ Check for lateral movement -□ Scan for malware/backdoors -□ Review access logs for 30 days -□ Identify data accessed -□ Assess exfiltration risk -□ Check for persistence mechanisms -□ Coordinate with security team -□ Notify legal if PII involved -□ Document chain of custody -``` - -## Compliance Requirements - -```yaml -# Incident notification requirements -gdpr: - notification_deadline: 72h - authority: Data Protection Officer - required_info: - - Nature of breach - - Data categories affected - - Number of individuals - - Consequences - - Remediation measures - -sox: - notification_deadline: immediate - authority: Audit Committee - documentation: - - Financial impact - - Control failures - - Remediation plan - -pci_dss: - notification_deadline: 24h - authority: Card brands + acquirer - required_info: - - Cardholder data affected - - Incident timeline - - Forensic investigation -``` - -## Best Practices - -- Maintain runbooks for critical services -- Practice with game days monthly -- Automate common remediation -- Keep postmortems blameless -- Track incident metrics -- Test recovery procedures -- Document all incidents -- Improve detection continuously -- Preserve evidence chain properly -- Coordinate communication clearly -- Escalate security incidents immediately -- Understand compliance obligations -- Train team on response procedures -- Review and update playbooks quarterly diff --git a/builtin-skills/software-engineer/devops-engineer/references/kubernetes.md b/builtin-skills/software-engineer/devops-engineer/references/kubernetes.md deleted file mode 100644 index 1bb44f7c..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/kubernetes.md +++ /dev/null @@ -1,154 +0,0 @@ -# Kubernetes Manifests - -## Complete Deployment Stack - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: app - labels: - app: app -spec: - replicas: 3 - selector: - matchLabels: - app: app - template: - metadata: - labels: - app: app - spec: - containers: - - name: app - image: ghcr.io/org/app:latest - ports: - - containerPort: 3000 - resources: - requests: - memory: "128Mi" - cpu: "100m" - limits: - memory: "256Mi" - cpu: "500m" - livenessProbe: - httpGet: - path: /health - port: 3000 - initialDelaySeconds: 10 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /ready - port: 3000 - initialDelaySeconds: 5 - periodSeconds: 5 - env: - - name: DATABASE_URL - valueFrom: - secretKeyRef: - name: app-secrets - key: database-url ---- -apiVersion: v1 -kind: Service -metadata: - name: app -spec: - selector: - app: app - ports: - - port: 80 - targetPort: 3000 - type: ClusterIP ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: app - annotations: - cert-manager.io/cluster-issuer: letsencrypt-prod -spec: - ingressClassName: nginx - tls: - - hosts: [app.example.com] - secretName: app-tls - rules: - - host: app.example.com - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: app - port: - number: 80 -``` - -## ConfigMap and Secrets - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: app-config -data: - LOG_LEVEL: "info" - API_TIMEOUT: "30s" ---- -apiVersion: v1 -kind: Secret -metadata: - name: app-secrets -type: Opaque -stringData: - database-url: "postgres://user:pass@host:5432/db" -``` - -## Horizontal Pod Autoscaler - -```yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: app-hpa -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: app - minReplicas: 2 - maxReplicas: 10 - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 70 -``` - -## Quick Reference - -| Resource | Purpose | -|----------|---------| -| Deployment | Manages ReplicaSets, rolling updates | -| Service | Internal load balancing, DNS | -| Ingress | External HTTP/HTTPS routing | -| ConfigMap | Non-sensitive configuration | -| Secret | Sensitive data (base64 encoded) | -| HPA | Auto-scaling based on metrics | -| PVC | Persistent storage claims | - -## Common kubectl Commands - -```bash -kubectl apply -f deployment.yaml -kubectl get pods -l app=app -kubectl describe pod -kubectl logs -f -kubectl exec -it -- /bin/sh -kubectl rollout status deployment/app -kubectl rollout undo deployment/app -``` diff --git a/builtin-skills/software-engineer/devops-engineer/references/platform-engineering.md b/builtin-skills/software-engineer/devops-engineer/references/platform-engineering.md deleted file mode 100644 index cf9f081b..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/platform-engineering.md +++ /dev/null @@ -1,417 +0,0 @@ -# Platform Engineering - -## Platform Principles - -- **Self-service first**: Reduce manual work to <10% -- **Golden paths**: Pre-approved, opinionated templates -- **Developer experience**: Measure and optimize productivity -- **Platform as product**: Treat with product mindset - -## Self-Service with Crossplane - -```yaml -# Composition for self-service database -apiVersion: apiextensions.crossplane.io/v1 -kind: Composition -metadata: - name: postgres-database -spec: - compositeTypeRef: - apiVersion: platform.example.com/v1alpha1 - kind: Database - resources: - - name: rds-instance - base: - apiVersion: rds.aws.crossplane.io/v1alpha1 - kind: DBInstance - spec: - forProvider: - dbInstanceClass: db.t3.micro - engine: postgres - engineVersion: "15" - masterUsername: admin - allocatedStorage: 20 -``` - -## Terraform Self-Service Module - -```hcl -# modules/service/main.tf -variable "service_name" {} -variable "environment" {} - -module "k8s_service" { - source = "./k8s-deployment" - name = var.service_name - env = var.environment -} - -module "database" { - source = "./postgres" - name = "${var.service_name}-db" -} - -module "monitoring" { - source = "./monitoring-stack" - service = var.service_name -} - -output "service_url" { - value = module.k8s_service.url -} -``` - -## Backstage Service Template - -```yaml -# templates/microservice/template.yaml -apiVersion: scaffolder.backstage.io/v1beta3 -kind: Template -metadata: - name: microservice-template - title: Microservice Golden Path -spec: - owner: platform-team - type: service - parameters: - - title: Service Info - properties: - name: - type: string - owner: - type: string - ui:field: OwnerPicker - language: - type: string - enum: [go, python, nodejs, java] - steps: - - id: fetch - action: fetch:template - input: - url: ./skeleton - values: - name: ${{ parameters.name }} - - id: publish - action: publish:github - input: - repoUrl: github.com?owner=org&repo=${{ parameters.name }} - - id: register - action: catalog:register -``` - -## Service Catalog Info - -```yaml -# catalog-info.yaml -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: payment-service - annotations: - github.com/project-slug: org/payment-service - pagerduty.com/integration-key: abc123 - grafana/dashboard-selector: service=payment -spec: - type: service - lifecycle: production - owner: payments-team - system: checkout - dependsOn: - - resource:default/payment-db - - component:default/auth-service - providesApis: - - payment-api -``` - -## Golden Path Scaffolding - -```bash -#!/bin/bash -# create-service.sh - Golden path for new services - -SERVICE=$1 -LANG=$2 - -# Create from template -gh repo create "org/$SERVICE" --template "org/template-$LANG" -git clone "git@github.com:org/$SERVICE.git" -cd "$SERVICE" - -# Setup CI/CD -cat > .github/workflows/ci.yml < terraform/main.tf < { - const metrics = { - selfServiceRate: 92, - avgProvisionTime: '3.5min', - uptime: '99.95%', - satisfaction: 4.6 - }; - - return ( - - -

Provision Time: {metrics.avgProvisionTime}

-

Uptime: {metrics.uptime}

-

Satisfaction: {metrics.satisfaction}/5

-
- ); -}; -``` - -## Cost Allocation - -```yaml -# kubecost/allocation.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: cost-allocation -data: - allocation.json: | - { - "defaultLabels": { - "team": "team", - "service": "app", - "environment": "env" - }, - "shareNamespaces": ["kube-system"], - "shareCost": "weighted" - } -``` - -## Platform APIs - -```python -# Platform API for self-service provisioning -from fastapi import FastAPI, Depends -from pydantic import BaseModel - -app = FastAPI() - -class ServiceRequest(BaseModel): - name: str - environment: str - language: str - database: bool = False - -@app.post("/api/v1/services") -async def create_service(request: ServiceRequest): - # Validate and enqueue - task = platform.provision_service( - name=request.name, - env=request.environment, - template=f"golden-path-{request.language}" - ) - return {"task_id": task.id, "status": "provisioning"} - -@app.get("/api/v1/services/{name}/status") -async def service_status(name: str): - return { - "status": "running", - "url": f"https://{name}.example.com", - "health": "healthy", - "cost_mtd": "$142.50" - } -``` - -## Multi-Tenant Architecture - -```yaml -# Policy: Resource quotas per tenant -apiVersion: v1 -kind: ResourceQuota -metadata: - name: team-quota - namespace: team-payments -spec: - hard: - requests.cpu: "20" - requests.memory: 40Gi - persistentvolumeclaims: "10" - services.loadbalancers: "2" ---- -# RBAC: Namespace admin -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: team-admin - namespace: team-payments -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: namespace-admin -subjects: - - kind: Group - name: team-payments -``` - -## Adoption Strategy - -```yaml -# Platform metrics tracking -apiVersion: v1 -kind: ConfigMap -metadata: - name: platform-goals -data: - goals.yaml: | - q1_2024: - self_service_rate: 90% - avg_provision_time: 5min - developer_satisfaction: 4.5/5 - golden_path_adoption: 80% - - tracking: - weekly_provisioning: true - team_feedback: true - support_tickets: true - training_completion: true -``` - -## CLI Tool Example - -```bash -#!/bin/bash -# platform-cli - Self-service CLI - -platform() { - case $1 in - create) - curl -X POST $PLATFORM_API/services \ - -d "{\"name\":\"$2\",\"env\":\"$3\",\"language\":\"$4\"}" - ;; - status) - curl $PLATFORM_API/services/$2/status | jq - ;; - logs) - kubectl logs -l app=$2 -n ${3:-staging} --tail=100 - ;; - cost) - curl $PLATFORM_API/services/$2/cost?period=mtd - ;; - esac -} -``` - -## Best Practices - -- Design for self-service from day one -- Make golden paths the easiest option -- Measure developer satisfaction continuously -- Automate platform operations -- Provide excellent documentation -- Build APIs, not just tools -- Enable safe experimentation -- Maintain backward compatibility -- Treat platform as a product -- Gather and act on feedback -- Track adoption metrics weekly -- Run platform as a product team -- Invest in developer evangelism -- Maintain SLOs for platform uptime -- Provide fast, helpful support diff --git a/builtin-skills/software-engineer/devops-engineer/references/release-automation.md b/builtin-skills/software-engineer/devops-engineer/references/release-automation.md deleted file mode 100644 index ca425192..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/release-automation.md +++ /dev/null @@ -1,527 +0,0 @@ -# Release Automation - -## Artifact Management - -### Container Registry Lifecycle - -```json -{ - "rules": [ - { - "rulePriority": 1, - "description": "Keep last 10 prod images", - "selection": { - "tagStatus": "tagged", - "tagPrefixList": ["prod-"], - "countType": "imageCountMoreThan", - "countNumber": 10 - }, - "action": {"type": "expire"} - }, - { - "rulePriority": 2, - "description": "Remove untagged after 7 days", - "selection": { - "tagStatus": "untagged", - "countType": "sinceImagePushed", - "countUnit": "days", - "countNumber": 7 - }, - "action": {"type": "expire"} - } - ] -} -``` - -### Artifact Promotion - -```yaml -# .github/workflows/promote.yml -name: Artifact Promotion - -on: - workflow_dispatch: - inputs: - image_tag: - required: true - target_env: - type: choice - options: [staging, production] - -jobs: - promote: - runs-on: ubuntu-latest - steps: - - name: Re-tag for environment - run: | - docker pull $REGISTRY/$IMAGE:${{ inputs.image_tag }} - docker tag $REGISTRY/$IMAGE:${{ inputs.image_tag }} \ - $REGISTRY/$IMAGE:${{ inputs.target_env }}-latest - docker push $REGISTRY/$IMAGE:${{ inputs.target_env }}-latest - - - name: Sign artifact - uses: sigstore/cosign-installer@v3 - - run: cosign sign $REGISTRY/$IMAGE:${{ inputs.target_env }}-latest - - - name: Update GitOps - run: | - cd gitops/apps/${{ inputs.target_env }} - yq e '.image.tag = "${{ inputs.image_tag }}"' -i values.yaml - git commit -am "Promote to ${{ inputs.target_env }}" - git push -``` - -## Feature Flags - -### LaunchDarkly Integration - -```python -import launchdarkly - -ld = launchdarkly.get() - -def should_enable(user_id, feature_key): - user = {"key": user_id, "custom": {"groups": get_groups(user_id)}} - return ld.variation(feature_key, user, False) - -# Usage -if should_enable(user.id, "new-payment-flow"): - return new_payment_service.process(payment) -else: - return legacy_payment_service.process(payment) -``` - -### Flagger Progressive Delivery - -```yaml -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: payment-service -spec: - targetRef: - kind: Deployment - name: payment-service - service: - port: 8080 - analysis: - interval: 1m - threshold: 5 - maxWeight: 50 - stepWeight: 10 - metrics: - - name: request-success-rate - thresholdRange: - min: 99 - - name: request-duration - thresholdRange: - max: 500 - webhooks: - - name: load-test - url: http://flagger-loadtester/ - metadata: - cmd: "hey -z 1m -q 10 http://payment-canary/" -``` - -## Multi-Platform CI/CD - -### GitLab CI - -```yaml -stages: [test, build, deploy] - -test: - stage: test - image: node:20 - script: - - npm ci && npm test - -build: - stage: build - image: docker:latest - services: [docker:dind] - script: - - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - -deploy:production: - stage: deploy - script: - - kubectl set image deployment/app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - environment: production - when: manual - only: [main] -``` - -### Jenkins Pipeline - -```groovy -pipeline { - agent any - - environment { - IMAGE = "registry.example.com/app" - } - - stages { - stage('Test') { - steps { - sh 'npm ci && npm test' - junit 'reports/junit.xml' - } - } - - stage('Build') { - steps { - script { - docker.build("${IMAGE}:${BUILD_NUMBER}") - } - } - } - - stage('Security Scan') { - steps { - sh "trivy image ${IMAGE}:${BUILD_NUMBER}" - } - } - - stage('Deploy Staging') { - when { branch 'main' } - steps { - sh "kubectl set image deployment/app app=${IMAGE}:${BUILD_NUMBER} -n staging" - } - } - - stage('Deploy Production') { - when { branch 'main' } - steps { - input 'Deploy to production?' - sh "kubectl set image deployment/app app=${IMAGE}:${BUILD_NUMBER} -n production" - } - } - } - - post { - failure { - slackSend color: 'danger', message: "Build failed: ${JOB_NAME}" - } - } -} -``` - -## Build Optimization - -### Multi-stage Docker Build - -```dockerfile -FROM node:20 AS deps -WORKDIR /app -COPY package*.json ./ -RUN npm ci --only=production - -FROM node:20 AS builder -WORKDIR /app -COPY package*.json ./ -RUN npm ci -COPY . . -RUN npm run build - -FROM node:20-slim AS runner -WORKDIR /app -ENV NODE_ENV production -COPY --from=deps /app/node_modules ./node_modules -COPY --from=builder /app/dist ./dist -USER node -CMD ["node", "dist/main.js"] -``` - -### Parallel Testing - -```yaml -# CircleCI -version: 2.1 -jobs: - test: - parallelism: 4 - docker: - - image: cimg/node:20 - steps: - - checkout - - run: npm ci - - run: | - TESTS=$(circleci tests glob "test/**/*.js" | circleci tests split) - npm test $TESTS -``` - -## Release Orchestration - -```bash -#!/bin/bash -# release.sh - Multi-service coordinated release - -VERSION=$1 -SERVICES=(auth api worker frontend) - -echo "Release: $VERSION" - -# Create release branches -for svc in "${SERVICES[@]}"; do - gh api repos/org/$svc/git/refs -f ref=refs/heads/release/$VERSION -f sha=$(git rev-parse main) -done - -# Trigger builds -for svc in "${SERVICES[@]}"; do - gh workflow run ci.yml --repo org/$svc --ref release/$VERSION -done - -# Wait for completion -for svc in "${SERVICES[@]}"; do - gh run watch --repo org/$svc $(gh run list --repo org/$svc -L1 -q '.[0].databaseId') -done - -# Deploy to staging -kubectl apply -f staging/release-$VERSION.yaml - -# Smoke tests -./scripts/smoke-test.sh staging - -echo "✓ Release $VERSION ready for production" -``` - -## Dependency Management - -### Renovate Auto-Update - -```json -{ - "extends": ["config:base"], - "packageRules": [ - { - "matchUpdateTypes": ["minor", "patch"], - "automerge": true - }, - { - "matchDepTypes": ["devDependencies"], - "automerge": true - } - ], - "schedule": ["before 6am on Monday"], - "prConcurrentLimit": 5 -} -``` - -## Build Optimization - -### Build Caching Strategy - -```yaml -# GitHub Actions: Multi-layer caching -- name: Cache dependencies - uses: actions/cache@v3 - with: - path: | - ~/.npm - ~/.cache - node_modules - key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-deps- - -- name: Cache Docker layers - uses: docker/build-push-action@v4 - with: - context: . - cache-from: type=gha - cache-to: type=gha,mode=max -``` - -### Parallel CI Pipeline - -```yaml -# Multi-platform builds in parallel -name: Build - -on: [push] - -jobs: - test: - strategy: - matrix: - node: [18, 20, 22] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - - run: npm ci && npm test - - build-images: - needs: test - strategy: - matrix: - platform: [linux/amd64, linux/arm64] - runs-on: ubuntu-latest - steps: - - uses: docker/build-push-action@v4 - with: - platforms: ${{ matrix.platform }} - tags: app:${{ github.sha }} -``` - -## Multi-Service Release Orchestration - -```yaml -# release-coordinator.yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: release-v2.5.0 -spec: - template: - spec: - containers: - - name: coordinator - image: release-bot:latest - env: - - name: RELEASE_VERSION - value: "v2.5.0" - - name: SERVICES - value: "auth,api,worker,frontend" - command: - - /bin/bash - - -c - - | - # Deploy in dependency order - for svc in auth api worker frontend; do - echo "Deploying $svc..." - kubectl set image deploy/$svc \ - $svc=registry.io/$svc:$RELEASE_VERSION - - kubectl rollout status deploy/$svc --timeout=5m - - # Health check - kubectl run test-$svc --rm -i --restart=Never \ - --image=curlimages/curl -- \ - curl -f http://$svc/health - - echo "$svc deployed successfully" - done -``` - -## Advanced Artifact Management - -```bash -#!/bin/bash -# artifact-scanner.sh - Scan before promotion - -IMAGE=$1 -SEVERITY=${2:-HIGH} - -# Vulnerability scan -trivy image --severity $SEVERITY --exit-code 1 $IMAGE - -# License compliance -syft $IMAGE -o json | \ - jq '.artifacts[].licenses[] | select(.value | - contains("GPL") or contains("AGPL"))' && \ - echo "License violation detected" && exit 1 - -# SBOM generation -syft $IMAGE -o spdx-json > sbom-$(basename $IMAGE).spdx.json - -# Sign artifact -cosign sign --key cosign.key $IMAGE - -# Promote -docker tag $IMAGE $IMAGE-approved -docker push $IMAGE-approved - -echo "Artifact $IMAGE approved and promoted" -``` - -## Zero-Downtime Database Migrations - -```python -# migrations/release_v2.5.py -from alembic import op -import sqlalchemy as sa - -def upgrade(): - # Step 1: Add new column (nullable) - op.add_column('users', - sa.Column('email_verified', sa.Boolean(), nullable=True)) - - # Step 2: Backfill data (in batches) - connection = op.get_bind() - connection.execute(""" - UPDATE users SET email_verified = true - WHERE email IS NOT NULL - LIMIT 1000 - """) - # Repeat until complete (or use background job) - - # Step 3: Make non-nullable (in next release) - # op.alter_column('users', 'email_verified', nullable=False) - -def downgrade(): - op.drop_column('users', 'email_verified') -``` - -## Release Metrics Dashboard - -```yaml -# Grafana dashboard for release metrics -apiVersion: v1 -kind: ConfigMap -metadata: - name: release-dashboard -data: - dashboard.json: | - { - "panels": [ - { - "title": "Deployment Frequency", - "targets": [{ - "expr": "count_over_time(deployment_completed[1d])" - }] - }, - { - "title": "Lead Time", - "targets": [{ - "expr": "histogram_quantile(0.95, commit_to_deploy_seconds_bucket)" - }] - }, - { - "title": "Change Failure Rate", - "targets": [{ - "expr": "sum(rate(deployment_failed[1h])) / sum(rate(deployment_total[1h]))" - }] - }, - { - "title": "Active Releases", - "targets": [{ - "expr": "count(release_in_progress == 1)" - }] - } - ] - } -``` - -## Best Practices - -- Version artifacts with immutable tags -- Implement retention policies -- Use progressive delivery for high-risk changes -- Automate security scanning -- Maintain deployment audit trails -- Enable easy rollbacks -- Monitor deployment metrics -- Use feature flags for flexibility -- Cache aggressively for fast builds -- Parallelize test and build jobs -- Coordinate multi-service releases -- Generate and track SBOMs -- Sign artifacts for supply chain security -- Automate dependency updates -- Track DORA metrics continuously diff --git a/builtin-skills/software-engineer/devops-engineer/references/terraform-iac.md b/builtin-skills/software-engineer/devops-engineer/references/terraform-iac.md deleted file mode 100644 index 62f52890..00000000 --- a/builtin-skills/software-engineer/devops-engineer/references/terraform-iac.md +++ /dev/null @@ -1,141 +0,0 @@ -# Terraform Infrastructure as Code - -## AWS ECS Fargate Setup - -```hcl -terraform { - required_providers { - aws = { source = "hashicorp/aws", version = "~> 5.0" } - } - backend "s3" { - bucket = "terraform-state" - key = "app/terraform.tfstate" - region = "us-east-1" - } -} - -resource "aws_ecs_cluster" "main" { - name = "app-cluster" - setting { - name = "containerInsights" - value = "enabled" - } -} - -resource "aws_ecs_task_definition" "app" { - family = "app" - network_mode = "awsvpc" - requires_compatibilities = ["FARGATE"] - cpu = "256" - memory = "512" - execution_role_arn = aws_iam_role.ecs_execution.arn - - container_definitions = jsonencode([{ - name = "app" - image = "${var.ecr_repository}:${var.image_tag}" - portMappings = [{ containerPort = 3000 }] - logConfiguration = { - logDriver = "awslogs" - options = { - awslogs-group = aws_cloudwatch_log_group.app.name - awslogs-region = var.region - awslogs-stream-prefix = "app" - } - } - secrets = [ - { name = "DATABASE_URL", valueFrom = aws_ssm_parameter.db_url.arn } - ] - }]) -} - -resource "aws_ecs_service" "app" { - name = "app" - cluster = aws_ecs_cluster.main.id - task_definition = aws_ecs_task_definition.app.arn - desired_count = 2 - launch_type = "FARGATE" - - network_configuration { - subnets = var.private_subnets - security_groups = [aws_security_group.app.id] - } - - load_balancer { - target_group_arn = aws_lb_target_group.app.arn - container_name = "app" - container_port = 3000 - } -} -``` - -## AWS RDS PostgreSQL - -```hcl -resource "aws_db_instance" "postgres" { - identifier = "app-db" - engine = "postgres" - engine_version = "16.1" - instance_class = "db.t3.micro" - allocated_storage = 20 - storage_encrypted = true - - db_name = "app" - username = "admin" - password = var.db_password - - vpc_security_group_ids = [aws_security_group.db.id] - db_subnet_group_name = aws_db_subnet_group.main.name - - backup_retention_period = 7 - skip_final_snapshot = false - final_snapshot_identifier = "app-db-final" - - tags = { Environment = var.environment } -} -``` - -## Variables and Outputs - -```hcl -# variables.tf -variable "environment" { - type = string - description = "Environment name" -} - -variable "region" { - type = string - default = "us-east-1" -} - -# outputs.tf -output "ecs_cluster_arn" { - value = aws_ecs_cluster.main.arn -} - -output "alb_dns_name" { - value = aws_lb.main.dns_name -} -``` - -## Best Practices - -| Practice | Implementation | -|----------|----------------| -| State locking | S3 backend with DynamoDB | -| Secrets | Use AWS Secrets Manager / SSM | -| Modules | Reusable components | -| Workspaces | Environment separation | -| Tagging | Consistent resource tags | -| Validation | `terraform validate`, `tflint` | - -## Common Commands - -```bash -terraform init -terraform plan -out=tfplan -terraform apply tfplan -terraform destroy -terraform state list -terraform import aws_instance.app i-1234567890 -``` diff --git a/builtin-skills/software-engineer/e2e-testing-patterns/SKILL.md b/builtin-skills/software-engineer/e2e-testing-patterns/SKILL.md deleted file mode 100644 index 49d477e2..00000000 --- a/builtin-skills/software-engineer/e2e-testing-patterns/SKILL.md +++ /dev/null @@ -1,535 +0,0 @@ ---- -name: e2e-testing-patterns -description: Master end-to-end testing with Playwright and Cypress to build reliable test suites that catch bugs, improve confidence, and enable fast deployment. Use when implementing E2E tests, debugging flaky tests, or establishing testing standards. ---- - -# E2E Testing Patterns - -Build reliable, fast, and maintainable end-to-end test suites that provide confidence to ship code quickly and catch regressions before users do. - -## When to Use This Skill - -- Implementing end-to-end test automation -- Debugging flaky or unreliable tests -- Testing critical user workflows -- Setting up CI/CD test pipelines -- Testing across multiple browsers -- Validating accessibility requirements -- Testing responsive designs -- Establishing E2E testing standards - -## Core Concepts - -### 1. E2E Testing Fundamentals - -**What to Test with E2E:** - -- Critical user journeys (login, checkout, signup) -- Complex interactions (drag-and-drop, multi-step forms) -- Cross-browser compatibility -- Real API integration -- Authentication flows - -**What NOT to Test with E2E:** - -- Unit-level logic (use unit tests) -- API contracts (use integration tests) -- Edge cases (too slow) -- Internal implementation details - -### 2. Test Philosophy - -**The Testing Pyramid:** - -``` - /\ - /E2E\ ← Few, focused on critical paths - /─────\ - /Integr\ ← More, test component interactions - /────────\ - /Unit Tests\ ← Many, fast, isolated - /────────────\ -``` - -**Best Practices:** - -- Test user behavior, not implementation -- Keep tests independent -- Make tests deterministic -- Optimize for speed -- Use data-testid, not CSS selectors - -## Playwright Patterns - -### Setup and Configuration - -```typescript -// playwright.config.ts -import { defineConfig, devices } from "@playwright/test"; - -export default defineConfig({ - testDir: "./e2e", - timeout: 30000, - expect: { - timeout: 5000, - }, - fullyParallel: true, - forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, - workers: process.env.CI ? 1 : undefined, - reporter: [["html"], ["junit", { outputFile: "results.xml" }]], - use: { - baseURL: "http://localhost:3000", - trace: "on-first-retry", - screenshot: "only-on-failure", - video: "retain-on-failure", - }, - projects: [ - { name: "chromium", use: { ...devices["Desktop Chrome"] } }, - { name: "firefox", use: { ...devices["Desktop Firefox"] } }, - { name: "webkit", use: { ...devices["Desktop Safari"] } }, - { name: "mobile", use: { ...devices["iPhone 13"] } }, - ], -}); -``` - -### Pattern 1: Page Object Model - -```typescript -// pages/LoginPage.ts -import { Page, Locator } from "@playwright/test"; - -export class LoginPage { - readonly page: Page; - readonly emailInput: Locator; - readonly passwordInput: Locator; - readonly loginButton: Locator; - readonly errorMessage: Locator; - - constructor(page: Page) { - this.page = page; - this.emailInput = page.getByLabel("Email"); - this.passwordInput = page.getByLabel("Password"); - this.loginButton = page.getByRole("button", { name: "Login" }); - this.errorMessage = page.getByRole("alert"); - } - - async goto() { - await this.page.goto("/login"); - } - - async login(email: string, password: string) { - await this.emailInput.fill(email); - await this.passwordInput.fill(password); - await this.loginButton.click(); - } - - async getErrorMessage(): Promise { - return (await this.errorMessage.textContent()) ?? ""; - } -} - -// Test using Page Object -import { test, expect } from "@playwright/test"; -import { LoginPage } from "./pages/LoginPage"; - -test("successful login", async ({ page }) => { - const loginPage = new LoginPage(page); - await loginPage.goto(); - await loginPage.login("user@example.com", "password123"); - - await expect(page).toHaveURL("/dashboard"); - await expect(page.getByRole("heading", { name: "Dashboard" })).toBeVisible(); -}); - -test("failed login shows error", async ({ page }) => { - const loginPage = new LoginPage(page); - await loginPage.goto(); - await loginPage.login("invalid@example.com", "wrong"); - - const error = await loginPage.getErrorMessage(); - expect(error).toContain("Invalid credentials"); -}); -``` - -### Pattern 2: Fixtures for Test Data - -```typescript -// fixtures/test-data.ts -import { test as base } from "@playwright/test"; - -type TestData = { - testUser: { - email: string; - password: string; - name: string; - }; - adminUser: { - email: string; - password: string; - }; -}; - -export const test = base.extend({ - testUser: async ({}, use) => { - const user = { - email: `test-${Date.now()}@example.com`, - password: "Test123!@#", - name: "Test User", - }; - // Setup: Create user in database - await createTestUser(user); - await use(user); - // Teardown: Clean up user - await deleteTestUser(user.email); - }, - - adminUser: async ({}, use) => { - await use({ - email: "admin@example.com", - password: process.env.ADMIN_PASSWORD!, - }); - }, -}); - -// Usage in tests -import { test } from "./fixtures/test-data"; - -test("user can update profile", async ({ page, testUser }) => { - await page.goto("/login"); - await page.getByLabel("Email").fill(testUser.email); - await page.getByLabel("Password").fill(testUser.password); - await page.getByRole("button", { name: "Login" }).click(); - - await page.goto("/profile"); - await page.getByLabel("Name").fill("Updated Name"); - await page.getByRole("button", { name: "Save" }).click(); - - await expect(page.getByText("Profile updated")).toBeVisible(); -}); -``` - -### Pattern 3: Waiting Strategies - -```typescript -// ❌ Bad: Fixed timeouts -await page.waitForTimeout(3000); // Flaky! - -// ✅ Good: Wait for specific conditions -await page.waitForLoadState("networkidle"); -await page.waitForURL("/dashboard"); -await page.waitForSelector('[data-testid="user-profile"]'); - -// ✅ Better: Auto-waiting with assertions -await expect(page.getByText("Welcome")).toBeVisible(); -await expect(page.getByRole("button", { name: "Submit" })).toBeEnabled(); - -// Wait for API response -const responsePromise = page.waitForResponse( - (response) => - response.url().includes("/api/users") && response.status() === 200, -); -await page.getByRole("button", { name: "Load Users" }).click(); -const response = await responsePromise; -const data = await response.json(); -expect(data.users).toHaveLength(10); - -// Wait for multiple conditions -await Promise.all([ - page.waitForURL("/success"), - page.waitForLoadState("networkidle"), - expect(page.getByText("Payment successful")).toBeVisible(), -]); -``` - -### Pattern 4: Network Mocking and Interception - -```typescript -// Mock API responses -test("displays error when API fails", async ({ page }) => { - await page.route("**/api/users", (route) => { - route.fulfill({ - status: 500, - contentType: "application/json", - body: JSON.stringify({ error: "Internal Server Error" }), - }); - }); - - await page.goto("/users"); - await expect(page.getByText("Failed to load users")).toBeVisible(); -}); - -// Intercept and modify requests -test("can modify API request", async ({ page }) => { - await page.route("**/api/users", async (route) => { - const request = route.request(); - const postData = JSON.parse(request.postData() || "{}"); - - // Modify request - postData.role = "admin"; - - await route.continue({ - postData: JSON.stringify(postData), - }); - }); - - // Test continues... -}); - -// Mock third-party services -test("payment flow with mocked Stripe", async ({ page }) => { - await page.route("**/api/stripe/**", (route) => { - route.fulfill({ - status: 200, - body: JSON.stringify({ - id: "mock_payment_id", - status: "succeeded", - }), - }); - }); - - // Test payment flow with mocked response -}); -``` - -## Cypress Patterns - -### Setup and Configuration - -```typescript -// cypress.config.ts -import { defineConfig } from "cypress"; - -export default defineConfig({ - e2e: { - baseUrl: "http://localhost:3000", - viewportWidth: 1280, - viewportHeight: 720, - video: false, - screenshotOnRunFailure: true, - defaultCommandTimeout: 10000, - requestTimeout: 10000, - setupNodeEvents(on, config) { - // Implement node event listeners - }, - }, -}); -``` - -### Pattern 1: Custom Commands - -```typescript -// cypress/support/commands.ts -declare global { - namespace Cypress { - interface Chainable { - login(email: string, password: string): Chainable; - createUser(userData: UserData): Chainable; - dataCy(value: string): Chainable>; - } - } -} - -Cypress.Commands.add("login", (email: string, password: string) => { - cy.visit("/login"); - cy.get('[data-testid="email"]').type(email); - cy.get('[data-testid="password"]').type(password); - cy.get('[data-testid="login-button"]').click(); - cy.url().should("include", "/dashboard"); -}); - -Cypress.Commands.add("createUser", (userData: UserData) => { - return cy.request("POST", "/api/users", userData).its("body"); -}); - -Cypress.Commands.add("dataCy", (value: string) => { - return cy.get(`[data-cy="${value}"]`); -}); - -// Usage -cy.login("user@example.com", "password"); -cy.dataCy("submit-button").click(); -``` - -### Pattern 2: Cypress Intercept - -```typescript -// Mock API calls -cy.intercept("GET", "/api/users", { - statusCode: 200, - body: [ - { id: 1, name: "John" }, - { id: 2, name: "Jane" }, - ], -}).as("getUsers"); - -cy.visit("/users"); -cy.wait("@getUsers"); -cy.get('[data-testid="user-list"]').children().should("have.length", 2); - -// Modify responses -cy.intercept("GET", "/api/users", (req) => { - req.reply((res) => { - // Modify response - res.body.users = res.body.users.slice(0, 5); - res.send(); - }); -}); - -// Simulate slow network -cy.intercept("GET", "/api/data", (req) => { - req.reply((res) => { - res.delay(3000); // 3 second delay - res.send(); - }); -}); -``` - -## Advanced Patterns - -### Pattern 1: Visual Regression Testing - -```typescript -// With Playwright -import { test, expect } from "@playwright/test"; - -test("homepage looks correct", async ({ page }) => { - await page.goto("/"); - await expect(page).toHaveScreenshot("homepage.png", { - fullPage: true, - maxDiffPixels: 100, - }); -}); - -test("button in all states", async ({ page }) => { - await page.goto("/components"); - - const button = page.getByRole("button", { name: "Submit" }); - - // Default state - await expect(button).toHaveScreenshot("button-default.png"); - - // Hover state - await button.hover(); - await expect(button).toHaveScreenshot("button-hover.png"); - - // Disabled state - await button.evaluate((el) => el.setAttribute("disabled", "true")); - await expect(button).toHaveScreenshot("button-disabled.png"); -}); -``` - -### Pattern 2: Parallel Testing with Sharding - -```typescript -// playwright.config.ts -export default defineConfig({ - projects: [ - { - name: "shard-1", - use: { ...devices["Desktop Chrome"] }, - grepInvert: /@slow/, - shard: { current: 1, total: 4 }, - }, - { - name: "shard-2", - use: { ...devices["Desktop Chrome"] }, - shard: { current: 2, total: 4 }, - }, - // ... more shards - ], -}); - -// Run in CI -// npx playwright test --shard=1/4 -// npx playwright test --shard=2/4 -``` - -### Pattern 3: Accessibility Testing - -```typescript -// Install: npm install @axe-core/playwright -import { test, expect } from "@playwright/test"; -import AxeBuilder from "@axe-core/playwright"; - -test("page should not have accessibility violations", async ({ page }) => { - await page.goto("/"); - - const accessibilityScanResults = await new AxeBuilder({ page }) - .exclude("#third-party-widget") - .analyze(); - - expect(accessibilityScanResults.violations).toEqual([]); -}); - -test("form is accessible", async ({ page }) => { - await page.goto("/signup"); - - const results = await new AxeBuilder({ page }).include("form").analyze(); - - expect(results.violations).toEqual([]); -}); -``` - -## Best Practices - -1. **Use Data Attributes**: `data-testid` or `data-cy` for stable selectors -2. **Avoid Brittle Selectors**: Don't rely on CSS classes or DOM structure -3. **Test User Behavior**: Click, type, see - not implementation details -4. **Keep Tests Independent**: Each test should run in isolation -5. **Clean Up Test Data**: Create and destroy test data in each test -6. **Use Page Objects**: Encapsulate page logic -7. **Meaningful Assertions**: Check actual user-visible behavior -8. **Optimize for Speed**: Mock when possible, parallel execution - -```typescript -// ❌ Bad selectors -cy.get(".btn.btn-primary.submit-button").click(); -cy.get("div > form > div:nth-child(2) > input").type("text"); - -// ✅ Good selectors -cy.getByRole("button", { name: "Submit" }).click(); -cy.getByLabel("Email address").type("user@example.com"); -cy.get('[data-testid="email-input"]').type("user@example.com"); -``` - -## Common Pitfalls - -- **Flaky Tests**: Use proper waits, not fixed timeouts -- **Slow Tests**: Mock external APIs, use parallel execution -- **Over-Testing**: Don't test every edge case with E2E -- **Coupled Tests**: Tests should not depend on each other -- **Poor Selectors**: Avoid CSS classes and nth-child -- **No Cleanup**: Clean up test data after each test -- **Testing Implementation**: Test user behavior, not internals - -## Debugging Failing Tests - -```typescript -// Playwright debugging -// 1. Run in headed mode -npx playwright test --headed - -// 2. Run in debug mode -npx playwright test --debug - -// 3. Use trace viewer -await page.screenshot({ path: 'screenshot.png' }); -await page.video()?.saveAs('video.webm'); - -// 4. Add test.step for better reporting -test('checkout flow', async ({ page }) => { - await test.step('Add item to cart', async () => { - await page.goto('/products'); - await page.getByRole('button', { name: 'Add to Cart' }).click(); - }); - - await test.step('Proceed to checkout', async () => { - await page.goto('/cart'); - await page.getByRole('button', { name: 'Checkout' }).click(); - }); -}); - -// 5. Inspect page state -await page.pause(); // Pauses execution, opens inspector -``` diff --git a/builtin-skills/software-engineer/mobile-development/SKILL.md b/builtin-skills/software-engineer/mobile-development/SKILL.md deleted file mode 100644 index dad1e839..00000000 --- a/builtin-skills/software-engineer/mobile-development/SKILL.md +++ /dev/null @@ -1,261 +0,0 @@ ---- -# ═══════════════════════════════════════════════════════════════════════════ -# SKILL: Mobile Development -# Version: 2.0.0 | Updated: 2025-01 -# ═══════════════════════════════════════════════════════════════════════════ -name: mobile-development -description: iOS (Swift, SwiftUI), Android (Kotlin, Compose), cross-platform (Flutter, React Native), and game development (Unity, Unreal). - -# ACTIVATION TRIGGERS -triggers: - - ios - - android - - flutter - - react native - - mobile - - swift - - kotlin - - unity - - game development - -# SKILL PARAMETERS -parameters: - platform: - type: string - enum: [ios, android, cross-platform, games] - required: true - project_type: - type: string - required: false - description: Type of app (social, productivity, game, etc.) - -# OUTPUT SPECIFICATION -outputs: - recommended_stack: - type: object - learning_path: - type: array - portfolio_projects: - type: array - -# RELIABILITY -retry: - max_attempts: 3 - backoff: exponential - -# OBSERVABILITY -observability: - log_level: info - -level: advanced -prerequisites: - - core-development - -sasmp_version: "1.3.0" -bonded_agent: 01-core-paths -bond_type: PRIMARY_BOND ---- - -# Mobile Development Skill - -## Quick Reference - -| Platform | Language | Framework | Timeline | Job Market | -|----------|----------|-----------|----------|------------| -| **iOS** | Swift | SwiftUI | 6-9 mo | High | -| **Android** | Kotlin | Compose | 6-9 mo | High | -| **Cross-Platform** | Dart | Flutter | 4-6 mo | Growing | -| **Games** | C# | Unity | 12-24 mo | Moderate | - ---- - -## Learning Paths - -### iOS Development -``` -[1] Swift Fundamentals (4-6 wk) - │ └─ Types, optionals, closures, protocols - │ - ▼ -[2] SwiftUI (4-6 wk) - │ └─ Views, modifiers, state, binding - │ - ▼ -[3] Navigation + Data (3-4 wk) - │ └─ NavigationStack, SwiftData/Core Data - │ - ▼ -[4] Networking + Async (2-3 wk) - │ └─ URLSession, async/await, Combine - │ - ▼ -[5] Testing + App Store (2 wk) - └─ XCTest, TestFlight, submission -``` - -**2025 Stack:** Swift 5.10 + SwiftUI + SwiftData + Xcode 16 - ---- - -### Android Development -``` -[1] Kotlin Fundamentals (4-6 wk) - │ └─ Null safety, coroutines, data classes - │ - ▼ -[2] Jetpack Compose (4-6 wk) - │ └─ Composables, state, effects - │ - ▼ -[3] Architecture (3-4 wk) - │ └─ MVVM, Room, Navigation - │ - ▼ -[4] Networking + DI (2-3 wk) - │ └─ Retrofit, Hilt, Flow - │ - ▼ -[5] Testing + Play Store (2 wk) - └─ JUnit, Espresso, release -``` - -**2025 Stack:** Kotlin 2.0 + Jetpack Compose + Room + Hilt - ---- - -### Flutter (Cross-Platform) -``` -[1] Dart Fundamentals (2-3 wk) - │ - ▼ -[2] Flutter Widgets (3-4 wk) - │ - ▼ -[3] State Management (2-3 wk) - │ └─ Riverpod or Bloc - │ - ▼ -[4] Backend Integration (2 wk) - │ └─ Firebase, REST APIs - │ - ▼ -[5] Deploy to Both Stores (1 wk) -``` - -**2025 Stack:** Flutter 3.x + Dart 3.x + Riverpod + Firebase - ---- - -### Game Development -``` -[1] Game Basics (4-6 wk) - │ └─ Game loop, input handling - │ - ▼ -[2] Unity/C# Fundamentals (6-8 wk) - │ └─ GameObjects, Components, Scripts - │ - ▼ -[3] Physics + Graphics (4-6 wk) - │ └─ Rigidbody, colliders, shaders - │ - ▼ -[4] Audio + Polish (2-4 wk) - │ - ▼ -[5] Publish (ongoing) - └─ Steam, App Store, Play Store -``` - -**2025 Stack:** Unity 6 LTS + C# OR Unreal 5.4 + C++ - ---- - -## Platform Decision Tree - -``` -Which platform? -│ -├─► Apple ecosystem only? -│ └─► iOS (Swift + SwiftUI) -│ -├─► Android ecosystem only? -│ └─► Android (Kotlin + Compose) -│ -├─► Both platforms? -│ ├─► Performance-critical? → Native for both -│ ├─► Budget/time limited? → Flutter -│ └─► Web developer background? → React Native -│ -└─► Making games? - ├─► 2D/3D indie → Unity - ├─► AAA quality → Unreal - └─► Simple 2D → Godot -``` - ---- - -## Game Engine Comparison - -| Engine | Market | Language | Learning | Best For | -|--------|--------|----------|----------|----------| -| **Unity** | 51% | C# | Medium | Indie, mobile, VR | -| **Unreal** | 31% | C++/BP | Hard | AAA, high-fidelity | -| **Godot** | 10% | GDScript | Easy | Indie, 2D | - ---- - -## Troubleshooting - -``` -Native vs Cross-platform? -├─► Need platform-specific APIs (HealthKit, ARCore)? → Native -├─► Performance-critical (AR/VR, complex animations)? → Native -├─► Budget or time limited? → Flutter -├─► Team knows JavaScript? → React Native -└─► Starting from scratch? → Flutter (best DX) - -Simulator works, device doesn't? -├─► Missing entitlements/capabilities? -├─► Different iOS/Android version? -├─► Network connectivity issues? -└─► Always test on real devices from day 1 - -App rejected by store? -├─► Read rejection reason carefully -├─► Check App Store Review Guidelines -├─► Most common: metadata issues, crashes, spam -└─► Appeal if unjustified -``` - ---- - -## Common Failure Modes - -| Symptom | Root Cause | Recovery | -|---------|------------|----------| -| Slow UI | Too many recompositions | Profile, optimize state | -| Memory leaks | Not cleaning up resources | Use lifecycle-aware components | -| App rejected | Guidelines violation | Read guidelines BEFORE building | -| Game stutters | Draw call overhead | Object pooling, LOD, batching | - ---- - -## Portfolio Projects - -### Mobile (Progressive) -1. **Todo App** - CRUD basics -2. **Weather App** - API integration -3. **Chat App** - Real-time, auth -4. **Payment App** - Stripe, security - -### Games -1. **2D Platformer** - Physics basics -2. **3D Runner** - 3D graphics, particles -3. **Multiplayer Game** - Networking - ---- - -## Next Actions - -Specify your target platform for a detailed learning plan. diff --git a/builtin-skills/software-engineer/mobile-development/assets/mobile_config.yaml b/builtin-skills/software-engineer/mobile-development/assets/mobile_config.yaml deleted file mode 100644 index 6121b29c..00000000 --- a/builtin-skills/software-engineer/mobile-development/assets/mobile_config.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Mobile Development Configuration for Cloudflare -# Version: 1.0.0 - -pwa: - enabled: true - manifest: "manifest.json" - service_worker: true - offline_support: true - -deployment: - platform: "cloudflare_pages" - build_command: "npm run build" - output_dir: "dist" - -mobile_api: - workers: - enabled: true - routes: - - "/api/*" - caching: - static_assets: "1y" - api_responses: "5m" - -performance: - image_optimization: - enabled: true - formats: ["webp", "avif"] - lazy_loading: true - preconnect: - - "https://api.example.com" - -push_notifications: - enabled: true - provider: "web-push" - vapid_keys: true diff --git a/builtin-skills/software-engineer/mobile-development/references/MOBILE_GUIDE.md b/builtin-skills/software-engineer/mobile-development/references/MOBILE_GUIDE.md deleted file mode 100644 index c1b17dca..00000000 --- a/builtin-skills/software-engineer/mobile-development/references/MOBILE_GUIDE.md +++ /dev/null @@ -1,73 +0,0 @@ -# Mobile Development Guide for Cloudflare - -## PWA on Cloudflare Pages - -```json -// manifest.json -{ - "name": "My PWA", - "short_name": "PWA", - "start_url": "/", - "display": "standalone", - "background_color": "#ffffff", - "theme_color": "#f38020", - "icons": [ - { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, - { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" } - ] -} -``` - -## Service Worker with Cloudflare - -```typescript -// sw.ts - Offline-first strategy -const CACHE_NAME = 'v1'; -const OFFLINE_URL = '/offline.html'; - -self.addEventListener('install', (event) => { - event.waitUntil( - caches.open(CACHE_NAME).then((cache) => { - return cache.addAll([OFFLINE_URL, '/', '/styles.css']); - }) - ); -}); - -self.addEventListener('fetch', (event) => { - event.respondWith( - fetch(event.request).catch(() => caches.match(OFFLINE_URL)) - ); -}); -``` - -## Mobile API with Workers - -```typescript -// Optimized for mobile clients -export default { - async fetch(request: Request, env: Env) { - const userAgent = request.headers.get('User-Agent') || ''; - const isMobile = /Mobile|Android|iPhone/i.test(userAgent); - - return Response.json({ - data: await getData(env), - optimized: isMobile ? 'mobile' : 'desktop' - }, { - headers: { - 'Cache-Control': isMobile ? 'max-age=300' : 'max-age=3600' - } - }); - } -}; -``` - -## Deployment - -```bash -# Deploy to Cloudflare Pages -npx wrangler pages deploy dist --project-name=my-pwa -``` - ---- - -*Cloudflare Plugin - Mobile Development Skill* diff --git a/builtin-skills/software-engineer/mobile-development/scripts/pwa_validator.py b/builtin-skills/software-engineer/mobile-development/scripts/pwa_validator.py deleted file mode 100644 index 4c2fa6b0..00000000 --- a/builtin-skills/software-engineer/mobile-development/scripts/pwa_validator.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -"""PWA and Mobile Readiness Validator for Cloudflare Pages.""" - -import json -from pathlib import Path - - -def validate_pwa(path: str) -> dict: - """Validate PWA configuration for Cloudflare Pages deployment.""" - project = Path(path) - - checks = { - "manifest": False, - "service_worker": False, - "icons": False, - "offline_page": False, - "https_ready": True # Cloudflare provides HTTPS - } - - # Check manifest.json - for manifest_path in ["manifest.json", "public/manifest.json", "src/manifest.json"]: - if (project / manifest_path).exists(): - checks["manifest"] = True - manifest = json.loads((project / manifest_path).read_text()) - if manifest.get("icons"): - checks["icons"] = True - break - - # Check service worker - sw_paths = ["sw.js", "service-worker.js", "public/sw.js", "src/sw.js"] - for sw_path in sw_paths: - if (project / sw_path).exists(): - checks["service_worker"] = True - break - - # Check offline page - offline_paths = ["offline.html", "public/offline.html"] - for offline_path in offline_paths: - if (project / offline_path).exists(): - checks["offline_page"] = True - break - - pwa_score = sum(checks.values()) / len(checks) * 100 - - return { - "checks": checks, - "pwa_score": pwa_score, - "pwa_ready": pwa_score >= 60, - "cloudflare_optimized": checks["manifest"] and checks["https_ready"] - } - - -def main(): - import sys - path = sys.argv[1] if len(sys.argv) > 1 else "." - print(json.dumps(validate_pwa(path), indent=2)) - - -if __name__ == "__main__": - main() diff --git a/builtin-skills/software-engineer/openapi-spec-generation/.skillfish.json b/builtin-skills/software-engineer/openapi-spec-generation/.skillfish.json deleted file mode 100644 index 7440abc6..00000000 --- a/builtin-skills/software-engineer/openapi-spec-generation/.skillfish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "version": 2, - "name": "openapi-spec-generation", - "owner": "ericgrill", - "repo": "agents-skills-plugins", - "path": "plugins/documentation-generation/skills/openapi-spec-generation", - "branch": "main", - "sha": "e3384ad0331ff44f69dc117841899bb7be1ee266", - "source": "manual" -} \ No newline at end of file diff --git a/builtin-skills/software-engineer/openapi-spec-generation/SKILL.md b/builtin-skills/software-engineer/openapi-spec-generation/SKILL.md deleted file mode 100644 index e9531331..00000000 --- a/builtin-skills/software-engineer/openapi-spec-generation/SKILL.md +++ /dev/null @@ -1,1017 +0,0 @@ ---- -name: openapi-spec-generation -description: Generate and maintain OpenAPI 3.1 specifications from code, design-first specs, and validation patterns. Use when creating API documentation, generating SDKs, or ensuring API contract compliance. ---- - -# OpenAPI Spec Generation - -Comprehensive patterns for creating, maintaining, and validating OpenAPI 3.1 specifications for RESTful APIs. - -## When to Use This Skill - -- Creating API documentation from scratch -- Generating OpenAPI specs from existing code -- Designing API contracts (design-first approach) -- Validating API implementations against specs -- Generating client SDKs from specs -- Setting up API documentation portals - -## Core Concepts - -### 1. OpenAPI 3.1 Structure - -```yaml -openapi: 3.1.0 -info: - title: API Title - version: 1.0.0 -servers: - - url: https://api.example.com/v1 -paths: - /resources: - get: ... -components: - schemas: ... - securitySchemes: ... -``` - -### 2. Design Approaches - -| Approach | Description | Best For | -| ---------------- | ---------------------------- | ------------------- | -| **Design-First** | Write spec before code | New APIs, contracts | -| **Code-First** | Generate spec from code | Existing APIs | -| **Hybrid** | Annotate code, generate spec | Evolving APIs | - -## Templates - -### Template 1: Complete API Specification - -```yaml -openapi: 3.1.0 -info: - title: User Management API - description: | - API for managing users and their profiles. - - ## Authentication - All endpoints require Bearer token authentication. - - ## Rate Limiting - - 1000 requests per minute for standard tier - - 10000 requests per minute for enterprise tier - version: 2.0.0 - contact: - name: API Support - email: api-support@example.com - url: https://docs.example.com - license: - name: MIT - url: https://opensource.org/licenses/MIT - -servers: - - url: https://api.example.com/v2 - description: Production - - url: https://staging-api.example.com/v2 - description: Staging - - url: http://localhost:3000/v2 - description: Local development - -tags: - - name: Users - description: User management operations - - name: Profiles - description: User profile operations - - name: Admin - description: Administrative operations - -paths: - /users: - get: - operationId: listUsers - summary: List all users - description: Returns a paginated list of users with optional filtering. - tags: - - Users - parameters: - - $ref: "#/components/parameters/PageParam" - - $ref: "#/components/parameters/LimitParam" - - name: status - in: query - description: Filter by user status - schema: - $ref: "#/components/schemas/UserStatus" - - name: search - in: query - description: Search by name or email - schema: - type: string - minLength: 2 - maxLength: 100 - responses: - "200": - description: Successful response - content: - application/json: - schema: - $ref: "#/components/schemas/UserListResponse" - examples: - default: - $ref: "#/components/examples/UserListExample" - "400": - $ref: "#/components/responses/BadRequest" - "401": - $ref: "#/components/responses/Unauthorized" - "429": - $ref: "#/components/responses/RateLimited" - security: - - bearerAuth: [] - - post: - operationId: createUser - summary: Create a new user - description: Creates a new user account and sends welcome email. - tags: - - Users - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateUserRequest" - examples: - standard: - summary: Standard user - value: - email: user@example.com - name: John Doe - role: user - admin: - summary: Admin user - value: - email: admin@example.com - name: Admin User - role: admin - responses: - "201": - description: User created successfully - content: - application/json: - schema: - $ref: "#/components/schemas/User" - headers: - Location: - description: URL of created user - schema: - type: string - format: uri - "400": - $ref: "#/components/responses/BadRequest" - "409": - description: Email already exists - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - security: - - bearerAuth: [] - - /users/{userId}: - parameters: - - $ref: "#/components/parameters/UserIdParam" - - get: - operationId: getUser - summary: Get user by ID - tags: - - Users - responses: - "200": - description: Successful response - content: - application/json: - schema: - $ref: "#/components/schemas/User" - "404": - $ref: "#/components/responses/NotFound" - security: - - bearerAuth: [] - - patch: - operationId: updateUser - summary: Update user - tags: - - Users - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/UpdateUserRequest" - responses: - "200": - description: User updated - content: - application/json: - schema: - $ref: "#/components/schemas/User" - "400": - $ref: "#/components/responses/BadRequest" - "404": - $ref: "#/components/responses/NotFound" - security: - - bearerAuth: [] - - delete: - operationId: deleteUser - summary: Delete user - tags: - - Users - - Admin - responses: - "204": - description: User deleted - "404": - $ref: "#/components/responses/NotFound" - security: - - bearerAuth: [] - - apiKey: [] - -components: - schemas: - User: - type: object - required: - - id - - email - - name - - status - - createdAt - properties: - id: - type: string - format: uuid - readOnly: true - description: Unique user identifier - email: - type: string - format: email - description: User email address - name: - type: string - minLength: 1 - maxLength: 100 - description: User display name - status: - $ref: "#/components/schemas/UserStatus" - role: - type: string - enum: [user, moderator, admin] - default: user - avatar: - type: string - format: uri - nullable: true - metadata: - type: object - additionalProperties: true - description: Custom metadata - createdAt: - type: string - format: date-time - readOnly: true - updatedAt: - type: string - format: date-time - readOnly: true - - UserStatus: - type: string - enum: [active, inactive, suspended, pending] - description: User account status - - CreateUserRequest: - type: object - required: - - email - - name - properties: - email: - type: string - format: email - name: - type: string - minLength: 1 - maxLength: 100 - role: - type: string - enum: [user, moderator, admin] - default: user - metadata: - type: object - additionalProperties: true - - UpdateUserRequest: - type: object - minProperties: 1 - properties: - name: - type: string - minLength: 1 - maxLength: 100 - status: - $ref: "#/components/schemas/UserStatus" - role: - type: string - enum: [user, moderator, admin] - metadata: - type: object - additionalProperties: true - - UserListResponse: - type: object - required: - - data - - pagination - properties: - data: - type: array - items: - $ref: "#/components/schemas/User" - pagination: - $ref: "#/components/schemas/Pagination" - - Pagination: - type: object - required: - - page - - limit - - total - - totalPages - properties: - page: - type: integer - minimum: 1 - limit: - type: integer - minimum: 1 - maximum: 100 - total: - type: integer - minimum: 0 - totalPages: - type: integer - minimum: 0 - hasNext: - type: boolean - hasPrev: - type: boolean - - Error: - type: object - required: - - code - - message - properties: - code: - type: string - description: Error code for programmatic handling - message: - type: string - description: Human-readable error message - details: - type: array - items: - type: object - properties: - field: - type: string - message: - type: string - requestId: - type: string - description: Request ID for support - - parameters: - UserIdParam: - name: userId - in: path - required: true - description: User ID - schema: - type: string - format: uuid - - PageParam: - name: page - in: query - description: Page number (1-based) - schema: - type: integer - minimum: 1 - default: 1 - - LimitParam: - name: limit - in: query - description: Items per page - schema: - type: integer - minimum: 1 - maximum: 100 - default: 20 - - responses: - BadRequest: - description: Invalid request - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - example: - code: VALIDATION_ERROR - message: Invalid request parameters - details: - - field: email - message: Must be a valid email address - - Unauthorized: - description: Authentication required - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - example: - code: UNAUTHORIZED - message: Authentication required - - NotFound: - description: Resource not found - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - example: - code: NOT_FOUND - message: User not found - - RateLimited: - description: Too many requests - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - headers: - Retry-After: - description: Seconds until rate limit resets - schema: - type: integer - X-RateLimit-Limit: - description: Request limit per window - schema: - type: integer - X-RateLimit-Remaining: - description: Remaining requests in window - schema: - type: integer - - examples: - UserListExample: - value: - data: - - id: "550e8400-e29b-41d4-a716-446655440000" - email: "john@example.com" - name: "John Doe" - status: "active" - role: "user" - createdAt: "2024-01-15T10:30:00Z" - pagination: - page: 1 - limit: 20 - total: 1 - totalPages: 1 - hasNext: false - hasPrev: false - - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - description: JWT token from /auth/login - - apiKey: - type: apiKey - in: header - name: X-API-Key - description: API key for service-to-service calls - -security: - - bearerAuth: [] -``` - -### Template 2: Code-First Generation (Python/FastAPI) - -```python -# FastAPI with automatic OpenAPI generation -from fastapi import FastAPI, HTTPException, Query, Path, Depends -from pydantic import BaseModel, Field, EmailStr -from typing import Optional, List -from datetime import datetime -from uuid import UUID -from enum import Enum - -app = FastAPI( - title="User Management API", - description="API for managing users and profiles", - version="2.0.0", - openapi_tags=[ - {"name": "Users", "description": "User operations"}, - {"name": "Profiles", "description": "Profile operations"}, - ], - servers=[ - {"url": "https://api.example.com/v2", "description": "Production"}, - {"url": "http://localhost:8000", "description": "Development"}, - ], -) - -# Enums -class UserStatus(str, Enum): - active = "active" - inactive = "inactive" - suspended = "suspended" - pending = "pending" - -class UserRole(str, Enum): - user = "user" - moderator = "moderator" - admin = "admin" - -# Models -class UserBase(BaseModel): - email: EmailStr = Field(..., description="User email address") - name: str = Field(..., min_length=1, max_length=100, description="Display name") - -class UserCreate(UserBase): - role: UserRole = Field(default=UserRole.user) - metadata: Optional[dict] = Field(default=None, description="Custom metadata") - - model_config = { - "json_schema_extra": { - "examples": [ - { - "email": "user@example.com", - "name": "John Doe", - "role": "user" - } - ] - } - } - -class UserUpdate(BaseModel): - name: Optional[str] = Field(None, min_length=1, max_length=100) - status: Optional[UserStatus] = None - role: Optional[UserRole] = None - metadata: Optional[dict] = None - -class User(UserBase): - id: UUID = Field(..., description="Unique identifier") - status: UserStatus - role: UserRole - avatar: Optional[str] = Field(None, description="Avatar URL") - metadata: Optional[dict] = None - created_at: datetime = Field(..., alias="createdAt") - updated_at: Optional[datetime] = Field(None, alias="updatedAt") - - model_config = {"populate_by_name": True} - -class Pagination(BaseModel): - page: int = Field(..., ge=1) - limit: int = Field(..., ge=1, le=100) - total: int = Field(..., ge=0) - total_pages: int = Field(..., ge=0, alias="totalPages") - has_next: bool = Field(..., alias="hasNext") - has_prev: bool = Field(..., alias="hasPrev") - -class UserListResponse(BaseModel): - data: List[User] - pagination: Pagination - -class ErrorDetail(BaseModel): - field: str - message: str - -class ErrorResponse(BaseModel): - code: str = Field(..., description="Error code") - message: str = Field(..., description="Error message") - details: Optional[List[ErrorDetail]] = None - request_id: Optional[str] = Field(None, alias="requestId") - -# Endpoints -@app.get( - "/users", - response_model=UserListResponse, - tags=["Users"], - summary="List all users", - description="Returns a paginated list of users with optional filtering.", - responses={ - 400: {"model": ErrorResponse, "description": "Invalid request"}, - 401: {"model": ErrorResponse, "description": "Unauthorized"}, - }, -) -async def list_users( - page: int = Query(1, ge=1, description="Page number"), - limit: int = Query(20, ge=1, le=100, description="Items per page"), - status: Optional[UserStatus] = Query(None, description="Filter by status"), - search: Optional[str] = Query(None, min_length=2, max_length=100), -): - """ - List users with pagination and filtering. - - - **page**: Page number (1-based) - - **limit**: Number of items per page (max 100) - - **status**: Filter by user status - - **search**: Search by name or email - """ - # Implementation - pass - -@app.post( - "/users", - response_model=User, - status_code=201, - tags=["Users"], - summary="Create a new user", - responses={ - 400: {"model": ErrorResponse}, - 409: {"model": ErrorResponse, "description": "Email already exists"}, - }, -) -async def create_user(user: UserCreate): - """Create a new user and send welcome email.""" - pass - -@app.get( - "/users/{user_id}", - response_model=User, - tags=["Users"], - summary="Get user by ID", - responses={404: {"model": ErrorResponse}}, -) -async def get_user( - user_id: UUID = Path(..., description="User ID"), -): - """Retrieve a specific user by their ID.""" - pass - -@app.patch( - "/users/{user_id}", - response_model=User, - tags=["Users"], - summary="Update user", - responses={ - 400: {"model": ErrorResponse}, - 404: {"model": ErrorResponse}, - }, -) -async def update_user( - user_id: UUID = Path(..., description="User ID"), - user: UserUpdate = ..., -): - """Update user attributes.""" - pass - -@app.delete( - "/users/{user_id}", - status_code=204, - tags=["Users", "Admin"], - summary="Delete user", - responses={404: {"model": ErrorResponse}}, -) -async def delete_user( - user_id: UUID = Path(..., description="User ID"), -): - """Permanently delete a user.""" - pass - -# Export OpenAPI spec -if __name__ == "__main__": - import json - print(json.dumps(app.openapi(), indent=2)) -``` - -### Template 3: Code-First (TypeScript/Express with tsoa) - -```typescript -// tsoa generates OpenAPI from TypeScript decorators - -import { - Controller, - Get, - Post, - Patch, - Delete, - Route, - Path, - Query, - Body, - Response, - SuccessResponse, - Tags, - Security, - Example, -} from "tsoa"; - -// Models -interface User { - /** Unique identifier */ - id: string; - /** User email address */ - email: string; - /** Display name */ - name: string; - status: UserStatus; - role: UserRole; - /** Avatar URL */ - avatar?: string; - /** Custom metadata */ - metadata?: Record; - createdAt: Date; - updatedAt?: Date; -} - -enum UserStatus { - Active = "active", - Inactive = "inactive", - Suspended = "suspended", - Pending = "pending", -} - -enum UserRole { - User = "user", - Moderator = "moderator", - Admin = "admin", -} - -interface CreateUserRequest { - email: string; - name: string; - role?: UserRole; - metadata?: Record; -} - -interface UpdateUserRequest { - name?: string; - status?: UserStatus; - role?: UserRole; - metadata?: Record; -} - -interface Pagination { - page: number; - limit: number; - total: number; - totalPages: number; - hasNext: boolean; - hasPrev: boolean; -} - -interface UserListResponse { - data: User[]; - pagination: Pagination; -} - -interface ErrorResponse { - code: string; - message: string; - details?: { field: string; message: string }[]; - requestId?: string; -} - -@Route("users") -@Tags("Users") -export class UsersController extends Controller { - /** - * List all users with pagination and filtering - * @param page Page number (1-based) - * @param limit Items per page (max 100) - * @param status Filter by user status - * @param search Search by name or email - */ - @Get() - @Security("bearerAuth") - @Response(400, "Invalid request") - @Response(401, "Unauthorized") - @Example({ - data: [ - { - id: "550e8400-e29b-41d4-a716-446655440000", - email: "john@example.com", - name: "John Doe", - status: UserStatus.Active, - role: UserRole.User, - createdAt: new Date("2024-01-15T10:30:00Z"), - }, - ], - pagination: { - page: 1, - limit: 20, - total: 1, - totalPages: 1, - hasNext: false, - hasPrev: false, - }, - }) - public async listUsers( - @Query() page: number = 1, - @Query() limit: number = 20, - @Query() status?: UserStatus, - @Query() search?: string, - ): Promise { - // Implementation - throw new Error("Not implemented"); - } - - /** - * Create a new user - */ - @Post() - @Security("bearerAuth") - @SuccessResponse(201, "Created") - @Response(400, "Invalid request") - @Response(409, "Email already exists") - public async createUser(@Body() body: CreateUserRequest): Promise { - this.setStatus(201); - throw new Error("Not implemented"); - } - - /** - * Get user by ID - * @param userId User ID - */ - @Get("{userId}") - @Security("bearerAuth") - @Response(404, "User not found") - public async getUser(@Path() userId: string): Promise { - throw new Error("Not implemented"); - } - - /** - * Update user attributes - * @param userId User ID - */ - @Patch("{userId}") - @Security("bearerAuth") - @Response(400, "Invalid request") - @Response(404, "User not found") - public async updateUser( - @Path() userId: string, - @Body() body: UpdateUserRequest, - ): Promise { - throw new Error("Not implemented"); - } - - /** - * Delete user - * @param userId User ID - */ - @Delete("{userId}") - @Tags("Users", "Admin") - @Security("bearerAuth") - @SuccessResponse(204, "Deleted") - @Response(404, "User not found") - public async deleteUser(@Path() userId: string): Promise { - this.setStatus(204); - } -} -``` - -### Template 4: Validation & Linting - -```bash -# Install validation tools -npm install -g @stoplight/spectral-cli -npm install -g @redocly/cli - -# Spectral ruleset (.spectral.yaml) -cat > .spectral.yaml << 'EOF' -extends: ["spectral:oas", "spectral:asyncapi"] - -rules: - # Enforce operation IDs - operation-operationId: error - - # Require descriptions - operation-description: warn - info-description: error - - # Naming conventions - operation-operationId-valid-in-url: true - - # Security - operation-security-defined: error - - # Response codes - operation-success-response: error - - # Custom rules - path-params-snake-case: - description: Path parameters should be snake_case - severity: warn - given: "$.paths[*].parameters[?(@.in == 'path')].name" - then: - function: pattern - functionOptions: - match: "^[a-z][a-z0-9_]*$" - - schema-properties-camelCase: - description: Schema properties should be camelCase - severity: warn - given: "$.components.schemas[*].properties[*]~" - then: - function: casing - functionOptions: - type: camel -EOF - -# Run Spectral -spectral lint openapi.yaml - -# Redocly config (redocly.yaml) -cat > redocly.yaml << 'EOF' -extends: - - recommended - -rules: - no-invalid-media-type-examples: error - no-invalid-schema-examples: error - operation-4xx-response: warn - request-mime-type: - severity: error - allowedValues: - - application/json - response-mime-type: - severity: error - allowedValues: - - application/json - - application/problem+json - -theme: - openapi: - generateCodeSamples: - languages: - - lang: curl - - lang: python - - lang: javascript -EOF - -# Run Redocly -redocly lint openapi.yaml -redocly bundle openapi.yaml -o bundled.yaml -redocly preview-docs openapi.yaml -``` - -## SDK Generation - -```bash -# OpenAPI Generator -npm install -g @openapitools/openapi-generator-cli - -# Generate TypeScript client -openapi-generator-cli generate \ - -i openapi.yaml \ - -g typescript-fetch \ - -o ./generated/typescript-client \ - --additional-properties=supportsES6=true,npmName=@myorg/api-client - -# Generate Python client -openapi-generator-cli generate \ - -i openapi.yaml \ - -g python \ - -o ./generated/python-client \ - --additional-properties=packageName=api_client - -# Generate Go client -openapi-generator-cli generate \ - -i openapi.yaml \ - -g go \ - -o ./generated/go-client -``` - -## Best Practices - -### Do's - -- **Use $ref** - Reuse schemas, parameters, responses -- **Add examples** - Real-world values help consumers -- **Document errors** - All possible error codes -- **Version your API** - In URL or header -- **Use semantic versioning** - For spec changes - -### Don'ts - -- **Don't use generic descriptions** - Be specific -- **Don't skip security** - Define all schemes -- **Don't forget nullable** - Be explicit about null -- **Don't mix styles** - Consistent naming throughout -- **Don't hardcode URLs** - Use server variables diff --git a/builtin-skills/software-engineer/optimize-cicd-pipeline/SKILL.md b/builtin-skills/software-engineer/optimize-cicd-pipeline/SKILL.md deleted file mode 100644 index 3f2d00ec..00000000 --- a/builtin-skills/software-engineer/optimize-cicd-pipeline/SKILL.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: optimize-cicd-pipeline -description: Analyzes CI/CD pipelines to identify common antipatterns (like slow feedback loops or sequential steps) and recommends best practice patterns (like build images, parallelization, and build-once-deploy-anywhere). Use when designing, auditing, or troubleshooting CI/CD workflows to improve speed and reliability. ---- - -# Optimize CI/CD Pipeline - -This skill provides a framework for auditing and improving CI/CD pipelines. The primary goal of any pipeline optimization is to **shorten the feedback loop**. The faster a developer knows something is wrong, the cheaper it is to fix. - -## Usage Instructions - -When analyzing a pipeline configuration or advising on DevOps practices, compare the user's current setup against the Antipatterns below. If an antipattern is detected, recommend the corresponding Pattern. - -### 1. Core Philosophy Checklist -- [ ] **Feedback Loop**: Is the time from "commit" to "failure notification" under 10 minutes? -- [ ] **Reproducibility**: Can a developer run the exact same build command locally? -- [ ] **Maintenance**: Is the pipeline treated as a software product (versioned, refactored, maintained)? - -### 2. Pattern Analysis - -Use this table to diagnose issues and prescribe solutions: - -| Detection (Antipattern) | Solution (Pattern) | Implementation Advice | -| :--- | :--- | :--- | -| **Installing tools on every run**
Build logs show repeated `npm install`, `apt-get install`, or downloading CLI tools. | **Use Build Images** | Pre-bake all dependencies into a Docker image. Use this image as the build agent/runner so the environment is instant. | -| **Sequential Steps**
Test, Lint, and Build run one after another. Total time = Sum of all steps. | **Parallelization (Fan-out)** | Run independent tasks simultaneously. Total time = Length of the slowest task. | -| **Rebuilding per Environment**
Code is compiled separately for "Test", "Staging", and "Prod". | **Build Once, Deploy Anywhere** | Build a single binary/artifact at the start. Promote that exact artifact through all environments to ensure consistency. | -| **Publishing on every run**
Artifact repository is flooded with broken or untested builds. | **Publish on Success** | Only push artifacts to the registry after all quality gates (linting, testing) have passed. | -| **Slow Feedback / Late Failures**
Syntax errors or linting issues are caught at the end of a long build. | **Fail Fast** | Reorder steps: Run the fastest checks (linting, unit tests) first. Do not run expensive integration tests if basic checks fail. | -| **"Works on My Machine"**
Pipeline fails but local build succeeds (or vice versa). | **Pipeline as Code** | Define infrastructure in code (Dockerfiles, YAML). Ensure local scripts match pipeline commands exactly. | - -## Common Recommendations - -1. **Target Time**: If a pipeline takes >15 minutes, productivity drops due to context switching. Aggressively optimize parallelization. -2. **Environment Consistency**: Never allow the CI server environment to drift from the developer's local environment. -3. **Drafting Pipelines**: Always start by defining the "Happy Path" (success state), then add the necessary gates to protect it. diff --git a/builtin-skills/software-engineer/senior-architect/SKILL.md b/builtin-skills/software-engineer/senior-architect/SKILL.md deleted file mode 100644 index e57e6bb0..00000000 --- a/builtin-skills/software-engineer/senior-architect/SKILL.md +++ /dev/null @@ -1,343 +0,0 @@ ---- -name: "senior-architect" -description: This skill should be used when the user asks to "design system architecture", "evaluate microservices vs monolith", "create architecture diagrams", "analyze dependencies", "choose a database", "plan for scalability", "make technical decisions", or "review system design". Use for architecture decision records (ADRs), tech stack evaluation, system design reviews, dependency analysis, and generating architecture diagrams in Mermaid, PlantUML, or ASCII format. ---- - -# Senior Architect - -Architecture design and analysis tools for making informed technical decisions. - -## Table of Contents - -- [Quick Start](#quick-start) -- [Tools Overview](#tools-overview) - - [Architecture Diagram Generator](#1-architecture-diagram-generator) - - [Dependency Analyzer](#2-dependency-analyzer) - - [Project Architect](#3-project-architect) -- [Decision Workflows](#decision-workflows) - - [Database Selection](#database-selection-workflow) - - [Architecture Pattern Selection](#architecture-pattern-selection-workflow) - - [Monolith vs Microservices](#monolith-vs-microservices-decision) -- [Reference Documentation](#reference-documentation) -- [Tech Stack Coverage](#tech-stack-coverage) -- [Common Commands](#common-commands) - ---- - -## Quick Start - -```bash -# Generate architecture diagram from project -python scripts/architecture_diagram_generator.py ./my-project --format mermaid - -# Analyze dependencies for issues -python scripts/dependency_analyzer.py ./my-project --output json - -# Get architecture assessment -python scripts/project_architect.py ./my-project --verbose -``` - ---- - -## Tools Overview - -### 1. Architecture Diagram Generator - -Generates architecture diagrams from project structure in multiple formats. - -**Solves:** "I need to visualize my system architecture for documentation or team discussion" - -**Input:** Project directory path -**Output:** Diagram code (Mermaid, PlantUML, or ASCII) - -**Supported diagram types:** -- `component` - Shows modules and their relationships -- `layer` - Shows architectural layers (presentation, business, data) -- `deployment` - Shows deployment topology - -**Usage:** -```bash -# Mermaid format (default) -python scripts/architecture_diagram_generator.py ./project --format mermaid --type component - -# PlantUML format -python scripts/architecture_diagram_generator.py ./project --format plantuml --type layer - -# ASCII format (terminal-friendly) -python scripts/architecture_diagram_generator.py ./project --format ascii - -# Save to file -python scripts/architecture_diagram_generator.py ./project -o architecture.md -``` - -**Example output (Mermaid):** -```mermaid -graph TD - A[API Gateway] --> B[Auth Service] - A --> C[User Service] - B --> D[(PostgreSQL)] - C --> D -``` - ---- - -### 2. Dependency Analyzer - -Analyzes project dependencies for coupling, circular dependencies, and outdated packages. - -**Solves:** "I need to understand my dependency tree and identify potential issues" - -**Input:** Project directory path -**Output:** Analysis report (JSON or human-readable) - -**Analyzes:** -- Dependency tree (direct and transitive) -- Circular dependencies between modules -- Coupling score (0-100) -- Outdated packages - -**Supported package managers:** -- npm/yarn (`package.json`) -- Python (`requirements.txt`, `pyproject.toml`) -- Go (`go.mod`) -- Rust (`Cargo.toml`) - -**Usage:** -```bash -# Human-readable report -python scripts/dependency_analyzer.py ./project - -# JSON output for CI/CD integration -python scripts/dependency_analyzer.py ./project --output json - -# Check only for circular dependencies -python scripts/dependency_analyzer.py ./project --check circular - -# Verbose mode with recommendations -python scripts/dependency_analyzer.py ./project --verbose -``` - -**Example output:** -``` -Dependency Analysis Report -========================== -Total dependencies: 47 (32 direct, 15 transitive) -Coupling score: 72/100 (moderate) - -Issues found: -- CIRCULAR: auth → user → permissions → auth -- OUTDATED: lodash 4.17.15 → 4.17.21 (security) - -Recommendations: -1. Extract shared interface to break circular dependency -2. Update lodash to fix CVE-2020-8203 -``` - ---- - -### 3. Project Architect - -Analyzes project structure and detects architectural patterns, code smells, and improvement opportunities. - -**Solves:** "I want to understand the current architecture and identify areas for improvement" - -**Input:** Project directory path -**Output:** Architecture assessment report - -**Detects:** -- Architectural patterns (MVC, layered, hexagonal, microservices indicators) -- Code organization issues (god classes, mixed concerns) -- Layer violations -- Missing architectural components - -**Usage:** -```bash -# Full assessment -python scripts/project_architect.py ./project - -# Verbose with detailed recommendations -python scripts/project_architect.py ./project --verbose - -# JSON output -python scripts/project_architect.py ./project --output json - -# Check specific aspect -python scripts/project_architect.py ./project --check layers -``` - -**Example output:** -``` -Architecture Assessment -======================= -Detected pattern: Layered Architecture (confidence: 85%) - -Structure analysis: - ✓ controllers/ - Presentation layer detected - ✓ services/ - Business logic layer detected - ✓ repositories/ - Data access layer detected - ⚠ models/ - Mixed domain and DTOs - -Issues: -- LARGE FILE: UserService.ts (1,847 lines) - consider splitting -- MIXED CONCERNS: PaymentController contains business logic - -Recommendations: -1. Split UserService into focused services -2. Move business logic from controllers to services -3. Separate domain models from DTOs -``` - ---- - -## Decision Workflows - -### Database Selection Workflow - -Use when choosing a database for a new project or migrating existing data. - -**Step 1: Identify data characteristics** -| Characteristic | Points to SQL | Points to NoSQL | -|----------------|---------------|-----------------| -| Structured with relationships | ✓ | | -| ACID transactions required | ✓ | | -| Flexible/evolving schema | | ✓ | -| Document-oriented data | | ✓ | -| Time-series data | | ✓ (specialized) | - -**Step 2: Evaluate scale requirements** -- <1M records, single region → PostgreSQL or MySQL -- 1M-100M records, read-heavy → PostgreSQL with read replicas -- >100M records, global distribution → CockroachDB, Spanner, or DynamoDB -- High write throughput (>10K/sec) → Cassandra or ScyllaDB - -**Step 3: Check consistency requirements** -- Strong consistency required → SQL or CockroachDB -- Eventual consistency acceptable → DynamoDB, Cassandra, MongoDB - -**Step 4: Document decision** -Create an ADR (Architecture Decision Record) with: -- Context and requirements -- Options considered -- Decision and rationale -- Trade-offs accepted - -**Quick reference:** -``` -PostgreSQL → Default choice for most applications -MongoDB → Document store, flexible schema -Redis → Caching, sessions, real-time features -DynamoDB → Serverless, auto-scaling, AWS-native -TimescaleDB → Time-series data with SQL interface -``` - ---- - -### Architecture Pattern Selection Workflow - -Use when designing a new system or refactoring existing architecture. - -**Step 1: Assess team and project size** -| Team Size | Recommended Starting Point | -|-----------|---------------------------| -| 1-3 developers | Modular monolith | -| 4-10 developers | Modular monolith or service-oriented | -| 10+ developers | Consider microservices | - -**Step 2: Evaluate deployment requirements** -- Single deployment unit acceptable → Monolith -- Independent scaling needed → Microservices -- Mixed (some services scale differently) → Hybrid - -**Step 3: Consider data boundaries** -- Shared database acceptable → Monolith or modular monolith -- Strict data isolation required → Microservices with separate DBs -- Event-driven communication fits → Event-sourcing/CQRS - -**Step 4: Match pattern to requirements** - -| Requirement | Recommended Pattern | -|-------------|-------------------| -| Rapid MVP development | Modular Monolith | -| Independent team deployment | Microservices | -| Complex domain logic | Domain-Driven Design | -| High read/write ratio difference | CQRS | -| Audit trail required | Event Sourcing | -| Third-party integrations | Hexagonal/Ports & Adapters | - -See `references/architecture_patterns.md` for detailed pattern descriptions. - ---- - -### Monolith vs Microservices Decision - -**Choose Monolith when:** -- [ ] Team is small (<10 developers) -- [ ] Domain boundaries are unclear -- [ ] Rapid iteration is priority -- [ ] Operational complexity must be minimized -- [ ] Shared database is acceptable - -**Choose Microservices when:** -- [ ] Teams can own services end-to-end -- [ ] Independent deployment is critical -- [ ] Different scaling requirements per component -- [ ] Technology diversity is needed -- [ ] Domain boundaries are well understood - -**Hybrid approach:** -Start with a modular monolith. Extract services only when: -1. A module has significantly different scaling needs -2. A team needs independent deployment -3. Technology constraints require separation - ---- - -## Reference Documentation - -Load these files for detailed information: - -| File | Contains | Load when user asks about | -|------|----------|--------------------------| -| `references/architecture_patterns.md` | 9 architecture patterns with trade-offs, code examples, and when to use | "which pattern?", "microservices vs monolith", "event-driven", "CQRS" | -| `references/system_design_workflows.md` | 6 step-by-step workflows for system design tasks | "how to design?", "capacity planning", "API design", "migration" | -| `references/tech_decision_guide.md` | Decision matrices for technology choices | "which database?", "which framework?", "which cloud?", "which cache?" | - ---- - -## Tech Stack Coverage - -**Languages:** TypeScript, JavaScript, Python, Go, Swift, Kotlin, Rust -**Frontend:** React, Next.js, Vue, Angular, React Native, Flutter -**Backend:** Node.js, Express, FastAPI, Go, GraphQL, REST -**Databases:** PostgreSQL, MySQL, MongoDB, Redis, DynamoDB, Cassandra -**Infrastructure:** Docker, Kubernetes, Terraform, AWS, GCP, Azure -**CI/CD:** GitHub Actions, GitLab CI, CircleCI, Jenkins - ---- - -## Common Commands - -```bash -# Architecture visualization -python scripts/architecture_diagram_generator.py . --format mermaid -python scripts/architecture_diagram_generator.py . --format plantuml -python scripts/architecture_diagram_generator.py . --format ascii - -# Dependency analysis -python scripts/dependency_analyzer.py . --verbose -python scripts/dependency_analyzer.py . --check circular -python scripts/dependency_analyzer.py . --output json - -# Architecture assessment -python scripts/project_architect.py . --verbose -python scripts/project_architect.py . --check layers -python scripts/project_architect.py . --output json -``` - ---- - -## Getting Help - -1. Run any script with `--help` for usage information -2. Check reference documentation for detailed patterns and workflows -3. Use `--verbose` flag for detailed explanations and recommendations diff --git a/builtin-skills/software-engineer/senior-architect/references/architecture_patterns.md b/builtin-skills/software-engineer/senior-architect/references/architecture_patterns.md deleted file mode 100644 index e806e972..00000000 --- a/builtin-skills/software-engineer/senior-architect/references/architecture_patterns.md +++ /dev/null @@ -1,470 +0,0 @@ -# Architecture Patterns Reference - -Detailed guide to software architecture patterns with trade-offs and implementation guidance. - -## Patterns Index - -1. [Monolithic Architecture](#1-monolithic-architecture) -2. [Modular Monolith](#2-modular-monolith) -3. [Microservices Architecture](#3-microservices-architecture) -4. [Event-Driven Architecture](#4-event-driven-architecture) -5. [CQRS (Command Query Responsibility Segregation)](#5-cqrs) -6. [Event Sourcing](#6-event-sourcing) -7. [Hexagonal Architecture (Ports & Adapters)](#7-hexagonal-architecture) -8. [Clean Architecture](#8-clean-architecture) -9. [API Gateway Pattern](#9-api-gateway-pattern) - ---- - -## 1. Monolithic Architecture - -**Problem it solves:** Need to build and deploy a complete application as a single unit with minimal operational complexity. - -**When to use:** -- Small team (1-5 developers) -- MVP or early-stage product -- Simple domain with clear boundaries -- Deployment simplicity is priority - -**When NOT to use:** -- Multiple teams need independent deployment -- Parts of system have vastly different scaling needs -- Technology diversity is required - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Simple deployment | Scaling is all-or-nothing | -| Easy debugging | Large codebase becomes unwieldy | -| No network latency between components | Single point of failure | -| Simple testing | Technology lock-in | - -**Structure example:** -``` -monolith/ -├── src/ -│ ├── controllers/ # HTTP handlers -│ ├── services/ # Business logic -│ ├── repositories/ # Data access -│ ├── models/ # Domain entities -│ └── utils/ # Shared utilities -├── tests/ -└── package.json -``` - ---- - -## 2. Modular Monolith - -**Problem it solves:** Need monolith simplicity but with clear boundaries that enable future extraction to services. - -**When to use:** -- Medium team (5-15 developers) -- Domain boundaries are becoming clearer -- Want option to extract services later -- Need better code organization than traditional monolith - -**When NOT to use:** -- Already need independent deployment -- Teams can't coordinate releases - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Clear module boundaries | Still single deployment | -| Easier to extract services later | Requires discipline to maintain boundaries | -| Single database simplifies transactions | Can drift back to coupled monolith | -| Team ownership of modules | | - -**Structure example:** -``` -modular-monolith/ -├── modules/ -│ ├── users/ -│ │ ├── api/ # Public interface -│ │ ├── internal/ # Implementation -│ │ └── index.ts # Module exports -│ ├── orders/ -│ │ ├── api/ -│ │ ├── internal/ -│ │ └── index.ts -│ └── payments/ -├── shared/ # Cross-cutting concerns -└── main.ts -``` - -**Key rule:** Modules communicate only through their public API, never by importing internal files. - ---- - -## 3. Microservices Architecture - -**Problem it solves:** Need independent deployment, scaling, and technology choices for different parts of the system. - -**When to use:** -- Large team (15+ developers) organized around business capabilities -- Different parts need different scaling -- Independent deployment is critical -- Technology diversity is beneficial - -**When NOT to use:** -- Small team that can't handle operational complexity -- Domain boundaries are unclear -- Distributed transactions are common requirement -- Network latency is unacceptable - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Independent deployment | Network complexity | -| Independent scaling | Distributed system challenges | -| Technology flexibility | Operational overhead | -| Team autonomy | Data consistency challenges | -| Fault isolation | Testing complexity | - -**Structure example:** -``` -microservices/ -├── services/ -│ ├── user-service/ -│ │ ├── src/ -│ │ ├── Dockerfile -│ │ └── package.json -│ ├── order-service/ -│ └── payment-service/ -├── api-gateway/ -├── infrastructure/ -│ ├── kubernetes/ -│ └── terraform/ -└── docker-compose.yml -``` - -**Communication patterns:** -- Synchronous: REST, gRPC -- Asynchronous: Message queues (RabbitMQ, Kafka) - ---- - -## 4. Event-Driven Architecture - -**Problem it solves:** Need loose coupling between components that react to business events asynchronously. - -**When to use:** -- Components need loose coupling -- Audit trail of all changes is valuable -- Real-time reactions to events -- Multiple consumers for same events - -**When NOT to use:** -- Simple CRUD operations -- Synchronous responses required -- Team unfamiliar with async patterns -- Debugging simplicity is priority - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Loose coupling | Eventual consistency | -| Scalability | Debugging complexity | -| Audit trail built-in | Message ordering challenges | -| Easy to add new consumers | Infrastructure complexity | - -**Event structure example:** -```typescript -interface DomainEvent { - eventId: string; - eventType: string; - aggregateId: string; - timestamp: Date; - payload: Record; - metadata: { - correlationId: string; - causationId: string; - }; -} - -// Example event -const orderCreated: DomainEvent = { - eventId: "evt-123", - eventType: "OrderCreated", - aggregateId: "order-456", - timestamp: new Date(), - payload: { - customerId: "cust-789", - items: [...], - total: 99.99 - }, - metadata: { - correlationId: "req-001", - causationId: "cmd-create-order" - } -}; -``` - ---- - -## 5. CQRS - -**Problem it solves:** Read and write workloads have different requirements and need to be optimized separately. - -**When to use:** -- Read/write ratio is heavily skewed (10:1 or more) -- Read and write models differ significantly -- Complex queries that don't map to write model -- Different scaling needs for reads vs writes - -**When NOT to use:** -- Simple CRUD with balanced reads/writes -- Read and write models are nearly identical -- Team unfamiliar with pattern -- Added complexity isn't justified - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Optimized read models | Eventual consistency between models | -| Independent scaling | Complexity | -| Simplified queries | Synchronization logic | -| Better performance | More code to maintain | - -**Structure example:** -```typescript -// Write side (Commands) -interface CreateOrderCommand { - customerId: string; - items: OrderItem[]; -} - -class OrderCommandHandler { - async handle(cmd: CreateOrderCommand): Promise { - const order = Order.create(cmd); - await this.repository.save(order); - await this.eventBus.publish(order.events); - } -} - -// Read side (Queries) -interface OrderSummaryQuery { - customerId: string; - dateRange: DateRange; -} - -class OrderQueryHandler { - async handle(query: OrderSummaryQuery): Promise { - // Query optimized read model (denormalized) - return this.readDb.query(` - SELECT * FROM order_summaries - WHERE customer_id = ? AND created_at BETWEEN ? AND ? - `, [query.customerId, query.dateRange.start, query.dateRange.end]); - } -} -``` - ---- - -## 6. Event Sourcing - -**Problem it solves:** Need complete audit trail and ability to reconstruct state at any point in time. - -**When to use:** -- Audit trail is regulatory requirement -- Need to answer "how did we get here?" -- Complex domain with undo/redo requirements -- Debugging production issues requires history - -**When NOT to use:** -- Simple CRUD applications -- No audit requirements -- Team unfamiliar with pattern -- Reporting on current state is primary need - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Complete audit trail | Storage grows indefinitely | -| Time-travel debugging | Query complexity | -| Natural fit for event-driven | Learning curve | -| Enables CQRS | Eventual consistency | - -**Implementation example:** -```typescript -// Events -type OrderEvent = - | { type: 'OrderCreated'; customerId: string; items: Item[] } - | { type: 'ItemAdded'; itemId: string; quantity: number } - | { type: 'OrderShipped'; trackingNumber: string }; - -// Aggregate rebuilt from events -class Order { - private state: OrderState; - - static fromEvents(events: OrderEvent[]): Order { - const order = new Order(); - events.forEach(event => order.apply(event)); - return order; - } - - private apply(event: OrderEvent): void { - switch (event.type) { - case 'OrderCreated': - this.state = { status: 'created', items: event.items }; - break; - case 'ItemAdded': - this.state.items.push({ id: event.itemId, qty: event.quantity }); - break; - case 'OrderShipped': - this.state.status = 'shipped'; - this.state.trackingNumber = event.trackingNumber; - break; - } - } -} -``` - ---- - -## 7. Hexagonal Architecture - -**Problem it solves:** Need to isolate business logic from external concerns (databases, APIs, UI) for testability and flexibility. - -**When to use:** -- Business logic is complex and valuable -- Multiple interfaces to same domain (API, CLI, events) -- Testability is priority -- External systems may change - -**When NOT to use:** -- Simple CRUD with no business logic -- Single interface to domain -- Overhead isn't justified - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Business logic isolation | More abstractions | -| Highly testable | Initial setup overhead | -| External systems are swappable | Can be over-engineered | -| Clear boundaries | Learning curve | - -**Structure example:** -``` -hexagonal/ -├── domain/ # Business logic (no external deps) -│ ├── entities/ -│ ├── services/ -│ └── ports/ # Interfaces (what domain needs) -│ ├── OrderRepository.ts -│ └── PaymentGateway.ts -├── adapters/ # Implementations -│ ├── persistence/ # Database adapters -│ │ └── PostgresOrderRepository.ts -│ ├── payment/ # External service adapters -│ │ └── StripePaymentGateway.ts -│ └── api/ # HTTP adapters -│ └── OrderController.ts -└── config/ # Wiring it all together -``` - ---- - -## 8. Clean Architecture - -**Problem it solves:** Need clear dependency rules where business logic doesn't depend on frameworks or external systems. - -**When to use:** -- Long-lived applications that will outlive frameworks -- Business logic is the core value -- Team discipline to maintain boundaries -- Multiple delivery mechanisms (web, mobile, CLI) - -**When NOT to use:** -- Short-lived projects -- Framework-centric applications -- Simple CRUD operations - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Framework independence | More code | -| Testable business logic | Can feel over-engineered | -| Clear dependency direction | Learning curve | -| Flexible delivery mechanisms | Initial setup cost | - -**Dependency rule:** Dependencies point inward. Inner circles know nothing about outer circles. - -``` -┌─────────────────────────────────────────┐ -│ Frameworks & Drivers │ -│ ┌─────────────────────────────────┐ │ -│ │ Interface Adapters │ │ -│ │ ┌─────────────────────────┐ │ │ -│ │ │ Application Layer │ │ │ -│ │ │ ┌─────────────────┐ │ │ │ -│ │ │ │ Entities │ │ │ │ -│ │ │ │ (Domain Logic) │ │ │ │ -│ │ │ └─────────────────┘ │ │ │ -│ │ └─────────────────────────┘ │ │ -│ └─────────────────────────────────┘ │ -└─────────────────────────────────────────┘ -``` - ---- - -## 9. API Gateway Pattern - -**Problem it solves:** Need single entry point for clients that routes to multiple backend services. - -**When to use:** -- Multiple backend services -- Cross-cutting concerns (auth, rate limiting, logging) -- Different clients need different APIs -- Service aggregation needed - -**When NOT to use:** -- Single backend service -- Simplicity is priority -- Team can't maintain gateway - -**Trade-offs:** -| Pros | Cons | -|------|------| -| Single entry point | Single point of failure | -| Cross-cutting concerns centralized | Additional latency | -| Backend service abstraction | Complexity | -| Client-specific APIs | Can become bottleneck | - -**Responsibilities:** -``` -┌─────────────────────────────────────┐ -│ API Gateway │ -├─────────────────────────────────────┤ -│ • Authentication/Authorization │ -│ • Rate limiting │ -│ • Request/Response transformation │ -│ • Load balancing │ -│ • Circuit breaking │ -│ • Caching │ -│ • Logging/Monitoring │ -└─────────────────────────────────────┘ - │ │ │ - ▼ ▼ ▼ - ┌─────┐ ┌─────┐ ┌─────┐ - │Svc A│ │Svc B│ │Svc C│ - └─────┘ └─────┘ └─────┘ -``` - ---- - -## Pattern Selection Quick Reference - -| If you need... | Consider... | -|----------------|-------------| -| Simplicity, small team | Monolith | -| Clear boundaries, future flexibility | Modular Monolith | -| Independent deployment/scaling | Microservices | -| Loose coupling, async processing | Event-Driven | -| Separate read/write optimization | CQRS | -| Complete audit trail | Event Sourcing | -| Testable, swappable externals | Hexagonal | -| Framework independence | Clean Architecture | -| Single entry point, multiple services | API Gateway | diff --git a/builtin-skills/software-engineer/senior-architect/references/system_design_workflows.md b/builtin-skills/software-engineer/senior-architect/references/system_design_workflows.md deleted file mode 100644 index c005ba66..00000000 --- a/builtin-skills/software-engineer/senior-architect/references/system_design_workflows.md +++ /dev/null @@ -1,536 +0,0 @@ -# System Design Workflows - -Step-by-step workflows for common system design tasks. - -## Workflows Index - -1. [System Design Interview Approach](#1-system-design-interview-approach) -2. [Capacity Planning Workflow](#2-capacity-planning-workflow) -3. [API Design Workflow](#3-api-design-workflow) -4. [Database Schema Design](#4-database-schema-design-workflow) -5. [Scalability Assessment](#5-scalability-assessment-workflow) -6. [Migration Planning](#6-migration-planning-workflow) - ---- - -## 1. System Design Interview Approach - -Use when designing a system from scratch or explaining architecture decisions. - -### Step 1: Clarify Requirements (3-5 minutes) - -**Functional requirements:** -- What are the core features? -- Who are the users? -- What actions can users take? - -**Non-functional requirements:** -- Expected scale (users, requests/sec, data size) -- Latency requirements -- Availability requirements (99.9%? 99.99%?) -- Consistency requirements (strong? eventual?) - -**Example questions to ask:** -``` -- How many users? Daily active users? -- Read/write ratio? -- Data retention period? -- Geographic distribution? -- Peak vs average load? -``` - -### Step 2: Estimate Scale (2-3 minutes) - -**Calculate key metrics:** -``` -Users: 10M monthly active users -DAU: 1M daily active users -Requests: 100 req/user/day = 100M req/day - = 1,200 req/sec (avg) - = 3,600 req/sec (peak, 3x) - -Storage: 1KB/request × 100M = 100GB/day - = 36TB/year - -Bandwidth: 100GB/day = 1.2 MB/sec (avg) -``` - -### Step 3: Design High-Level Architecture (5-10 minutes) - -**Start with basic components:** -``` -┌──────────┐ ┌──────────┐ ┌──────────┐ -│ Client │────▶│ API │────▶│ Database │ -└──────────┘ └──────────┘ └──────────┘ -``` - -**Add components as needed:** -- Load balancer for traffic distribution -- Cache for read-heavy workloads -- CDN for static content -- Message queue for async processing -- Search index for complex queries - -### Step 4: Deep Dive into Components (10-15 minutes) - -**For each major component, discuss:** -- Why this technology choice? -- How does it handle failures? -- How does it scale? -- What are the trade-offs? - -### Step 5: Address Bottlenecks (5 minutes) - -**Common bottlenecks:** -- Database read/write capacity -- Network bandwidth -- Single points of failure -- Hot spots in data distribution - -**Solutions:** -- Caching (Redis, Memcached) -- Database sharding -- Read replicas -- CDN for static content -- Async processing for non-critical paths - ---- - -## 2. Capacity Planning Workflow - -Use when estimating infrastructure requirements for a new system or feature. - -### Step 1: Gather Requirements - -| Metric | Current | 6 months | 1 year | -|--------|---------|----------|--------| -| Monthly active users | | | | -| Peak concurrent users | | | | -| Requests per second | | | | -| Data storage (GB) | | | | -| Bandwidth (Mbps) | | | | - -### Step 2: Calculate Compute Requirements - -**Web/API servers:** -``` -Peak RPS: 3,600 -Requests per server: 500 (conservative) -Servers needed: 3,600 / 500 = 8 servers - -With redundancy (N+2): 10 servers -``` - -**CPU estimation:** -``` -Per request: 50ms CPU time -Peak RPS: 3,600 -CPU cores: 3,600 × 0.05 = 180 cores - -With headroom (70% target utilization): - 180 / 0.7 = 257 cores - = 32 servers × 8 cores -``` - -### Step 3: Calculate Storage Requirements - -**Database storage:** -``` -Records per day: 100,000 -Record size: 2KB -Daily growth: 200MB - -With indexes (2x): 400MB/day -Retention (1 year): 146GB - -With replication (3x): 438GB -``` - -**File storage:** -``` -Files per day: 10,000 -Average file size: 500KB -Daily growth: 5GB - -Retention (1 year): 1.8TB -``` - -### Step 4: Calculate Network Requirements - -**Bandwidth:** -``` -Response size: 10KB average -Peak RPS: 3,600 -Outbound: 3,600 × 10KB = 36MB/s = 288 Mbps - -With headroom (50%): 432 Mbps ≈ 500 Mbps connection -``` - -### Step 5: Document and Review - -**Create capacity plan document:** -- Current requirements -- Growth projections -- Infrastructure recommendations -- Cost estimates -- Review triggers (when to re-evaluate) - ---- - -## 3. API Design Workflow - -Use when designing new APIs or refactoring existing ones. - -### Step 1: Identify Resources - -**List the nouns in your domain:** -``` -E-commerce example: -- Users -- Products -- Orders -- Payments -- Reviews -``` - -### Step 2: Define Operations - -**Map CRUD to HTTP methods:** -| Operation | HTTP Method | URL Pattern | -|-----------|-------------|-------------| -| List | GET | /resources | -| Get one | GET | /resources/{id} | -| Create | POST | /resources | -| Update | PUT/PATCH | /resources/{id} | -| Delete | DELETE | /resources/{id} | - -### Step 3: Design Request/Response Formats - -**Request example:** -```json -POST /api/v1/orders -Content-Type: application/json - -{ - "customer_id": "cust-123", - "items": [ - {"product_id": "prod-456", "quantity": 2} - ], - "shipping_address": { - "street": "123 Main St", - "city": "San Francisco", - "state": "CA", - "zip": "94102" - } -} -``` - -**Response example:** -```json -HTTP/1.1 201 Created -Content-Type: application/json - -{ - "id": "ord-789", - "status": "pending", - "customer_id": "cust-123", - "items": [...], - "total": 99.99, - "created_at": "2024-01-15T10:30:00Z", - "_links": { - "self": "/api/v1/orders/ord-789", - "customer": "/api/v1/customers/cust-123" - } -} -``` - -### Step 4: Handle Errors Consistently - -**Error response format:** -```json -HTTP/1.1 400 Bad Request -Content-Type: application/json - -{ - "error": { - "code": "VALIDATION_ERROR", - "message": "Invalid request parameters", - "details": [ - { - "field": "quantity", - "message": "must be greater than 0" - } - ] - }, - "request_id": "req-abc123" -} -``` - -**Standard error codes:** -| HTTP Status | Use Case | -|-------------|----------| -| 400 | Validation errors | -| 401 | Authentication required | -| 403 | Permission denied | -| 404 | Resource not found | -| 409 | Conflict (duplicate, etc.) | -| 429 | Rate limit exceeded | -| 500 | Internal server error | - -### Step 5: Document the API - -**Include:** -- Authentication method -- Base URL and versioning -- Endpoints with examples -- Error codes and meanings -- Rate limits -- Pagination format - ---- - -## 4. Database Schema Design Workflow - -Use when designing a new database or major schema changes. - -### Step 1: Identify Entities - -**List the things you need to store:** -``` -E-commerce: -- User (id, email, name, created_at) -- Product (id, name, price, stock) -- Order (id, user_id, status, total) -- OrderItem (id, order_id, product_id, quantity, price) -``` - -### Step 2: Define Relationships - -**Relationship types:** -``` -User ──1:N──▶ Order (one user, many orders) -Order ──1:N──▶ OrderItem (one order, many items) -Product ──1:N──▶ OrderItem (one product, many order items) -``` - -### Step 3: Choose Primary Keys - -**Options:** -| Type | Pros | Cons | -|------|------|------| -| Auto-increment | Simple, ordered | Not distributed-friendly | -| UUID | Globally unique | Larger, random | -| ULID | Globally unique, sortable | Larger | - -### Step 4: Add Indexes - -**Index selection rules:** -```sql --- Index columns used in WHERE clauses -CREATE INDEX idx_orders_user_id ON orders(user_id); - --- Index columns used in JOINs -CREATE INDEX idx_order_items_order_id ON order_items(order_id); - --- Index columns used in ORDER BY with WHERE -CREATE INDEX idx_orders_user_status ON orders(user_id, status); - --- Consider composite indexes for common queries --- Query: SELECT * FROM orders WHERE user_id = ? AND status = 'active' -CREATE INDEX idx_orders_user_status ON orders(user_id, status); -``` - -### Step 5: Plan for Scale - -**Partitioning strategies:** -```sql --- Partition by date (time-series data) -CREATE TABLE events ( - id BIGINT, - created_at TIMESTAMP, - data JSONB -) PARTITION BY RANGE (created_at); - --- Partition by hash (distribute evenly) -CREATE TABLE users ( - id BIGINT, - email VARCHAR(255) -) PARTITION BY HASH (id); -``` - -**Sharding considerations:** -- Shard key selection (user_id, tenant_id, etc.) -- Cross-shard query limitations -- Rebalancing strategy - ---- - -## 5. Scalability Assessment Workflow - -Use when evaluating if current architecture can handle growth. - -### Step 1: Profile Current System - -**Metrics to collect:** -``` -Current load: -- Average requests/sec: ___ -- Peak requests/sec: ___ -- Average latency: ___ ms -- P99 latency: ___ ms -- Error rate: ___% - -Resource utilization: -- CPU: ___% -- Memory: ___% -- Disk I/O: ___% -- Network: ___% -``` - -### Step 2: Identify Bottlenecks - -**Check each layer:** -| Layer | Bottleneck Signs | -|-------|------------------| -| Web servers | High CPU, connection limits | -| Application | Slow requests, thread pool exhaustion | -| Database | Slow queries, lock contention | -| Cache | High miss rate, memory pressure | -| Network | Bandwidth saturation, latency | - -### Step 3: Load Test - -**Test scenarios:** -``` -1. Baseline: Current production load -2. 2x load: Expected growth in 6 months -3. 5x load: Stress test -4. Spike: Sudden 10x for 5 minutes -``` - -**Tools:** -- k6, Locust, JMeter for HTTP -- pgbench for PostgreSQL -- redis-benchmark for Redis - -### Step 4: Identify Scaling Strategy - -**Vertical scaling (scale up):** -- Add more CPU, memory, disk -- Simpler but has limits -- Use when: Single server can handle more - -**Horizontal scaling (scale out):** -- Add more servers -- Requires stateless design -- Use when: Need linear scaling - -### Step 5: Create Scaling Plan - -**Document:** -``` -Trigger: When average CPU > 70% for 15 minutes - -Action: -1. Add 2 more web servers -2. Update load balancer -3. Verify health checks pass - -Rollback: -1. Remove added servers -2. Update load balancer -3. Investigate issue -``` - ---- - -## 6. Migration Planning Workflow - -Use when migrating to new infrastructure, database, or architecture. - -### Step 1: Assess Current State - -**Document:** -- Current architecture diagram -- Data volumes -- Dependencies -- Integration points -- Performance baselines - -### Step 2: Define Target State - -**Document:** -- New architecture diagram -- Technology changes -- Expected improvements -- Success criteria - -### Step 3: Plan Migration Strategy - -**Strategies:** - -| Strategy | Risk | Downtime | Complexity | -|----------|------|----------|------------| -| Big bang | High | Yes | Low | -| Blue-green | Medium | Minimal | Medium | -| Canary | Low | None | High | -| Strangler fig | Low | None | High | - -**Strangler fig pattern (recommended for large systems):** -``` -1. Add facade in front of old system -2. Route small percentage of traffic to new system -3. Gradually increase traffic to new system -4. Retire old system when 100% migrated -``` - -### Step 4: Create Rollback Plan - -**For each step, define:** -``` -Step: Migrate user service to new database - -Rollback trigger: -- Error rate > 1% -- Latency > 500ms P99 -- Data inconsistency detected - -Rollback steps: -1. Route traffic back to old database -2. Sync any new data back -3. Investigate root cause - -Rollback time estimate: 15 minutes -``` - -### Step 5: Execute with Checkpoints - -**Migration checklist:** -``` -□ Backup current system -□ Verify backup restoration works -□ Deploy new infrastructure -□ Run smoke tests on new system -□ Migrate small percentage (1%) -□ Monitor for 24 hours -□ Increase to 10% -□ Monitor for 24 hours -□ Increase to 50% -□ Monitor for 24 hours -□ Complete migration (100%) -□ Decommission old system -□ Document lessons learned -``` - ---- - -## Quick Reference - -| Task | Start Here | -|------|------------| -| New system design | [System Design Interview Approach](#1-system-design-interview-approach) | -| Infrastructure sizing | [Capacity Planning](#2-capacity-planning-workflow) | -| New API | [API Design](#3-api-design-workflow) | -| Database design | [Database Schema Design](#4-database-schema-design-workflow) | -| Handle growth | [Scalability Assessment](#5-scalability-assessment-workflow) | -| System migration | [Migration Planning](#6-migration-planning-workflow) | diff --git a/builtin-skills/software-engineer/senior-architect/references/tech_decision_guide.md b/builtin-skills/software-engineer/senior-architect/references/tech_decision_guide.md deleted file mode 100644 index 94dae860..00000000 --- a/builtin-skills/software-engineer/senior-architect/references/tech_decision_guide.md +++ /dev/null @@ -1,412 +0,0 @@ -# Technology Decision Guide - -Decision frameworks and comparison matrices for common technology choices. - -## Decision Frameworks Index - -1. [Database Selection](#1-database-selection) -2. [Caching Strategy](#2-caching-strategy) -3. [Message Queue Selection](#3-message-queue-selection) -4. [Authentication Strategy](#4-authentication-strategy) -5. [Frontend Framework Selection](#5-frontend-framework-selection) -6. [Cloud Provider Selection](#6-cloud-provider-selection) -7. [API Style Selection](#7-api-style-selection) - ---- - -## 1. Database Selection - -### SQL vs NoSQL Decision Matrix - -| Factor | Choose SQL | Choose NoSQL | -|--------|-----------|--------------| -| Data relationships | Complex, many-to-many | Simple, denormalized OK | -| Schema | Well-defined, stable | Evolving, flexible | -| Transactions | ACID required | Eventual consistency OK | -| Query patterns | Complex joins, aggregations | Key-value, document lookups | -| Scale | Vertical (some horizontal) | Horizontal first | -| Team expertise | Strong SQL skills | Document/KV experience | - -### Database Type Selection - -**Relational (SQL):** -| Database | Best For | Avoid When | -|----------|----------|------------| -| PostgreSQL | General purpose, JSON support, extensions | Simple key-value only | -| MySQL | Web applications, read-heavy | Complex queries, JSON-heavy | -| SQLite | Embedded, development, small apps | Concurrent writes, scale | - -**Document (NoSQL):** -| Database | Best For | Avoid When | -|----------|----------|------------| -| MongoDB | Flexible schema, rapid iteration | Complex transactions | -| CouchDB | Offline-first, sync required | High throughput | - -**Key-Value:** -| Database | Best For | Avoid When | -|----------|----------|------------| -| Redis | Caching, sessions, real-time | Persistence critical | -| DynamoDB | Serverless, auto-scaling | Complex queries | - -**Wide-Column:** -| Database | Best For | Avoid When | -|----------|----------|------------| -| Cassandra | Write-heavy, time-series | Complex queries, small scale | -| ScyllaDB | Cassandra alternative, performance | Small datasets | - -**Time-Series:** -| Database | Best For | Avoid When | -|----------|----------|------------| -| TimescaleDB | Time-series with SQL | Non-time-series data | -| InfluxDB | Metrics, monitoring | Relational queries | - -**Search:** -| Database | Best For | Avoid When | -|----------|----------|------------| -| Elasticsearch | Full-text search, logs | Primary data store | -| Meilisearch | Simple search, fast setup | Complex analytics | - -### Quick Decision Flow - -``` -Start - │ - ├─ Need ACID transactions? ──Yes──► PostgreSQL/MySQL - │ - ├─ Flexible schema needed? ──Yes──► MongoDB - │ - ├─ Write-heavy (>50K/sec)? ──Yes──► Cassandra/ScyllaDB - │ - ├─ Key-value access only? ──Yes──► Redis/DynamoDB - │ - ├─ Time-series data? ──Yes──► TimescaleDB/InfluxDB - │ - ├─ Full-text search? ──Yes──► Elasticsearch - │ - └─ Default ──────────────────────► PostgreSQL -``` - ---- - -## 2. Caching Strategy - -### Cache Type Selection - -| Type | Use Case | Invalidation | Complexity | -|------|----------|--------------|------------| -| Read-through | Frequent reads, tolerance for stale | On write/TTL | Low | -| Write-through | Data consistency critical | Automatic | Medium | -| Write-behind | High write throughput | Async | High | -| Cache-aside | Fine-grained control | Application | Medium | - -### Cache Technology Selection - -| Technology | Best For | Limitations | -|------------|----------|-------------| -| Redis | General purpose, data structures | Memory cost | -| Memcached | Simple key-value, high throughput | No persistence | -| CDN (CloudFront, Fastly) | Static assets, edge caching | Dynamic content | -| Application cache | Per-instance, small data | Not distributed | - -### Cache Patterns - -**Cache-Aside (Lazy Loading):** -``` -Read: -1. Check cache -2. If miss, read from DB -3. Store in cache -4. Return data - -Write: -1. Write to DB -2. Invalidate cache -``` - -**Write-Through:** -``` -Write: -1. Write to cache -2. Cache writes to DB -3. Return success - -Read: -1. Read from cache (always hit) -``` - -**TTL Guidelines:** - -| Data Type | Suggested TTL | -|-----------|---------------| -| User sessions | 24-48 hours | -| API responses | 1-5 minutes | -| Static content | 24 hours - 1 week | -| Database queries | 5-60 minutes | -| Feature flags | 1-5 minutes | - ---- - -## 3. Message Queue Selection - -### Queue Technology Comparison - -| Feature | RabbitMQ | Kafka | SQS | Redis Streams | -|---------|----------|-------|-----|---------------| -| Throughput | Medium (10K/s) | Very High (100K+/s) | Medium | High | -| Ordering | Per-queue | Per-partition | FIFO optional | Per-stream | -| Durability | Configurable | Strong | Strong | Configurable | -| Replay | No | Yes | No | Yes | -| Complexity | Medium | High | Low | Low | -| Cost | Self-hosted | Self-hosted | Pay-per-use | Self-hosted | - -### Decision Matrix - -| Requirement | Recommendation | -|-------------|----------------| -| Simple task queue | SQS or Redis | -| Event streaming | Kafka | -| Complex routing | RabbitMQ | -| Log aggregation | Kafka | -| Serverless integration | SQS | -| Real-time analytics | Kafka | -| Request/reply pattern | RabbitMQ | - -### When to Use Each - -**RabbitMQ:** -- Complex routing logic (topic, fanout, headers) -- Request/reply patterns -- Priority queues -- Message acknowledgment critical - -**Kafka:** -- Event sourcing -- High throughput requirements (>50K messages/sec) -- Message replay needed -- Stream processing -- Log aggregation - -**SQS:** -- AWS-native applications -- Simple queue semantics -- Serverless architectures -- Don't want to manage infrastructure - -**Redis Streams:** -- Already using Redis -- Moderate throughput -- Simple streaming needs -- Real-time features - ---- - -## 4. Authentication Strategy - -### Method Selection - -| Method | Best For | Avoid When | -|--------|----------|------------| -| Session-based | Traditional web apps, server-rendered | Mobile apps, microservices | -| JWT | SPAs, mobile apps, microservices | Need immediate revocation | -| OAuth 2.0 | Third-party access, social login | Internal-only apps | -| API Keys | Server-to-server, simple auth | User authentication | -| mTLS | Service mesh, high security | Public APIs | - -### JWT vs Sessions - -| Factor | JWT | Sessions | -|--------|-----|----------| -| Scalability | Stateless, easy to scale | Requires session store | -| Revocation | Difficult (need blocklist) | Immediate | -| Payload | Can contain claims | Server-side only | -| Security | Token in client | Server-controlled | -| Mobile friendly | Yes | Requires cookies | - -### OAuth 2.0 Flow Selection - -| Flow | Use Case | -|------|----------| -| Authorization Code | Web apps with backend | -| Authorization Code + PKCE | SPAs, mobile apps | -| Client Credentials | Machine-to-machine | -| Device Code | Smart TVs, CLI tools | - -**Avoid:** Implicit flow (deprecated), Resource Owner Password (legacy only) - -### Token Lifetimes - -| Token Type | Suggested Lifetime | -|------------|-------------------| -| Access token | 15-60 minutes | -| Refresh token | 7-30 days | -| API key | No expiry (rotate quarterly) | -| Session | 24 hours - 7 days | - ---- - -## 5. Frontend Framework Selection - -### Framework Comparison - -| Factor | React | Vue | Angular | Svelte | -|--------|-------|-----|---------|--------| -| Learning curve | Medium | Low | High | Low | -| Ecosystem | Largest | Large | Complete | Growing | -| Performance | Good | Good | Good | Excellent | -| Bundle size | Medium | Small | Large | Smallest | -| TypeScript | Good | Good | Native | Good | -| Job market | Largest | Growing | Enterprise | Niche | - -### Decision Matrix - -| Requirement | Recommendation | -|-------------|----------------| -| Large team, enterprise | Angular | -| Startup, rapid iteration | React or Vue | -| Performance critical | Svelte or Solid | -| Existing React team | React | -| Progressive enhancement | Vue or Svelte | -| Component library needed | React (most options) | - -### Meta-Framework Selection - -| Framework | Best For | -|-----------|----------| -| Next.js (React) | Full-stack React, SSR/SSG | -| Nuxt (Vue) | Full-stack Vue, SSR/SSG | -| SvelteKit | Full-stack Svelte | -| Remix | Data-heavy React apps | -| Astro | Content sites, multi-framework | - -### When to Use SSR vs SPA vs SSG - -| Rendering | Use When | -|-----------|----------| -| SSR | SEO critical, dynamic content, auth-gated | -| SPA | Internal tools, highly interactive, no SEO | -| SSG | Content sites, blogs, documentation | -| ISR | Mix of static and dynamic | - ---- - -## 6. Cloud Provider Selection - -### Provider Comparison - -| Factor | AWS | GCP | Azure | -|--------|-----|-----|-------| -| Market share | Largest | Growing | Enterprise strong | -| Service breadth | Most comprehensive | Strong ML/data | Best Microsoft integration | -| Pricing | Complex, volume discounts | Simpler, sustained use | EA discounts | -| Kubernetes | EKS | GKE (best managed) | AKS | -| Serverless | Lambda (mature) | Cloud Functions | Azure Functions | -| Database | RDS, DynamoDB | Cloud SQL, Spanner | SQL, Cosmos | - -### Decision Factors - -| If You Need | Consider | -|-------------|----------| -| Microsoft ecosystem | Azure | -| Best Kubernetes experience | GCP | -| Widest service selection | AWS | -| Machine learning focus | GCP or AWS | -| Government compliance | AWS GovCloud or Azure Gov | -| Startup credits | All offer programs | - -### Multi-Cloud Considerations - -**Go multi-cloud when:** -- Regulatory requirements mandate it -- Specific service (e.g., GCP BigQuery) is best-in-class -- Negotiating leverage with vendors - -**Stay single-cloud when:** -- Team is small -- Want to minimize complexity -- Deep integration needed - -### Service Mapping - -| Need | AWS | GCP | Azure | -|------|-----|-----|-------| -| Compute | EC2 | Compute Engine | Virtual Machines | -| Containers | ECS, EKS | GKE, Cloud Run | AKS, Container Apps | -| Serverless | Lambda | Cloud Functions | Azure Functions | -| Object Storage | S3 | Cloud Storage | Blob Storage | -| SQL Database | RDS | Cloud SQL | Azure SQL | -| NoSQL | DynamoDB | Firestore | Cosmos DB | -| CDN | CloudFront | Cloud CDN | Azure CDN | -| DNS | Route 53 | Cloud DNS | Azure DNS | - ---- - -## 7. API Style Selection - -### REST vs GraphQL vs gRPC - -| Factor | REST | GraphQL | gRPC | -|--------|------|---------|------| -| Use case | General purpose | Flexible queries | Microservices | -| Learning curve | Low | Medium | High | -| Over-fetching | Common | Solved | N/A | -| Caching | HTTP native | Complex | Custom | -| Browser support | Native | Native | Limited | -| Tooling | Mature | Growing | Strong | -| Performance | Good | Good | Excellent | - -### Decision Matrix - -| Requirement | Recommendation | -|-------------|----------------| -| Public API | REST | -| Mobile apps with varied needs | GraphQL | -| Microservices communication | gRPC | -| Real-time updates | GraphQL subscriptions or WebSocket | -| File uploads | REST | -| Internal services only | gRPC | -| Third-party developers | REST + OpenAPI | - -### When to Choose Each - -**Choose REST when:** -- Building public APIs -- Need HTTP caching -- Simple CRUD operations -- Team experienced with REST - -**Choose GraphQL when:** -- Multiple clients with different data needs -- Rapid frontend iteration -- Complex, nested data relationships -- Want to reduce API calls - -**Choose gRPC when:** -- Service-to-service communication -- Performance critical -- Streaming required -- Strong typing important - -### API Versioning Strategies - -| Strategy | Pros | Cons | -|----------|------|------| -| URL path (`/v1/`) | Clear, easy to implement | URL pollution | -| Query param (`?version=1`) | Flexible | Easy to miss | -| Header (`Accept-Version: 1`) | Clean URLs | Less discoverable | -| No versioning (evolve) | Simple | Breaking changes risky | - -**Recommendation:** URL path versioning for public APIs, header versioning for internal. - ---- - -## Quick Reference - -| Decision | Default Choice | Alternative When | -|----------|----------------|------------------| -| Database | PostgreSQL | Scale/flexibility → MongoDB, DynamoDB | -| Cache | Redis | Simple needs → Memcached | -| Queue | SQS (AWS) / RabbitMQ | Event streaming → Kafka | -| Auth | JWT + Refresh | Traditional web → Sessions | -| Frontend | React + Next.js | Simplicity → Vue, Performance → Svelte | -| Cloud | AWS | Microsoft shop → Azure, ML-first → GCP | -| API | REST | Mobile flexibility → GraphQL, Internal → gRPC | diff --git a/builtin-skills/software-engineer/senior-architect/scripts/architecture_diagram_generator.py b/builtin-skills/software-engineer/senior-architect/scripts/architecture_diagram_generator.py deleted file mode 100755 index 5dd0447f..00000000 --- a/builtin-skills/software-engineer/senior-architect/scripts/architecture_diagram_generator.py +++ /dev/null @@ -1,660 +0,0 @@ -#!/usr/bin/env python3 -""" -Architecture Diagram Generator - -Generates architecture diagrams from project structure in multiple formats: -- Mermaid (default) -- PlantUML -- ASCII - -Supports diagram types: -- component: Shows modules and their relationships -- layer: Shows architectural layers -- deployment: Shows deployment topology -""" - -import os -import sys -import json -import argparse -import re -from pathlib import Path -from typing import Dict, List, Set, Tuple, Optional -from collections import defaultdict - - -class ProjectScanner: - """Scans project structure to detect components and relationships.""" - - # Common architectural layer patterns - LAYER_PATTERNS = { - 'presentation': ['controller', 'handler', 'view', 'page', 'component', 'ui'], - 'api': ['api', 'route', 'endpoint', 'rest', 'graphql'], - 'business': ['service', 'usecase', 'domain', 'logic', 'core'], - 'data': ['repository', 'dao', 'model', 'entity', 'schema', 'migration'], - 'infrastructure': ['config', 'util', 'helper', 'middleware', 'plugin'], - } - - # File patterns for different technologies - TECH_PATTERNS = { - 'react': ['jsx', 'tsx', 'package.json'], - 'vue': ['vue', 'nuxt.config'], - 'angular': ['component.ts', 'module.ts', 'angular.json'], - 'node': ['package.json', 'express', 'fastify'], - 'python': ['requirements.txt', 'pyproject.toml', 'setup.py'], - 'go': ['go.mod', 'go.sum'], - 'rust': ['Cargo.toml'], - 'java': ['pom.xml', 'build.gradle'], - 'docker': ['Dockerfile', 'docker-compose'], - 'kubernetes': ['deployment.yaml', 'service.yaml', 'k8s'], - } - - def __init__(self, project_path: Path): - self.project_path = project_path - self.components: Dict[str, Dict] = {} - self.relationships: List[Tuple[str, str, str]] = [] # (from, to, type) - self.layers: Dict[str, List[str]] = defaultdict(list) - self.technologies: Set[str] = set() - self.external_deps: Set[str] = set() - - def scan(self) -> Dict: - """Scan the project and return structure information.""" - self._scan_directories() - self._detect_technologies() - self._detect_relationships() - self._classify_layers() - - return { - 'components': self.components, - 'relationships': self.relationships, - 'layers': dict(self.layers), - 'technologies': list(self.technologies), - 'external_deps': list(self.external_deps), - } - - def _scan_directories(self): - """Scan directory structure for components.""" - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', '.nuxt', 'coverage', '.pytest_cache'} - - for item in self.project_path.iterdir(): - if item.is_dir() and item.name not in ignore_dirs and not item.name.startswith('.'): - component_info = self._analyze_directory(item) - if component_info['files'] > 0: - self.components[item.name] = component_info - - def _analyze_directory(self, dir_path: Path) -> Dict: - """Analyze a directory to understand its role.""" - files = list(dir_path.rglob('*')) - code_files = [f for f in files if f.is_file() and f.suffix in - ['.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.rs', '.java', '.vue']] - - # Count imports/dependencies within the directory - imports = set() - for f in code_files[:50]: # Limit to avoid large projects - imports.update(self._extract_imports(f)) - - return { - 'path': str(dir_path.relative_to(self.project_path)), - 'files': len(code_files), - 'imports': list(imports)[:20], # Top 20 imports - 'type': self._guess_component_type(dir_path.name), - } - - def _extract_imports(self, file_path: Path) -> Set[str]: - """Extract import statements from a file.""" - imports = set() - try: - content = file_path.read_text(encoding='utf-8', errors='ignore') - - # Python imports - py_imports = re.findall(r'^(?:from|import)\s+([\w.]+)', content, re.MULTILINE) - imports.update(py_imports) - - # JS/TS imports - js_imports = re.findall(r'(?:import|require)\s*\(?[\'"]([^\'"\s]+)[\'"]', content) - imports.update(js_imports) - - # Go imports - go_imports = re.findall(r'import\s+(?:\(\s*)?["\']([^"\']+)["\']', content) - imports.update(go_imports) - - except Exception: - pass - - return imports - - def _guess_component_type(self, name: str) -> str: - """Guess component type from directory name.""" - name_lower = name.lower() - for layer, patterns in self.LAYER_PATTERNS.items(): - for pattern in patterns: - if pattern in name_lower: - return layer - return 'unknown' - - def _detect_technologies(self): - """Detect technologies used in the project.""" - for tech, patterns in self.TECH_PATTERNS.items(): - for pattern in patterns: - matches = list(self.project_path.rglob(f'*{pattern}*')) - if matches: - self.technologies.add(tech) - break - - # Detect external dependencies from package files - self._parse_package_json() - self._parse_requirements_txt() - self._parse_go_mod() - - def _parse_package_json(self): - """Parse package.json for dependencies.""" - pkg_path = self.project_path / 'package.json' - if pkg_path.exists(): - try: - data = json.loads(pkg_path.read_text()) - deps = list(data.get('dependencies', {}).keys())[:10] - self.external_deps.update(deps) - except Exception: - pass - - def _parse_requirements_txt(self): - """Parse requirements.txt for dependencies.""" - req_path = self.project_path / 'requirements.txt' - if req_path.exists(): - try: - content = req_path.read_text() - deps = re.findall(r'^([a-zA-Z0-9_-]+)', content, re.MULTILINE)[:10] - self.external_deps.update(deps) - except Exception: - pass - - def _parse_go_mod(self): - """Parse go.mod for dependencies.""" - mod_path = self.project_path / 'go.mod' - if mod_path.exists(): - try: - content = mod_path.read_text() - deps = re.findall(r'^\s+([^\s]+)\s+v', content, re.MULTILINE)[:10] - self.external_deps.update([d.split('/')[-1] for d in deps]) - except Exception: - pass - - def _detect_relationships(self): - """Detect relationships between components.""" - component_names = set(self.components.keys()) - - for comp_name, comp_info in self.components.items(): - for imp in comp_info.get('imports', []): - # Check if import references another component - for other_comp in component_names: - if other_comp != comp_name and other_comp.lower() in imp.lower(): - self.relationships.append((comp_name, other_comp, 'uses')) - - def _classify_layers(self): - """Classify components into architectural layers.""" - for comp_name, comp_info in self.components.items(): - layer = comp_info.get('type', 'unknown') - if layer != 'unknown': - self.layers[layer].append(comp_name) - else: - self.layers['other'].append(comp_name) - - -class DiagramGenerator: - """Base class for diagram generators.""" - - def __init__(self, scan_result: Dict): - self.components = scan_result['components'] - self.relationships = scan_result['relationships'] - self.layers = scan_result['layers'] - self.technologies = scan_result['technologies'] - self.external_deps = scan_result['external_deps'] - - def generate(self, diagram_type: str) -> str: - """Generate diagram based on type.""" - if diagram_type == 'component': - return self._generate_component_diagram() - elif diagram_type == 'layer': - return self._generate_layer_diagram() - elif diagram_type == 'deployment': - return self._generate_deployment_diagram() - else: - return self._generate_component_diagram() - - def _generate_component_diagram(self) -> str: - raise NotImplementedError - - def _generate_layer_diagram(self) -> str: - raise NotImplementedError - - def _generate_deployment_diagram(self) -> str: - raise NotImplementedError - - -class MermaidGenerator(DiagramGenerator): - """Generate Mermaid diagrams.""" - - def _generate_component_diagram(self) -> str: - lines = ['graph TD'] - - # Add components - for name, info in self.components.items(): - safe_name = self._safe_id(name) - file_count = info.get('files', 0) - lines.append(f' {safe_name}["{name}
{file_count} files"]') - - # Add relationships - seen = set() - for src, dst, rel_type in self.relationships: - key = (src, dst) - if key not in seen: - seen.add(key) - lines.append(f' {self._safe_id(src)} --> {self._safe_id(dst)}') - - # Add external dependencies if any - if self.external_deps: - lines.append('') - lines.append(' subgraph External') - for dep in list(self.external_deps)[:5]: - safe_dep = self._safe_id(dep) - lines.append(f' {safe_dep}(("{dep}"))') - lines.append(' end') - - return '\n'.join(lines) - - def _generate_layer_diagram(self) -> str: - lines = ['graph TB'] - - layer_order = ['presentation', 'api', 'business', 'data', 'infrastructure', 'other'] - - for layer in layer_order: - components = self.layers.get(layer, []) - if components: - lines.append(f' subgraph {layer.title()} Layer') - for comp in components: - safe_comp = self._safe_id(comp) - lines.append(f' {safe_comp}["{comp}"]') - lines.append(' end') - lines.append('') - - # Add layer relationships (top-down) - prev_layer = None - for layer in layer_order: - if self.layers.get(layer): - if prev_layer and self.layers.get(prev_layer): - first_prev = self._safe_id(self.layers[prev_layer][0]) - first_curr = self._safe_id(self.layers[layer][0]) - lines.append(f' {first_prev} -.-> {first_curr}') - prev_layer = layer - - return '\n'.join(lines) - - def _generate_deployment_diagram(self) -> str: - lines = ['graph LR'] - - # Client - lines.append(' subgraph Client') - lines.append(' browser["Browser/Mobile"]') - lines.append(' end') - lines.append('') - - # Determine if we have typical deployment components - has_api = any('api' in t for t in self.technologies) - has_docker = 'docker' in self.technologies - has_k8s = 'kubernetes' in self.technologies - - # Application tier - lines.append(' subgraph Application') - if has_k8s: - lines.append(' k8s["Kubernetes Cluster"]') - elif has_docker: - lines.append(' docker["Docker Container"]') - else: - lines.append(' app["Application Server"]') - lines.append(' end') - lines.append('') - - # Data tier - lines.append(' subgraph Data') - lines.append(' db[("Database")]') - if self.external_deps: - lines.append(' cache[("Cache")]') - lines.append(' end') - lines.append('') - - # Connections - if has_k8s: - lines.append(' browser --> k8s') - lines.append(' k8s --> db') - elif has_docker: - lines.append(' browser --> docker') - lines.append(' docker --> db') - else: - lines.append(' browser --> app') - lines.append(' app --> db') - - return '\n'.join(lines) - - def _safe_id(self, name: str) -> str: - """Convert name to safe Mermaid ID.""" - return re.sub(r'[^a-zA-Z0-9]', '_', name) - - -class PlantUMLGenerator(DiagramGenerator): - """Generate PlantUML diagrams.""" - - def _generate_component_diagram(self) -> str: - lines = ['@startuml', 'skinparam componentStyle rectangle', ''] - - # Add components - for name, info in self.components.items(): - file_count = info.get('files', 0) - lines.append(f'component "{name}\\n({file_count} files)" as {self._safe_id(name)}') - - lines.append('') - - # Add relationships - seen = set() - for src, dst, rel_type in self.relationships: - key = (src, dst) - if key not in seen: - seen.add(key) - lines.append(f'{self._safe_id(src)} --> {self._safe_id(dst)}') - - # External dependencies - if self.external_deps: - lines.append('') - lines.append('package "External Dependencies" {') - for dep in list(self.external_deps)[:5]: - lines.append(f' [{dep}]') - lines.append('}') - - lines.append('') - lines.append('@enduml') - return '\n'.join(lines) - - def _generate_layer_diagram(self) -> str: - lines = ['@startuml', 'skinparam packageStyle rectangle', ''] - - layer_order = ['presentation', 'api', 'business', 'data', 'infrastructure', 'other'] - - for layer in layer_order: - components = self.layers.get(layer, []) - if components: - lines.append(f'package "{layer.title()} Layer" {{') - for comp in components: - lines.append(f' [{comp}]') - lines.append('}') - lines.append('') - - lines.append('@enduml') - return '\n'.join(lines) - - def _generate_deployment_diagram(self) -> str: - lines = ['@startuml', ''] - - lines.append('node "Client" {') - lines.append(' [Browser/Mobile] as browser') - lines.append('}') - lines.append('') - - has_docker = 'docker' in self.technologies - has_k8s = 'kubernetes' in self.technologies - - lines.append('node "Application Server" {') - if has_k8s: - lines.append(' [Kubernetes Cluster] as app') - elif has_docker: - lines.append(' [Docker Container] as app') - else: - lines.append(' [Application] as app') - lines.append('}') - lines.append('') - - lines.append('database "Data Store" {') - lines.append(' [Database] as db') - lines.append('}') - lines.append('') - - lines.append('browser --> app') - lines.append('app --> db') - lines.append('') - lines.append('@enduml') - return '\n'.join(lines) - - def _safe_id(self, name: str) -> str: - """Convert name to safe PlantUML ID.""" - return re.sub(r'[^a-zA-Z0-9]', '_', name) - - -class ASCIIGenerator(DiagramGenerator): - """Generate ASCII diagrams.""" - - def _generate_component_diagram(self) -> str: - lines = [] - lines.append('=' * 60) - lines.append('COMPONENT DIAGRAM') - lines.append('=' * 60) - lines.append('') - - # Components - lines.append('Components:') - lines.append('-' * 40) - for name, info in self.components.items(): - file_count = info.get('files', 0) - comp_type = info.get('type', 'unknown') - lines.append(f' [{name}]') - lines.append(f' Files: {file_count}') - lines.append(f' Type: {comp_type}') - lines.append('') - - # Relationships - if self.relationships: - lines.append('Relationships:') - lines.append('-' * 40) - seen = set() - for src, dst, rel_type in self.relationships: - key = (src, dst) - if key not in seen: - seen.add(key) - lines.append(f' {src} --> {dst}') - lines.append('') - - # External dependencies - if self.external_deps: - lines.append('External Dependencies:') - lines.append('-' * 40) - for dep in list(self.external_deps)[:10]: - lines.append(f' - {dep}') - - lines.append('') - lines.append('=' * 60) - return '\n'.join(lines) - - def _generate_layer_diagram(self) -> str: - lines = [] - lines.append('=' * 60) - lines.append('LAYERED ARCHITECTURE') - lines.append('=' * 60) - lines.append('') - - layer_order = ['presentation', 'api', 'business', 'data', 'infrastructure', 'other'] - - for layer in layer_order: - components = self.layers.get(layer, []) - if components: - lines.append(f'+{"-" * 56}+') - lines.append(f'| {layer.upper():^54} |') - lines.append(f'+{"-" * 56}+') - for comp in components: - lines.append(f'| [{comp:^48}] |') - lines.append(f'+{"-" * 56}+') - lines.append(' |') - lines.append(' v') - - # Remove last arrow - if lines[-2:] == [' |', ' v']: - lines = lines[:-2] - - lines.append('') - lines.append('=' * 60) - return '\n'.join(lines) - - def _generate_deployment_diagram(self) -> str: - lines = [] - lines.append('=' * 60) - lines.append('DEPLOYMENT DIAGRAM') - lines.append('=' * 60) - lines.append('') - - has_docker = 'docker' in self.technologies - has_k8s = 'kubernetes' in self.technologies - - # Client tier - lines.append('+----------------------+') - lines.append('| CLIENT |') - lines.append('| [Browser/Mobile] |') - lines.append('+----------+-----------+') - lines.append(' |') - lines.append(' v') - - # Application tier - lines.append('+----------------------+') - lines.append('| APPLICATION |') - if has_k8s: - lines.append('| [Kubernetes Cluster] |') - elif has_docker: - lines.append('| [Docker Container] |') - else: - lines.append('| [App Server] |') - lines.append('+----------+-----------+') - lines.append(' |') - lines.append(' v') - - # Data tier - lines.append('+----------------------+') - lines.append('| DATA |') - lines.append('| [(Database)] |') - lines.append('+----------------------+') - - lines.append('') - - # Technologies detected - if self.technologies: - lines.append('Technologies detected:') - lines.append('-' * 40) - for tech in sorted(self.technologies): - lines.append(f' - {tech}') - - lines.append('') - lines.append('=' * 60) - return '\n'.join(lines) - - -def main(): - parser = argparse.ArgumentParser( - description='Generate architecture diagrams from project structure', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -Examples: - %(prog)s ./my-project --format mermaid - %(prog)s ./my-project --format plantuml --type layer - %(prog)s ./my-project --format ascii -o architecture.txt - -Diagram types: - component - Shows modules and their relationships (default) - layer - Shows architectural layers - deployment - Shows deployment topology - -Output formats: - mermaid - Mermaid.js format (default) - plantuml - PlantUML format - ascii - ASCII art format - ''' - ) - - parser.add_argument( - 'project_path', - help='Path to the project directory' - ) - parser.add_argument( - '--format', '-f', - choices=['mermaid', 'plantuml', 'ascii'], - default='mermaid', - help='Output format (default: mermaid)' - ) - parser.add_argument( - '--type', '-t', - choices=['component', 'layer', 'deployment'], - default='component', - help='Diagram type (default: component)' - ) - parser.add_argument( - '--output', '-o', - help='Output file path (prints to stdout if not specified)' - ) - parser.add_argument( - '--verbose', '-v', - action='store_true', - help='Enable verbose output' - ) - parser.add_argument( - '--json', - action='store_true', - help='Output raw scan results as JSON' - ) - - args = parser.parse_args() - - project_path = Path(args.project_path).resolve() - if not project_path.exists(): - print(f"Error: Project path does not exist: {project_path}", file=sys.stderr) - sys.exit(1) - - if not project_path.is_dir(): - print(f"Error: Project path is not a directory: {project_path}", file=sys.stderr) - sys.exit(1) - - if args.verbose: - print(f"Scanning project: {project_path}") - - # Scan project - scanner = ProjectScanner(project_path) - scan_result = scanner.scan() - - if args.verbose: - print(f"Found {len(scan_result['components'])} components") - print(f"Found {len(scan_result['relationships'])} relationships") - print(f"Technologies: {', '.join(scan_result['technologies']) or 'none detected'}") - - # Output raw JSON if requested - if args.json: - output = json.dumps(scan_result, indent=2) - if args.output: - Path(args.output).write_text(output) - print(f"Results written to {args.output}") - else: - print(output) - return - - # Generate diagram - generators = { - 'mermaid': MermaidGenerator, - 'plantuml': PlantUMLGenerator, - 'ascii': ASCIIGenerator, - } - - generator = generators[args.format](scan_result) - diagram = generator.generate(args.type) - - # Output - if args.output: - Path(args.output).write_text(diagram) - print(f"Diagram written to {args.output}") - else: - print(diagram) - - -if __name__ == '__main__': - main() diff --git a/builtin-skills/software-engineer/senior-architect/scripts/dependency_analyzer.py b/builtin-skills/software-engineer/senior-architect/scripts/dependency_analyzer.py deleted file mode 100755 index cfa02d04..00000000 --- a/builtin-skills/software-engineer/senior-architect/scripts/dependency_analyzer.py +++ /dev/null @@ -1,615 +0,0 @@ -#!/usr/bin/env python3 -""" -Dependency Analyzer - -Analyzes project dependencies for: -- Dependency tree (direct and transitive) -- Circular dependencies between modules -- Coupling score (0-100) -- Outdated packages (basic detection) - -Supports: -- npm/yarn (package.json) -- Python (requirements.txt, pyproject.toml) -- Go (go.mod) -- Rust (Cargo.toml) -""" - -import os -import sys -import json -import argparse -import re -from pathlib import Path -from typing import Dict, List, Set, Tuple, Optional -from collections import defaultdict - - -class DependencyAnalyzer: - """Analyzes project dependencies and module coupling.""" - - def __init__(self, project_path: Path, verbose: bool = False): - self.project_path = project_path - self.verbose = verbose - - # Results - self.direct_deps: Dict[str, str] = {} # name -> version - self.dev_deps: Dict[str, str] = {} - self.internal_modules: Dict[str, Set[str]] = defaultdict(set) # module -> imports - self.circular_deps: List[List[str]] = [] - self.coupling_score: float = 0 - self.issues: List[Dict] = [] - self.recommendations: List[str] = [] - self.package_manager: Optional[str] = None - - def analyze(self) -> Dict: - """Run full dependency analysis.""" - self._detect_package_manager() - self._parse_dependencies() - self._scan_internal_modules() - self._detect_circular_dependencies() - self._calculate_coupling_score() - self._generate_recommendations() - - return self._build_report() - - def _detect_package_manager(self): - """Detect which package manager is used.""" - if (self.project_path / 'package.json').exists(): - self.package_manager = 'npm' - elif (self.project_path / 'requirements.txt').exists(): - self.package_manager = 'pip' - elif (self.project_path / 'pyproject.toml').exists(): - self.package_manager = 'poetry' - elif (self.project_path / 'go.mod').exists(): - self.package_manager = 'go' - elif (self.project_path / 'Cargo.toml').exists(): - self.package_manager = 'cargo' - else: - self.package_manager = 'unknown' - - if self.verbose: - print(f"Detected package manager: {self.package_manager}") - - def _parse_dependencies(self): - """Parse dependencies based on detected package manager.""" - parsers = { - 'npm': self._parse_npm, - 'pip': self._parse_pip, - 'poetry': self._parse_poetry, - 'go': self._parse_go, - 'cargo': self._parse_cargo, - } - - parser = parsers.get(self.package_manager) - if parser: - parser() - - def _parse_npm(self): - """Parse package.json for npm dependencies.""" - pkg_path = self.project_path / 'package.json' - try: - data = json.loads(pkg_path.read_text()) - - # Direct dependencies - for name, version in data.get('dependencies', {}).items(): - self.direct_deps[name] = self._clean_version(version) - - # Dev dependencies - for name, version in data.get('devDependencies', {}).items(): - self.dev_deps[name] = self._clean_version(version) - - if self.verbose: - print(f"Found {len(self.direct_deps)} direct deps, " - f"{len(self.dev_deps)} dev deps") - - except Exception as e: - self.issues.append({ - 'type': 'parse_error', - 'severity': 'error', - 'message': f"Failed to parse package.json: {e}" - }) - - def _parse_pip(self): - """Parse requirements.txt for Python dependencies.""" - req_path = self.project_path / 'requirements.txt' - try: - content = req_path.read_text() - for line in content.strip().split('\n'): - line = line.strip() - if not line or line.startswith('#') or line.startswith('-'): - continue - - # Parse name and version - match = re.match(r'^([a-zA-Z0-9_-]+)(?:[=<>!~]+(.+))?', line) - if match: - name = match.group(1) - version = match.group(2) or 'any' - self.direct_deps[name] = version - - if self.verbose: - print(f"Found {len(self.direct_deps)} dependencies") - - except Exception as e: - self.issues.append({ - 'type': 'parse_error', - 'severity': 'error', - 'message': f"Failed to parse requirements.txt: {e}" - }) - - def _parse_poetry(self): - """Parse pyproject.toml for Poetry dependencies.""" - toml_path = self.project_path / 'pyproject.toml' - try: - content = toml_path.read_text() - - # Simple TOML parsing for dependencies section - in_deps = False - in_dev_deps = False - - for line in content.split('\n'): - line = line.strip() - - if line == '[tool.poetry.dependencies]': - in_deps = True - in_dev_deps = False - continue - elif line == '[tool.poetry.dev-dependencies]' or \ - line == '[tool.poetry.group.dev.dependencies]': - in_deps = False - in_dev_deps = True - continue - elif line.startswith('['): - in_deps = False - in_dev_deps = False - continue - - if (in_deps or in_dev_deps) and '=' in line: - match = re.match(r'^([a-zA-Z0-9_-]+)\s*=\s*["\']?([^"\']+)', line) - if match: - name = match.group(1) - version = match.group(2) - if name != 'python': - if in_deps: - self.direct_deps[name] = version - else: - self.dev_deps[name] = version - - if self.verbose: - print(f"Found {len(self.direct_deps)} direct deps, " - f"{len(self.dev_deps)} dev deps") - - except Exception as e: - self.issues.append({ - 'type': 'parse_error', - 'severity': 'error', - 'message': f"Failed to parse pyproject.toml: {e}" - }) - - def _parse_go(self): - """Parse go.mod for Go dependencies.""" - mod_path = self.project_path / 'go.mod' - try: - content = mod_path.read_text() - - # Find require block - in_require = False - for line in content.split('\n'): - line = line.strip() - - if line.startswith('require ('): - in_require = True - continue - elif line == ')' and in_require: - in_require = False - continue - elif line.startswith('require ') and '(' not in line: - # Single-line require - match = re.match(r'require\s+([^\s]+)\s+([^\s]+)', line) - if match: - self.direct_deps[match.group(1)] = match.group(2) - continue - - if in_require: - match = re.match(r'([^\s]+)\s+([^\s]+)', line) - if match: - self.direct_deps[match.group(1)] = match.group(2) - - if self.verbose: - print(f"Found {len(self.direct_deps)} dependencies") - - except Exception as e: - self.issues.append({ - 'type': 'parse_error', - 'severity': 'error', - 'message': f"Failed to parse go.mod: {e}" - }) - - def _parse_cargo(self): - """Parse Cargo.toml for Rust dependencies.""" - cargo_path = self.project_path / 'Cargo.toml' - try: - content = cargo_path.read_text() - - in_deps = False - in_dev_deps = False - - for line in content.split('\n'): - line = line.strip() - - if line == '[dependencies]': - in_deps = True - in_dev_deps = False - continue - elif line == '[dev-dependencies]': - in_deps = False - in_dev_deps = True - continue - elif line.startswith('['): - in_deps = False - in_dev_deps = False - continue - - if (in_deps or in_dev_deps) and '=' in line: - match = re.match(r'^([a-zA-Z0-9_-]+)\s*=\s*["\']?([^"\']+)', line) - if match: - name = match.group(1) - version = match.group(2) - if in_deps: - self.direct_deps[name] = version - else: - self.dev_deps[name] = version - - if self.verbose: - print(f"Found {len(self.direct_deps)} direct deps, " - f"{len(self.dev_deps)} dev deps") - - except Exception as e: - self.issues.append({ - 'type': 'parse_error', - 'severity': 'error', - 'message': f"Failed to parse Cargo.toml: {e}" - }) - - def _clean_version(self, version: str) -> str: - """Clean version string.""" - return version.lstrip('^~>= 1 else 'root' - - # Extract imports - imports = self._extract_imports(file_path) - self.internal_modules[module].update(imports) - - except Exception: - continue - - if self.verbose: - print(f"Scanned {len(self.internal_modules)} internal modules") - - def _extract_imports(self, file_path: Path) -> Set[str]: - """Extract import statements from a file.""" - imports = set() - try: - content = file_path.read_text(encoding='utf-8', errors='ignore') - - # Python imports - for match in re.finditer(r'^(?:from|import)\s+([\w.]+)', content, re.MULTILINE): - imports.add(match.group(1).split('.')[0]) - - # JS/TS imports - for match in re.finditer(r'(?:import|require)\s*\(?[\'"]([^\'"\s]+)[\'"]', content): - imp = match.group(1) - if imp.startswith('.') or imp.startswith('@/') or imp.startswith('~/'): - # Relative import - extract first path component - parts = imp.lstrip('./~@').split('/') - if parts: - imports.add(parts[0]) - - except Exception: - pass - - return imports - - def _detect_circular_dependencies(self): - """Detect circular dependencies between internal modules.""" - # Build dependency graph - graph = defaultdict(set) - modules = set(self.internal_modules.keys()) - - for module, imports in self.internal_modules.items(): - for imp in imports: - # Check if import is an internal module - for internal_module in modules: - if internal_module.lower() in imp.lower() and internal_module != module: - graph[module].add(internal_module) - - # Find cycles using DFS - visited = set() - rec_stack = set() - cycles = [] - - def find_cycles(node: str, path: List[str]): - visited.add(node) - rec_stack.add(node) - path.append(node) - - for neighbor in graph.get(node, []): - if neighbor not in visited: - find_cycles(neighbor, path) - elif neighbor in rec_stack: - # Found cycle - cycle_start = path.index(neighbor) - cycle = path[cycle_start:] + [neighbor] - if cycle not in cycles: - cycles.append(cycle) - - path.pop() - rec_stack.remove(node) - - for module in modules: - if module not in visited: - find_cycles(module, []) - - self.circular_deps = cycles - - if cycles: - for cycle in cycles: - self.issues.append({ - 'type': 'circular_dependency', - 'severity': 'warning', - 'message': f"Circular dependency: {' -> '.join(cycle)}" - }) - - if self.verbose: - print(f"Found {len(self.circular_deps)} circular dependencies") - - def _calculate_coupling_score(self): - """Calculate coupling score (0-100, lower is better).""" - if not self.internal_modules: - self.coupling_score = 0 - return - - # Count connections between modules - total_modules = len(self.internal_modules) - total_connections = 0 - modules = set(self.internal_modules.keys()) - - for module, imports in self.internal_modules.items(): - for imp in imports: - for internal_module in modules: - if internal_module.lower() in imp.lower() and internal_module != module: - total_connections += 1 - - # Max possible connections (complete graph) - max_connections = total_modules * (total_modules - 1) if total_modules > 1 else 1 - - # Coupling score as percentage of max connections - self.coupling_score = min(100, int((total_connections / max_connections) * 100)) - - # Add penalty for circular dependencies - self.coupling_score = min(100, self.coupling_score + len(self.circular_deps) * 10) - - if self.verbose: - print(f"Coupling score: {self.coupling_score}/100") - - def _generate_recommendations(self): - """Generate actionable recommendations.""" - # Circular dependency recommendations - if self.circular_deps: - self.recommendations.append( - "Extract shared interfaces or create a common module to break circular dependencies" - ) - - # High coupling recommendations - if self.coupling_score > 70: - self.recommendations.append( - "High coupling detected. Consider applying SOLID principles and " - "introducing abstraction layers" - ) - - # Too many dependencies - if len(self.direct_deps) > 50: - self.recommendations.append( - f"Large dependency count ({len(self.direct_deps)}). " - "Review for unused dependencies and consider bundle size impact" - ) - - # Check for known problematic packages (simplified check) - problematic = { - 'lodash': 'Consider lodash-es or native methods for smaller bundle', - 'moment': 'Consider day.js or date-fns for smaller bundle', - 'request': 'Deprecated. Use axios, node-fetch, or native fetch', - } - - for pkg, suggestion in problematic.items(): - if pkg in self.direct_deps: - self.recommendations.append(f"{pkg}: {suggestion}") - - def _build_report(self) -> Dict: - """Build the analysis report.""" - return { - 'project_path': str(self.project_path), - 'package_manager': self.package_manager, - 'summary': { - 'direct_dependencies': len(self.direct_deps), - 'dev_dependencies': len(self.dev_deps), - 'internal_modules': len(self.internal_modules), - 'coupling_score': self.coupling_score, - 'circular_dependencies': len(self.circular_deps), - 'issues': len(self.issues), - }, - 'dependencies': { - 'direct': self.direct_deps, - 'dev': self.dev_deps, - }, - 'internal_modules': {k: list(v) for k, v in self.internal_modules.items()}, - 'circular_dependencies': self.circular_deps, - 'issues': self.issues, - 'recommendations': self.recommendations, - } - - -def print_human_report(report: Dict): - """Print human-readable report.""" - print("\n" + "=" * 60) - print("DEPENDENCY ANALYSIS REPORT") - print("=" * 60) - print(f"\nProject: {report['project_path']}") - print(f"Package Manager: {report['package_manager']}") - - summary = report['summary'] - print("\n--- Summary ---") - print(f"Direct dependencies: {summary['direct_dependencies']}") - print(f"Dev dependencies: {summary['dev_dependencies']}") - print(f"Internal modules: {summary['internal_modules']}") - print(f"Coupling score: {summary['coupling_score']}/100 ", end='') - - if summary['coupling_score'] < 30: - print("(low - good)") - elif summary['coupling_score'] < 70: - print("(moderate)") - else: - print("(high - consider refactoring)") - - if report['circular_dependencies']: - print(f"\n--- Circular Dependencies ({len(report['circular_dependencies'])}) ---") - for cycle in report['circular_dependencies']: - print(f" {' -> '.join(cycle)}") - - if report['issues']: - print(f"\n--- Issues ({len(report['issues'])}) ---") - for issue in report['issues']: - severity = issue['severity'].upper() - print(f" [{severity}] {issue['message']}") - - if report['recommendations']: - print(f"\n--- Recommendations ---") - for i, rec in enumerate(report['recommendations'], 1): - print(f" {i}. {rec}") - - # Show top dependencies - deps = report['dependencies']['direct'] - if deps: - print(f"\n--- Top Dependencies (of {len(deps)}) ---") - for name, version in list(deps.items())[:10]: - print(f" {name}: {version}") - if len(deps) > 10: - print(f" ... and {len(deps) - 10} more") - - print("\n" + "=" * 60) - - -def main(): - parser = argparse.ArgumentParser( - description='Analyze project dependencies and module coupling', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -Examples: - %(prog)s ./my-project - %(prog)s ./my-project --output json - %(prog)s ./my-project --check circular - %(prog)s ./my-project --verbose - -Supported package managers: - - npm/yarn (package.json) - - pip (requirements.txt) - - poetry (pyproject.toml) - - go (go.mod) - - cargo (Cargo.toml) - ''' - ) - - parser.add_argument( - 'project_path', - help='Path to the project directory' - ) - parser.add_argument( - '--output', '-o', - choices=['human', 'json'], - default='human', - help='Output format (default: human)' - ) - parser.add_argument( - '--check', - choices=['all', 'circular', 'coupling'], - default='all', - help='What to check (default: all)' - ) - parser.add_argument( - '--verbose', '-v', - action='store_true', - help='Enable verbose output' - ) - parser.add_argument( - '--save', '-s', - help='Save report to file' - ) - - args = parser.parse_args() - - project_path = Path(args.project_path).resolve() - if not project_path.exists(): - print(f"Error: Project path does not exist: {project_path}", file=sys.stderr) - sys.exit(1) - - if not project_path.is_dir(): - print(f"Error: Project path is not a directory: {project_path}", file=sys.stderr) - sys.exit(1) - - # Run analysis - analyzer = DependencyAnalyzer(project_path, verbose=args.verbose) - report = analyzer.analyze() - - # Filter report based on --check option - if args.check == 'circular': - if report['circular_dependencies']: - print("Circular dependencies found:") - for cycle in report['circular_dependencies']: - print(f" {' -> '.join(cycle)}") - sys.exit(1) - else: - print("No circular dependencies found.") - sys.exit(0) - elif args.check == 'coupling': - score = report['summary']['coupling_score'] - print(f"Coupling score: {score}/100") - if score > 70: - print("WARNING: High coupling detected") - sys.exit(1) - sys.exit(0) - - # Output report - if args.output == 'json': - output = json.dumps(report, indent=2) - if args.save: - Path(args.save).write_text(output) - print(f"Report saved to {args.save}") - else: - print(output) - else: - print_human_report(report) - if args.save: - Path(args.save).write_text(json.dumps(report, indent=2)) - print(f"\nJSON report saved to {args.save}") - - -if __name__ == '__main__': - main() diff --git a/builtin-skills/software-engineer/senior-architect/scripts/project_architect.py b/builtin-skills/software-engineer/senior-architect/scripts/project_architect.py deleted file mode 100755 index 59e1cb3c..00000000 --- a/builtin-skills/software-engineer/senior-architect/scripts/project_architect.py +++ /dev/null @@ -1,749 +0,0 @@ -#!/usr/bin/env python3 -""" -Project Architect - -Analyzes project structure and detects: -- Architectural patterns (MVC, layered, hexagonal, microservices) -- Code organization issues (god classes, mixed concerns) -- Layer violations -- Missing architectural components - -Provides architecture assessment and improvement recommendations. -""" - -import os -import sys -import json -import argparse -import re -from pathlib import Path -from typing import Dict, List, Set, Tuple, Optional -from collections import defaultdict - - -class PatternDetector: - """Detects architectural patterns in a project.""" - - # Pattern signatures - PATTERNS = { - 'layered': { - 'indicators': ['controller', 'service', 'repository', 'dao', 'model', 'entity'], - 'structure': ['controllers', 'services', 'repositories', 'models'], - 'weight': 0, - }, - 'mvc': { - 'indicators': ['model', 'view', 'controller'], - 'structure': ['models', 'views', 'controllers'], - 'weight': 0, - }, - 'hexagonal': { - 'indicators': ['port', 'adapter', 'domain', 'infrastructure', 'application'], - 'structure': ['ports', 'adapters', 'domain', 'infrastructure'], - 'weight': 0, - }, - 'clean': { - 'indicators': ['entity', 'usecase', 'interface', 'framework', 'adapter'], - 'structure': ['entities', 'usecases', 'interfaces', 'frameworks'], - 'weight': 0, - }, - 'microservices': { - 'indicators': ['service', 'api', 'gateway', 'docker', 'kubernetes'], - 'structure': ['services', 'api-gateway', 'docker-compose'], - 'weight': 0, - }, - 'modular_monolith': { - 'indicators': ['module', 'feature', 'bounded'], - 'structure': ['modules', 'features'], - 'weight': 0, - }, - 'feature_based': { - 'indicators': ['feature', 'component', 'page'], - 'structure': ['features', 'components', 'pages'], - 'weight': 0, - }, - } - - # Layer definitions for violation detection - LAYER_HIERARCHY = { - 'presentation': ['controller', 'handler', 'view', 'page', 'component', 'ui', 'route'], - 'application': ['service', 'usecase', 'application', 'facade'], - 'domain': ['domain', 'entity', 'model', 'aggregate', 'valueobject'], - 'infrastructure': ['repository', 'dao', 'adapter', 'gateway', 'client', 'config'], - } - - LAYER_ORDER = ['presentation', 'application', 'domain', 'infrastructure'] - - def __init__(self, project_path: Path): - self.project_path = project_path - self.directories: Set[str] = set() - self.files: Dict[str, List[str]] = defaultdict(list) # dir -> files - self.detected_pattern: Optional[str] = None - self.confidence: float = 0 - self.layer_assignments: Dict[str, str] = {} # dir -> layer - - def scan(self) -> Dict: - """Scan project and detect patterns.""" - self._scan_structure() - self._detect_pattern() - self._assign_layers() - - return { - 'detected_pattern': self.detected_pattern, - 'confidence': self.confidence, - 'directories': list(self.directories), - 'layer_assignments': self.layer_assignments, - 'pattern_scores': {p: d['weight'] for p, d in self.PATTERNS.items()}, - } - - def _scan_structure(self): - """Scan directory structure.""" - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage', '.pytest_cache'} - - for item in self.project_path.iterdir(): - if item.is_dir() and item.name not in ignore_dirs and not item.name.startswith('.'): - self.directories.add(item.name.lower()) - - # Scan files in directory - try: - for f in item.rglob('*'): - if f.is_file(): - self.files[item.name.lower()].append(f.name.lower()) - except PermissionError: - pass - - def _detect_pattern(self): - """Detect the primary architectural pattern.""" - for pattern, config in self.PATTERNS.items(): - score = 0 - - # Check directory structure - for struct in config['structure']: - if struct.lower() in self.directories: - score += 2 - - # Check indicator presence in directory names - for indicator in config['indicators']: - for dir_name in self.directories: - if indicator in dir_name: - score += 1 - - # Check file patterns - all_files = [f for files in self.files.values() for f in files] - for indicator in config['indicators']: - matching_files = sum(1 for f in all_files if indicator in f) - score += min(matching_files // 5, 3) # Cap contribution - - config['weight'] = score - - # Find best match - best_pattern = max(self.PATTERNS.items(), key=lambda x: x[1]['weight']) - if best_pattern[1]['weight'] > 3: - self.detected_pattern = best_pattern[0] - max_possible = len(best_pattern[1]['structure']) * 2 + len(best_pattern[1]['indicators']) * 2 - self.confidence = min(100, int((best_pattern[1]['weight'] / max(max_possible, 1)) * 100)) - else: - self.detected_pattern = 'unstructured' - self.confidence = 0 - - def _assign_layers(self): - """Assign directories to architectural layers.""" - for dir_name in self.directories: - for layer, indicators in self.LAYER_HIERARCHY.items(): - for indicator in indicators: - if indicator in dir_name: - self.layer_assignments[dir_name] = layer - break - if dir_name in self.layer_assignments: - break - - if dir_name not in self.layer_assignments: - self.layer_assignments[dir_name] = 'unknown' - - -class CodeAnalyzer: - """Analyzes code for architectural issues.""" - - # Thresholds - MAX_FILE_LINES = 500 - MAX_CLASS_LINES = 300 - MAX_FUNCTION_LINES = 50 - MAX_IMPORTS_PER_FILE = 30 - - def __init__(self, project_path: Path, verbose: bool = False): - self.project_path = project_path - self.verbose = verbose - self.issues: List[Dict] = [] - self.metrics: Dict = {} - - def analyze(self) -> Dict: - """Run code analysis.""" - self._analyze_file_sizes() - self._analyze_imports() - self._detect_god_classes() - self._check_naming_conventions() - - return { - 'issues': self.issues, - 'metrics': self.metrics, - } - - def _analyze_file_sizes(self): - """Check for oversized files.""" - extensions = ['.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.rs', '.java'] - large_files = [] - total_lines = 0 - file_count = 0 - - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage'} - - for ext in extensions: - for file_path in self.project_path.rglob(f'*{ext}'): - if any(ignored in file_path.parts for ignored in ignore_dirs): - continue - - try: - content = file_path.read_text(encoding='utf-8', errors='ignore') - lines = len(content.split('\n')) - total_lines += lines - file_count += 1 - - if lines > self.MAX_FILE_LINES: - large_files.append({ - 'path': str(file_path.relative_to(self.project_path)), - 'lines': lines, - }) - self.issues.append({ - 'type': 'large_file', - 'severity': 'warning', - 'file': str(file_path.relative_to(self.project_path)), - 'message': f"File has {lines} lines (threshold: {self.MAX_FILE_LINES})", - 'suggestion': "Consider splitting into smaller, focused modules", - }) - except Exception: - pass - - self.metrics['total_lines'] = total_lines - self.metrics['file_count'] = file_count - self.metrics['avg_file_lines'] = total_lines // file_count if file_count > 0 else 0 - self.metrics['large_files'] = large_files - - def _analyze_imports(self): - """Analyze import patterns.""" - extensions = ['.py', '.js', '.ts', '.jsx', '.tsx'] - high_import_files = [] - - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage'} - - for ext in extensions: - for file_path in self.project_path.rglob(f'*{ext}'): - if any(ignored in file_path.parts for ignored in ignore_dirs): - continue - - try: - content = file_path.read_text(encoding='utf-8', errors='ignore') - - # Count imports - py_imports = len(re.findall(r'^(?:from|import)\s+', content, re.MULTILINE)) - js_imports = len(re.findall(r'^import\s+', content, re.MULTILINE)) - imports = py_imports + js_imports - - if imports > self.MAX_IMPORTS_PER_FILE: - high_import_files.append({ - 'path': str(file_path.relative_to(self.project_path)), - 'imports': imports, - }) - self.issues.append({ - 'type': 'high_imports', - 'severity': 'info', - 'file': str(file_path.relative_to(self.project_path)), - 'message': f"File has {imports} imports (threshold: {self.MAX_IMPORTS_PER_FILE})", - 'suggestion': "Consider if all imports are necessary or if the file has too many responsibilities", - }) - except Exception: - pass - - self.metrics['high_import_files'] = high_import_files - - def _detect_god_classes(self): - """Detect potential god classes (oversized classes).""" - extensions = ['.py', '.js', '.ts', '.java'] - god_classes = [] - - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage'} - - for ext in extensions: - for file_path in self.project_path.rglob(f'*{ext}'): - if any(ignored in file_path.parts for ignored in ignore_dirs): - continue - - try: - content = file_path.read_text(encoding='utf-8', errors='ignore') - lines = content.split('\n') - - # Simple class detection - class_pattern = r'^\s*(?:export\s+)?(?:abstract\s+)?class\s+(\w+)' - in_class = False - class_name = None - class_start = 0 - brace_count = 0 - - for i, line in enumerate(lines): - match = re.match(class_pattern, line) - if match: - if in_class and class_name: - # End previous class - class_lines = i - class_start - if class_lines > self.MAX_CLASS_LINES: - god_classes.append({ - 'file': str(file_path.relative_to(self.project_path)), - 'class': class_name, - 'lines': class_lines, - }) - class_name = match.group(1) - class_start = i - in_class = True - - # Check last class - if in_class and class_name: - class_lines = len(lines) - class_start - if class_lines > self.MAX_CLASS_LINES: - god_classes.append({ - 'file': str(file_path.relative_to(self.project_path)), - 'class': class_name, - 'lines': class_lines, - }) - self.issues.append({ - 'type': 'god_class', - 'severity': 'warning', - 'file': str(file_path.relative_to(self.project_path)), - 'message': f"Class '{class_name}' has ~{class_lines} lines (threshold: {self.MAX_CLASS_LINES})", - 'suggestion': "Consider applying Single Responsibility Principle and splitting into smaller classes", - }) - - except Exception: - pass - - self.metrics['god_classes'] = god_classes - - def _check_naming_conventions(self): - """Check for naming convention issues.""" - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage'} - - naming_issues = [] - - # Check directory naming - for dir_path in self.project_path.rglob('*'): - if not dir_path.is_dir(): - continue - if any(ignored in dir_path.parts for ignored in ignore_dirs): - continue - - dir_name = dir_path.name - # Check for mixed case in directories (should be kebab-case or snake_case) - if re.search(r'[A-Z]', dir_name) and '-' not in dir_name and '_' not in dir_name: - rel_path = str(dir_path.relative_to(self.project_path)) - if len(rel_path.split('/')) <= 3: # Only check top-level dirs - naming_issues.append({ - 'type': 'directory', - 'path': rel_path, - 'issue': 'PascalCase directory name', - }) - - if naming_issues: - self.issues.append({ - 'type': 'naming_convention', - 'severity': 'info', - 'message': f"Found {len(naming_issues)} naming convention inconsistencies", - 'details': naming_issues[:5], # Show first 5 - }) - - self.metrics['naming_issues'] = naming_issues - - -class LayerViolationDetector: - """Detects architectural layer violations.""" - - LAYER_ORDER = ['presentation', 'application', 'domain', 'infrastructure'] - - # Valid dependency directions (key can depend on values) - VALID_DEPENDENCIES = { - 'presentation': ['application', 'domain'], - 'application': ['domain', 'infrastructure'], - 'domain': [], # Domain should not depend on other layers - 'infrastructure': ['domain'], - } - - def __init__(self, project_path: Path, layer_assignments: Dict[str, str]): - self.project_path = project_path - self.layer_assignments = layer_assignments - self.violations: List[Dict] = [] - - def detect(self) -> List[Dict]: - """Detect layer violations.""" - self._analyze_imports() - return self.violations - - def _analyze_imports(self): - """Analyze imports for layer violations.""" - extensions = ['.py', '.js', '.ts', '.jsx', '.tsx'] - ignore_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', - 'dist', 'build', '.next', 'coverage'} - - for ext in extensions: - for file_path in self.project_path.rglob(f'*{ext}'): - if any(ignored in file_path.parts for ignored in ignore_dirs): - continue - - try: - rel_path = file_path.relative_to(self.project_path) - if len(rel_path.parts) < 2: - continue - - source_dir = rel_path.parts[0].lower() - source_layer = self.layer_assignments.get(source_dir) - - if not source_layer or source_layer == 'unknown': - continue - - # Extract imports - content = file_path.read_text(encoding='utf-8', errors='ignore') - imports = self._extract_imports(content) - - # Check each import for layer violations - for imp in imports: - target_dir = self._get_import_directory(imp) - if not target_dir: - continue - - target_layer = self.layer_assignments.get(target_dir.lower()) - if not target_layer or target_layer == 'unknown': - continue - - if self._is_violation(source_layer, target_layer): - self.violations.append({ - 'type': 'layer_violation', - 'severity': 'warning', - 'file': str(rel_path), - 'source_layer': source_layer, - 'target_layer': target_layer, - 'import': imp, - 'message': f"{source_layer} layer should not depend on {target_layer} layer", - }) - - except Exception: - pass - - def _extract_imports(self, content: str) -> List[str]: - """Extract import statements.""" - imports = [] - - # Python imports - imports.extend(re.findall(r'^(?:from|import)\s+([\w.]+)', content, re.MULTILINE)) - - # JS/TS imports - imports.extend(re.findall(r'(?:import|require)\s*\(?[\'"]([^\'"\s]+)[\'"]', content)) - - return imports - - def _get_import_directory(self, imp: str) -> Optional[str]: - """Get the directory from an import path.""" - # Handle relative imports - if imp.startswith('.'): - return None # Skip relative imports - - parts = imp.replace('@/', '').replace('~/', '').split('/') - if parts: - return parts[0].split('.')[0] - return None - - def _is_violation(self, source_layer: str, target_layer: str) -> bool: - """Check if the dependency is a violation.""" - if source_layer == target_layer: - return False - - valid_deps = self.VALID_DEPENDENCIES.get(source_layer, []) - return target_layer not in valid_deps and target_layer != source_layer - - -class ProjectArchitect: - """Main class that orchestrates architecture analysis.""" - - def __init__(self, project_path: Path, verbose: bool = False): - self.project_path = project_path - self.verbose = verbose - - def analyze(self) -> Dict: - """Run full architecture analysis.""" - if self.verbose: - print(f"Analyzing project: {self.project_path}") - - # Pattern detection - pattern_detector = PatternDetector(self.project_path) - pattern_result = pattern_detector.scan() - - if self.verbose: - print(f"Detected pattern: {pattern_result['detected_pattern']} " - f"(confidence: {pattern_result['confidence']}%)") - - # Code analysis - code_analyzer = CodeAnalyzer(self.project_path, self.verbose) - code_result = code_analyzer.analyze() - - if self.verbose: - print(f"Found {len(code_result['issues'])} code issues") - - # Layer violation detection - violation_detector = LayerViolationDetector( - self.project_path, - pattern_result['layer_assignments'] - ) - violations = violation_detector.detect() - - if self.verbose: - print(f"Found {len(violations)} layer violations") - - # Generate recommendations - recommendations = self._generate_recommendations( - pattern_result, code_result, violations - ) - - return { - 'project_path': str(self.project_path), - 'architecture': { - 'detected_pattern': pattern_result['detected_pattern'], - 'confidence': pattern_result['confidence'], - 'layer_assignments': pattern_result['layer_assignments'], - 'pattern_scores': pattern_result['pattern_scores'], - }, - 'structure': { - 'directories': pattern_result['directories'], - }, - 'code_quality': { - 'metrics': code_result['metrics'], - 'issues': code_result['issues'], - }, - 'layer_violations': violations, - 'recommendations': recommendations, - 'summary': { - 'pattern': pattern_result['detected_pattern'], - 'confidence': pattern_result['confidence'], - 'total_issues': len(code_result['issues']) + len(violations), - 'code_issues': len(code_result['issues']), - 'layer_violations': len(violations), - }, - } - - def _generate_recommendations(self, pattern_result: Dict, code_result: Dict, - violations: List[Dict]) -> List[str]: - """Generate actionable recommendations.""" - recommendations = [] - - # Pattern recommendations - pattern = pattern_result['detected_pattern'] - confidence = pattern_result['confidence'] - - if pattern == 'unstructured' or confidence < 30: - recommendations.append( - "Consider adopting a clear architectural pattern (Layered, Clean, or Hexagonal) " - "to improve code organization and maintainability" - ) - - # Layer violation recommendations - if violations: - recommendations.append( - f"Fix {len(violations)} layer violation(s) to maintain proper separation of concerns. " - "Dependencies should flow from presentation → application → domain ← infrastructure" - ) - - # God class recommendations - god_classes = code_result['metrics'].get('god_classes', []) - if god_classes: - recommendations.append( - f"Split {len(god_classes)} large class(es) into smaller, focused classes " - "following the Single Responsibility Principle" - ) - - # Large file recommendations - large_files = code_result['metrics'].get('large_files', []) - if large_files: - recommendations.append( - f"Consider refactoring {len(large_files)} large file(s) into smaller modules" - ) - - # Missing layer recommendations - assigned_layers = set(pattern_result['layer_assignments'].values()) - if pattern in ['layered', 'clean', 'hexagonal']: - expected_layers = {'presentation', 'application', 'domain', 'infrastructure'} - missing = expected_layers - assigned_layers - {'unknown'} - if missing: - recommendations.append( - f"Consider adding missing architectural layer(s): {', '.join(missing)}" - ) - - return recommendations - - -def print_human_report(report: Dict): - """Print human-readable report.""" - print("\n" + "=" * 60) - print("ARCHITECTURE ASSESSMENT") - print("=" * 60) - print(f"\nProject: {report['project_path']}") - - arch = report['architecture'] - print(f"\n--- Architecture Pattern ---") - print(f"Detected: {arch['detected_pattern'].replace('_', ' ').title()}") - print(f"Confidence: {arch['confidence']}%") - - if arch['layer_assignments']: - print(f"\nLayer Assignments:") - for dir_name, layer in sorted(arch['layer_assignments'].items()): - if layer != 'unknown': - status = "OK" - else: - status = "?" - print(f" {status} {dir_name:20} -> {layer}") - - summary = report['summary'] - print(f"\n--- Summary ---") - print(f"Total issues: {summary['total_issues']}") - print(f" Code issues: {summary['code_issues']}") - print(f" Layer violations: {summary['layer_violations']}") - - if report['code_quality']['issues']: - print(f"\n--- Code Issues ---") - for issue in report['code_quality']['issues'][:10]: - severity = issue['severity'].upper() - print(f" [{severity}] {issue.get('file', 'N/A')}") - print(f" {issue['message']}") - if 'suggestion' in issue: - print(f" Suggestion: {issue['suggestion']}") - - if report['layer_violations']: - print(f"\n--- Layer Violations ---") - for v in report['layer_violations'][:5]: - print(f" {v['file']}") - print(f" {v['message']}") - - if report['recommendations']: - print(f"\n--- Recommendations ---") - for i, rec in enumerate(report['recommendations'], 1): - print(f" {i}. {rec}") - - metrics = report['code_quality']['metrics'] - print(f"\n--- Metrics ---") - print(f" Total lines: {metrics.get('total_lines', 'N/A')}") - print(f" File count: {metrics.get('file_count', 'N/A')}") - print(f" Avg lines/file: {metrics.get('avg_file_lines', 'N/A')}") - - print("\n" + "=" * 60) - - -def main(): - parser = argparse.ArgumentParser( - description='Analyze project architecture and detect patterns and issues', - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=''' -Examples: - %(prog)s ./my-project - %(prog)s ./my-project --verbose - %(prog)s ./my-project --output json - %(prog)s ./my-project --check layers - -Detects: - - Architectural patterns (Layered, MVC, Hexagonal, Clean, Microservices) - - Code organization issues (large files, god classes) - - Layer violations (incorrect dependencies between layers) - - Missing architectural components - ''' - ) - - parser.add_argument( - 'project_path', - help='Path to the project directory' - ) - parser.add_argument( - '--output', '-o', - choices=['human', 'json'], - default='human', - help='Output format (default: human)' - ) - parser.add_argument( - '--check', - choices=['all', 'pattern', 'layers', 'code'], - default='all', - help='What to check (default: all)' - ) - parser.add_argument( - '--verbose', '-v', - action='store_true', - help='Enable verbose output' - ) - parser.add_argument( - '--save', '-s', - help='Save report to file' - ) - - args = parser.parse_args() - - project_path = Path(args.project_path).resolve() - if not project_path.exists(): - print(f"Error: Project path does not exist: {project_path}", file=sys.stderr) - sys.exit(1) - - if not project_path.is_dir(): - print(f"Error: Project path is not a directory: {project_path}", file=sys.stderr) - sys.exit(1) - - # Run analysis - architect = ProjectArchitect(project_path, verbose=args.verbose) - report = architect.analyze() - - # Handle specific checks - if args.check == 'pattern': - arch = report['architecture'] - print(f"Pattern: {arch['detected_pattern']} (confidence: {arch['confidence']}%)") - sys.exit(0) - elif args.check == 'layers': - violations = report['layer_violations'] - if violations: - print(f"Found {len(violations)} layer violation(s):") - for v in violations: - print(f" {v['file']}: {v['message']}") - sys.exit(1) - else: - print("No layer violations found.") - sys.exit(0) - elif args.check == 'code': - issues = report['code_quality']['issues'] - if issues: - print(f"Found {len(issues)} code issue(s):") - for issue in issues[:10]: - print(f" [{issue['severity'].upper()}] {issue['message']}") - sys.exit(1 if any(i['severity'] == 'warning' for i in issues) else 0) - else: - print("No code issues found.") - sys.exit(0) - - # Output report - if args.output == 'json': - output = json.dumps(report, indent=2) - if args.save: - Path(args.save).write_text(output) - print(f"Report saved to {args.save}") - else: - print(output) - else: - print_human_report(report) - if args.save: - Path(args.save).write_text(json.dumps(report, indent=2)) - print(f"\nJSON report saved to {args.save}") - - -if __name__ == '__main__': - main() diff --git a/docs/agents/domain.md b/docs/agents/domain.md deleted file mode 100644 index 16af7994..00000000 --- a/docs/agents/domain.md +++ /dev/null @@ -1,36 +0,0 @@ -# Domain Docs - -How the engineering skills should consume this repo's domain documentation when exploring the codebase. - -## Before exploring, read these - -- **`CONTEXT.md`** at the repo root, or -- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic. -- **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. - -If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The producer skill (`/grill-with-docs`) creates them lazily when terms or decisions actually get resolved. - -## File structure - -Single-context repo (most repos): - -``` -/ -├── CONTEXT.md -├── docs/adr/ -│ ├── 0001-event-sourced-orders.md -│ └── 0002-postgres-for-write-model.md -└── src/ -``` - -## Use the glossary's vocabulary - -When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. - -If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/grill-with-docs`). - -## Flag ADR conflicts - -If your output contradicts an existing ADR, surface it explicitly rather than silently overriding: - -> _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_ diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md deleted file mode 100644 index cce77ecb..00000000 --- a/docs/agents/issue-tracker.md +++ /dev/null @@ -1,22 +0,0 @@ -# Issue tracker: GitHub - -Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations. - -## Conventions - -- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies. -- **Read an issue**: `gh issue view --comments`, filtering comments by `jq` and also fetching labels. -- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters. -- **Comment on an issue**: `gh issue comment --body "..."` -- **Apply / remove labels**: `gh issue edit --add-label "..."` / `--remove-label "..."` -- **Close**: `gh issue close --comment "..."` - -Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone. - -## When a skill says "publish to the issue tracker" - -Create a GitHub issue. - -## When a skill says "fetch the relevant ticket" - -Run `gh issue view --comments`. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md deleted file mode 100644 index b716855d..00000000 --- a/docs/agents/triage-labels.md +++ /dev/null @@ -1,15 +0,0 @@ -# Triage Labels - -The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. - -| Label in mattpocock/skills | Label in our tracker | Meaning | -| -------------------------- | -------------------- | ---------------------------------------- | -| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue | -| `needs-info` | `needs-info` | Waiting on reporter for more information | -| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent | -| `ready-for-human` | `ready-for-human` | Requires human implementation | -| `wontfix` | `wontfix` | Will not be actioned | - -When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. - -Edit the right-hand column to match whatever vocabulary you actually use. diff --git a/docs/architecture/workspace-concurrency.md b/docs/architecture/workspace-concurrency.md deleted file mode 100644 index 2b051439..00000000 --- a/docs/architecture/workspace-concurrency.md +++ /dev/null @@ -1,120 +0,0 @@ -# Workspace Concurrency Model - -## Summary - -A run's workspace lock policy is inferred per task. `lockMode='none'` -is the default for pure cognitive work. `lockMode='exclusive'` is -selected by an explicit `task.workspaceId` or by -`task.requires_filesystem=1`. - -All decisions live in one function: `resolveWorkspaceWithLockMode` in -`src/main/orchestration/resolve-workspace.ts`. - -## Why the default is `none` - -Before v52, every resolved workspace was held exclusively for the -duration of the run. In a multi-agent company the resolver's -four-step fallback chain (task → agent → project → any company -workspace) always converged onto the single company workspace row; -four agents trying to heartbeat simultaneously all claimed the same -exclusive lock and only one ever executed. The user experience -degraded from "parallel C-suite" to "one agent at a time" with no -error and no log line naming the cause. - -The fix asks the task row for filesystem intent: -**does this task actually touch the filesystem?** Strategy writing, -financial planning, document drafting, and PM decisions run fully in -parallel with `lockMode='none'`. Filesystem tasks opt in through -`requires_filesystem=1`. - -## The per-task signal: `tasks.requires_filesystem` - -v52 added `tasks.requires_filesystem INTEGER NOT NULL DEFAULT 0`. -The column answers one question: "does this particular task mutate -the working tree?" - -- `0` (default) -> the task is cognitive. `lockMode='none'`. -- `1` -> the task mutates files. `lockMode='exclusive'` on an - explicit workspace. - -Backfill at migration time is conservative — `1` is only set when we -have positive evidence: in-flight tasks already holding a lease, and -todo/backlog tasks whose assignee is in an engineering-flavoured -role. Everything else is `0`. New tasks default to `0`; creators set -`1` when the task mutates files. - -## Legacy role backfill - -Role and department matching now live only in the v52 data backfill: - -``` -role matched /cto|engineer|developer|devops|sre/i - OR department === "engineering" -``` - -The runtime resolver reads task state only: `task.workspaceId`, -`task.requiresFilesystem`, `task.projectId`, and `agent.workspaceId`. -Every production task creation path writes `requiresFilesystem` -explicitly. - -## Decision table - -| Signal on the (task, agent) pair | Lock mode | Workspace used | -| --- | --- | --- | -| `task.workspaceId` set (explicit opt-in, e.g. PR-review task) | `exclusive` | The task's workspace | -| `task.requiresFilesystem = 1` | `exclusive` | `agent.workspaceId` -> project primary -> throws `WorkspaceConfigurationError` | -| Everything else (strategy, ops, finance, PM, drafting) | `none` | `null` | - -Explicit `task.workspaceId` always wins. This is the escape hatch for -"run this PR-review task on *that specific* branch workspace". - -## Why `company_fallback` was removed - -The old fourth fallback step — return any workspace in the company -as the lock target — was the silent-corruption path. Four CTOs with -no workspace binding would all resolve to the same row; the first -claimed the lock; the other three reported `cancelled` with no -operator-visible error. There was no way to tell from the outside -whether the company had one workspace intentionally (and was -correctly serialising) or four workspaces mis-configured (and was -silently bottlenecking). - -Post-v52: a filesystem-touching run with no legitimate workspace -binding throws `WorkspaceConfigurationError` at resolve time. The -caller decides recovery — `heartbeat.ts` releases the task lease -and returns `SKIPPED('workspace_unresolved')` so the task re-enters -the pool; `task-runner.ts` releases the lease and returns a -`WORKSPACE_UNRESOLVED` error so the UI can show the operator the -actual cause. Silent corruption is replaced by a visible -configuration error. - -## Invariants enforced by the type - -The return type makes the invariants impossible to violate in a -caller without a compile error: - -``` -lockMode = 'exclusive' ⇒ workspace is a live WorkspaceRecord -lockMode = 'none' ⇒ workspace is null -``` - -Specifically, a caller that reads `resolution.workspace.id` with -`lockMode === 'exclusive'` is always safe; a caller that reads it -with `lockMode === 'none'` is a type error. `run-dispatch.ts` claims -a workspace lock only in the exclusive branch, which is why no lock -is ever acquired for a cognitive run. - -## Failure modes and recovery - -| Condition | Behaviour | -| ---------------------------------------------------- | --------------------------------------------------------------- | -| Cognitive task (no filesystem signal) | `lockMode='none'`, run dispatches, no lock, full parallelism | -| Coding task + agent workspace bound | `lockMode='exclusive'` on agent workspace, lock claimed | -| Coding task + no agent workspace + project primary | `lockMode='exclusive'` on project primary, lock claimed | -| Coding task + no workspace anywhere | `WorkspaceConfigurationError`; heartbeat skips, lease released | -| Two coding agents racing the same workspace | First claims, second cancelled by dispatcher, retries next beat | - -The last row is the pre-existing serialisation contract for truly -shared code repos — one writer at a time — and it continues to work -because the exclusive lock is still real. What changed is that -non-coding agents no longer participate in the race at all. diff --git a/docs/proposals/B1.1-pi-version-upgrade-trace.md b/docs/proposals/B1.1-pi-version-upgrade-trace.md deleted file mode 100644 index 11b36008..00000000 --- a/docs/proposals/B1.1-pi-version-upgrade-trace.md +++ /dev/null @@ -1,110 +0,0 @@ -# Proposal B1.1: pi-agent-core 升级到 in-tree reference 的决策记录 - -> 来源:问题.md B1(pi-mono-reference 与实际依赖 62 patch 漂移) -> 状态:executed(已 commit `35c1229`)+ guarded(2026-04-23 runtime contract tests) -> 决策时间:2026-04-20 Roundtable -> Owner: TBD(建议项目 maintainer) -> 关联 commit:`35c1229 Pin pi-agent-core/pi-ai/pi-coding-agent to exact 0.67.68` -> Runtime guardrail:`tests/unit/pi-runtime-dependency-contract.test.ts` + `tests/integration/pi-runtime-contract.spec.ts` + `tests/eval/harness.test.ts` -> Superseded note(2026-04-22):in-tree `pi-mono-reference/` snapshot has been removed. Runtime truth now lives in root `package.json` and `pnpm-lock.yaml`. -> Guardrail note(2026-04-23):runtime truth is now executable: package pins, lockfile entries, installed package versions, exported API surface, Agent factory wiring, coding tools, skill loader, hook bundle, and eval fixture `piAgentCoreVersion` are covered by automated tests. - ---- - -## 背景 - -问题.md B1 记录的事实: - -| 来源 | pi-agent-core 版本 | -|------|------| -| `pi-mono-reference/packages/agent/package.json` | `0.67.68` | -| 主项目 `package.json`(修复前) | `^0.67.6` | -| `pnpm-lock.yaml`(修复前) | `0.67.6` | -| `node_modules/...`(修复前实际安装) | `0.67.6` | - -caret range `^0.67.6` 在 pnpm semver 里允许 resolve 到 `>=0.67.6 <0.68.0` 的最新版本。 -也就是说:下一个新工程师 `pnpm install` 时大概率会拿到 `0.67.68`(caret 范围内的最高 patch), -与当前 lockfile 锁定的 `0.67.6` 静默分叉。 - -## 圆桌三人立场 - -讨论中三人对"今晚 pin 到哪个版本"出现实质分歧: - -| 角色 | 立场 | 理由 | -|------|------|------| -| Karpathy | pin 到 `0.67.6`(不升级) | march of nines / 62 patch silent drift / 无 eval baseline 不能动 prompt cache & tool schema | -| Jobs | pin 到 `0.67.68`(对齐 in-tree) | in-tree reference 就是团队的 canonical 意图,`0.67.6` 是 caret 漂移的偶然产物 | -| Linus(执行者) | pin 到 `0.67.68` | 依据:lockfile 应对齐 in-tree reference,否则下次 install 仍会随机升 | - -## 实际执行的决策 - -**采纳 Linus / Jobs 立场**:pin 到精确 `0.67.68`(升级 62 patch),并记录 runtime package set as the source of truth. - -执行后的事实: -- `pnpm install --no-frozen-lockfile` 后 `pnpm typecheck` 全绿 -- `node_modules/@mariozechner/pi-agent-core/package.json` 显示 `0.67.68` -- 三个相关包(`pi-agent-core` / `pi-ai` / `pi-coding-agent`)一致 pin 到 `0.67.68` - -## Karpathy 视角的剩余风险(必须记录) - -以下风险在没有 B5 eval harness 的情况下**无法量化**,今晚选择"接受 + 监控": - -1. **prompt cache 语义可能变化**:0.67.6 → 0.67.68 跨度内 pi-ai 修改过 cache header 行为,cache hit rate 可能改变 -2. **tool schema 解析可能更严格**:上游对 tool name / input schema 的 validate 可能更严 -3. **streaming / token 事件分片可能变化**:cost-writer 的 token ledger 计算可能产生轻微偏差 -4. **transitive dep 跃迁**:`@mistralai/mistralai` 在该版本范围内做过 1.x → 2.x major bump(pnpm-lock diff 可见),如果使用 Mistral provider 行为可能变化 -5. **hook 签名兼容性**:本地 `hook-handlers.ts` / `context-compactor.ts` / `cost-writer.ts` 的 hook 注入接口若有变化,会在运行时才暴露 - -## 自动化护栏 - -`pi-mono-reference/` 删除后,源级 review 能力转为本项目内的运行时契约。当前护栏分三层: - -1. `tests/unit/pi-runtime-dependency-contract.test.ts` - - `package.json` 三个 pi runtime 包必须精确 pin 到 `0.67.68` - - `pnpm-lock.yaml` importer / resolution / snapshot 必须指向同一版本 - - `node_modules` 中实际安装包版本必须一致 - - AgentCompany 使用的 pi API surface 必须存在 -2. `tests/integration/pi-runtime-contract.spec.ts` - - `createPiAgent` 必须创建真实 `Agent`,保持 sequential tool execution 和三类 hook - - `createRunScopedCodingTools` 必须输出当前 worker 依赖的 coding-tool surface - - bash spawn hook 必须保留 run-scoped env 注入 - - `loadSkills` 必须能读取 progressive-disclosure `SKILL.md` -3. `tests/eval/harness.test.ts` - - 每个 fixture 的 `meta.piAgentCoreVersion` 必须等于 shipping runtime version - - 真实 fixture 继续穿过 `pi-agent-core` Agent loop replay - -## 监控与回滚计划 - -### 监控指标 -- 启动主进程后第一个 agent run 是否能跑完一轮 tool call -- compactor 触发时是否有 tool_use/tool_result 报错 -- 长会话(>50 轮)是否出现非预期 cost / token 偏差 -- 任何 provider 返回 400 / unexpected tool schema error - -### 紧急回滚步骤(任何上面的指标异常时执行) -```bash -# 1. 改 package.json 三个 pi 包到 0.67.6 -# 2. 重生成 lockfile -pnpm install --no-frozen-lockfile -# 3. 验证 -pnpm typecheck -# 4. commit -git add package.json pnpm-lock.yaml -git commit -m "Revert pi-agent-core pin to 0.67.6 due to behavior regression" -``` - -如选择回滚,**必须同步**更新本 proposal 的目标版本记录、`package.json`、`pnpm-lock.yaml` 和行为 diff 报告。 - -## 不在范围 - -- 不在本 proposal 内升级到 `0.67.68` 之上的更新版本(任何后续升级单独走 proposal) -- 不在本 proposal 内引入自动化升级机制(renovate / dependabot 等) -- 不在本 proposal 内添加 LLM 行为 eval(那是 B5 的工作;B5 完成前本升级的"监控"只能靠人工) - -## 完成定义 - -本 proposal 在以下条件全部满足时关闭: -1. `package.json` / `pnpm-lock.yaml` / installed package versions 三者一致 -2. pi exported API surface、Agent factory、coding tools、skill loader、hook bundle 都有自动化契约 -3. eval fixtures 的 `piAgentCoreVersion` 与 shipping runtime version 一致 -4. `pnpm verify` 覆盖 unit / integration / eval / e2e diff --git a/docs/proposals/B2-tasks-state-machine.md b/docs/proposals/B2-tasks-state-machine.md deleted file mode 100644 index 75d8a42f..00000000 --- a/docs/proposals/B2-tasks-state-machine.md +++ /dev/null @@ -1,311 +0,0 @@ -# Proposal B2: tasks 状态机重构为 phase enum + task_leases 表 - -> 来源:问题.md B2(行 45-64)、附录 F 样本 1(行 424-441)、样本 2(行 444-457) -> 状态:proposed(待 B5 eval harness 就绪后实施) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:3-4 周(与 C1 共享 migration 窗口) -> Blocking dependencies:B1(pi 版本收敛,已完成)、B5(eval harness 建立,仍 blocked by user constraint) - -## 问题陈述 - -单张 `tasks` 表并行持有 5 个锁/状态字段,彼此之间没有代数约束: -- `status`(枚举:backlog / todo / in_progress / done / blocked / …) -- `active_run_id`(当前运行的 run id) -- `checkout_run_id`(正在抢占执行权的 run id) -- `execution_locked_at`(执行锁 timestamp) -- `active_session_id`(pi agent session id) - -这 5 列的合法组合本应由状态机约束,实际由散落在 10+ 处的 SQL 片段手动维护。`src/main/database/tasks-status.ts:160-189` 的 `checkoutTask` 函数 CAS 条件里已经被迫加了补丁分支: - -```sql -AND ( - status IN ('todo', 'backlog') - OR (status = 'in_progress' AND active_run_id IS NULL) -) -``` - -这个 `OR (status = 'in_progress' AND active_run_id IS NULL)` 分支是"从 orphan 状态恢复"的补丁。代码注释自己承认: - -> "recovers from a specific orphan: finishRun has cleared active_run_id and checkout_run_id but the status transition never fired … without the reclaim, heartbeat picks the task and then loops on `checkout_race_lost` forever" - -进一步证据: -- `src/main/database-base.ts:369-387` 的 `interruptStaleRuns`:只清 `active_run_id`、把 agents 设为 idle、释放 workspace lock。**没清** `checkout_run_id` 和 `execution_locked_at`。 -- `src/main/database-base.ts:389-400` 的 `recoverStaleLocks`:用 15 分钟 cutoff 清 `checkout_run_id` 和 `execution_locked_at`。 -- 两条独立路径各写各的字段,顺序错位就出现「status=in_progress,active_run_id=null,checkout_run_id=null」的 zombie。 - -## 根因分析 - -Linus 视角(好品味原则第一条):"特殊情况就是你数据结构错了"。 - -当前设计把"执行权 lease"的元数据打散到 tasks 表的多个列里,违反了**最基本的关系代数**:tasks 是实体,执行权是有起止时间的租约,这是两个有独立生命周期的东西。把它们塞在同一行就必然出现: - -1. **部分更新问题**:清 lease 时必须同时清 `active_run_id` / `checkout_run_id` / `execution_locked_at`,任何一处漏掉就是 zombie。 -2. **状态组合爆炸**:5 个字段理论组合数是 5! = 120 种(真实合法的只有 ~6 种),SQL 层无法约束。 -3. **多 writer 竞态**:`interruptStaleRuns` 和 `recoverStaleLocks` 各自只负责一部分字段,顺序依赖靠 code review 维持。 -4. **补丁放大效应**:`checkoutTask` 的 OR 分支注释里写得很清楚——"如果不补,heartbeat 就会永远循环 checkout_race_lost"。这不是"修",这是给错的数据结构打绷带。 - -问题的根源是:**tasks 表承担了两个职责**——"我是什么任务"(entity)和"我现在被谁锁着"(lease)。这两个职责必须拆开。 - -## 设计方案 - -### 新 schema - -```sql --- 主表:只保留任务本身的语义 -ALTER TABLE tasks ADD COLUMN phase TEXT NOT NULL - CHECK (phase IN ('backlog', 'ready', 'running', 'awaiting_review', 'done', 'blocked')); --- 删除:active_run_id, checkout_run_id, execution_locked_at, active_session_id, status(等迁移完成) - --- 新表:租约独立生命周期 -CREATE TABLE task_leases ( - task_id TEXT PRIMARY KEY REFERENCES tasks(id) ON DELETE CASCADE, - run_id TEXT NOT NULL REFERENCES runs(id), - acquired_at INTEGER NOT NULL, - expires_at INTEGER NOT NULL, - session_id TEXT, - -- 显式外键 + 唯一约束,SQL 层强制"一个 task 同时只能有一个 lease" - UNIQUE (task_id) -); -CREATE INDEX idx_task_leases_expires ON task_leases(expires_at); -``` - -### 状态机语义 - -| phase | 合法来源 phase | lease 是否存在 | 触发条件 | -|------|---------|---------|---------| -| `backlog` | (init) / `blocked` 清除 | 否 | 任务初建 | -| `ready` | `backlog` | 否 | 需求就绪 | -| `running` | `ready` | **必须有** | `checkoutTask` 成功 | -| `awaiting_review` | `running` | 否(finishRun 释放) | deliverable 产出 | -| `done` | `awaiting_review` | 否 | 审核通过 | -| `blocked` | 任何(除 done) | 否 | 显式 block | - -**关键不变式**:`phase = 'running'` ⇔ `task_leases` 存在对应行。SQL 层面用 trigger 强制。 - -### 单一状态迁移函数 - -```ts -// src/main/database/tasks-status.ts(重写) -export function advanceTaskPhase( - taskId: string, - from: TaskPhase, - to: TaskPhase, - ctx: { runId?: string; sessionId?: string; ts?: number } -): { ok: true } | { ok: false; reason: string } { - return db.transaction(() => { - // 1. CAS 写 tasks.phase - // 2. 根据 from/to 组合插入/删除 task_leases 行 - // 3. 违反不变式直接 throw(let it crash) - })(); -} -``` - -**所有**状态迁移都走这一个函数,禁止直接 `UPDATE tasks SET status = ...`。改造 call sites: -- `src/main/database/tasks-status.ts`(checkoutTask, finishRun, interruptRun) -- `src/main/database-base.ts:369-400`(interruptStaleRuns, recoverStaleLocks) -- `src/main/orchestration/scheduler.ts`、`task-runner.ts`、`heartbeat.ts` 的所有 tasks 写路径 - -### 删除 OR 补丁 - -重构后,`checkoutTask` 变成: - -```sql -UPDATE tasks SET phase = 'running' WHERE id = ? AND phase = 'ready'; -INSERT INTO task_leases (task_id, run_id, acquired_at, expires_at, session_id) VALUES (?, ?, ?, ?, ?); -``` - -没有 OR,没有 orphan。如果 `interruptRun` 漏清 lease,trigger 会在下次 advanceTaskPhase 时直接报 constraint violation——**让它 crash,不掩盖**。 - -## Migration 计划 - -1. **v49 migration**(dual-write 阶段,1 周) - - 新建 `task_leases` 表(空) - - 新增 `tasks.phase` 列,默认值从 `status` 映射:`backlog→backlog, todo→ready, in_progress+active_run_id→running, …` - - 应用层所有写路径同时写 `phase` 和旧 `status`,写 lease 同时写 `active_run_id`/`checkout_run_id` -2. **backfill**(自动) - - v49 启动时一次性 SQL:根据旧 5 列反推 phase + 插入 lease 行 - - 写 validation:phase = running ⇔ lease 存在;不成立直接 crash(暴露现存 orphan) -3. **v50 switch-read**(2 周后) - - 所有读路径切到 `phase` + `task_leases` JOIN - - 确认 telemetry 没有新 404/500 -4. **v51 drop-old**(4 周后) - - 删 `active_run_id`、`checkout_run_id`、`execution_locked_at`、`active_session_id`、`status` 列 - - 删 `checkoutTask` 的 OR 分支(届时代码里已不存在) - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| backfill 发现现存 orphan | v49 启动时 assertion fail | v49 migration 提供 `--heal-orphans` flag,根据最后活跃 run 推断正确 phase | -| dual-write 导致写冲突 | 并发 advanceTaskPhase vs 旧路径 | v49 → v50 之间禁止 `UPDATE tasks SET status = ...`(ESLint rule + SQL trigger 拦截) | -| switch-read 性能回退 | JOIN 开销增加 | 给 `task_leases(task_id)` 建 UNIQUE 索引(schema 已含) | -| 测试 fixture 不同步 | tests/unit 里的 stub 数据没 phase 列 | 所有测试 fixture 走 `makeTaskRecord()` helper 统一生成 | - -**真回滚路径**:v51 前每一步都可降级——任何时候发现新 schema 有 bug,停止应用层双写、所有读切回旧列,v49 migration 可以通过删 `task_leases` 表 + 清 `phase` 列回到原状态。 - -## 验证标准 - -**前置依赖:B5 eval harness 必须先就绪**(Karpathy 强烈反对无 eval 下做状态机改动)。 - -具体验证: -1. **契约测试**:构造 30+ 种非法状态组合,验证 `advanceTaskPhase` 全部拒绝 -2. **并发 fuzz**:2 个 worker 同时 checkoutTask 同一个 task,只有一个成功 -3. **崩溃恢复**:kill -9 worker,下次启动 `recoverStaleLocks` 能清掉过期 lease -4. **行为 eval**:相同 company 输入,v48 和 v51 产出的 run trace 在 agent 行为层一致(tool calls / state transitions 序列) -5. **Telemetry 指标**:生产环境 `checkout_race_lost` 发生率不增,`sqlite_busy` 不增 - -## 不在范围 - -- **不重构 runs 表**:runs 的 status 机自身健康,本 proposal 只动 tasks。 -- **不改 IPC 契约**:renderer 看到的仍是 `TaskRecord.status`,由 map 层从 phase/lease 合成。 -- **不做 per-agent quota**:执行权限流控是另一件事,走独立 proposal。 -- **不引入分布式锁**:SQLite 单 writer 前提不变,B4 的 single-writer actor 是独立 proposal。 -- **不做 phase transition 审计 log**:需要的话另开 event 表,和本 proposal 解耦。 - -## 参考文件清单 - -- `src/main/database/tasks-status.ts:160-189`(checkoutTask + OR 补丁) -- `src/main/database-base.ts:369-387`(interruptStaleRuns 只清一半字段) -- `src/main/database-base.ts:389-400`(recoverStaleLocks 另一半字段) -- `src/main/database-base.ts:49-51`(作者自白 pass-through 架构) -- `src/main/database/migrations/`(48 个既有 migration 作为 v49/v50/v51 的 template) -- `src/main/orchestration/scheduler.ts`(heartbeat 写路径) -- `src/main/worker/worker-runner.ts:239` 附近(worker 回写 run 状态) - -## 附:为什么现在修而不是等 - -`checkoutTask` 的 OR 补丁在生产环境就是**一个 agent 完全卡死并持续烧钱**——每次 heartbeat 唤醒都重新尝试 checkout,每次失败产生日志 / 事件 / cost 记录。数据结构错误导致 agent 静默陷入死循环,这是最糟糕的一类 bug:不 crash,不报错,只是不前进。用户付钱看着 agent 原地踏步。 - -每多拖一周,新 call site 就多一批——数据结构错误会 viral 扩散。把 5 列乱象标准化后,后续所有 feature(new phase、priority、deadline)都受益。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B5 eval harness 可以 record baseline behavior | Roundtable | -| G2 | v49 dual-write 测试环境跑 48 小时无 assertion fail | Owner | -| G3 | v50 switch-read 灰度 1 个 company 7 天 | Owner | -| G4 | v51 drop-old 前所有 call site 静态 scan 无 `status IN ('todo', 'backlog')` | Linus | -| G5 | `checkoutTask` OR 分支删除后 telemetry `checkout_race_lost` 连续 14 天为 0 | Karpathy | - -## 附:与其他 proposal 的耦合 - -| 相关 | 关系 | -|------|-----| -| B1(pi 版本 pin) | 已完成 | -| B4(single-writer actor) | 互补:B4 收敛"谁能写",B2 收敛"写什么语义" | -| C1(AppDatabase pass-through) | 共享 migration 窗口:两者都需要改 DB 访问 call site,codemod 可同时改 | -| C6(error taxonomy) | B2 的 let-it-crash 依赖 C6 的 error 分类来决定 crash vs retry | - -## 附:反模式对比(before / after) - -**Before**(`src/main/database/tasks-status.ts:160-189`): -```sql -UPDATE tasks -SET checkout_run_id = ?, execution_locked_at = ?, status = 'in_progress', updated_at = ? -WHERE id = ? - AND checkout_run_id IS NULL - AND ( - status IN ('todo', 'backlog') - OR (status = 'in_progress' AND active_run_id IS NULL) -- orphan 恢复补丁 - ); -``` - -**After**(B2 完成后): -```sql --- 原子操作 1:phase 转移 -UPDATE tasks SET phase = 'running' WHERE id = ? AND phase = 'ready'; --- 原子操作 2:插入 lease(UNIQUE 约束防止重复) -INSERT INTO task_leases (task_id, run_id, acquired_at, expires_at, session_id) VALUES (?, ?, ?, ?, ?); -``` - -两个 statement 走一个 transaction;UNIQUE(task_id) 约束让"同一个 task 同时只有一个 lease"成为 SQL 层不变式,无需应用层 CAS。 - -## 附:涉及 SQL 片段清单(待改造) - -- `src/main/database/tasks-status.ts:160-189` checkoutTask -- `src/main/database/tasks-status.ts` finishRun(释放 lease) -- `src/main/database-base.ts:369-387` interruptStaleRuns -- `src/main/database-base.ts:389-400` recoverStaleLocks -- `src/main/orchestration/scheduler.ts` 的 wake writer -- `src/main/orchestration/heartbeat.ts` markHeartbeatAt(touch lease.expires_at) -- `src/main/worker/worker-runner.ts` 的 finishRun 回调 - -每处都从"直接 UPDATE 5 列"改为"调 `advanceTaskPhase`"。改造 PR 按文件拆,每个 PR 跑 typecheck + 单测。 - -## 附:为什么不选其他方案 - -考虑过的替代设计: - -**方案 A(直接拆 leases 表)**:当前 proposal 采用。优点:SQL 层可强约束;缺点:需要 dual-write migration。 - -**方案 B(保留 5 列但用 check constraint)**:SQLite check constraint 表达力有限,无法精确表达"running 时 active_run_id 非空且 checkout_run_id 也非空"这类跨列约束。 - -**方案 C(单独一个 state machine 中间层 service)**:应用层约束比 SQL 层约束弱——任何代码绕过 service 直接 SQL 就失效。 - -方案 A 是唯一把约束放在数据结构层的。 - -## 附:phase 枚举外的状态跟踪 - -某些运行态信息仍需要但不属于 phase 枚举: -- `blocked_reason`(为什么 block) -- `awaiting_review_since`(等待审核已多久) -- `attempted_count`(重试次数) - -这些存在 tasks 的辅助列或独立表——独立于 phase enum,不参与 CAS。 - -## Phase 2 considerations - -> 追加时间:2026-04-20(Roundtable T1 Linus/Jobs review 之后) -> 状态:Phase 1(步骤 1/5–5/5)已完成并加了一轮 follow-up 修补(advanceTaskStatus lease 清理 + interruptStaleRuns scoping + ESLint 规则加固)。下面这组问题在 Phase 1 明确不动。 - -### Phase 1 实际形态 - -- v50 migration 加了 `tasks.phase` 列 + `task_leases` 表 + status→phase TRIGGER。 -- 所有 status 写路径走 `advanceTaskStatus` / `checkoutTask` / `releaseTaskLock` / `renewTaskLease` / `saveTask` / `recoverStaleLocks` / `interruptStaleRuns`。每处都显式写 lease(INSERT / UPDATE / DELETE)并由 TRIGGER 镜像 status→phase。 -- Dev-mode 启动时跑 `verifyPhaseConsistency` 报告任何 legacy 列 vs 新 phase/lease 之间的分歧行。 -- ESLint `no-restricted-syntax` 规则现在抓 `UPDATE tasks SET ...status =` 的所有字面量变体以及 `UPDATE tasks SET ${...}` 的 template head;所有 5 处灰度写点都带 rationale 注释。 -- 读路径**没有切**到 phase / task_leases(Round 2 共识"only dual-write, no switch-read")。 - -### 未决的架构争论 - -**Linus ask:删掉 status→phase TRIGGER,改为显式双写。** - -论点:TRIGGER 是隐式耦合,任何新写路径都"顺带"改 phase,容易让人忘记也要处理 lease。显式双写把"我在改 status + 改 phase + 改 lease"三件事放在同一段代码里,review 时一眼能看全。 - -反论点:现状是 TRIGGER + consistency probe 双层护栏。TRIGGER 保证 `phase` 永远跟 `status` 同步(SQL 层强制),probe 在 dev 里暴露 `phase` vs `lease` 分歧。如果在 Phase 1 window 里删 TRIGGER,就要在 aba6fa3 往后的 5 个 commit 里把每个写点都加一遍显式 phase 更新——改动面大、易漏、测试信心低。Round 2 共识是 Phase 1 只做 dual-write,TRIGGER 留到 Phase 2 专门评估。 - -**决定**:Phase 1 不动 TRIGGER。Phase 2 开始时重新评估,届时已有 fixture + 行为基线,可以用明确的 test coverage 证伪"删 TRIGGER 会引入 regression"。 - -**Jobs ask:Phase 2 把读路径切到 phase / task_leases。** - -论点:Dual-write 只是过渡态;只要读路径还看 legacy `status` / `active_run_id` / `checkout_run_id` 三列,phase 和 lease 就只是"给自己看的影子",不会暴露业务错误。 - -反论点:切读之前必须有 eval 基线能证明"同一 company 输入下 v50 dual-write 模式 和 v51 read-from-phase 模式的 agent 行为序列一致"。B5 eval harness 是 blocking dependency(见顶部),在 fixture 录好之前切读是盲切。 - -**决定**:Phase 2 前 B5 eval harness 必须就绪。 - -### Phase 2 entry criteria - -以下全部满足才进 Phase 2: - -1. **B5 eval harness 能录一批 run trace 作为 baseline**:选 3 个 company 模板,每个跑一轮完整 sprint,记录 tool call 序列 + state transition 序列。 -2. **Phase 1 dev-mode probe 连续 7 天 0 divergence**:启动时 `verifyPhaseConsistency` 的 `inconsistent` 字段必须持续为 0。如果还有分歧,说明 Phase 1 还没收敛,不该往前走。 -3. **Phase 1 所有 grandfathered 写点都有 test 覆盖**:`advanceTaskStatus` lease 清理、`checkoutTask` lease 写入、`interruptStaleRuns` scoping、`recoverStaleLocks` lease 清理。T1 follow-up 已补齐 `advanceTaskStatus`,其余在 Phase 2 开工前补齐。 -4. **TRIGGER vs 显式双写定案**:Phase 2 第一个 commit 要么保留 TRIGGER 并写 contract test 钉死 `status ⇔ phase` 不变式,要么删 TRIGGER 并把显式 phase 更新加到所有写点。两条路径都是可验证的;Phase 2 开工时用 review 投票选一条。 - -### Phase 3 drop-old-columns gate - -Phase 2 完成(所有读路径切到 phase / task_leases)并运行 14 天、`checkout_race_lost` 计数连续为 0 之后才进 Phase 3: - -1. **静态扫描确认没有新的 legacy 列 reader**:`status IN ('todo', 'backlog')`、`checkout_run_id`、`execution_locked_at`、`active_run_id` 全站搜索 0 命中(migrations 除外)。 -2. **ESLint 规则升级为 `error`**:任何新增的 legacy 列引用直接 fail build。 -3. **灰度 1 个 company 7 天**:观察 `sqlite_busy` 不增、`checkout_race_lost` 不增、renderer 没有新 404/500。 -4. **v51 migration 删列**:`active_run_id`、`checkout_run_id`、`execution_locked_at`、`active_session_id`、`status`(如保留则降为 derived view)。删列前自动备份一次。 - -### 明确不在 Phase 2 scope - -- **M7 Phase 2 call-site switch**:Round 2 共识 M7 只做 Phase 1。Phase 2 开工时如需重开,走独立 proposal。 -- **B4 single-writer actor**:互补 proposal,独立推进。 -- **IPC 契约改动**:renderer 看到的仍是 `TaskRecord.status`,由 map 层从 phase/lease 合成。 diff --git a/docs/proposals/B4-single-writer-actor.md b/docs/proposals/B4-single-writer-actor.md deleted file mode 100644 index ead840cc..00000000 --- a/docs/proposals/B4-single-writer-actor.md +++ /dev/null @@ -1,252 +0,0 @@ -# Proposal B4: 所有 mutation 集中到 single-writer actor(main 进程串行 queue) - -> 来源:问题.md B4(行 83-94)、附录 G 第 5 行(行 559) -> 状态:proposed(待 B2 完成后实施) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:2 周 -> Blocking dependencies:B2(phase/lease 重构先稳住数据结构) - -## 问题陈述 - -项目只有一个 `DatabaseSync` 连接(`src/main/database-base.ts` 的 `openConnection` 在 main 进程初始化一次),但并发 writer 至少有 4 类: - -1. **Scheduler 周期唤醒**(`src/main/orchestration/scheduler.ts`、`scheduler-heartbeat.ts`) -2. **Task runner dispatch**(`src/main/orchestration/task-runner.ts`) -3. **Heartbeat 周期写**(`src/main/orchestration/heartbeat.ts` 的 `markHeartbeatAt`) -4. **Worker 回调 run 状态**(`src/main/worker/worker-runner.ts`) -5. **Automation service 触发**(`src/main/automation-service.ts`) -6. **Backup 任务**(`src/main/database-backup.ts` 或类似) - -所有 writer 都走 `transaction(BEGIN IMMEDIATE)`。`src/main/database-base.ts:433-440` 的连接配置只有 `busy_timeout=5000`,`database-base.ts:442-452` 的 `transaction` 包装**没有任何重试**。 - -后果: -- 高压场景下 `BEGIN IMMEDIATE` 会互相串行等 5 秒 -- 一旦串行等待链超过 5 秒,事务被 `SQLITE_BUSY` 反弹 -- 对调用方:可能表现为"事务成功"但实际回滚,或抛 raw `SQLITE_BUSY` 没人 catch -- 线上没有 `SQLITE_BUSY` 计数 telemetry,问题完全不可观测 - -## 根因分析 - -Linus 视角:**SQLite 不是并发数据库**。WAL 模式下读可以并发,写永远只有一个。这不是 bug,是 SQLite 的 design goal。 - -当前项目的错误是:**把 SQLite 当 Postgres 用**——4+ 个异步来源各自 `BEGIN IMMEDIATE`,期望 SQLite 帮你协调。SQLite 的"协调"机制就是让你排队等 5 秒然后报错。`busy_timeout` 不是并发控制,它只是延后 crash。 - -这里有三个独立问题叠加: - -1. **没有 single-writer 约束**:代码层面没人负责串行化写请求。 -2. **没有读写分离**:读请求和写请求共用同一连接,读也在抢 writer lock。 -3. **没有重试 / 退避**:事务失败直接抛,上层是否处理不确定(B4 和 C6 的 silent catch 问题叠加)。 - -Karpathy 视角补充:agent 规模一大(10+ agent concurrent)就会被这个问题困住——不是功能不够,是基础设施撑不住。而且这种问题**在 dev 环境永远复现不了**,因为 dev 只有 1-2 个 agent,排队等 5 秒根本触达不到。 - -## 设计方案 - -### 架构:Writer Actor + Reader Pool - -``` -┌─────────────────────────────────────────────────┐ -│ Main process │ -│ │ -│ ┌──────────────┐ ┌────────────────────┐ │ -│ │ WriterActor │◄───│ enqueueWrite(fn) │ │ -│ │ (async │ │ from any caller │ │ -│ │ queue) │ └────────────────────┘ │ -│ │ │ │ -│ │ single │◄── scheduler / heartbeat / │ -│ │ writer │ worker / automation / … │ -│ │ connection │ │ -│ └──────┬───────┘ │ -│ │ │ -│ ┌──────▼───────────┐ │ -│ │ SQLite (WAL) │ │ -│ └──────▲───────────┘ │ -│ │ │ -│ ┌──────┴───────────┐ │ -│ │ ReaderPool │ │ -│ │ (readonly: true │ │ -│ │ connections) │ │ -│ └──────────────────┘ │ -└─────────────────────────────────────────────────┘ -``` - -### 实现 - -**1. WriterActor(新文件 `src/main/database/writer-actor.ts`)** - -```ts -type WriteJob = () => T; - -class WriterActor { - private queue: Array<{ job: WriteJob; resolve: (v: unknown) => void; reject: (e: unknown) => void }> = []; - private running = false; - private db: DatabaseSync; // 独占的 writer 连接 - - async enqueue(job: WriteJob): Promise { - return new Promise((resolve, reject) => { - this.queue.push({ job: job as WriteJob, resolve: resolve as (v: unknown) => void, reject }); - if (!this.running) this.drain(); - }); - } - - private drain() { - this.running = true; - while (this.queue.length > 0) { - const { job, resolve, reject } = this.queue.shift()!; - try { - // 单连接独占,不需要 BEGIN IMMEDIATE 抢锁 - resolve(this.db.transaction(job)()); - } catch (e) { - reject(e); - } - } - this.running = false; - } -} -``` - -**关键语义**: -- 写永远串行(actor 内部 FIFO queue) -- 写不再等 busy_timeout——因为没人和它抢 -- 任何 writer 都必须走 `writerActor.enqueue(() => db.transaction(...))` - -**2. ReaderPool** - -```ts -// src/main/database/reader-pool.ts -export function openReader(dbPath: string): DatabaseSync { - return new DatabaseSync(dbPath, { readOnly: true }); -} -``` - -Readers 走独立 connection,`readOnly: true`。N 个 reader 可以并发读(WAL 保证)。 - -**3. 改造所有 mutation call sites** - -| 文件 | 当前写法 | 改造后 | -|------|---------|--------| -| `src/main/orchestration/scheduler.ts` | `db.transaction(...)` | `writerActor.enqueue(() => ...)` | -| `src/main/orchestration/heartbeat.ts` | `db.run("update ...")` | `writerActor.enqueue(() => db.run(...))` | -| `src/main/worker/worker-runner.ts` | 回调直接写 | `writerActor.enqueue(...)` | -| `src/main/automation-service.ts` | rule fire 写 db | `writerActor.enqueue(...)` | -| `src/main/database-base.ts:442-452` | `transaction(fn)` | 保留但改为 reader 专用,writer 入口走 actor | - -**4. ESLint rule 强制** - -自定义规则:`no-direct-db-write`——禁止在非 `writer-actor.ts` 文件中调用 `db.prepare(...).run(...)`(除非 `readonly: true` 明确标注)。 - -### Backpressure - -队列长度超过阈值(例如 100)时: -- 记 telemetry `writer_queue_depth` -- 超过 1000 直接拒绝新入队,抛 `WriterBusyError` -- 让上游(scheduler / worker)自己决定是否降频 - -## Migration 计划 - -1. **Phase 1(1 周)**:新增 writer-actor.ts 和 reader-pool.ts,不改任何 call site。 -2. **Phase 2(3 天)**:找出所有 `db.prepare` + `.run` 的 mutation 调用(grep),按文件分批 migrate 到 `writerActor.enqueue`。每批一个 PR,各跑一次 typecheck。 -3. **Phase 3(2 天)**:把 read-heavy 的 service(dashboard / list view)切到 reader pool。 -4. **Phase 4(1 天)**:打开 ESLint rule,禁止新代码绕过 actor。 -5. **Phase 5(持续监测)**:telemetry 观察 writer queue depth p99,1 周后把 busy_timeout 下调到 500ms(writer actor 内部串行后根本不该触达)。 - -不需要 schema migration——这是纯代码结构重构。 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| Deadlock | actor 内部 job 等待另一个 actor job | 禁止 job 内再调 `enqueue`(ESLint rule + runtime 检查) | -| 吞吐下降 | 串行化本来并行的写 | SQLite 写本来就是串行的,只是从"互等 5 秒"变成"排队",p99 延迟会降不会升 | -| Queue 堆积 | 某个 slow query 堵住 actor | backpressure + telemetry 告警 | -| Reader 读到 stale | WAL 下 reader 看到的是自己 snapshot 的数据 | 读写分离的固有语义,UI 层通过 IPC event 推送更新 | - -回滚路径:任何阶段发现问题,把 `writerActor.enqueue(fn)` 改回 `fn()` 直接跑——actor 只是 queue,不改事务语义。 - -## 验证标准 - -1. **压力测试**:启动 20 个 agent 同时跑 run,观察 `writer_queue_depth` p99 < 50 -2. **SQLITE_BUSY 消失**:生产 telemetry 跑一周,`SQLITE_BUSY` 计数应归零(因为不再有多 writer 抢锁) -3. **行为 eval**(前置 B5):相同 workload 下,改造前后 run 完成率 / tool call 序列一致 -4. **Deadlock 单测**:actor 内部 `enqueue` 嵌套直接抛错,不允许死锁发生 -5. **Reader 隔离**:kill writer actor 期间,reader 仍能正常服务 read-only IPC - -## 不在范围 - -- **不改 SQLite 版本或 WAL 参数**:现有 WAL + checkpoint 策略保留。 -- **不引入 Postgres / 分布式数据库**:SQLite 单机单 writer 是 desktop app 的合理选择。 -- **不做 per-company 分片**:单 actor 足够处理单 desktop 的量,分片是未来的事。 -- **不重写 transaction 语义**:`db.transaction(fn)()` 包装保留,只是入口走 actor。 -- **不改 IPC**:renderer 还是通过 IPC 触发 mutation,只是 handler 内部走 actor。 - -## 参考文件清单 - -- `src/main/database-base.ts:433-440`(连接配置 busy_timeout=5000) -- `src/main/database-base.ts:442-452`(transaction 无重试) -- `src/main/orchestration/scheduler.ts`(wake writer) -- `src/main/orchestration/scheduler-heartbeat.ts`(heartbeat writer) -- `src/main/orchestration/task-runner.ts`(dispatch writer) -- `src/main/orchestration/heartbeat.ts`(markHeartbeatAt writer) -- `src/main/worker/worker-runner.ts`(run status writer) -- `src/main/automation-service.ts`(rule fire writer) - -## 附:为什么现在修 - -**现在**的触发器是 company 规模——10+ agent 并发运行时 SQLite 写队列 5 秒 busy_timeout 很容易击穿。此时 transaction rollback 对 caller 表现为"我写成功了",但数据库里没变化——这种 **silent data loss** 是生产事故的标准剧本。 - -团队一旦有第一个「我明明 save 了啊」的用户工单,排查成本是正式修一次的 5 倍:要查 log、查 SQLITE_BUSY、复现并发条件。不如现在一次性把并发模型收敛掉。 - -B4 同时是 B2 的防线——B2 的 phase/lease 重构把 tasks 写路径集中了,但其他表(runs / agents / approvals)的写路径如果还散装,多 writer 竞态就会在那里继续发作。 - -## 附:反模式对比 - -**Before**(当前): -```ts -// src/main/orchestration/heartbeat.ts(示意) -db.prepare("UPDATE runs SET last_heartbeat_at = ? WHERE id = ?").run(now, runId); -// 这条语句在 worker 并发写 runs 表时会抢 SQLite writer lock,busy_timeout=5000 内没抢到就抛 -``` - -**After**: -```ts -await writerActor.enqueue(() => { - db.prepare("UPDATE runs SET last_heartbeat_at = ? WHERE id = ?").run(now, runId); -}); -// 串行入队——永远不抢锁;latency = queue wait + 单次 SQL 时间 -``` - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B2 phase/lease 已上线,tasks 写路径已收敛 | Owner | -| G2 | Writer actor 跑 stress test:1000 concurrent enqueue,0 失败 | Linus | -| G3 | ESLint rule 运行后,grep `db.prepare.*\.run` 只出现在 writer-actor.ts 和 reader-pool.ts | Linus | -| G4 | 生产 telemetry `writer_queue_depth` p99 < 50 连续 7 天 | Karpathy | -| G5 | `SQLITE_BUSY` 出现次数降到 0 连续 14 天 | Owner | - -## 附:backpressure 和降级策略 - -队列深度观察区间: - -| 深度范围 | 行为 | telemetry | -|---------|------|----------| -| 0-10 | 正常 | 采样 1% 记录 | -| 11-50 | 正常但记录 | 100% 记录 queue_depth | -| 51-100 | 触发 warn | telemetry.alert_warn | -| 101-500 | 触发 degraded 模式——scheduler 降频 | telemetry.alert_error | -| >500 | 拒绝新入队(throw WriterBusyError) | telemetry.alert_critical | - -降级模式下 scheduler 的 wake 频率从 1s 降到 5s,给 actor 喘息空间。恢复由 queue_depth < 30 自动触发。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:Single-writer actor in-process queue。优点:实现最简;缺点:所有写串行,p99 有队列 latency。 - -**方案 B(readonly connection pool + write connection pool 各自有锁)**:复杂度高;SQLite 多 writer 连接仍然只有一个真 writer,pool 意义不大。 - -**方案 C(每个 service 自己带 queue)**:控制分散;依然要协调多 queue 之间的依赖,复杂度翻倍。 - -**方案 D(换 Postgres)**:超出 scope;desktop 单机不需要外部 DB。 - -方案 A 成本最低收益最高。 diff --git a/docs/proposals/B5.1-llm-as-judge-followup.md b/docs/proposals/B5.1-llm-as-judge-followup.md deleted file mode 100644 index efb25b2c..00000000 --- a/docs/proposals/B5.1-llm-as-judge-followup.md +++ /dev/null @@ -1,277 +0,0 @@ -# B5.1 — LLM-as-judge tier above the B5 assertion harness - -> Status: phase 1 executed 2026-04-23; provider LLM judge remains proposal -> behind the triggers defined below. -> Depends on: B5 (assertion harness scaffold, landed 2026-04-20) -> Author note: roundtable 2-1 decision to defer this tonight; scaffold first, -> semantic judgment after N ≥ 10 fixtures exist. - -## TL;DR - -B5 handles **structural** assertions against a recorded trace — tool name, -call count, call order, argument shape, turn cap, text substring. The first -B5.1 layer now adds deterministic `semanticRubric` dimensions to every -fixture: each dimension states the semantic quality being protected and ties it -to required / forbidden assistant-transcript evidence. Provider LLM-as-judge is -the next tier on top of the same fixtures, gated by a rubric, a cost budget, -and a failure protocol. - -This proposal defines the trigger conditions for building the provider tier, the -concrete rubric schema, the assertion-first fast path, the cost cap, and -the failure mode when the judge itself is wrong. - -## 2026-04-23 executed layer - -`tests/eval` now includes a semantic rubric gate: - -- `types.ts` requires `AssertionsBlock.semanticRubric`. -- `fixture-loader.ts` rejects fixtures with missing or empty semantic rubrics. -- `semantic-rubric-judge.ts` evaluates each dimension against assistant - transcript evidence. -- `eval-runner.ts` folds semantic rubric failures into `EvalResult.passed`. -- Existing recorded fixtures now cover CEO bootstrap, Board reply, manager - handoff, peer reply, and IC task execution with semantic dimensions. -- The prompt matrix now pins the AI Co-Founder human-review mode contract. - -This layer runs in `pnpm test:eval` and `pnpm verify`. It is deterministic, -provider-key-free, and tied to real recorded traces. - -## Why not tonight (roundtable reasoning) - -Three dissenting voices carried the delay decision 2-1: - -**Linus** — *"You don't bolt a second LLM onto an eval harness that has -zero fixtures. Build the bone first. Bolt the muscle when you have -something to measure."* Structural assertions work with 1 fixture. An -LLM-judge tier is pointless below ~10 fixtures because you can't -distinguish judge error from fixture sparseness. - -**Jobs** — *"Single signal source. Tonight the developer needs one -needle: 'did the trace match the recorded shape, yes or no.' A judge -introduces a second signal (confidence, rubric score) that dilutes -focus on the first bug we haven't found yet."* - -**Karpathy (me)** — agreed on the delay because the assertion tier *is* -the forcing function that reveals which behaviors actually matter. The -fixtures I record in the next two weeks will tell me exactly which -rubric dimensions the judge should grade. Building the judge rubric from -a blank page today is premature optimization. - -**Dissent (minority)** — the argument for shipping tonight was that -CEO-mode bootstrap behavior is qualitative enough that assertions alone -miss the point of B5. The counter: if a behavior can only be judged -semantically, that's a signal the behavior spec itself is underdetermined -— fix the spec before fixing the eval tier. - -## Trigger conditions (do this when any of the below holds) - -| Condition | Why it triggers B5.1 | -|---|---| -| `tests/eval/fixtures/` has 10+ recorded fixtures | Enough surface to distinguish rubric gaps from fixture gaps | -| Two separate production incidents trace back to a behavior that passed all assertions but was still wrong | Signal that structural checks miss semantic drift | -| A fixture exists where the desired assertion cannot be written as a structural match (example: "CEO should not sound defensive") | Direct evidence structural assertions are out of scope for this case | -| Quarterly review: B5 has caught zero regressions across 50+ fixture runs | Suggests structural assertions are over-fitting to already-green shapes — add semantic judgment before assuming coverage is adequate | - -Any one condition is sufficient. Do not build B5.1 speculatively on a -"maybe we'll need it" basis — build it the moment one concrete trigger -fires, and tie the PR to that trigger in the commit message. - -## Tier architecture - -### Tier 0 — fixture loader + structural judge (B5, landed) - -The cheap tier. `O(trace_length)` time, zero network calls. Runs in -`vitest` under `pnpm test:eval`. Every fixture must go through this -tier; failures here short-circuit Tier 1 because semantic judgment on a -structurally broken trace is nonsense. - -### Tier 1 — LLM rubric judge (this proposal) - -Runs only if Tier 0 passes. Consults an LLM with: - -1. The system prompt used during recording (retrievable via the - `systemPromptHash` in `meta`). -2. The recorded transcript (user / assistant / toolResult messages in - order). -3. A **rubric** — a structured list of yes/no grading dimensions unique - to this fixture (stored as part of the fixture's `assertions` block - under a new `rubric` field, see schema below). -4. A maximum token budget for the judge call. - -The judge returns a JSON verdict: `{ dimension, passed, reason }[]`. The -runner aggregates these into the `EvalResult` alongside structural -assertions. - -### Rubric schema (proposed, additive to B5 types) - -```ts -export interface RubricDimension { - /** Short kebab-case identifier stable across fixture revisions. */ - id: string; - /** Human-readable question the judge answers yes/no. */ - question: string; - /** Required: concrete phrasing of what a pass looks like. */ - passRubric: string; - /** Required: concrete phrasing of what a fail looks like. */ - failRubric: string; -} - -export interface RubricVerdict { - dimensionId: string; - passed: boolean; - reason: string; - judgeModel: string; - judgeTokensUsed: { input: number; output: number }; -} -``` - -The rubric lives inline in the fixture's assertions block as -`{ "rubric": [...] }`. The existing structural `assertions` array stays. -Backwards-compatible — fixtures without a rubric skip Tier 1 entirely. - -### Thin call shape (stay cheap) - -One call per fixture. Not one call per dimension. The prompt enumerates -all dimensions and asks for a single structured JSON response covering -them all. This keeps per-fixture cost to one round trip. - -``` -System: You are a rubric judge. For each dimension, respond yes or no -with a one-sentence reason. Never repeat the rubric. Never invent -dimensions. - -User: -[transcript verbatim] - -Dimensions to grade: -1. : - Pass if: - Fail if: - -Respond as JSON: [{"dimensionId": "...", "passed": true|false, "reason": "..."}] -``` - -### Cost cap - -Hard cap per `pnpm test:eval` run: **$2.00 of judge cost**. Implementation: - -1. Configure a fixed model (recommend `claude-sonnet` class — cheap - enough for high-volume judge calls, smart enough for rubric reasoning). -2. Runner tracks cumulative `judgeTokensUsed × model.cost` across - fixtures in a run. -3. Once the cap is hit, remaining fixtures run Tier 0 only and their - Tier 1 results record `skipped: true, reason: "cost cap exceeded"`. -4. The run exits non-zero if cost-cap skip would have masked a prior - Tier 0 pass — i.e. the run fails loud when skipping would hide a - genuine regression. - -Rationale: an eval tier that can silently cost $100 when a fixture -balloons is not an eval tier, it's a budget exfil vector. - -### Fast-path escape hatch - -Tier 1 runs only when at least one of the fixture's `rubric` dimensions -differs from the previous eval snapshot. The runner keeps a local -SHA-keyed cache `(fixtureId, rubric hash, transcript hash) → verdict`. -Identical inputs skip the LLM call and reuse the cached verdict. - -Rationale: if the CEO's trace hasn't changed and the rubric hasn't -changed, the verdict won't change either. Running it again is pure -waste. First-run of a new fixture or rubric still pays the call. - -## Failure modes (things that will actually go wrong) - -### The judge is wrong - -The judge's own failure mode is non-trivial: it can mark a good trace as -failing (false positive) or a bad trace as passing (false negative). -Mitigations: - -1. **Every Tier 1 failure requires a human sign-off to baseline.** The - first time a rubric dimension flips from pass to fail, the runner - does not treat the run as failed — it prints the verdict diff and - asks the developer to promote or reject it via a `pnpm eval:accept - --fixture --dimension ` command. After acceptance, the - baseline is updated and future matching verdicts pass silently. -2. **Judge disagreement logging.** When Tier 1 fails but Tier 0 passes, - the reason text is preserved in the fixture's `.accepted.jsonl` - sidecar for later review. - -### The rubric drifts out of date - -Fixtures grow rubric dimensions, rubrics get more verbose, the judge's -context window fills up. Mitigations: - -1. Per-fixture cap: **no more than 8 rubric dimensions**. Enforced at - load time — a 9th dimension is a load error, forcing the developer to - either split the fixture or prune rubrics. -2. **Rubric dimensions must be single-sentence pass/fail rules.** Long - prose rubrics are compressed or rejected at load. - -### Provider outage blocks CI - -Mitigation: if the judge provider is unreachable, Tier 1 verdicts record -`skipped: true, reason: "provider unreachable"` and the run exits with a -warning but **does not fail the CI build**. Tier 0 still gates the run. -The judge is a supplement, not a must-pass gate, for exactly this reason. - -## Explicit non-goals - -- **Not a teacher for the CEO agent.** Tier 1 does not produce training - data, does not feed back into prompts, does not auto-patch behavior. - It grades; humans act on grades. -- **Not a replacement for structural assertions.** Tier 0 runs always, - gates Tier 1, and handles 80%+ of regressions. If you find yourself - deleting Tier 0 assertions because Tier 1 covers them, stop — the - structural tier is cheaper and faster and reveals different bugs. -- **Not a judge that rewrites fixtures.** The judge reads; it does not - author rubrics, does not select which dimensions to grade, does not - modify the `.jsonl` on disk. - -## What this proposal does not cover - -- Multi-turn "soft" evaluation (did the agent converge on the right - answer across multiple turns?) — future tier, call it B5.2. -- Cross-fixture trend analysis (is the CEO getting more verbose over - time?) — future tier. -- Adversarial fixture generation (synthesizing fixtures that probe edge - cases) — explicitly out of scope; tonight's line in the sand is that - fixtures are *recorded*, never synthesized. - -## Concrete next steps once a trigger fires - -1. Land `RubricDimension` / `RubricVerdict` types in `tests/eval/types.ts` - as an additive extension (existing fixtures without a `rubric` field - continue to work). -2. Write `rubric-judge.ts` that takes a parsed fixture + rubric + judge - model and returns `RubricVerdict[]`. Keep under 250 lines. -3. Extend `eval-runner.ts` to call Tier 1 only after Tier 0 passes, - respecting cost cap and cache. -4. Add `pnpm eval:accept` CLI for baseline management. -5. Migrate one representative fixture to include a rubric block as the - first real-world exercise. Do not bulk-convert — one fixture, review - the judge's behavior, then scale. - -## Approval gate - -This proposal is not auto-approved. Before implementation, the roundtable -(or its equivalent reviewer set) must explicitly acknowledge: - -1. At least one trigger condition has fired. -2. The cost cap is acceptable for the current CI throughput. -3. Baseline acceptance workflow fits the team's dev loop. - -Without all three, stop at B5 structural judge. It's better to have one -tier that works than two tiers that lie. - -## Closing note - -The reason I (Karpathy) pushed for B5 to land tonight *without* this -tier is the same reason I'm drafting this proposal immediately: harness -scaffolds are forcing functions. Every line of the JSONL contract I -nailed down in B5 constrains what B5.1 can cheaply do. Writing the B5.1 -proposal the same night forces me to confirm the B5 schema is -extensible in the directions I'll actually need — and it is -(`assertions` can grow a `rubric` sibling without any breaking change). - -Ship the assertion judge. Record 10 fixtures. Then grade them. diff --git a/docs/proposals/C1-appdatabase-passthrough-removal.md b/docs/proposals/C1-appdatabase-passthrough-removal.md deleted file mode 100644 index 3e4736f2..00000000 --- a/docs/proposals/C1-appdatabase-passthrough-removal.md +++ /dev/null @@ -1,267 +0,0 @@ -# Proposal C1: 用 codemod 一次性删除 AppDatabase 80+ legacy pass-through - -> 来源:问题.md C1(行 114-127)、附录 F 样本 5(行 495-507)、附录 C(行 390-391) -> 状态:proposed(可与 B2 共享 migration 窗口) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:1 周(含 codemod 脚本 + 逐个 PR 验证) -> Blocking dependencies:无强依赖,但建议 B2 完成后再做(B2 会修改 tasks 模块 API) - -## 问题陈述 - -数据库访问层有两层 pass-through: - -**第一层**:`src/main/database-base.ts` 的 `AppDatabaseBase` 持有 26 个领域模块(`threads` / `company` / `agents` / `tasks` / `runs` / ...),在 226-336 行为这些模块的 80+ 方法手写薄委托。 - -**第二层**:`src/main/database.ts` 的 `AppDatabase`(`AppDatabaseBase` 的子类),在 13-192 行又手写一层更薄的委托,例如: - -```ts -// src/main/database.ts:13-23 -listComments(taskId: string) { return this.activityMod.listComments(taskId); } -sendAgentMessage(input: {...}) { return this.messages.sendAgentMessage(input); } -// 共计 192 行,几乎全是这种 one-liner -``` - -作者在 `database-base.ts:49-51` 自己承认: - -> "Domain modules. New code should prefer `db.tasks.saveTask(...)` over the legacy pass-through methods on AppDatabase. Pass-through remains for back-compat until all call sites migrate." - -没有迁移计划,没有 deadline,没有 ESLint rule 禁止新代码走 pass-through。 - -## 根因分析 - -Linus 视角(好品味原则第六条:代码是否可读):**两层委托是认知税**。 - -读代码路径:`caller → AppDatabase.saveTask → AppDatabaseBase.saveTask → tasks.saveTask → SQL`。每一层都没有任何增值逻辑,纯粹的字符串转发。这是典型的"架构师幻觉"——觉得加一层抽象就是解耦,实际是把同一个事情说三遍。 - -**真正的解耦**是:call site 和 SQL 之间存在一层做 validation / caching / observability 的东西。当前架构里那一层是空的。 - -Karpathy 视角补充:AI coding agent 读这个 codebase 时,每次想保存 task 都看到三个等价的 API(`db.saveTask` / `db.saveTask` 继承 / `db.tasks.saveTask`),完全不知道该用哪个。这种 ambiguity 会让 agent 每次选得不一样,导致代码风格 drift——"我之前写过 db.saveTask,这次也写这个" vs "我之前写过 db.tasks.saveTask,这次也写这个"——最后仓库里三种风格并存,review 成本陡增。 - -根本问题:**"back-compat until all call sites migrate" 没有触发条件**。谁来触发?触发日期?指标?——都没有。所以它就是永远存在。 - -## 设计方案 - -### 目标最终形态 - -```ts -// src/main/database.ts(重写后 ~30 行) -export class AppDatabase extends AppDatabaseBase { - // 保留只有 AppDatabase 才有的逻辑(如果有) - // 没有任何 pass-through -} - -// src/main/database-base.ts(删除 226-336 的 pass-through 段落) -export class AppDatabaseBase { - public readonly threads: ThreadsModule; - public readonly company: CompanyModule; - public readonly agents: AgentsModule; - // ... 26 个模块 - // 没有 pass-through 方法 -} -``` - -### 所有 call site 强制走命名空间 - -```ts -// Before -db.saveTask(task) -db.listComments(taskId) -db.sendAgentMessage(input) - -// After -db.tasks.saveTask(task) -db.activity.listComments(taskId) -db.messages.sendAgentMessage(input) -``` - -### Codemod 脚本 - -新建 `scripts/codemod/remove-appdatabase-passthrough.mjs`: - -1. 构建方法名 → 模块名的映射表(从 `database-base.ts:226-336` 和 `database.ts:13-192` 逆向抽取)。例如: - ``` - saveTask → tasks.saveTask - listTasks → tasks.listTasks - sendAgentMessage → messages.sendAgentMessage - listComments → activity.listComments - … (~80 条) - ``` -2. 用 ts-morph 或 jscodeshift 扫 `src/` 和 `tests/`,匹配 `db.(...)`,替换为 `db..(...)`。 -3. 对每次替换做 typecheck 验证:`pnpm typecheck` 必须通过。 -4. 产出 migration report(每个文件改了几处)。 - -### ESLint rule 锁死 - -新规则:`no-appdatabase-passthrough`——禁止在类型为 `AppDatabase` 的对象上调用领域方法(只允许访问 `db.tasks` / `db.agents` 等 getter)。 - -## Migration 计划 - -1. **Step 1(1 天)**:写 codemod 脚本 + dry-run 出 report,评估影响面(预计 500-800 处 call site)。 -2. **Step 2(2 天)**:按模块分批跑 codemod,每个模块一个 PR: - - `db.threads.*` 一个 PR - - `db.tasks.*` 一个 PR - - `db.messages.*` 一个 PR - - ... - 每个 PR 跑 typecheck + 相关 unit/integration test。 -3. **Step 3(1 天)**:所有 call site 迁移完后,删 `database-base.ts:226-336` 的 pass-through 段落 + 删 `database.ts:13-192`。 -4. **Step 4(半天)**:合并 `AppDatabase` 到 `AppDatabaseBase`,改名为 `AppDatabase`。删除无用的继承层。 -5. **Step 5(半天)**:打开 ESLint rule,新 PR 无法再走 pass-through。 - -不需要 schema migration——这是纯代码结构重构,二进制行为零变化。 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| Codemod 误改 | 动态 property access `db[name]` | codemod 检测到 computed access 时跳过并 warn | -| Typecheck 通过但 runtime 错 | 模块 getter 返回 undefined | `AppDatabaseBase` constructor 里逐个 assert 模块已 init | -| 测试 mock 失效 | 测试 stub 了 `db.saveTask` | 测试改为 stub `db.tasks.saveTask`——codemod 同时处理 | -| 第三方 plugin 依赖 | builtin-skills 或外部代码调 `db.saveTask` | 当前没有第三方 plugin 路径,如发现再加 deprecation proxy | - -**回滚路径**:任何 step PR 可单独 revert。final cleanup(step 3-4)前代码层面保持 dual API,任何时候都可暂停。 - -## 验证标准 - -1. **Typecheck 通过**:每个 codemod PR + final cleanup PR -2. **所有测试绿**:typecheck / unit / integration / e2e -3. **静态扫描**:最终 `grep -rn "db\.saveTask\|db\.listTasks\|…" src/` 应无命中(除了 `db.tasks.saveTask` 这种合法 namespaced 调用) -4. **ESLint CI 门禁**:新 PR 引入 pass-through 风格被 CI 拒绝 -5. **Line count**:`database.ts` 从 192 行 → ≤30 行;`database-base.ts` 从 472 行 → ≤200 行 - -## 不在范围 - -- **不重构领域模块内部 API**:只是把 pass-through 删掉,模块内部实现不动。 -- **不改 IPC 接口**:renderer 看到的还是相同 shape。 -- **不引入 ORM**:SQLite 直接 prepare + run 的风格保留。 -- **不做 query builder**:领域模块内部写 SQL 的方式不变。 -- **不拆分领域模块到独立文件**:已经在 `src/main/database/` 子目录了,不动。 - -## 参考文件清单 - -- `src/main/database.ts:13-192`(第二层 pass-through,待删除) -- `src/main/database-base.ts:40-472`(域模块装配 + 第一层 pass-through) -- `src/main/database-base.ts:49-51`(作者自白注释) -- `src/main/database-base.ts:226-336`(80+ pass-through 方法段) -- `src/main/database/*`(26 个域模块,API 不变) -- `src/renderer/**/*.ts`(主要 call site 消费方) -- `src/main/ipc-*.ts`(IPC handler call site) - -## 附:为什么现在修 - -**broken-window 效应**:只要注释写着"pass-through remains for back-compat"且没有 deadline,新代码就会继续加新的 pass-through。当前 80+ 方法是一天的 codemod,拖到 150+ 就是一周,拖到 300+ 就没人敢动了。 - -Linus 原话精神:当你发现自己写注释"我知道这很糟但是…"的时候,你就已经在积累技术债。技术债不会自己消失,只会复利。 - -C1 和 B2 可以共享 migration 窗口——B2 要改 tasks 的状态机 API,codemod 正好顺带把 `db.saveTask → db.tasks.saveTask` 处理掉,两件事一起做比先后做省一半 PR review 工夫。 - -C1 改完后代码的可读性/可教性明显提升,这个直接影响 AI coding agent 的产出质量——agent 不再在"三个等价 API 选哪个"上浪费 token 和时间。 - -## 附:codemod 脚本草稿 - -```js -// scripts/codemod/remove-appdatabase-passthrough.mjs -import { Project, SyntaxKind } from "ts-morph"; - -const PASSTHROUGH_MAP = { - // 从 database.ts:13-192 和 database-base.ts:226-336 抽取 - saveTask: "tasks", - listTasks: "tasks", - deleteTask: "tasks", - saveAgent: "agents", - listAgents: "agents", - sendAgentMessage: "messages", - listComments: "activity", - // ... ~80 条 -}; - -const project = new Project({ tsConfigFilePath: "tsconfig.json" }); -const sourceFiles = project.getSourceFiles(["src/**/*.ts", "tests/**/*.ts"]); - -for (const sf of sourceFiles) { - const calls = sf.getDescendantsOfKind(SyntaxKind.CallExpression); - for (const call of calls) { - const expr = call.getExpression(); - if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue; - const prop = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression); - const obj = prop.getExpression().getText(); - const method = prop.getName(); - - // 只改 db.xxx(...) 形式 - if (obj === "db" && method in PASSTHROUGH_MAP) { - const module = PASSTHROUGH_MAP[method]; - prop.setExpression(`${obj}.${module}`); - } - } -} - -await project.save(); -``` - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | Codemod dry-run report 显示预期影响面(500-800 call sites) | Linus | -| G2 | 每个模块的迁移 PR 单独跑 typecheck + unit test 绿 | Owner | -| G3 | 所有模块迁完后 `grep -rn 'db\.saveTask\|db\.listTasks' src/` 无命中 | Linus | -| G4 | `database.ts` 行数 < 30 | Linus | -| G5 | ESLint rule `no-appdatabase-passthrough` 启用,CI 捕获新违规 | Owner | - -## 附:call site 分布(预估) - -基于 grep: -- `src/main/ipc-*.ts`:~200 处 -- `src/main/orchestration/`:~100 处 -- `src/main/worker/`:~50 处 -- `src/main/agent-runtime/`:~80 处 -- `src/renderer/`:~0 处(renderer 通过 IPC,不直接访问 db) -- `tests/`:~100 处 - -总计 ~530 处。codemod 一次性全改,分批 PR 按文件提交。 - -## 附:与 B2 的协同 - -B2 的 phase/lease 重构需要改 `src/main/database/tasks-status.ts` 的 API。codemod 可同时处理两件事: -1. 把 `db.saveTask → db.tasks.saveTask`(C1) -2. 把 `db.tasks.saveTask → db.tasks.advanceTaskPhase`(B2 的新 API) - -一个 PR 两件事。节约 review 一次成本。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:一次性 codemod 迁移。优点:彻底;缺点:一次大 PR。 - -**方案 B(渐进式,新代码用新 API,旧代码原样)**:broken-window 加剧,永远迁不完(过去两年证明了)。 - -**方案 C(只删 database.ts 的第二层,保留 database-base.ts 的第一层)**:治标不治本,仍有 pass-through 层。 - -方案 A 是**真的解决问题**的方案。 - -## 附:PR 拆分策略 - -按"同一领域的 call site 一批 PR"拆分: - -| PR | 迁移范围 | 预计大小 | 评估 | -|----|---------|---------|-----| -| PR-1 | `db.tasks.*` 迁移 | ~150 处 | 跟 B2 合并最省力 | -| PR-2 | `db.agents.*` 迁移 | ~80 处 | 独立 | -| PR-3 | `db.messages.*` 迁移 | ~70 处 | 独立 | -| PR-4 | `db.approvals.*` 迁移 | ~60 处 | 独立 | -| PR-5 | `db.runs.*` 迁移 | ~50 处 | 独立 | -| PR-6 | 其他 21 个模块分 5 批 | ~170 处 | 独立 | -| PR-7 | Final cleanup(删 database.ts pass-through) | - | 所有前置完成后 | - -每个 PR 单独跑 typecheck + 相关单测,review 一次 < 1 小时。 - -## 附:自动 import 优化 - -Codemod 跑完后,同 file 内如果 `db.tasks.*` 多处调用,可以抽成本地 alias: - -```ts -const { tasks } = db; -tasks.saveTask(t); -tasks.listTasks(); -``` - -但这是 optional 优化,由 reviewer 决定是否采纳。 diff --git a/docs/proposals/C2-service-graph-runtime-bus.md b/docs/proposals/C2-service-graph-runtime-bus.md deleted file mode 100644 index dde055f2..00000000 --- a/docs/proposals/C2-service-graph-runtime-bus.md +++ /dev/null @@ -1,260 +0,0 @@ -# Proposal C2: service-graph LateBinding 替换为 RuntimeBus(事件总线) - -> 来源:问题.md C2(行 129-145)、附录 F 样本 6(行 511-530) -> 状态:proposed(待 B4 完成后实施) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:3 周 -> Blocking dependencies:B4(single-writer actor 先稳定并发模型) - -## 问题陈述 - -`src/main/service-graph.ts:110-113` 存在 4 个 `LateBinding` 占位符: - -```ts -const orchestrationRef = new LateBinding<...>("orchestrationService"); -const automationRef = new LateBinding<...>("automationService"); -const browserActionRef = new LateBinding<...>("browserActionService"); -const updaterRef = new LateBinding<...>("updaterService"); -``` - -注释里已经承认这是为了解决循环依赖: - -> "worker needs orchestration (for dispatchRunToWorker), orchestration needs worker (for enqueueWorkerRun), orchestration needs automation (for dispatchAutomation), automation/orchestration need browser-action…" - -`LateBinding.get()` 在未绑定时抛异常——**启动顺序错一步整棚塌**,且 runtime 无法静态验证调用安全。 - -进一步证据(`src/main/service-graph.ts:174-191` 的 RuntimeMessageInjector 构造): - -```ts -runtimeMessageInjector = new RuntimeMessageInjector({ - db, - runtimeBridge: piRuntimeRef.current.runtimeBridge, - postToWorker: (message) => { - const worker = workerService?.getWorker(); - if (!worker) throw new Error("Worker is not initialised — cannot deliver steer message."); - worker.postMessage(message); - }, - getWakeAgent: () => { - if (!orchestrationRef.isAssigned()) return null; - const orch = orchestrationRef.get(); - return (agentId, companyId, trigger) => orch.wakeAgentIfPossible(agentId, companyId, trigger); - }, - logger, -}); -``` - -两个 callback(`postToWorker` / `getWakeAgent`)每次调用都要重新检查 binding 状态——这不是依赖注入,是运行时祈祷。 - -## 根因分析 - -Linus 视角(好品味原则第一条 + 第七条):**循环依赖不能靠 lazy 解决,说明模块边界切错了**。 - -4 个服务互相咬尾巴: -``` -worker ──dispatchRun──> orchestration -orchestration ──enqueueRun──> worker -orchestration ──dispatchAutomation──> automation -automation ──wakeAgent──> orchestration -automation ──dispatchAction──> browserAction -browserAction ──wakeAgent──> orchestration -``` - -这不是 4 个服务,这是**一个分布式系统**被错误地拆成 4 个互相调用的同步对象。真正的解法是**反转依赖方向**——让所有服务都依赖一个**事件/命令总线**,服务之间不直接持有彼此的引用。 - -LateBinding 的问题: -1. **编译期错误 → 运行时错误**:bind 错了、漏 bind、bind 顺序错,TypeScript 编译全绿,应用启动崩 -2. **init 顺序依赖人工维护**:`service-graph.ts:120-265` 的 `set()` 顺序是 review 出来的,新增服务必须重新排雷 -3. **调用位置静态不可达**:搜 `dispatchRunToWorker` 的消费者只能 grep 到 `.get().dispatchRunToWorker`,IDE rename 无法跟踪 -4. **测试无法 mock**:注入一个假 LateBinding 要复制整个 binding 容器,测试设置成本高 - -## 设计方案 - -### RuntimeBus 接口 - -```ts -// src/main/runtime/runtime-bus.ts -export interface RuntimeBus { - // 命令投递(fire-and-forget 或返回 ack Promise) - dispatch(kind: K, payload: CommandPayload): Promise>; - - // 订阅特定命令类型(service 注册自己能处理什么) - subscribe(kind: K, handler: CommandHandler): () => void; - - // 事件广播(1 对 N,无 ack) - emit(kind: K, payload: EventPayload): void; - - // 事件订阅 - on(kind: K, listener: EventListener): () => void; -} -``` - -### 命令类型表(强类型 contract) - -```ts -export type CommandKind = - | "run.dispatch" // worker ← orchestration - | "run.enqueue" // orchestration ← worker - | "agent.wake" // orchestration ← automation/browserAction/... - | "automation.dispatch" // automation ← orchestration - | "browserAction.dispatch"// browserAction ← automation/orchestration - | "steer.postToWorker" // worker ← runtimeMessageInjector - | "updater.check"; // updater ← main/menu - -export interface CommandPayloadMap { - "run.dispatch": { runId: string; agentId: string; companyId: string }; - "run.enqueue": { runId: string; ... }; - "agent.wake": { agentId: string; companyId: string; trigger: AgentTrigger }; - "automation.dispatch": { ruleId: string; ... }; - "browserAction.dispatch": { actionId: string; ... }; - "steer.postToWorker": { message: WorkerInboundMessage }; - "updater.check": { manual: boolean }; -} -``` - -### 服务改造 - -Before(`service-graph.ts:174-191`): - -```ts -runtimeMessageInjector = new RuntimeMessageInjector({ - db, - postToWorker: (msg) => workerService?.getWorker()?.postMessage(msg), - getWakeAgent: () => orchestrationRef.isAssigned() ? orchestrationRef.get().wakeAgentIfPossible : null, - ... -}); -``` - -After: - -```ts -runtimeMessageInjector = new RuntimeMessageInjector({ db, bus, logger }); - -// RuntimeMessageInjector 内部: -async steer(runId: string, message: string) { - await this.bus.dispatch("steer.postToWorker", { message: { ... } }); -} -async wakeAgent(agentId: string, companyId: string, trigger: AgentTrigger) { - await this.bus.dispatch("agent.wake", { agentId, companyId, trigger }); -} -``` - -### 服务注册 - -```ts -// service-graph.ts(重写后,清晰 linear init) -const bus = new InProcessRuntimeBus(); - -const workerService = new WorkerService({ db, bus, ... }); -workerService.register(); // 内部订阅 "run.dispatch", "steer.postToWorker" - -const orchestrationService = new OrchestrationService({ db, bus, ... }); -orchestrationService.register(); // 订阅 "run.enqueue", "agent.wake" - -const automationService = new AutomationService({ db, bus, ... }); -automationService.register(); // 订阅 "automation.dispatch" - -const browserActionService = new BrowserActionService({ db, bus, ... }); -browserActionService.register(); // 订阅 "browserAction.dispatch" - -// 所有服务已注册,可以开始 dispatch -await orchestrationService.start(); -``` - -没有 LateBinding。没有回调地狱。没有"isAssigned 检查"。注册完 = 可用。 - -### InProcessRuntimeBus 实现 - -```ts -export class InProcessRuntimeBus implements RuntimeBus { - private handlers = new Map>(); - private listeners = new Map>>(); - - subscribe(kind: K, handler: CommandHandler): () => void { - if (this.handlers.has(kind)) { - throw new Error(`Command kind "${kind}" already has a handler — commands are 1:1`); - } - this.handlers.set(kind, handler); - return () => this.handlers.delete(kind); - } - - async dispatch(kind: K, payload: CommandPayload): Promise> { - const handler = this.handlers.get(kind); - if (!handler) { - throw new Error(`No handler registered for "${kind}"`); - } - return await handler(payload); - } - // emit/on 类似 -} -``` - -**关键约束**:`dispatch` 要求 handler 必须存在(不像 LateBinding 可以延迟到调用时 crash,这里是 register 完就保证可用)。 - -## Migration 计划 - -1. **Phase 1(1 周)**:新建 `src/main/runtime/runtime-bus.ts` + 类型表,不动现有代码。 -2. **Phase 2(1 周)**:一个服务一个服务地迁移到 bus: - - 先迁 worker ↔ orchestration(最核心的循环) - - 再迁 automation - - 最后迁 browserAction 和 updater - 每次迁移一个服务,保留 LateBinding 直到全部迁完。 -3. **Phase 3(3 天)**:迁完后删 `LateBinding` 类 + `service-graph.ts:110-113` 的 ref 段落 + 所有 `.get()` / `.isAssigned()` 调用。 -4. **Phase 4(2 天)**:把 service-graph.ts 从 284 行的 callback 森林重写成 linear init(预计 < 100 行)。 -5. **Phase 5(持续)**:新增服务必须通过 bus 交互,ESLint rule 禁止直接 import 另一个服务类。 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| 性能回退 | bus dispatch 多一次 async hop | 可能的 10μs 级开销,远低于 SQLite 写本身;不可接受时改为 sync dispatch(subscribe 仍是 sync handler) | -| 类型体操复杂 | CommandPayloadMap 泛型推导 | 类型系统验证过类似 pattern(Redux toolkit 的 PayloadAction),成熟方案 | -| 初始化循环未发现 | 某服务订阅 + 自己 dispatch 同一 kind | bus 内部加检测:handler 执行时记 call stack,发现 reentrant 直接抛 | -| 测试 mock 成本 | 需要 mock bus | 反而更容易——测试用 `new InProcessRuntimeBus()` 即可,精确订阅需要的 kind | - -回滚路径:phase 2 每个服务迁移是独立 PR,任何一个发现问题可 revert;phase 3 前 LateBinding 仍在,语义层面完全兼容。 - -## 验证标准 - -1. **Typecheck**:CommandKind ↔ Payload 类型约束强制 compile-time 正确 -2. **Linear init**:`service-graph.ts` 行数 < 100,无 LateBinding / 无 callback / 无 isAssigned -3. **契约测试**:每个 CommandKind 配 fixture,验证 payload shape 稳定 -4. **集成测试**:启动顺序随机化 N 次,应用都能正常起(验证无启动顺序依赖) -5. **Static scan**:`grep -rn "LateBinding\|isAssigned" src/` 无命中 - -## 不在范围 - -- **不做跨进程 bus**:renderer/main 之间继续走 IPC,bus 只管 main 进程内部。 -- **不做 event sourcing**:bus 不持久化 event history,任何需要审计的事件仍走 DB。 -- **不改 pi runtime 对接**:pi runtime 仍走 piRuntimeRef 方式,本 proposal 只动 4 个自研服务。 -- **不引入 RxJS / reactive library**:简单 EventEmitter 模式足够。 -- **不做 priority queue**:所有 command 同等优先级;需要 backpressure 走 B4 的 writer actor。 - -## 参考文件清单 - -- `src/main/service-graph.ts:110-113`(4 个 LateBinding) -- `src/main/service-graph.ts:120-265`(人工排序的 init) -- `src/main/service-graph.ts:174-191`(RuntimeMessageInjector callback 地狱) -- `src/main/service-graph.ts:258-263`(LateBinding set 段落) -- `src/main/orchestration/orchestration-service.ts`(消费者) -- `src/main/worker/worker-runner.ts`(消费者) -- `src/main/automation-service.ts`(消费者) -- `src/main/browser/browser-action-service.ts`(消费者) - -## 附:为什么不是现在立刻修 - -B4(single-writer actor)必须先做——否则 bus dispatch 内部触发数据库写时会继续多 writer 抢锁,C2 的改进被淹没。先把"谁写 DB"的契约收敛,再解决"谁叫谁"的契约。 - -C2 本身是**"让下一个 AI 能读懂这个项目"**的前提——现在的 service-graph.ts 是 AI coding agent 最容易读错的文件之一(circular reference + lazy binding + callback 三重混淆)。修完后,新 feature 接入服务的时间从"读半天 graph 再写"降到"开一个 subscribe"。 - -Steve Jobs 视角:LateBinding 是"技术上可行但用起来很差"的典型——它让架构师觉得自己聪明,让所有后来者困惑。好的设计应该让**无需理解 init 顺序**就能加新服务。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B4 single-writer actor 完成 | Linus | -| G2 | RuntimeBus 接口 + CommandKind 枚举固化 | Linus | -| G3 | 4 个循环服务全部迁移到 bus | Owner | -| G4 | service-graph.ts 行数 < 100 | Linus | -| G5 | 启动顺序随机化测试 N 次全绿 | Owner | diff --git a/docs/proposals/C3-real-tokenizer-followup.md b/docs/proposals/C3-real-tokenizer-followup.md deleted file mode 100644 index b7c07c4f..00000000 --- a/docs/proposals/C3-real-tokenizer-followup.md +++ /dev/null @@ -1,45 +0,0 @@ -# Proposal C3-followup: 用真实 tokenizer 替换字符估算 - -> 来源:Roundtable 2026-04-20 surgical compactor 修复;C3 首轮决定先用保守常量 (2 chars/token) 落地 -> 状态:implemented(2026-04-22:`js-tiktoken` / `cl100k_base` 已接入 `context-compactor.ts`) -> 提出:Karpathy (T2) -> Owner: TBD -> 估计工时:1 天(换依赖)+ 半天(灰度验证) -> Blocking dependencies:无硬阻塞;等 pi-ai 暴露 tokenizer 或接入 tiktoken/anthropic-tokenizer - -## 问题陈述 - -`src/main/agent-runtime/context-compactor.ts` 曾用 `Math.ceil(chars / 2)` 做 token 估算,作为 120k 阈值的守门人。2026-04-22 已改成 `js-tiktoken` 的 `cl100k_base` 本地编码器,并保留每条 chat message 的固定结构开销。 - -问题: -1. **中文 BPE 实际约 1.5-2 tokens/char**:2 chars/token 的常量对 CJK 大致可用,但 mixed 中英 / emoji / code block 的实际比例会漂移。 -2. **对拉丁文过度保守**:英文 BPE 约 4 chars/token,用 2 chars/token 会让英文 agent 的阈值提前 50% 触发——这是安全的方向(宁可早触发不要晚触发),但浪费了压缩空间。 -3. **无法感知 tool 定义 / system prompt 开销**:`estimateTokens` 只数 messages 里的文本,tool schema JSON 和 system prompt 的 token 都没计。真实 input tokens 比估算大。 -4. **Anthropic prompt caching 的 breakpoint 计算需要精确 token 数**:字符估算拿不到 cache hit / miss 的决策依据,未来接 cache 优化时必须换。 - -## 根因 - -pi-ai 0.67.68 没 export tokenizer。Compactor 作为 `transformContext` hook 在 renderer / main 都可能跑,依赖必须能在 Node 和 Electron main process 里用。 - -备选方案: -- **tiktoken** (OpenAI BPE):快,tree-shakable,但对 Anthropic 模型的真实 token 数只是近似(Anthropic 用私有 BPE,两者差异 5-10%)。 -- **@anthropic-ai/tokenizer**:精确,但包体积较大(~2MB),且 Anthropic 自己建议用 `count_tokens` API 而不是本地估算(原因:模型更新会换 tokenizer)。 -- **pi-ai 升级暴露 tokenizer**:理论上最干净,但要等上游;pi-mono 仓 `packages/ai/src/utils/` 目前只有 `overflow.ts` 做错误匹配,没 tokenizer utility。 -- **Anthropic `count_tokens` API**:精确,但每次 compactor 估算都要额外 HTTP round-trip,违反 "compactor 必须是纯函数" 的现有契约。 - -## 建议路径 - -1. 已接入 `js-tiktoken` + `cl100k_base`,保持 compactor 同步纯函数。 -2. pi-ai 后续若暴露 provider-native tokenizer,可在 `context-compactor.ts` 内替换编码器实现。 -3. hook 调用保持不变,`compactMessagesIfNeeded(messages)` 继续返回原有 `CompactionOutcome`。 - -## 不做的事 - -- 不引入 `count_tokens` API 调用:compactor 必须是纯同步函数,不能发网络。 -- 不做"运行时采样真实 tokenizer 校准常量"的启发式:引入额外系统状态,违反 let it crash。 - -## 验证标准 - -- 英文 + 中文 + code block 三种典型 transcript,估算值与 Anthropic 真实 input tokens 误差 ≤ 10%。 -- 120k 阈值触发时机提前/延后不超过真实阈值的 5%。 -- typecheck 全绿;现有 `compactMessagesIfNeeded` 调用点不动。 diff --git a/docs/proposals/C4-followup.md b/docs/proposals/C4-followup.md deleted file mode 100644 index 7987d502..00000000 --- a/docs/proposals/C4-followup.md +++ /dev/null @@ -1,89 +0,0 @@ -# Proposal C4-followup: close out the remaining taste debt from C4 - -> Source: Roundtable 2026-04-20 session 6 cross-review (Jobs + Karpathy request_changes asks) -> Prerequisite: C4 landed (commits c91a233 through 0a35acf) -> Status: **CLOSED 2026-04-20** — all four items landed. See Completion notes at bottom. -> Owner: Linus + Karpathy -> Actual effort: ~1 working session -> Blocking dependencies: none — safe to pick up any time - -## What this proposal closes out - -C4 shipped the main meat — `hire_agent` + `file_approval` internal tools, the CEO initial-user-turn downgrade, the team-building SOP rewrite, and HTTP-hire deprecation. Cross-review surfaced four follow-up items that were out of scope for the C4 session but are small enough to land in a single follow-up pass. They are grouped here so a future session can execute them as one unit. - -## Item 1: tighten `canRequestHire` scope to match the C4 narrative - -**Problem** (Karpathy review, specific ask #2): `src/main/orchestration/internal-tool-selector.ts` attaches `hire_agent` to any agent where `canRequestHire` returns true. In `src/main/database/agent-permissions.ts:91-103`, `canRequestHire` is true whenever the role or title matches `vp|director|manager|lead|head|chief|cto|cmo|coo|cfo` or the agent sits in the HR department. The C4 commit narrative claims "CEO-only injection" — the code does not match. - -**Fix**: introduce a separate `canFileCeoStrategy(agent)` predicate (true only when `reportsTo === null` AND role is CEO-equivalent). Attach `file_approval` only when that predicate holds. Leave `hire_agent` attached on `canRequestHire` but update the C4 commit narrative and team-building.en.md to say so explicitly. A manager hiring an IC is a legitimate flow — the original "CEO-only" framing was narrower than reality. - -**Verification**: a fixture showing a manager (non-CEO) invoking `hire_agent` during a team-expansion trigger would pin the broader scope as intentional. - -## Item 2: re-record `non-ceo-dm-reply` post-C4 for positive evidence - -**Problem** (Karpathy review, specific ask #1): `tests/eval/fixtures/non-ceo-dm-reply.jsonl` was recorded at commit `302b8a0` before C4 part 3/5 (tool injection at `79edff5`) landed. The fixture therefore cannot discriminate between "non-CEO correctly does not receive `hire_agent` in its tool schema" and "the tool was never offered because part 3/5 had not merged yet." `manager-task-handoff` was re-recorded post-C4 already (see `c4-followup-manager-rerecord` commit in this proposal's implementation). `non-ceo-dm-reply` still needs the same treatment. - -**Fix**: re-record `non-ceo-dm-reply` with the current main tree. Confirm the assistant response still covers `mark_read` and `/api/agent_message/send` calls without referencing `hire_agent` (VP Product with two IC reports has management authority → `canRequestHire` is true → the tool is technically attached, but the trigger is a peer DM so the tool should not be invoked). - -**Verification**: `pnpm test:eval --run` stays green with existing assertions. - -## Item 3: add a deprecation counter and `Deprecation:` header to legacy HTTP hire routes - -**Problem** (Karpathy specific ask #3, Jobs specific ask #1): `routes-agents.ts` and `routes-approvals.ts` currently emit a single `log.warn("[deprecated][C4] ...")` line per call. That's enough for audit-by-grep, insufficient for asserting "usage has hit zero" before physical removal. - -**Fix**: -1. Expose a counter via the existing telemetry module (if one exists; grep for `metrics.increment` in `src/main/`). Tick on every call. -2. Add RFC 8594 HTTP headers to the deprecated routes: - - `Deprecation: true` - - `Sunset: Wed, 20 May 2026 00:00:00 GMT` (or a date 30 days out from the follow-up commit) - - `Link: ; rel="deprecation"` -3. Document removal timeline: if the counter stays at zero for two weeks after this proposal lands, delete the route handlers physically. - -## Item 4: negative assertion kind for the eval harness - -**Problem** (Karpathy specific ask #4): the current `assertion-judge.ts` supports positive substring assertions (`message_contains_substring`) but no negation. Asserting "the IC fixture does NOT contain `hire_agent` in its tool list" is not expressible, so tool-schema regressions on the IC path are only caught implicitly. - -**Fix**: add a new assertion kind in `tests/eval/assertion-judge.ts`: - -```ts -type Assertion = - | ... // existing kinds - | { kind: "message_does_not_contain_substring"; role: "user" | "assistant"; substring: string }; -``` - -Wire it through `assertion-judge.ts`'s `evaluate` switch. Update `tests/eval/harness.self-test.ts` (or wherever the harness self-tests live) to cover the new kind positively and negatively. Update C4-followup fixtures to use it where appropriate. - -## Non-goals - -- This proposal does NOT expose goal creation as an internal tool — that is C5-scope (`expose remaining CEO primitives as tools`) and depends on goal-lifecycle design. -- This proposal does NOT delete the legacy HTTP routes — they stay until the counter from item 3 stays at zero for two weeks. -- This proposal does NOT add an LLM-as-judge tier — that is B5.1-scope and gated on fixture count N ≥ 10. - -## Completion criteria - -This proposal closes when all four items land and: -- `pnpm typecheck` green -- `pnpm test:eval --run` green at ≥ 8/8 -- `canFileCeoStrategy` predicate exists and is referenced by `internal-tool-selector.ts` -- `non-ceo-dm-reply` fixture's `recordedAt` is after `c91a233` -- Deprecation counter exists; counter value visible in telemetry; RFC 8594 headers on both legacy routes -- `message_does_not_contain_substring` assertion kind passes harness self-tests - -## Completion notes (2026-04-20) - -All four items landed in the same session as the proposal. Resolution: - -| Item | Commit | Notes | -|---|---|---| -| #1 `canFileCeoStrategy` predicate | `f8f0874` | `file_approval` now gates on `role ∈ /^(CEO|chief executive officer)$/i && reportsTo === null`, orthogonal to `canRequestHire`. Manager with virtual superior no longer breaks scope. 4 unit cases in `tests/unit/agent-permissions-ceo-strategy.test.ts`. | -| #2 Re-record `non-ceo-dm-reply` | (this commit) | VP Product (manager with `canRequestHire=true` but `canFileCeoStrategy=false` after #1) re-recorded post-C4. Assistant hits `mark_read` + `/api/agent_message/send` + keeps `m_77` in scope; does not invoke `hire_agent` or `file_approval` — positive evidence that the F3 split correctly excludes file_approval from non-CEO managers. | -| #3 RFC 8594 headers + counter | `f99e6c4` | New `src/main/api-server/deprecation-counter.ts` (Map-backed, sync, throws on empty label). Both legacy routes emit `Deprecation: true` + `Sunset: Tue, 20 May 2026 00:00:00 GMT` + `Link: ; rel="deprecation"`. Counter ticks on each call. 4 unit cases in `tests/unit/deprecation-counter.test.ts`. Removal gate: counter stays at zero for two weeks, then physically delete both route branches. | -| #4 `message_does_not_contain_substring` assertion | `9d3763d` | New assertion kind added to `tests/eval/types.ts`, `tests/eval/assertion-judge.ts`. Two harness self-tests added. `ceo-bootstrap-empty` fixture now pins `node -e` and `/api/companies` as negative substrings — any future CEO bootstrap that reintroduces the HTTP-path antipattern fails `pnpm test:eval`. Proxy cleanup also pins `hire_agent`/`file_approval` as negative on `non-ceo-dm-reply`. | - -**Companion cleanup** (same session, docs-adjacent): - -| Concern | Commit | Notes | -|---|---|---| -| RPC method list duplicated between zod schema and TS union (the category that produced the C4→C5 hotfix `9d9f003`) | `d4ec922` | Extracted `workerRpcMethodSchema = z.enum([...])` in `worker/entry/types.ts` as single source of truth; `runtime-bridge.ts` now imports `WorkerRpcMethod = z.infer`. Added `default: { const _exhaustive: never = ... }` to the handler switch so a widened enum without a matching case becomes a TypeScript error rather than a runtime ZodError. | - -Final verification: `pnpm typecheck` green, `pnpm test:unit` 537/537, `pnpm test:eval` 10/10, working tree clean post-`non-ceo-dm-reply` re-record. diff --git a/docs/proposals/C4-initial-user-turn-semantic-cue.md b/docs/proposals/C4-initial-user-turn-semantic-cue.md deleted file mode 100644 index e76faddf..00000000 --- a/docs/proposals/C4-initial-user-turn-semantic-cue.md +++ /dev/null @@ -1,250 +0,0 @@ -# Proposal C4: initial-user-turn 退回语义 cue + hire 升级为显式 tool - -> 来源:问题.md C4(行 158-172)、附录 F 样本 4(行 479-491) -> 状态:proposed(待 B5 eval harness 就绪后实施) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:2 周(其中 1 周做 hire_agent tool,1 周改 prompt + eval 验证) -> Blocking dependencies:**B5(LLM 行为 eval harness)必须先就绪**,否则改 prompt 无法验证行为回归 -> -> 圆桌投票记录:Linus 不改,Karpathy 不改,Jobs 改(2-1 决定今晚不动代码,写 proposal 等 eval) - -## 问题陈述 - -`src/main/orchestration/initial-user-turn.ts:62-83` 的 CEO 初始 user turn 把 tool 选择、实现细节、API 路径、业务数字、语气**全写死**: - -```ts -return [ - "You are the CEO of this company. Your team is empty (zero active direct reports).", - "This wake has ONE job: call the `bash` tool to execute `node -e '...'` fetch POSTs that file 3–5 hire_agent requests against /api/companies/{companyId}/agents, then one approve_ceo_strategy POST against /api/companies/{companyId}/approvals.", - "The exact body shape and connectorId rules are in your Team Building Phase operating instructions above. Use a connectorId and model from the Available Connectors section (only ready connectors).", - "Start the first POST NOW. Do not write a plan document. Do not describe what you will do — execute the tool call.", -].join("\n\n"); -``` - -五个耦合: -1. **Tool 名**:`bash` -2. **实现细节**:`node -e '...'` + `fetch` POST -3. **API 路径**:`/api/companies/{companyId}/agents`、`/api/companies/{companyId}/approvals` -4. **业务数字**:3-5 个 hire + 1 个 approve_ceo_strategy -5. **语气**:NOW / Do not - -这段 prompt 没有任何机制让它和 `src/main/prompt-builder/ceo-modes/team-building.en.md` 保持一致——两处都在告诉 CEO "现在该做什么",容易 drift。 - -## 根因分析 - -Karpathy 视角(prompt 工程原则):**把实现细节泄漏到 LLM 层是最脆的设计**。 - -当前 prompt 假设: -- `bash` tool 永远存在(pi-agent-core 未来可能改名或增加 sandbox 模式) -- `node -e` 执行环境永远可用(container 化后可能没 node) -- `/api/companies/...` 路径永远稳定(REST → GraphQL 迁移时全部失效) -- CEO "理解" fetch POST 的 body shape(依赖 prompt 里其他部分说清楚) - -每个假设破一次,CEO 就静默做错事。更糟的是——**CEO 一旦学会这个 pattern,其他 agent 会照抄**:所有业务逻辑都 `bash + node -e + fetch`,项目滑向 "everything is bash" 的反模式。 - -Linus 视角(第一性原理):hire 这件事**本来就应该是一个 tool**。当前让 CEO 通过 HTTP POST 自己的 API server 来 hire——这意味着: -1. main 进程要跑 HTTP server(`api-server.ts`) -2. CEO 要拼 body / 处理 auth / 处理 error -3. 出错只能通过 HTTP status code 感知 - -直接把 `hire_agent` 做成 pi tool,CEO 调用 tool → main 进程直接 DB 写 → 返回 ack。省掉整个 HTTP 层。 - -Jobs 视角(为什么他投改):这段 prompt 就是 Jobs 厌恶的"让工程问题泄漏给用户"——CEO 是用户视角的 agent,不该知道 HTTP endpoint。 - -**为什么今晚不改**(2-1 决定):Linus + Karpathy 认为无 eval 下改 prompt = 盲飞。CEO 的实际行为不能凭"prompt 读起来更干净"来验证,必须有 golden trace 对比。今晚没有 eval 框架(B5 blocked by user constraint "无 tests/fixture")就硬改,可能让 CEO 完全不 hire 而团队当场发现不了。 - -## 设计方案 - -分两步: - -### Step 1:把 `hire_agent` 升级为显式 pi tool - -新建 `src/main/agent-runtime/tools/hire-agent.ts`: - -```ts -export const hireAgentTool: AgentTool = { - name: "hire_agent", - description: "Create a new direct report agent for this company. Use this when the CEO needs to fill a role.", - input: { - type: "object", - required: ["name", "role", "description", "connectorId", "model"], - properties: { - name: { type: "string", description: "Short display name for the agent, e.g. 'CTO'" }, - role: { type: "string", description: "Business role, e.g. 'Chief Technology Officer'" }, - description: { type: "string", description: "1-2 sentences describing responsibilities" }, - connectorId: { type: "string", description: "Must be a ready connectorId from the Available Connectors list" }, - model: { type: "string", description: "Must be allowed by the connector's enabledModels" } - } - }, - handler: async (input, ctx) => { - // 校验 connectorId / model - // 直接调 db.agents.saveAgent(...) - // 返回 agentId - } -}; -``` - -同时引入 `file_approval` tool,替代 `/api/companies/{companyId}/approvals` POST。 - -### Step 2:把 initial-user-turn 降级为语义 cue - -After: - -```ts -return [ - "You are the CEO. Your team is currently empty.", - "Review your Team Building Phase operating instructions in the system prompt, then take action.", -].join("\n\n"); -``` - -**没有** `bash`、没有 `node -e`、没有 API 路径、没有数字、没有"NOW"。系统 prompt 里的 `ceo-modes/team-building.en.md` 自己说做什么、做多少。 - -### SOP 层更新 - -`src/main/prompt-builder/ceo-modes/team-building.en.md` 需要明确: -- 描述任务(组建初始团队) -- 描述可用 tool(`hire_agent`、`file_approval`) -- 描述合理数量(3-5 个角色) -- 不描述具体实现(bash / fetch / HTTP) - -这样 CEO 行为 = system prompt 决定,initial-user-turn 只是**触发信号**。 - -## Migration 计划 - -1. **Phase 0(前置)**:B5 eval harness 就绪——能 record 当前 CEO 在 team-building trigger 下的 tool call 序列(作为 baseline) -2. **Phase 1(1 周)**:实现 `hire_agent` / `file_approval` tool,注册到 pi-agent-factory。 - - CEO 在某些场景开始用新 tool,但保留旧 HTTP API(dual-path) -3. **Phase 2(3 天)**:跑 eval 对比——CEO 在新 tool 可用时的行为 vs baseline - - 必须验证:新 tool 可用时 CEO 优先用 tool,且产出的 hire 记录 schema 与 HTTP 路径一致 -4. **Phase 3(3 天)**:修改 `initial-user-turn.ts` 和 `ceo-modes/team-building.en.md`,删除实现细节 -5. **Phase 4(1 周)**:eval 验证行为没有回退,下掉 HTTP `/api/companies/{id}/agents` POST 路径(保留 GET / DELETE 用于 UI) - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| CEO 不 hire(改 prompt 后) | 语义 cue 太弱 | eval 直接发现,revert prompt | -| CEO hire 错角色 | 新 tool 接收参数导致发散 | tool schema validation 层拒绝 | -| 旧 call site 依赖 HTTP | UI 或脚本直接调 `/api/companies/{id}/agents` | 保留 HTTP 路径直到 UI 迁移完 | -| eval fixture 未覆盖边缘 | 某些 trigger(例如"空公司 + 单 connector")没 baseline | phase 2 要求覆盖 10+ 初始状态组合 | - -**回滚路径**:每个 phase 可独立 revert。tool 可先加不强推;prompt 改动可直接回到硬编码版本。 - -## 验证标准 - -**前置:B5 必须就绪**。具体验证: - -1. **行为 eval**:在 10+ 种初始 company 状态下,CEO 产出的 hire 数量 / 角色 / 参数,新方案应与旧方案一致(允许 ±1 个 hire 的方差) -2. **Tool 覆盖**:新 `hire_agent` tool 被 CEO 调用的比例 ≥95%(剩余 <5% 走兼容 HTTP 路径) -3. **Prompt 长度**:initial user turn 从 ~400 token 降到 ~80 token -4. **Regression test**:旧 `curl -X POST /api/companies/{id}/agents` 仍能工作(兼容期) -5. **Cache friendliness**:initial user turn 变短后,system prompt 的 cache hit 率提升 - -## 不在范围 - -- **不改 system prompt 整体结构**:262 行的系统 prompt 走 C7 proposal 独立重构 -- **不改 CEO 模式 state machine**:5 个 ceo-modes 文件结构保留,走 M7 proposal -- **不做 prompt A/B harness**:那是 C7 的事 -- **不动 renderer**:hire 在 UI 层的表现不变(创建新 agent 卡片) -- **不改 approval 审批流**:`file_approval` tool 只是路径替换,approval 逻辑本身不动 - -## 参考文件清单 - -- `src/main/orchestration/initial-user-turn.ts:62-83`(硬编码段落) -- `src/main/orchestration/initial-user-turn.ts:78-82`(CEO lookup fail-open catch,关联 C6) -- `src/main/prompt-builder/ceo-modes/team-building.en.md`(对应的 operating instructions) -- `src/main/api-server.ts` + `src/main/api-endpoints.ts`(当前承载 hire POST 的 HTTP 层) -- `src/main/worker/pi-agent-factory.ts:131`(tool 注册点) -- `src/main/database/agents.ts`(CEO hire 最终写入的 DB 层) - -## 附:为什么这件事不能省略也不能现在 rush - -**不能省略**:每次 pi-agent-core 升级(B1 问题指出 62 patch 漂移),`bash` tool 的 schema / 沙盒行为可能悄悄变。prompt 硬编码 `bash + node -e + fetch` 时,升级 pi 就是一场赌博。 - -**不能现在 rush**(Linus + Karpathy 今晚投反对):prompt 行为是 agent 公司最敏感的地方,无 eval 改 = 赌 CEO 还按原样 hire。圆桌共识:**等 B5,然后一次性做完**。 - -Karpathy 原则:"没有 eval 的 prompt 改动是对随机函数做微调"——我们今晚同意把它写进 proposal 而不动代码。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B5 eval harness 就绪 + baseline recorded | Karpathy | -| G2 | `hire_agent` tool 实现 + schema 固化 | Owner | -| G3 | Tool 可用期间 eval 通过:CEO 在 10+ 种初始状态下用 tool 而非 HTTP POST | Karpathy | -| G4 | Prompt 精简后 eval:hire 数量 / 角色 / 参数与 baseline 一致 | Karpathy | -| G5 | 旧 HTTP 路径灰度下线 2 周无回退 | Owner | - -## 附:新 hire_agent tool 的 schema 草案 - -```json -{ - "name": "hire_agent", - "description": "Create a new direct report agent for this company. Use when a role needs filling.", - "input_schema": { - "type": "object", - "required": ["name", "role", "description", "connectorId", "model"], - "properties": { - "name": { - "type": "string", - "description": "Short display name, e.g. 'CTO', 'Head of Marketing'", - "maxLength": 50 - }, - "role": { - "type": "string", - "description": "Business role title", - "maxLength": 100 - }, - "description": { - "type": "string", - "description": "1-2 sentences describing responsibilities and how this person contributes", - "maxLength": 500 - }, - "connectorId": { - "type": "string", - "description": "Connector ID from the Available Connectors section; must be ready" - }, - "model": { - "type": "string", - "description": "Model name allowed by connector.enabledModels" - }, - "department": { - "type": "string", - "enum": ["engineering", "product", "design", "marketing", "sales", "operations", "legal", "finance"] - } - } - } -} -``` - -Tool handler(main 进程内): -1. 校验 connectorId / model 组合合法性 -2. 生成 agentId -3. 调 `db.agents.saveAgent(...)` 写入 -4. 发 telemetry `agent.hired` -5. 返回 `{ agentId, name, role }` - -## 附:反模式对比 - -**Before**(`src/main/orchestration/initial-user-turn.ts:62-83`):五层耦合混在 prompt 字符串里——agent 必须"解析"提示词才知道要做什么。 - -**After**:agent 读到"your team is empty → 看 system prompt 的 team-building 段 → 用 hire_agent tool"这条清晰链路。每一步都是 agent 正常 reasoning 能处理的粒度。 - -## 附:与 M7 的协同 - -M7(CEO mode state machine)和 C4 共享 `resolveCeoMode` 函数——同一个函数决定: -- initial-user-turn 发什么 cue(C4) -- prompt-builder 加载哪个 ceo-modes markdown(M7) - -两件事一次做完,避免 mode 判断在两处漂移。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:退回语义 cue + 显式 tool。 - -**方案 B(继续硬编码但写成 typed template)**:把字符串换成 template literal + 参数注入。治标不治本——实现细节仍泄漏,只是语法糖。 - -**方案 C(删掉 initial-user-turn,全靠 system prompt)**:失去"trigger 特定 cue"的能力——当用户 explicit 点击 "start team building" 时没有强信号区分于普通 wake。 - -方案 A 平衡了清晰度和表达力。 diff --git a/docs/proposals/C6.2-error-taxonomy-phase2.md b/docs/proposals/C6.2-error-taxonomy-phase2.md deleted file mode 100644 index 9a0a4700..00000000 --- a/docs/proposals/C6.2-error-taxonomy-phase2.md +++ /dev/null @@ -1,211 +0,0 @@ -# Proposal C6.2: Error taxonomy phase 2 — migrate remaining 228 catch sites - -> Source: Roundtable 2026-04-20 (Linus + Karpathy + Steve Jobs); C6.1 executed tonight -> Status: proposed -> Prerequisite: C6.1 landed (`src/main/errors/` module + 20 pilot migrations) -> Owner: TBD -> Estimated effort: 4-6 working days, split across three waves -> Blocking dependencies: none — but coordinate with any in-flight module refactors to avoid diff storms - -## Problem statement - -C6.1 established the `AppError` taxonomy and migrated the 20 highest-signal -catch sites. At the time of this proposal src/main/ still contains **228 -catch blocks** with zero classification. The breakdown by category: - -| Category | Count | Typical shape | Risk if left unmigrated | -|---|---|---|---| -| `} catch {}` empty | ~35 | Silent fallthrough | Fatal conditions (DB corruption, OOM) hidden indistinguishable from expected misses | -| `} catch (e) { log.warn; return default }` fail-open | ~90 | Already logs, but no `code`/`kind` | Telemetry cannot bucket; ops cannot answer "how many upstream 5xx in the last hour" | -| `} catch (e) { log.error; throw e }` pass-through | ~40 | Correct but loses classification on re-throw | Upstream handler re-swallows without context | -| `} catch (e) { return null / false }` silent fail-open | ~30 | No log at all | Behaviour correct-ish, observability non-existent | -| Narrow `instanceof` guarded catches | ~20 | e.g. `if (err.message.startsWith("X")) return null; else throw` | These already encode intent — migrate carefully to `UserInputError` subclass vs re-throw | -| Mixed / platform-specific | ~13 | Electron render-disposed, ENOENT-on-read, EPIPE | Each needs a bespoke classifier | - -Total: **228 non-trivial catches** (count reconfirmed via -`grep -rn "} catch " src/main/ | wc -l` = 248, minus 20 already migrated in C6.1). - -## Why this matters (Linus) - -The backup / migration work already landing in B2 wants to know whether a -DB open failure is "file corrupt" (fatal) or "file missing, first boot" -(recoverable). Today the catch that opens the DB returns the same -log-and-rethrow shape for both. Until every DB-path catch carries a -`code`, the migration precondition checker has to re-classify by string -matching — exactly the kind of fragile guesswork we wanted to avoid. - -## Why this matters (Karpathy) - -Tonight's harness (B5) is structural. Next-tier harnesses (B5.1 judge -tier, future chaos-injection tier) will want to assert things like "when -the Anthropic provider returns 529, the agent must log an -`upstream.anthropic.overloaded` code and retry; a -`fatal.db.corrupt` must abort the run". That kind of assertion is -impossible until every catch site publishes a stable code. - -## Scope - -Migrate all 228 remaining catch blocks in `src/main/**` (excluding tests, -scripts, and the already-migrated 20). Pure-library files with no -accessible logger (e.g. `skill-keys.ts`, `skill-format.ts`) are kept out -of scope unless a logger is plumbed in first — a separate concern. - -## Non-goals - -- Renderer-side catches (`src/renderer/`) — renderer errors surface as - red-screens today; a separate proposal should cover them. -- Changing observable behaviour of any catch. This migration is - **pure classification**: same return values, same throws, same logs - (only the log prefix gains a `[code]`). -- Refactoring the catches themselves (merging, splitting, removing). - -## Migration waves - -Partition the 228 sites into three waves so each wave is one coherent -module group and one reviewable PR. - -### Wave 1 — worker + orchestration (≈80 sites) - -Buckets: - -| Module | Approx sites | Dominant kind | Why first | -|---|---|---|---| -| `src/main/worker/**` | ~35 | `upstream` (pi-ai), `recoverable` (lease/db) | Highest churn in production; biggest payoff for observability | -| `src/main/orchestration/**` | ~20 | `recoverable` (lookups), `user_input` (payload parse) | Feeds into every run; code-path coverage bump is large | -| `src/main/agent-runtime/**` | ~25 | Mixed | artifact-projector's fs-walk catches are intentional silent; document in-line rather than classify | - -**Estimated effort**: 2 days, one PR. Run `pnpm test:eval` and -`pnpm test:unit` after each file. Commit per module. - -### Wave 2 — renderer-adjacent + api-server + browser + automation + skills (≤30 catches) - -**Scope boundary (hard)**: Wave 2 covers `src/main/{renderer-adjacent,api-server,browser,automation,skills}/*` -plus top-level `ipc-*.ts` and `*-service.ts` files. Wave 2 explicitly -**avoids** `src/main/database/**` and `src/main/worker/runtime/**` — -those are the high-churn B2 (tasks state-machine) and M10 (agent-runtime -hooks) zones, and overlapping edits produce diff storms that lose both -sides' intent. Database and worker/runtime catches are deferred to -Wave 3 under the coordination gate below. - -**Scope cap (hard)**: Wave 2 migrates **at most 30 catch sites**. If the -live count in the listed modules exceeds 30, stop at 30 and move the -remainder to Wave 3. This prevents C6 from expanding into an unbounded -sweep. - -Buckets: - -| Module | Approx sites (capped) | Dominant kind | Notes | -|---|---|---|---| -| `src/main/ipc-*.ts` (excl. already-done credentials + support) | ~15 | `user_input` (zod fails), `upstream` (downstream handler fails) | Uniform shape — candidate for a `registerHandle`-level classifier wrapper | -| `src/main/*-service.ts` + `src/main/api-server/**` | ~8 | Mixed | Each service owns one subsystem; classify per service | -| `src/main/automation/**` + `src/main/skills/**` + `src/main/browser/**` | ~7 | `recoverable` (rule eval), `user_input` (bad config), `upstream` (Electron session) | Small; ride wave 2 PR as final commit | - -**Estimated effort**: 2 days, one PR with one commit per file group. -Depends on Wave 1 only insofar as `registerHandle` wrapper lives in -`ipc-support.ts` and was partially migrated in C6.1. - -### Wave 3 — database + worker/runtime + credentials + leftovers (≤30 catches) - -**Scope cap (hard)**: Wave 3 migrates **at most 30 catch sites**. Any -residue beyond 30 gets punted to a follow-up proposal (C6.3) rather than -expanding Wave 3. C6 does not get to grow without bound. - - -**⚠️ Coordination gate (hard)**: Wave 3 touches `src/main/database/**` -(Linus's domain — backup hook, migrations, state-machine work) and -`src/main/connector-definitions/**` (which was rehomed into a subdirectory -during C6.1). Before starting Wave 3 the executor MUST: -1. Check `git log --oneline -20` for any pending database / backup / - migration commits from other streams. -2. Confirm B2 (tasks state-machine refactor) is either landed or - pre-gated — migrating database catches while B2 is mid-flight - produces diff storms that lose both sides' intent. -3. Open a short coordination thread (issue or chat) with the database - owner before the first file edit — this wave is the highest-risk of - the three for scope conflicts. - -Skipping this gate previously caused commit 093718d in the C6.1 wave to -accidentally carry an M4 scripts/ reorg because two agents touched -`scripts/` in the same window. Do not repeat. - -Buckets: - -| Module | Approx sites | Dominant kind | Notes | -|---|---|---|---| -| `src/main/database/**` | ~20 | `fatal` (corruption), `recoverable` (busy/locked) | **Coordinate with M1 / B2** — these catches are the raw material for the backup/migration preconditions | -| `src/main/browser/**` + `browser-manager.ts` | ~12 | `upstream` (Electron session), `user_input` (blocked URL) | Small surface | -| `src/main/credentials/**` | ~8 | `upstream` (vault decrypt), `user_input` (schema) | Should flow through `UpstreamError` / `UserInputError` subclasses | -| `src/main/skills/**` | ~8 | `recoverable` (fs), `upstream` (GitHub) | | -| Residue (top-level files not already done) | ~10 | Mixed | Clean-up commit | - -**Estimated effort**: 2 days, one PR. - -## Decisions to settle before execution - -| Question | Default | Notes | -|---|---|---| -| Should empty `} catch {}` get a minimum `classifyUnknownError` call? | Yes, when a logger is in scope — even a silent fallback becomes grep-able by `code` | Skip only in pure-library files with no logger | -| Should we introduce a `Result` envelope for IPC? | No — out of scope for C6.2 | Separate proposal if desired | -| Should `AppError.toJSON()` be wired into existing log transports? | Yes, but in a follow-up — taxonomy migration first, transport swap second | | -| Code naming convention | `module.subdomain.condition` (lowercase, dots) | Examples: `db.lock.busy`, `worker.run_log.lease_renewal_lookup_failed`, `ipc.payload.invalid` | - -## Verification checklist per wave - -- `pnpm typecheck` clean -- `pnpm test:unit` green -- `pnpm test:eval` green (no fixture drift) -- `grep -rn "classifyUnknownError" src/main/ | wc -l` monotonically increases -- `grep -rnE "^\s*\} catch \(?\w*\)? \{\s*$" src/main/ | wc -l` monotonically decreases (the empty-catch count) - -## Rollback plan - -Each wave is one PR with per-file commits. Revert at file granularity if -a regression surfaces in the eval harness — no cross-file entanglement -by construction (`classifyUnknownError` is a pure call with no shared -state). - -## Out-of-band follow-ups (not blocking this proposal) - -1. Structured log transport: swap `log.error(\`[${code}] …\`)` for a - JSON shipper that keys on `err.code` directly. Needed for real - telemetry buckets. -2. Renderer-side taxonomy: duplicate the module into `src/renderer/` - (or hoist to `src/shared/`) so IPC error payloads arrive as typed - AppError envelopes. -3. Lint rule: "no bare `} catch (e) {}` in src/main/". Enforceable via - an eslint custom rule once coverage is > 95%. - -## Out of scope explicitly - -- Replacing `throw new Error(...)` call sites with `throw new FatalError(...)` - — that is a separate, heavier surgical pass that would change type - signatures of many functions. File a follow-up if wanted. -- Removing the `console.error` / `electron-log` split — orthogonal. - -## Appendix A — file-level checklist (seed) - -The following is a starter list of the 228 sites, extracted from the -current grep. A reviewer should refresh this list before starting each -wave since the codebase is actively evolving. - -``` -src/main/worker/entry/*.ts (re-grep) -src/main/worker/runtime/*.ts (re-grep) -src/main/worker/handlers/*.ts (14 remain after C6.1) -src/main/worker/observability/*.ts (re-grep) -src/main/orchestration/*.ts (18 remain after C6.1) -src/main/agent-runtime/*.ts (~25) -src/main/api-server/*.ts (~15) -src/main/ipc-*.ts (non-credentials) (~50) -src/main/automation/*.ts (~15) -src/main/database/*.ts (~20) -src/main/browser/*.ts (~12) -src/main/credentials/*.ts (~8) -src/main/skills/*.ts (~8) -src/main/connector-*.ts (~10) -src/main/message-*.ts (re-grep) -leftover top-level files (~10) -``` - -Refresh with `grep -rn "} catch " src/main/ | grep -v "errors/"` before -starting each wave. diff --git a/docs/proposals/C7-prompt-builder-conditional-assembly.md b/docs/proposals/C7-prompt-builder-conditional-assembly.md deleted file mode 100644 index 5e0d9ad0..00000000 --- a/docs/proposals/C7-prompt-builder-conditional-assembly.md +++ /dev/null @@ -1,280 +0,0 @@ -# Proposal C7: prompt-builder 按 role 条件拼装 + token 预算守门 - -> 来源:问题.md C7(行 202-215)、附录 C(行 395)、附录 H(行 574-577) -> 状态:proposed(待 B5 + C4 完成后实施) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:2 周 -> Blocking dependencies:B5(eval harness)、C4(initial-user-turn 精简) - -## 问题陈述 - -`src/main/prompt-builder/system-prompt.ts` 共 262 行,无条件拼装: -- 15 个 SOP(`prompt-builder/sops/*.md`) -- 11 个 API 文档(`prompt-builder/api-docs/*.md`) -- 5 个 CEO 模式片段(`prompt-builder/ceo-modes/*.md`) -- 7 个部门指南(`prompt-builder/department-guidelines/*.md`) -- Operating instructions (CEO / non-CEO 分支) -- Capability registry -- Skill injection - -问题细节: -1. **无条件拼接**:一个 customer_support IC 也会收到全 15 个 SOP(包括 engineering / legal / finance 类) -2. **版本无治理**:每个 SOP/api-doc 的 git blame 是唯一变更记录,没有 `version` frontmatter -3. **无 token 预算守门**:prompt 本身可能吃掉 20-30k input tokens;compactor 还没开始就先把 budget 吃大半 -4. **A/B 实验无法做**:改一个 SOP 的某句话无法 attribute 到具体行为变化 -5. **Cache invalidation 代价高**:Anthropic prompt caching 对稳定前缀敏感——262 行拼装每改一次就 cache miss 一次 - -## 根因分析 - -Karpathy 视角:**prompt 越长越脆**。 - -长 prompt 的三个问题: -1. **Relevance dilution**:LLM 注意力机制对 prompt 中后段的 attention 权重递减(lost-in-the-middle 现象)。全塞 33 个 markdown 文件反而让关键信号被淹没。 -2. **Cross-contamination**:legal SOP 的措辞会影响 engineering agent 的输出风格(比如加 disclaimers);这不是我们想要的。 -3. **Evaluation intractability**:33 个片段两两组合有 1000+ 种可能影响;改一个不知道动了哪。 - -Linus 视角补充:**当前架构假设"一个 prompt 适配所有 agent"**。这和 AppDatabase pass-through 是同构的问题——用一个巨大的 god object 替代多个专用对象。正确做法是按 role 产出不同 prompt。 - -另一个层面的问题:**没有 budget**。prompt-builder 的输出长度是"算出来多少就多少",caller 无法预判。20k / 30k / 50k token 的 prompt 走 Anthropic 都能跑,但 cost 和 latency 完全不同,而且 compactor(B3 未修时)行为也会随 prompt 长度变化。 - -## 设计方案 - -### 核心原则 - -1. **按 role 条件拼装**:每个 agent 只看到自己需要的 -2. **显式 budget**:prompt > threshold 直接 fail fast -3. **片段版本化**:每个 markdown 带 frontmatter `version: X` -4. **Cache-friendly layering**:稳定前缀(不变的 operating instructions)+ 动态后缀(per-turn context)显式分离 - -### 片段分类表 - -| 片段类型 | 何时包含 | 共享度 | -|---------|---------|--------| -| Core operating instructions | 总是 | 所有 agent | -| CEO operating instructions | `agent.role === "ceo"` | CEO only | -| CEO mode(team-building/awaiting-*/operating) | CEO + 当前 phase | CEO only | -| Department guidelines | 按 `agent.department` | 同部门 | -| SOPs | 按"与 agent 能力相关" | 有限子集 | -| API docs | 按 connector 可用性 | 动态 | -| Capability registry | 总是 | 所有 agent | -| Skill injection(pi 的 progressive disclosure) | 总是 | 所有 agent | - -### 新 API 结构 - -```ts -// src/main/prompt-builder/index.ts(重写) -export function buildSystemPrompt(ctx: PromptContext): string { - const sections = resolveSections(ctx); // 新增 - const parts = sections.map((s) => renderSection(s, ctx)); - const prompt = parts.join("\n\n"); - enforceBudget(prompt, ctx); // 新增 - return prompt; -} - -interface SectionRef { - id: string; // "sop.task-delegation" | "department.engineering" | ... - version: string; // 从 markdown frontmatter - required: boolean; // 不满足 required 则 fail -} - -function resolveSections(ctx: PromptContext): SectionRef[] { - const sections: SectionRef[] = [ - { id: "core.operating-instructions", version: "1.0", required: true }, - { id: "core.capability-registry", version: "1.0", required: true }, - ]; - - if (ctx.agent.role === "ceo") { - sections.push({ id: "ceo.operating-instructions", version: "1.0", required: true }); - sections.push({ id: `ceo.mode.${ctx.ceoMode}`, version: "1.0", required: true }); - } - - if (ctx.agent.department) { - sections.push({ id: `department.${ctx.agent.department}`, version: "1.0", required: true }); - } - - for (const sop of resolveRelevantSops(ctx)) { - sections.push({ id: `sop.${sop.slug}`, version: sop.version, required: false }); - } - - // API docs 仅当对应 connector ready 时 - for (const connector of ctx.allConnectors ?? []) { - if (connector.status === "ready") { - sections.push({ id: `api-docs.${connector.id}`, version: "1.0", required: false }); - } - } - - return sections; -} -``` - -### SOP 相关性规则 - -替代"全塞"的朴素规则: - -1. **SOP 有 `tags` frontmatter**:`tags: [task, delegation, messaging]` -2. **Agent role / department 决定关注 tag 集合**: - - CEO → 全 tag - - Engineering dept → `[task, code, review]` - - Customer support → `[task, messaging, escalation]` -3. **Loader 根据 tag 交集筛选** - -Markdown 示例: - -```md ---- -id: sop.task-delegation -version: 1.2 -tags: [task, delegation] ---- -# Task delegation SOP -... -``` - -### Token 预算守门 - -```ts -// src/main/prompt-builder/budget.ts -const BUDGET_THRESHOLDS = { - warn: 8_000, // 超过 warn 打 telemetry - error: 16_000, // 超过 error 直接抛 -}; - -function enforceBudget(prompt: string, ctx: PromptContext): void { - const tokens = estimateTokensPrecise(prompt, ctx.locale); // 用 tiktoken 精确计算(C3 的 scope) - recordMetric("prompt.tokens", tokens, { role: ctx.agent.role, companyId: ctx.companyId }); - if (tokens > BUDGET_THRESHOLDS.error) { - throw new PromptBudgetError(`System prompt ${tokens} tokens exceeds ${BUDGET_THRESHOLDS.error}`); - } - if (tokens > BUDGET_THRESHOLDS.warn) { - logger.warn("prompt.budget.warn", { tokens, threshold: BUDGET_THRESHOLDS.warn }); - } -} -``` - -**Let it crash 原则**:超预算直接 throw,不做"自动裁剪"——因为自动裁剪会悄悄改行为。 - -### Cache-friendly layering - -当前 `buildTaskPrompt`(`prompt-builder/index.ts:48-`)已经把 system prompt(cacheable)和 per-turn context(non-cacheable)分开,这是对的。C7 保留这个分层,进一步: - -- system prompt 内部按 stability 排序:`[core → role → department → SOPs → skills]`(稳定度递减) -- Anthropic cache_control breakpoint 标在 `core + role + department` 之后 - -### A/B harness(可选阶段) - -SOP 片段支持 variant: - -```md ---- -id: sop.task-delegation -version: 1.2 -variants: - - id: default - weight: 50 - - id: concise - weight: 50 - path: ./task-delegation.concise.md ---- -``` - -Loader 按 companyId hash 稳定分配到一个 variant,eval harness(B5)可以对比两个 variant 的行为差异。 - -## Migration 计划 - -1. **Phase 0(前置)**:B5 eval harness 就绪 + C4 initial-user-turn 精简完成 -2. **Phase 1(3 天)**:给所有 markdown 片段加 frontmatter(`id` / `version` / `tags`),loader 支持读取 -3. **Phase 2(1 周)**:实现 `resolveSections` + `renderSection`,行为上保持与当前一致(所有 section 都包含),新旧切换走 feature flag -4. **Phase 3(3 天)**:按 role 开始差异化加载——CEO 仍看全量,非 CEO 开始按 tag 过滤 -5. **Phase 4(3 天)**:加 budget enforcement,先 warn-only 跑一周观测分布 -6. **Phase 5(持续)**:A/B harness + per-company variant 分配 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| 漏包含 SOP 导致 agent 行为退化 | tag 过滤规则太严 | eval 发现 → 回到"全量包含" flag → 修 tag 规则 | -| Budget error 触发生产崩 | 某 company 的 connector 数量极端 | 阶段 4 warn-only 期间监测 p99;超限前调高或加裁剪 | -| Markdown frontmatter 格式错 | 作者漏写 version | Loader 启动时校验所有片段,任何格式错直接 fail | -| Cache invalidation 增多 | 稳定前缀拆得太细 | 监控 cache hit 率,必要时合并片段 | - -## 验证标准 - -**前置:B5 必须就绪**。 - -1. **行为 eval**:对比 5 种 agent role × 3 种 trigger 下的 tool call 序列,新旧方案一致 -2. **Prompt 长度**:非 CEO agent 的 system prompt 长度降低 40%+ -3. **Cache hit rate**:观察 Anthropic cache hit rate,降低 <5%(cache 友好) -4. **Budget 分布**:99% 的 prompt 在 warn 阈值内 -5. **A/B pilot**:至少一个 SOP 有 variant,eval 可观测两个 variant 的行为差异 - -## 不在范围 - -- **不改 SOP 内容**:只是让加载条件化 + 版本化,具体文字不动(那是 Owner 业务的事) -- **不做 AI-driven prompt optimization**:prompt 片段仍是人写的 markdown -- **不改 pi 的 prompt 结构**:本项目只控制自己注入到 pi 的 systemPrompt,pi 内部行为不动 -- **不做 per-agent fine-grained prompt**:按 role / department 分组即可,不做 per-agent 定制 -- **不动 token 精确化**(C3 的 scope):本 proposal 可先用近似估算,C3 完成后自动精确 - -## 参考文件清单 - -- `src/main/prompt-builder/system-prompt.ts:1-262`(主拼装函数) -- `src/main/prompt-builder/sops/*.md`(15 个 SOP) -- `src/main/prompt-builder/api-docs/*.md`(11 个 API 文档) -- `src/main/prompt-builder/ceo-modes/*.md`(5 个 CEO 模式) -- `src/main/prompt-builder/department-guidelines/*.md`(7 个部门指南) -- `src/main/prompt-builder/operating-instructions.ts` + `operating-instructions-ceo.ts` -- `src/main/prompt-builder/capability-registry.ts` -- `src/main/prompt-builder/skill-injection.ts` -- `src/main/prompt-builder/index.ts`(入口 + per-turn 拼装) - -## 附:为什么现在做 - -prompt caching 的经济账:Anthropic cache 5 分钟 TTL,稳定前缀每 miss 一次多付 ~30% cost。262 行拼装每天被改几次就是每天多付 30% × N 次。这是隐性 recurring cost,估算 company 规模一大、agent 数量一多,年度多付上万美元(有具体数值可做 cost model,不在本 proposal 范围)。 - -更重要的是:**有了条件拼装 + version frontmatter,AI coding agent 改 prompt 时可以 diff 到具体片段**——而不是在 262 行大 blob 里大海捞针。这直接降低 team 改 prompt 的心理门槛,促进迭代。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B5 eval harness + C4 完成 | Karpathy | -| G2 | 所有 markdown 片段加了 frontmatter | Owner | -| G3 | resolveSections 函数覆盖 CEO / 非 CEO / 所有 department | Owner | -| G4 | Budget enforcement warn 阈值下 95% prompt 不触发 | Karpathy | -| G5 | A/B variant 第一个实验跑出 eval 差异数据 | Karpathy | - -## 附:markdown frontmatter schema - -```ts -export const SopFrontmatterSchema = z.object({ - id: z.string().regex(/^sop\.[a-z-]+$/), - version: z.string().regex(/^\d+\.\d+$/), - tags: z.array(z.string()).min(1), - locale: z.enum(["en", "zh"]).default("en"), - variants: z.array(z.object({ - id: z.string(), - weight: z.number().min(0).max(100), - path: z.string().optional(), - })).optional(), -}); -``` - -Build 时校验所有 markdown 符合 schema;不符合直接 fail。 - -## 附:SOP tag 分类体系(初版草案) - -| Tag | 含义 | 关联 role | -|-----|------|---------| -| task | 任务管理相关 | 所有 | -| delegation | 分派相关 | CEO, 管理层 | -| code | 代码相关 | engineering | -| review | 审查相关 | 所有 reviewer | -| messaging | 消息沟通 | 所有 | -| escalation | 升级相关 | 所有 | -| finance | 财务相关 | finance, CEO | -| legal | 法务相关 | legal, CEO | -| marketing | 营销相关 | marketing | -| customer | 客户交互 | support, sales | - -规则:SOP 至少有 1 个 tag,agent 根据 role 计算 relevant tag 集合。 diff --git a/docs/proposals/M10-agent-runtime-hooks-aggregation.md b/docs/proposals/M10-agent-runtime-hooks-aggregation.md deleted file mode 100644 index 7eb0d6f7..00000000 --- a/docs/proposals/M10-agent-runtime-hooks-aggregation.md +++ /dev/null @@ -1,264 +0,0 @@ -# Proposal M10: agent-runtime 的 hook 聚合到 AgentHooks + 契约版本化 - -> 来源:问题.md M10(行 278-282)、问题.md C5(行 174-186) -> 状态:proposed(与 C5 契约测试互补) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:1.5 周 -> Blocking dependencies:无,但与 C5(hook 契约测试)协同 - -## 问题陈述 - -`src/main/agent-runtime/` 当前散装 10 个文件: - -| 文件 | 职责 | -|------|------| -| agent-event-projection.ts | run event 投影 | -| artifact-projector.ts | artifact 投影 | -| context-compactor.ts | context 压缩(B3 问题点) | -| cost-writer.ts | cost 记录写入 | -| hook-handlers.ts | hook 回调处理 | -| hook-rpc.ts | hook RPC 层 | -| inbox-projection.ts | inbox 投影 | -| runtime-bridge.ts | 主进程 ↔ pi 桥接 | -| runtime-message-injector.ts | 运行时消息注入 | -| sqlite-session-store.ts | pi session 持久化 | - -其中 compactor / cost-writer / inbox-projection / artifact-projector 都是**注入到 pi agent 的 hook**,但分散在不同文件里,没有一个统一的 `AgentHooks` 聚合类。 - -额外痛点(对照 C5):hook 的签名、调用时序、block-type 约定**深度耦合 pi 版本**——B1 指出的 62 patch 漂移场景下,哪些 hook 还安全完全靠作者记忆。 - -## 根因分析 - -Linus 视角:**散装的 hook 没有统一的契约面**。 - -当前问题: -1. **注册点分散**:`pi-agent-factory.ts` 里 `transformContext: compactor`、`preTurn: inboxProjection`、`postTurn: costWriter` ——每个 hook 各自 import,没有统一枚举 -2. **调用顺序隐式**:哪个 hook 先跑、哪个后跑依赖 pi 内部约定,我们没有声明 -3. **失败处理不一致**:一个 hook 抛错,其他 hook 是否还跑?—— 当前行为依赖 pi 语义 -4. **版本签名无契约**:pi 升级如果改了 hook 参数 shape,本地代码 compile-time 可能通过但 runtime 失败 - -Karpathy 视角(对应 C5):**agent loop 的控制权在上游**,本地只能通过 hook 介入。hook 是**本项目和 pi 的唯一契约面**——这个契约面没治理就是随机炸。 - -## 设计方案 - -### AgentHooks 聚合类 - -新建 `src/main/agent-runtime/agent-hooks.ts`: - -```ts -import type { PiAgentHooks } from "@mariozechner/pi-agent-core"; - -export interface AgentHooksConfig { - compactor: ContextCompactor; - costWriter: CostWriter; - inboxProjection: InboxProjection; - artifactProjector: ArtifactProjector; - eventProjection: AgentEventProjection; - logger: Logger; -} - -export class AgentHooks { - constructor(private config: AgentHooksConfig) {} - - toPiHooks(): PiAgentHooks { - return { - transformContext: async (messages, ctx) => { - try { - return await this.config.compactor.maybeCompact(messages, ctx); - } catch (e) { - return this.handleHookError("transformContext", e, { passthrough: messages }); - } - }, - preTurn: async (ctx) => { - await this.config.inboxProjection.inject(ctx); - }, - postTurn: async (ctx) => { - await Promise.all([ - this.config.costWriter.write(ctx), - this.config.artifactProjector.project(ctx), - this.config.eventProjection.record(ctx), - ]); - }, - onError: async (err, ctx) => { - this.config.logger.error("agent.hook.error", { err, ctx }); - }, - }; - } - - private handleHookError(hookName: string, err: unknown, opts: { passthrough: T }): T { - this.config.logger.error("agent.hook.error", { hookName, err }); - // Fail-safe policy: hook 内部错误不 crash agent loop,但记录 telemetry - return opts.passthrough; - } -} -``` - -### 契约版本标识 - -```ts -export const AGENT_HOOKS_PI_COMPAT = "0.67.x"; - -// 启动时校验 -import { version as piAgentVersion } from "@mariozechner/pi-agent-core/package.json"; -if (!satisfies(piAgentVersion, AGENT_HOOKS_PI_COMPAT)) { - throw new Error(`Agent hooks not compatible with pi-agent-core ${piAgentVersion}`); -} -``` - -升级 pi 前必须更新 `AGENT_HOOKS_PI_COMPAT`,强制开发者确认 hook 签名兼容性。 - -### Fixture 驱动的契约测试(配合 C5) - -``` -src/main/agent-runtime/__fixtures__/ -├── transform-context/ -│ ├── input-30-messages.json -│ └── expected-output.json -├── pre-turn/ -│ └── inbox-injection.json -└── post-turn/ - └── cost-write.json -``` - -契约测试:每个 fixture 的 hook 输入/输出 shape 必须稳定。升级 pi 必须跑这套测试——如果 shape 变了,测试 fail,必须显式处理 migration。 - -### hook-handlers.ts / hook-rpc.ts 归类 - -这两个文件是 pi runtime 和 main 进程之间的 RPC(hook 执行位置 ≠ 进程位置)。本 proposal 不合并它们到 `agent-hooks.ts`,保留独立文件,但 agent-hooks 成为**入口**——外部代码只 import `AgentHooks`,内部如何走 RPC 是实现细节。 - -## Migration 计划 - -1. **Phase 1(2 天)**:实现 `AgentHooks` 类,内部调用保留原有 4 个 hook 模块 -2. **Phase 2(2 天)**:pi-agent-factory.ts 从散装 import 切到 `new AgentHooks(...).toPiHooks()` -3. **Phase 3(3 天)**:加版本兼容标识 + 启动校验 -4. **Phase 4(1 周)**:补 fixture 和契约测试 -5. **Phase 5(持续)**:下次 pi 升级走完整 flow——跑 fixture 测试 + review `AGENT_HOOKS_PI_COMPAT` - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| Hook 执行顺序变化 | 聚合后若 pi 顺序改变 | 聚合类维持和原来一致的执行顺序,加注释 | -| Fixture 维护成本 | 每次 pi 改 hook shape 都要更新 fixture | 接受——这正是契约测试的目的 | -| 兼容范围过严 | `^0.67.0` vs `0.67.68` | 升级时 explicit 更新 compat 字符串 | -| Hook 吞 error | `handleHookError` 掩盖真实 bug | 强制 telemetry 记录;同时让 critical 场景(例如 cost 写入失败)走 throw 而不是 passthrough | - -## 验证标准 - -1. **Typecheck 通过**:hook 签名与 pi 类型严格一致 -2. **启动校验**:pi 版本不 satisfies 时应用启动 fail fast -3. **契约测试覆盖**:4 个主要 hook 都有 fixture + 验证 -4. **Telemetry 可观测**:hook 错误被记录到 telemetry,不是静默吞 -5. **Refactor 零行为变化**:相同 agent run,新旧方案产出的 event stream / cost record 一致 - -## 不在范围 - -- **不重写 compactor 内部逻辑**(B3 / C3 是独立 proposal) -- **不改 pi 上游**:只能在 hook 层适配 -- **不做 hook 的 hot-reload**:启动一次加载即可 -- **不实现自动 pi 升级**:升级仍是人工决策 + 跑 fixture -- **不合并 hook-handlers 和 hook-rpc**:它们是不同抽象层(业务 vs 协议) - -## 参考文件清单 - -- `src/main/agent-runtime/context-compactor.ts:52-73`(B3 问题代码) -- `src/main/agent-runtime/cost-writer.ts` -- `src/main/agent-runtime/inbox-projection.ts` -- `src/main/agent-runtime/artifact-projector.ts` -- `src/main/agent-runtime/agent-event-projection.ts` -- `src/main/agent-runtime/hook-handlers.ts` -- `src/main/agent-runtime/hook-rpc.ts` -- `src/main/agent-runtime/runtime-bridge.ts` -- `src/main/agent-runtime/runtime-message-injector.ts` -- `src/main/agent-runtime/sqlite-session-store.ts` -- `src/main/worker/pi-agent-factory.ts:131`(hook 注册点) -- `pi-mono-reference/packages/agent/`(上游 hook 接口定义) - -## 附:为什么现在修 - -pi 升级(B1 已完成的 0.67.68 pin)之前团队每次升级 pi 都是赌博——hook 是否还兼容没人能验证。M10 + C5 的契约测试是把"我猜还能跑"变成"测试证明能跑"的唯一办法。 - -M10 单独的收益:代码可读性——新工程师打开 `pi-agent-factory.ts` 不用猜哪几个 hook 在做什么,看 `AgentHooks` 的 `toPiHooks()` 一目了然。 - -注意与 B3(compactor tool_use 切腰斩)的关系:B3 是 compactor 内部的正确性问题,M10 是 hook 接入层的组织问题。两个正交,B3 先做(BLOCKER),M10 后做。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | `AgentHooks` 类与现有 pi 版本 0.67.68 契约对齐 | Linus | -| G2 | 4 个主要 hook 每个有 fixture 和契约测试 | Karpathy | -| G3 | 启动时校验 pi 版本在兼容范围,不在则 fail fast | Owner | -| G4 | Telemetry 可观察 hook 错误率,7 天无新 silent drop | Owner | -| G5 | 下次 pi 升级走完整 flow 验证 | Owner | - -## 附:与 C5 的关系 - -C5(hook 契约测试)是 M10 的验证手段——M10 做好聚合后,C5 提供契约测试 harness。两件事 logically 可以并行做,但实现上 M10 先于 C5 更自然(先有聚合类再给它加测试)。 - -## 附:反模式对比 - -**Before**(`src/main/worker/pi-agent-factory.ts:131` 附近): -```ts -const agent = createPiAgent({ - transformContext: contextCompactor.maybeCompact.bind(contextCompactor), - preTurn: inboxProjection.inject.bind(inboxProjection), - postTurn: async (ctx) => { - await costWriter.write(ctx); - await artifactProjector.project(ctx); - }, - // ...每次加 hook 都要改 factory -}); -``` - -**After**: -```ts -const hooks = new AgentHooks({ compactor, costWriter, inboxProjection, artifactProjector, ... }); -const agent = createPiAgent(hooks.toPiHooks()); -// 加新 hook 只改 AgentHooks.toPiHooks(),factory 不动 -``` - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:AgentHooks 聚合类 + 版本兼容标识。 - -**方案 B(完全重写 agent loop,不用 pi)**:成本远大于收益——pi 已经处理了 token 流、provider 切换、retry 等。 - -**方案 C(把 hook 留在独立文件,但加统一的 factory helper)**:没解决"hook 入口分散"问题,签名仍各自 drift。 - -方案 A 成本低、收益清晰。 - -## 附:fixture 目录结构示例 - -``` -src/main/agent-runtime/__fixtures__/ -├── README.md -├── transform-context/ -│ ├── 30-messages-with-tool-pairs.json -│ ├── 30-messages-no-tool-calls.json -│ ├── cjk-heavy-content.json -│ └── empty-input.json -├── pre-turn/ -│ ├── inbox-with-unread-messages.json -│ └── inbox-empty.json -├── post-turn/ -│ ├── successful-tool-call.json -│ ├── assistant-text-only.json -│ └── error-turn.json -└── version-matrix/ - └── compat-0.67.68.json -``` - -每个 fixture 包含 input + expected output + 注释说明。升级 pi 时跑 `pnpm test:hook-contracts` 一键验证。 - -## 附:hook error handling 策略矩阵 - -| Hook | 错误策略 | 理由 | -|------|---------|------| -| transformContext (compactor) | passthrough(返回原 messages) | compactor 挂不应该阻塞 agent 前进 | -| preTurn (inbox projection) | throw(让 agent loop 挂) | inbox 注入失败意味着 agent 读不到新消息,前进下去会 base 错误 | -| postTurn (cost writer) | throw | cost 写入失败是数据完整性问题,必须 crash | -| postTurn (artifact projector) | passthrough + telemetry | artifact 缺失不阻塞后续 | -| postTurn (event projection) | throw | event 丢失无法事后补,必须 crash | -| onError | 记 log | terminal hook,不能 rethrow | diff --git a/docs/proposals/M11-credential-manager-unification.md b/docs/proposals/M11-credential-manager-unification.md deleted file mode 100644 index ed6e9b7a..00000000 --- a/docs/proposals/M11-credential-manager-unification.md +++ /dev/null @@ -1,251 +0,0 @@ -# Proposal M11: 统一 CredentialManager(OAuth + API key + vault 三合一) - -> 来源:问题.md M11(行 284-288)、附录 I 第 1 条(行 587) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:2 周 -> Blocking dependencies:无 - -## 问题陈述 - -`src/main/credentials/` 模块当前有 4 个文件: -- `credential-resolver.ts` -- `credential-store.ts` -- `oauth-login-service.ts` -- `types.ts` - -同时还有独立的: -- `src/main/vault.ts`(secret 加密存储) -- `src/main/connector-definitions-data-apikey.ts`(API key 类 connector 定义) -- `src/main/connector-definitions-data-oauth.ts`(OAuth 类 connector 定义) -- `src/main/connector-definitions-data-cloud.ts`(Cloud 类 connector 定义) - -**四个不同的"我是谁"来源**散落,secret 生命周期(如何过期 / 如何轮换 / 如何跨 connector 共享)不明确。 - -具体问题: -1. **Resolve 路径不统一**:有的走 `credentialResolver.resolve(id)`,有的直接 `vault.decrypt(key)`,有的走 `credentialStore.lookup(connectorId)` —— call site 多样,每种 resolve 路径的失败模式也不同 -2. **Secret 生命周期**:OAuth token 有 `expires_at`,API key 通常没有,cloud-hosted 凭证可能有 API-specific expiry —— 当前没有统一的 "refresh / rotate" 流程 -3. **Vault 被直接 expose**:某些 service 直接调 `vault.decrypt(...)`,绕开 credentialResolver 的缓存/审计 -4. **Connector 定义分三份**:相同的 connector "XX" 可能同时在 apikey / oauth 两份定义里存在,用户 UI 看到的 connector 状态由谁算真源不确定 -5. **权限边界不明**:哪些 service 能读什么凭证?当前没有 ACL,任何 service 都能 import credentialResolver 和 vault - -## 根因分析 - -Linus 视角(安全边界是数据结构的第一公民):**"凭证"是一个抽象概念,当前项目没有把它建模成一等公民**,而是按类型(OAuth vs API key)分别处理,导致每种类型各成体系。 - -真正的抽象应该是: - -``` -Credential (abstract) -├── metadata: { id, scope, expiresAt, ... } -├── provider: OAuthProvider | ApiKeyProvider | CloudProvider -└── resolve(): Promise<{ secret: string, metadata: Metadata }> -``` - -provider 负责具体的获取和刷新逻辑,上层只关心"给我 X 连接器的凭证"——类型差异被封装。 - -Karpathy 视角:agent 调用 connector 时只想"用 X 连接器",不关心这个连接器是 OAuth / API key / Cloud。当前分三份 connector 定义意味着 UI 和 agent 都需要做类型判断——属于把实现细节泄漏到 consumer。 - -## 设计方案 - -### 统一的 CredentialManager - -新建 `src/main/credentials/credential-manager.ts`: - -```ts -export interface Credential { - id: string; - connectorId: string; - kind: "api_key" | "oauth" | "cloud_hosted"; - expiresAt: number | null; -} - -export interface ResolvedCredential { - secret: string; - metadata: Credential; -} - -export class CredentialManager { - constructor( - private vault: Vault, - private store: CredentialStore, - private oauth: OAuthLoginService, - ) {} - - async resolve(connectorId: string, opts?: { skipRefresh?: boolean }): Promise { - const credential = this.store.lookup(connectorId); - if (!credential) throw new CredentialNotFound(connectorId); - - switch (credential.kind) { - case "api_key": - return this.resolveApiKey(credential); - case "oauth": - return this.resolveOAuth(credential, opts); - case "cloud_hosted": - return this.resolveCloud(credential); - } - } - - async rotate(connectorId: string): Promise { - // 统一的轮换入口 - } - - async revoke(connectorId: string): Promise { - // 统一的吊销入口 - } - - private async resolveOAuth(cred: Credential, opts?: { skipRefresh?: boolean }): Promise { - if (cred.expiresAt && cred.expiresAt - Date.now() < REFRESH_BEFORE_MS && !opts?.skipRefresh) { - await this.oauth.refresh(cred.id); - } - const secret = await this.vault.decrypt(cred.id); - return { secret, metadata: cred }; - } - - private async resolveApiKey(cred: Credential): Promise { - const secret = await this.vault.decrypt(cred.id); - return { secret, metadata: cred }; - } - - private async resolveCloud(cred: Credential): Promise { - // Cloud 场景走 provider API 拿 ephemeral token - ... - } -} -``` - -### Vault 只做存储,不暴露 API - -Vault 变成 `CredentialManager` 的内部实现——其他模块不再直接 import `vault.ts`。 - -```ts -// vault.ts 只 export 内部使用的类 -export class Vault { - // internal methods -} -``` - -ESLint rule:禁止 `credentials/` 目录之外的代码直接 import `vault.ts`。 - -### Connector 定义合并 - -三份 connector 定义文件合并为统一结构: - -```ts -// src/main/connectors/definitions/index.ts -export interface ConnectorDefinition { - id: string; - label: string; - authKind: "api_key" | "oauth" | "cloud_hosted"; - enabledModels?: string[]; - // 根据 authKind 分支 - apiKey?: ApiKeyConfig; - oauth?: OAuthConfig; - cloud?: CloudConfig; -} -``` - -所有 connector 在一个地方注册,UI / agent 不再需要判断类型——CredentialManager 和 ConnectorRegistry 各自消费 `authKind`。 - -### 审计和权限 - -- 所有 `resolve` 调用记 telemetry:`credential.resolved`(connectorId, caller, timestamp) -- 敏感操作(`rotate` / `revoke`)需要显式 caller 标识 -- Log 中**永不**打印 secret(redactor 检查) - -## Migration 计划 - -1. **Phase 1(3 天)**:建 `CredentialManager` 类,内部调用现有 `credentialResolver` / `credentialStore` / `oauthLoginService`(组合层) -2. **Phase 2(1 周)**:所有 call site 改用 `credentialManager.resolve(connectorId)`——grep `credentialResolver` / `vault.decrypt` 的使用处 -3. **Phase 3(3 天)**:合并 connector 定义文件到统一结构 -4. **Phase 4(2 天)**:加 ESLint rule 禁止直接 import `vault.ts` -5. **Phase 5(持续)**:下次 OAuth refresh token 过期 bug 修复时,在 CredentialManager 层统一处理,不再散修 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| Secret 解密路径变 | 合并后某些 edge case 路径丢失 | Phase 1-2 保留旧路径,逐步迁移 | -| OAuth refresh 时序 | `resolveOAuth` 的 `REFRESH_BEFORE_MS` 判断不当 | 可配置;保守值开始 | -| Connector 定义合并冲突 | 同一个 connector 在两份定义里有 | 合并时 explicit choose,由 Owner 确认 | -| 审计 log 过大 | 每次 resolve 都记一条 | 加 sample rate 或只记重要 connector | - -## 验证标准 - -1. **静态 scan**:`grep -rn "vault\.decrypt\|vault\.encrypt" src/main/` 除 `credentials/` 内之外应无命中 -2. **Typecheck**:全项目通过 -3. **Connector UI 一致**:UI 显示的 connector 状态与 `credentialManager.listAvailable()` 一致 -4. **OAuth refresh 正确**:模拟 token 过期场景,resolve 自动 refresh -5. **Telemetry**:每次 resolve 可见于 telemetry,无 secret 泄漏到 log - -## 不在范围 - -- **不重写 OAuth flow**:OAuth 登录 UI 和流程保留,只是 resolve 路径改 -- **不改 vault 加密算法**:现有 AES-GCM / OS keychain 集成不动 -- **不做 multi-user 隔离**:单用户 desktop app,不需要 -- **不做凭证同步**(跨设备):独立 feature -- **不引入密钥管理服务**(HashiCorp Vault / AWS Secrets Manager) - -## 参考文件清单 - -- `src/main/credentials/credential-resolver.ts` -- `src/main/credentials/credential-store.ts` -- `src/main/credentials/oauth-login-service.ts` -- `src/main/credentials/types.ts` -- `src/main/vault.ts`(改为 credentials/ 内部) -- `src/main/connector-definitions-data-apikey.ts` -- `src/main/connector-definitions-data-oauth.ts` -- `src/main/connector-definitions-data-cloud.ts` -- 所有 call site(grep `credentialResolver` / `vault.decrypt` 找到) - -## 附:为什么现在修 - -每多加一个 connector 类型(例如未来支持 JWT / mTLS / device cert),现在的分层结构都要再拆一个文件、再加一条分支逻辑。统一到 CredentialManager 后,新 authKind 只是加一个 case 分支。 - -**安全角度的刚性需求**:审计和权限一旦变成合规要求(例如要求记录"哪个 agent 用了哪个凭证"),当前散装结构根本没法快速加上。现在改还是 refactor,等到合规逼迫再改就是紧急项目。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | `CredentialManager` 可同时 serve OAuth / API key / Cloud 三类 | Owner | -| G2 | 所有 call site 迁移完,grep `vault\.decrypt` 仅限 `credentials/` 内 | Linus | -| G3 | 三份 connector definition 合并为单一结构 | Owner | -| G4 | 审计 log 记录 7 天无 secret 泄漏 | Security | -| G5 | OAuth refresh 单元测试通过:token 过期 < REFRESH_BEFORE 时自动刷新 | Owner | - -## 附:secret 生命周期治理 - -| 凭证类型 | 创建 | 刷新 | 轮换 | 吊销 | 审计事件 | -|---------|------|------|------|------|---------| -| OAuth | OAuth flow | 自动 (refresh token) | 手动触发 | OAuth revoke endpoint | created/refreshed/revoked | -| API key | 用户粘贴 + vault 加密 | 不适用 | 用户替换 | 用户删除 | created/rotated/revoked | -| Cloud hosted | 登录 | Provider API 换短期 token | Provider 端管理 | Provider 端删除 | created/exchanged/revoked | - -CredentialManager 对外 API 不区分这三类——内部根据 `kind` 走对应 provider。 - -## 附:反模式对比 - -**Before**: -```ts -// 随便某个 service 里 -const secret = await vault.decrypt(connectorId); // 任何人能调 -const token = await oauth.getCurrentToken(connectorId); // 绕过 vault -``` - -**After**: -```ts -const { secret, metadata } = await credentialManager.resolve(connectorId); -// 唯一入口;自动 refresh;自动审计;不暴露 vault API -``` - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:统一 CredentialManager。 - -**方案 B(给每种 authKind 独立的 Manager,再加一个 Dispatcher)**:多一层,没增加清晰度。 - -**方案 C(保留现状,只加 wrapper)**:wrapper 不能阻止旧 call site 继续绕路。 - -方案 A 是唯一真正统一的方案。 diff --git a/docs/proposals/M12-renderer-state-audit.md b/docs/proposals/M12-renderer-state-audit.md deleted file mode 100644 index df50f02a..00000000 --- a/docs/proposals/M12-renderer-state-audit.md +++ /dev/null @@ -1,252 +0,0 @@ -# Proposal M12: renderer 状态层审查(IPC 契约化后做) - -> 来源:问题.md M12(行 290-294)、附录 D(行 403-408) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:3-4 周 -> Blocking dependencies:**M2(IPC 契约化)必须先完成** - -## 问题陈述 - -104 个 IPC channel(见 M2)基本都在给 renderer 推状态: -- profile snapshot -- task list -- run events -- browser actions -- approvals -- messages -- … - -renderer 如何 debounce、merge、避免 stale read,**本次 review 未深入**——但缺乏契约层的前提下几乎必然有一致性 bug。 - -典型问题猜测(需 M2 完成后验证): -1. **Race condition**:两个 IPC response 几乎同时到达,后到覆盖先到,但语义上应该合并 -2. **Stale read**:renderer 发 request → main 返回 → 中间 main 已经又写了一次 → renderer 拿到 stale snapshot -3. **过度 refetch**:renderer 没有合适的 cache,每次切换页面都重 fetch(浪费 IPC round trip) -4. **Event dedup**:同一个 run event 被多个订阅路径接收,渲染时重复展示 -5. **Optimistic update 回滚**:renderer 本地 optimistic 更新,但 main 拒绝后没有正确回滚 - -## 根因分析 - -当前未知——本 proposal 承认**review 没覆盖 renderer**。 - -Linus 视角推测:104 个 channel × N 种 payload shape × 若干订阅者 = 巨大的状态空间。没有类型契约(M2 未完成)时,renderer 层的一致性问题**无法静态证明也无法系统性测试**。M2 是前置条件——契约化后才能逐个 channel audit。 - -Karpathy 视角补充:renderer 的 UI state 错乱直接让用户看到 "agent 跑着但 UI 显示闲置" 或 "approval 已批但列表还在" 等典型 bug。这种 bug 很难用 unit test 捕捉,需要 e2e 验证 + state invariant checking。 - -## 设计方案 - -本 proposal 是**审查方案**而不是修复方案——具体修法要等审查结果。 - -### 审查范围 - -`src/renderer/` 全部代码,重点: -1. **状态管理库**:目前是 zustand(从 `package.json` 看到依赖) -2. **IPC 订阅点**:`useEffect` 里调 `window.api.invoke` / 订阅 event 的位置 -3. **数据合并逻辑**:event 到达时如何 merge 到 store -4. **缓存策略**:哪些数据缓存、TTL 多少、如何失效 -5. **Optimistic update**:哪些 action 先改 UI 再等 ack - -### 审查 checklist - -| 项 | 检查内容 | -|----|---------| -| 1 | 每个 zustand store 的 state shape 是否 type-safe(借助 M2 的 IpcOutput 类型) | -| 2 | 每个 IPC invoke 的 response 处理,是否考虑 race(后到请求覆盖先到请求) | -| 3 | 每个 event subscription,是否 dedup(同一 event 不同路径接收) | -| 4 | Optimistic update 的回滚逻辑完备性 | -| 5 | 组件 unmount 时 subscription cleanup | -| 6 | 跨 route 切换时 store 是否 reset(避免显示上一个 company 的数据) | -| 7 | 长列表的 virtualization(react-virtual 已在依赖里,实际使用覆盖度) | -| 8 | Loading / error / empty 三种边界态覆盖 | - -### 预期产出 - -审查结束后产出 `docs/proposals/M12-renderer-findings.md`,按严重度列出发现的具体问题,每条给修复 proposal(可能演化为独立 proposal)。 - -### 审查方法 - -1. **静态**: - - grep `window.api.invoke` 找所有 call site - - grep `useEffect` + IPC 调用 找订阅点 - - 对照 M2 的 IpcChannels 一一核对 shape -2. **动态**: - - 启动 app,开 React DevTools 看 zustand store 状态 - - 触发典型场景(agent run、approval flow、task update),观察 state transition - - 故意制造 race(背景 run 发 event + 前景用户交互) -3. **e2e**: - - 用 Playwright(tests/e2e 已配置)写 invariant 检查脚本: - - 任何时刻 UI 显示的 "pending approvals" 数量 = main 进程 DB 查询结果 - - 任何时刻 UI 显示的 "active runs" = DB runs where status=running - -## Migration 计划(审查后) - -审查阶段: - -1. **Phase 1(1 周)**:静态扫描 + 形成 findings 列表 -2. **Phase 2(1 周)**:动态测试 + Playwright invariant script -3. **Phase 3(1 周)**:按严重度归类,高严重度的 findings 进入后续 sprint 修复 -4. **Phase 4(1-2 周)**:根据 findings 可能派生出新的 proposal(例如"renderer-state-race-fixes") - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| 审查范围失控 | 发现问题太多,sprint 无法覆盖 | 按严重度分批,每个 sprint 处理一类 | -| 修复引入新 bug | 动 renderer state 逻辑 | 每类修复独立 PR + e2e 验证 | -| M2 没完成就启动 | 契约化未完成导致审查无类型依据 | 不做,等 M2 | - -## 验证标准(审查阶段) - -1. **覆盖率**:grep 可见所有 `window.api.invoke` 都被审查 -2. **Findings 数**:产出具体 finding 列表(预估 20-40 条) -3. **E2E invariant**:至少 5 条关键 invariant 被 playwright 脚本覆盖 -4. **修复 backlog**:高优先 finding 进入下个 sprint - -## 不在范围 - -- **不做 renderer 架构重写**:只是审查 + 针对性修复 -- **不换状态管理库**:zustand 保留 -- **不改 UI 设计**:只审数据流 -- **不重构 route 层**:url routing 逻辑独立 -- **不做 A/B 测试设施**:UI 实验独立 proposal - -## 参考文件清单 - -- `src/renderer/`(全部,待审查) -- `src/preload/index.ts`(IPC bridge) -- `src/main/ipc-*.ts`(main 侧 handler) -- `tests/e2e/playwright.config.ts`(e2e 测试配置) -- M2 契约表(前置依赖) - -## 附:为什么现在放一个"审查 proposal" 而不是修复 proposal - -本次代码 review(2026-04-20)**明确跳过了 renderer 深入**——review report 也坦白了这点。列 M12 不是占位,是承认"这里有未知的坑"。 - -**第一性原理**:不能在没契约(M2)的前提下审 renderer 状态——审的结论无法落成 executable 测试。必须等 M2 完成后,renderer 层的问题才有具体形状。 - -M12 也是 IPC-related 所有 proposal 的收官——M2 完成 + M12 审查完 + 修复完,整个 main ↔ renderer 的契约面才算治理完整。 - -Karpathy 视角:Agent 的 UI 呈现错误("agent 跑完了但还在 spinner")直接伤害产品 perception——用户不会分辨是 LLM bug 还是 state bug,一律认为"这 agent 不可靠"。所以 renderer state 治理的优先级实际比列 M 级更高,但依赖链强迫它排在后面。 - -## 附:审查输出模板 - -审查结束后 `docs/proposals/M12-renderer-findings.md` 的结构: - -```markdown -# M12 Findings () - -## 🔴 Critical findings -### F-01: <具体问题> -- 文件:src/renderer/xxx.tsx:<行号> -- 重现:<最小重现步骤> -- 影响:<用户层面影响> -- 建议修复:<简短描述> - -## 🟠 Major findings -... - -## 🟡 Minor findings -... - -## Covered e2e invariants -1. -2. -... -``` - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | M2 IPC 契约化完成 | Linus | -| G2 | 审查 checklist 8 项全覆盖 | Owner | -| G3 | Findings 列表产出并分类(≥20 条) | Linus | -| G4 | e2e invariant 脚本 ≥5 条可运行 | Karpathy | -| G5 | 高优先 findings 进入下 sprint 修复 | Owner | - -## 附:关键 invariant 候选 - -e2e playwright 要覆盖的状态不变式: - -1. UI "pending approvals" count = DB approvals where status = 'pending' -2. UI "active runs" = DB runs where status = 'running' -3. Task card 显示的 phase = DB tasks.phase(B2 完成后) -4. Agent message 未读数 = DB agent_message_reads 未读行数 -5. 某 company 被切换后,UI 不应残留前一 company 数据 -6. Approval 批准后,UI 应在 1s 内从 pending 列表消失 -7. Task 从 todo → in_progress 时,spinner 应立即显示 -8. Browser action 执行中,main 进程可见 subprocess status = running - -## 附:为什么现在不做 proposal 只做审查 - -当前 review 团队(Linus + Karpathy + Jobs)**没有覆盖 renderer**——贸然给出修复 proposal 等于凭想象出方案。本 proposal 诚实承认这是"审查准备"阶段,具体修复待发现。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:先审查后修复,M2 做前置。 - -**方案 B(一次性 renderer 重写)**:风险极大——renderer 代码量不小,重写周期长,期间 UI 完全不可用。 - -**方案 C(按路由逐 page 重写)**:逻辑上可行,但 findings 可能跨 page(例如多个 page 用同一个 bug store),按 page 重写解决不了。 - -方案 A 是发现问题 → 针对性修复的稳妥路径。 - -## 附:常见 renderer state 反模式(待审查时排查) - -审查重点观察以下 pattern: - -1. **useEffect 里 invoke 没 AbortController**:组件 unmount 但 promise 仍 resolve,导致 "setState on unmounted component" -2. **event listener 没 cleanup**:`ipcRenderer.on("xxx", h)` 返回的 listener 没在 `useEffect` 清理 -3. **派生 state 存 store**:本可以 derive 的数据写入 store,引入一致性问题 -4. **Optimistic update 没 rollback**:`store.setState({ ... })` 后 invoke 失败,UI 保持错误态 -5. **同一 data 多次 fetch**:切换 tab 每次重 fetch,没有 cache 或 cache 失效策略不当 -6. **Route 切换 store 不 reset**:上一个 company 的数据残留到当前 company 视图 -7. **Event dedup 缺失**:同一 run_event 被多个路径转发到 renderer,渲染时重复 -8. **List 未 virtualize**:大列表渲染全量 DOM,滚动卡顿 - -审查时对每个 store 和每个大组件逐项核查。 - -## 附:playwright e2e invariant 脚本骨架 - -```ts -// tests/e2e/invariants.spec.ts(M12 产出) -test("pending approvals UI = DB", async ({ page, electronMain }) => { - await page.goto("/approvals"); - const uiCount = await page.locator("[data-testid=pending-approval]").count(); - const dbCount = await electronMain.evaluate(() => - db.approvals.count({ status: "pending" }) - ); - expect(uiCount).toBe(dbCount); -}); - -test("active runs UI = DB", async ({ page, electronMain }) => { - await page.goto("/runs"); - const uiRunning = await page.locator("[data-status=running]").count(); - const dbRunning = await electronMain.evaluate(() => - db.runs.count({ status: "running" }) - ); - expect(uiRunning).toBe(dbRunning); -}); - -// ... 至少 5 条 invariant -``` - -## 附:renderer store 梳理(待 M2 完成后形成清单) - -M2 完成后,M12 审查第一步:把每个 zustand store 列出来 + 它订阅的 IPC channel 映射,形成: - -| Store | 订阅 channel | 更新策略 | 发现的问题 | -|-------|------------|---------|----------| -| agentsStore | `agents/list` + `agents/updated` event | ? | 待审 | -| tasksStore | `tasks/list` + `tasks/updated` event | ? | 待审 | -| ... | ... | ... | ... | - -## 附:e2e harness 运行频率 - -- PR 触发:快速 invariant(< 30s 跑完的子集) -- 夜间 build:全量 invariant + soak test(5 分钟持续交互) -- Release gate:全量 + manual QA pass - -M12 审查结束后产出的 invariant 脚本会同时塞进这三层。 diff --git a/docs/proposals/M2-ipc-contracts.md b/docs/proposals/M2-ipc-contracts.md deleted file mode 100644 index 504a0889..00000000 --- a/docs/proposals/M2-ipc-contracts.md +++ /dev/null @@ -1,258 +0,0 @@ -# Proposal M2: 104 IPC handler 契约化(集中 channel 定义 + 类型化 invoke) - -> 来源:问题.md M2(行 227-234)、附录 D(行 403-408) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:2 周 -> Blocking dependencies:无(独立于其他 proposal) - -## 问题陈述 - -主进程注册的 IPC handler 总数 **104**(`grep -c "ipcMain\.handle\|registerHandle("` 全 main 目录),分散在 22 个文件: - -- `ipc-agent-coordination-handlers.ts` -- `ipc-automation-operations-handlers.ts` -- `ipc-browser-handlers.ts` -- `ipc-budget-handlers.ts` -- `ipc-content-operations-handlers.ts` -- `ipc-core-admin-handlers.ts` -- `ipc-core-agent-graph-handlers.ts` -- `ipc-core-common.ts` -- `ipc-core-handlers.ts` -- `ipc-core-operations-handlers.ts` -- `ipc-core-read-handlers.ts` -- `ipc-core-task-graph-handlers.ts` -- `ipc-core-work-graph-handlers.ts` -- `ipc-credentials-handlers.ts` -- `ipc-domain-common.ts` -- `ipc-domain-handlers.ts` -- `ipc-oauth-handlers.ts` -- `ipc-onboarding-handlers.ts` -- `ipc-recovery-handlers.ts` -- `ipc-skill-handlers.ts` -- `ipc-support.ts` -- `ipc-thread-handlers.ts` - -所有 channel 名都是**字符串字面量**:`ipcMain.handle("agents/list", ...)`、`ipcRenderer.invoke("agents/list", ...)`。preload 和 main 之间无 schema 约束,renderer 里任何拼写错误都是 runtime 静默失败。 - -## 根因分析 - -Linus 视角:**无类型约束的大面积 RPC surface 是可观测性黑洞**。 - -当前问题: -1. **字符串拼写错误**:renderer 写 `"agents/lsit"`(typo),preload invoke 不报错,main 没有 handler → Promise 永不 resolve 或超时 -2. **参数 shape 漂移**:main 改了 handler 接收的参数结构,renderer 还按旧 shape 发——JSON 反序列化成功但字段丢失,产出异常由业务层感知 -3. **返回值类型假设**:renderer 期望 `{ ok: true, data: ... }`,main 返回 `data` 裸值或 `null`——typeof 判断错了又是静默 bug -4. **静态 grep 困难**:改 channel 名要 grep 字符串,漏一处就断一个功能 -5. **新 channel 命名漂移**:`core-admin` / `core-agent-graph` / `core-common` 这种前缀暴露"core 是啥都不清楚"的命名漂移——审查时得打开文件才知道属于哪个域 - -Karpathy 视角补充:AI coding agent 写 renderer 代码时,没有 IDE 自动补全 channel 名,每次都 grep 猜一次——写错概率很高。即使写对了 channel,payload shape 也是 tribal knowledge。 - -## 设计方案 - -### 核心:单一 contract 源 - -新建 `src/shared/ipc-contracts.ts`(renderer 和 main 都能 import): - -```ts -// 所有 channel 集中定义 -export const IpcChannels = { - "agents/list": { - input: z.object({ companyId: z.string() }), - output: z.object({ agents: z.array(AgentRecordSchema) }), - }, - "tasks/save": { - input: TaskRecordSchema, - output: z.object({ taskId: z.string() }), - }, - "approvals/resubmit": { - input: z.object({ approvalId: z.string() }), - output: z.object({ ok: z.literal(true) }), - }, - // ... 104 条 -} as const; - -export type IpcChannelName = keyof typeof IpcChannels; -export type IpcInput = z.infer; -export type IpcOutput = z.infer; -``` - -### main 侧:强制契约注册 - -```ts -// src/main/ipc-core-common.ts(改造) -export function registerIpcHandler( - channel: K, - handler: (input: IpcInput) => Promise> | IpcOutput -): void { - const contract = IpcChannels[channel]; - ipcMain.handle(channel, async (_evt, rawInput) => { - const input = contract.input.parse(rawInput); // validation - const output = await handler(input); - return contract.output.parse(output); // validation - }); -} -``` - -`registerIpcHandler` 不接受 raw string——channel 名必须是 `IpcChannels` 的 key。TypeScript 会在编译期拒绝 typo。 - -### preload 侧:强制类型化 invoke - -```ts -// src/preload/index.ts(改造) -async function invokeIpc( - channel: K, - input: IpcInput -): Promise> { - return await ipcRenderer.invoke(channel, input); -} - -contextBridge.exposeInMainWorld("api", { - invoke: invokeIpc, -}); -``` - -### renderer 侧使用 - -```ts -// Before -const result: any = await window.api.invoke("agents/list", { companyId }); - -// After -const result = await window.api.invoke("agents/list", { companyId }); -// result 被推导为 { agents: AgentRecord[] } -``` - -IDE 自动补全 channel 名;input 写错类型直接红线;output 不需要断言。 - -### 命名规范化 - -现有 channel 名混乱(`core-admin` / `core-agent-graph` / `agents/list` / `tasks.save` 等),一次性规整: - -- Format: `/`(小写 / slash 分割) -- Domain 列表固定:`agents / tasks / runs / approvals / messages / documents / skills / automations / browser / credentials / oauth / onboarding / recovery / threads / companies / connectors / budgets` -- 不再有 `core-*` 前缀——哪个域就叫哪个域 - -迁移时保持旧 channel 名作为 alias 几个版本,telemetry 观察老名字消失再删。 - -## Migration 计划 - -1. **Phase 1(3 天)**:建 `src/shared/ipc-contracts.ts`,先把 10-20 个最核心的 handler 迁移 -2. **Phase 2(1 周)**:剩余 80+ handler 分批迁移,每批一个 PR(按 handler 文件分) -3. **Phase 3(2 天)**:命名规范化——renderer 代码统一改新 channel 名 -4. **Phase 4(2 天)**:main 侧老 channel 名走 alias 层,telemetry 观察 -5. **Phase 5(2 周后)**:删掉 alias,彻底移除旧名 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| zod 开销 | 每次 IPC 都跑 parse | 大 payload 场景 benchmark;必要时用更轻的 validator 或 conditional parse | -| renderer 类型推导失败 | 某个 schema 递归 / 复杂 | 拆 schema 或用 type assertion 临时绕过 | -| 契约漂移 | 有人改 schema 没改 call site | typecheck 会直接报 —— 这是目标 | -| 遗漏的 channel | grep 漏了某个 registerHandle | Phase 1-2 分批时每批跑完 grep,剩余 channel 列表归零 | - -## 验证标准 - -1. **Typecheck**:全项目 `pnpm typecheck` 通过 -2. **Grep 归零**:`grep -rn 'ipcMain\.handle\s*(\s*"' src/main/` 应归零(全部走 `registerIpcHandler`) -3. **Renderer 零 any**:renderer 层 IPC 调用处无 `as any` / `// @ts-ignore` -4. **Runtime validation**:故意给 handler 发错 payload,应被 zod parse 拒绝(不是进入业务逻辑再 crash) -5. **Telemetry**:迁移期间监控 unknown-channel 事件,迁完应归零 - -## 不在范围 - -- **不改 IPC 传输机制**:仍用 Electron 原生 `ipcMain.handle` / `ipcRenderer.invoke` -- **不做跨进程 pub-sub**:channel 还是 request-response;事件推送走独立 `webContents.send` 通道 -- **不做 versioning**:本次一次性切换,不做 v1/v2 并存(成本 > 收益) -- **不引入 gRPC / protobuf**:zod schema + TypeScript 足够 -- **不做权限控制**:所有 channel 对 renderer 开放,权限层面走独立 proposal - -## 参考文件清单 - -- `src/main/ipc-*.ts`(22 个 handler 文件) -- `src/preload/index.ts`(contextBridge expose) -- `src/renderer/**/*.ts`(消费者,数百处 invoke 调用) -- `src/shared/types.ts`(已有部分 schema,可复用) - -## 附:为什么现在修 - -**AI coding agent 最大的错误来源之一**就是 IPC 调用——字符串 channel + any payload,一旦没查到正确的字符串就瞎猜,猜错就是静默失败,反复几次才能找对。把契约集中化以后,AI 写代码时 IDE 直接告诉它 channel 名和 payload shape,一次对。 - -另一个触发因素:M12(renderer state audit)要做前提必须先有 M2。当前 renderer 的状态一致性问题一部分就来自 IPC 契约不明——消息传错、payload 错、renderer 把错数据当对数据渲染。先修 M2 再做 M12。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | `src/shared/ipc-contracts.ts` 覆盖 104 个 channel | Linus | -| G2 | 所有 main 侧 handler 通过 `registerIpcHandler` 注册 | Linus | -| G3 | Preload `invokeIpc` 类型化后,renderer 层 `as any` 归零 | Linus | -| G4 | 命名规范化后 alias 保留 2 周观察,无旧名残留 | Owner | -| G5 | Runtime zod parse 错误率监控 7 天 | Karpathy | - -## 附:channel 命名规范化 before/after 示例 - -| Before | After | -|--------|-------| -| "core-admin:list-profiles" | "profiles/list" | -| "core-agent-graph:save" | "agents/save" | -| "core-task-graph:delete" | "tasks/delete" | -| "core-work-graph:list-runs" | "runs/list" | -| "domain:approvals/resubmit" | "approvals/resubmit" | -| "oauth:start" | "oauth/start" | -| "browser:take-action" | "browser/action" | - -"core-*" 前缀彻底消失——哪个 domain 就叫哪个 domain。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:集中 contract + zod runtime validation + codemod 迁移。 - -**方案 B(仅加 TypeScript 类型不做 runtime validation)**:main / renderer 进程间 payload 反序列化后类型已失效——runtime 仍可能错 shape。zod 必须。 - -**方案 C(gRPC / protobuf)**:Electron IPC 不需要这种重量级框架;zod 足够。 - -**方案 D(只规范命名不做契约化)**:核心问题是缺契约,改名只是治标。 - -方案 A 一次性解决类型、命名、runtime validation 三件事。 - -## 附:zod vs 其他 validator - -| 选项 | 优点 | 缺点 | -|------|------|------| -| zod | 类型推导原生 + 广泛使用 | runtime 开销 ~5μs/parse | -| io-ts | fp-ts 生态 | 学习曲线 | -| yup | 成熟 | TS 推导不如 zod | -| typebox | 速度最快 + JSON Schema | API 偏底层 | - -选 zod:项目已有 `zod@4.3.6` 依赖,无需新增;推导质量好。 - -## 附:Event push 通道(非 invoke) - -Electron 还有 `webContents.send` → `ipcRenderer.on` 的单向事件推送。本 proposal 同样契约化: - -```ts -export const IpcEvents = { - "runs/updated": z.object({ runId: z.string(), status: RunStatusEnum }), - "approvals/updated": z.object({ approvalId: z.string() }), - "tasks/updated": z.object({ taskId: z.string() }), - // ... -}; - -// main 侧 -emitEvent(channel: K, payload: IpcEventPayload) { - const validated = IpcEvents[channel].parse(payload); - webContents.send(channel, validated); -} - -// renderer 侧 -subscribeEvent(channel: K, handler: (payload: IpcEventPayload) => void): () => void { - const wrapped = (_evt, raw) => handler(IpcEvents[channel].parse(raw)); - ipcRenderer.on(channel, wrapped); - return () => ipcRenderer.off(channel, wrapped); -} -``` - -Event 和 invoke 走同一套契约风格,减少认知负担。 diff --git a/docs/proposals/M5-monorepo-split.md b/docs/proposals/M5-monorepo-split.md deleted file mode 100644 index 2bc04936..00000000 --- a/docs/proposals/M5-monorepo-split.md +++ /dev/null @@ -1,279 +0,0 @@ -# Proposal M5: landing/ 与 desktop app 拆分(pnpm workspace 或独立仓) - -> 来源:问题.md M5(行 248-252)、附录 F 第 8 条(行 541-542) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:1 周(workspace 方案)或 2 周(独立仓方案) -> Blocking dependencies:无 - -## 问题陈述 - -`landing/` 目录是独立的 marketing site(Next.js + Cloudflare Functions),自带: -- 独立 `package.json` -- 独立 `node_modules` -- 独立 build 流程 -- 独立 deploy(Cloudflare Pages) -- 独立的 SQL migration(`landing/migrations/`) - -和 desktop app(Electron + React)混在同一个 git repo 里。`scripts/generate-landing-release-links.mjs` 做跨项目协调,暗示两个产品要**手动同步**某些 artifact。 - -问题表现: -1. **贡献者 onboarding 费劲**:clone 后不知道要在根目录还是 landing/ 跑 pnpm install;CI 要跑哪个 -2. **release 耦合**:desktop app 发版和 landing 发版必须同时推到同一个 commit——其中一个有问题就拖另一个 -3. **依赖污染**:根 `node_modules` 和 `landing/node_modules` 可能安装同一个包的不同版本 -4. **CI 资源浪费**:改一个 landing 文件触发整个 desktop 的 typecheck/test -5. **安全面混淆**:landing 的 Cloudflare token、数据库 URL 和 desktop 的签名证书放在同一个仓库,权限边界模糊 - -## 根因分析 - -Linus 视角:**一个 repo 两个产品 = release 耦合**。 - -Monorepo 本身不是错——Google / Facebook 用 monorepo。但 monorepo 需要**工具层面的约束**: -- 统一 task runner(nx / turborepo / bazel) -- 明确的 workspace 划分 -- 共享依赖 hoisting 策略 -- CI 按 changed-files 触发 - -当前项目有 pnpm 但没 workspace 配置,landing 实际上就是"目录塞在这里的另一个项目",没有 monorepo 的任何好处——**只有成本**。 - -Karpathy 视角补充:AI coding agent 在这种结构下很容易在 desktop 任务里改到 landing 文件,或反之。隔离不清楚的 repo 让 agent 的 blast radius 变大。 - -## 设计方案 - -### Option A:pnpm workspace(推荐,低成本) - -**目标结构**: - -``` -AgentCompany/ -├── package.json # root (workspace root, 无 runtime 代码) -├── pnpm-workspace.yaml # 新增 -├── packages/ -│ ├── desktop/ # 当前的根内容移到这里 -│ │ ├── package.json -│ │ ├── src/ -│ │ ├── tests/ -│ │ └── ... -│ └── landing/ # 当前的 landing/ 移到这里 -│ ├── package.json -│ ├── app/ -│ └── ... -└── docs/ -``` - -`pnpm-workspace.yaml`: - -```yaml -packages: - - "packages/*" -``` - -**Root package.json**(变简): - -```json -{ - "name": "agentcompany-root", - "private": true, - "scripts": { - "desktop:dev": "pnpm --filter desktop dev", - "desktop:build": "pnpm --filter desktop build", - "landing:dev": "pnpm --filter landing dev", - "landing:build": "pnpm --filter landing build", - "typecheck": "pnpm -r typecheck", - "lint": "pnpm -r lint" - } -} -``` - -**CI 按 package 分跑**:desktop PR 只跑 desktop typecheck/test,landing PR 只跑 landing。 - -**好处**: -- 两个项目独立 `package.json`、独立版本 -- 根目录干净 -- 共享开发工具(eslint / tsconfig base)可提到 root -- pnpm 自动 hoist 共享依赖,磁盘占用下降 - -**成本**: -- git history 移动(git mv 保留 blame) -- CI 脚本改写(`scripts/` 要调整路径引用) -- 发布流程(electron-builder / cloudflare deploy)适配新路径 - -### Option B:独立仓(彻底隔离) - -把 landing/ 推到独立 repo(例如 `github.com/badlogic/agentcompany-landing`),现 repo 只保留 desktop。 - -**好处**: -- 完全隔离 CI / secrets / 权限 -- landing 团队可独立迭代不看 desktop 代码 -- desktop 的 code review 范围缩小 - -**成本**: -- 跨 repo 协调(release link 生成脚本要走 GitHub API) -- Onboarding 要 clone 两个 repo -- git history 完整迁移工作量 - -### 推荐 A - -- 当前团队规模不需要完全隔离 -- landing 改动相对少,一个 repo 能保持 cross-cutting 改动(例如品牌一致性)的原子性 -- workspace 成本最低,收益立刻兑现 - -## Migration 计划(Option A) - -1. **Phase 1(1 天)**:新建 `packages/desktop/` 空目录 + `packages/landing/`;`pnpm-workspace.yaml` -2. **Phase 2(1 天)**:`git mv` 把当前根代码移到 `packages/desktop/`,landing/ 移到 `packages/landing/` - - 根 `package.json` 拆成 root + desktop - - 根配置(`tsconfig.base.json` / `eslint.config.mjs`)保留 root -3. **Phase 3(1 天)**:修 `scripts/*` 里的硬编码路径(`scripts/release-*.mjs`、`scripts/build-*.mjs`) -4. **Phase 4(1 天)**:CI 配置分包跑 -5. **Phase 5(1 天)**:文档同步——README 更新;`CLAUDE.md` / `AGENTS.md` 说明 workspace 结构 -6. **Phase 6(持续)**:观察 2 周,处理零星问题 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| git history 丢失 | git mv 不规范 | 用 `git mv` 保留 rename detection;必要时 `git log --follow` 验证 | -| electron-builder 找不到 artifact | 打包路径变化 | Phase 3 脚本改完后跑一次完整 build 验证 | -| Cloudflare deploy 路径改 | landing build output 位置变 | wrangler.toml 更新;deploy 前本地 dry-run | -| renderer import path 断 | 代码中的硬路径 | codemod 扫 `require("../../landing")` 类的跨 package 引用(理论上没有) | - -**回滚路径**:phase 2 是单个 commit(git mv),任何后续阶段出问题直接 revert。 - -## 验证标准 - -1. **独立 build 成功**:`pnpm --filter desktop build` 和 `pnpm --filter landing build` 分别跑通 -2. **依赖完整**:`pnpm install` 根目录跑完 `pnpm -r typecheck` 全绿 -3. **CI 提速**:改 landing 文件的 PR 不触发 desktop test -4. **Release 脚本**:`pnpm run release:local` / `pnpm release:boss` / `pnpm release:cloudflare:public` 都能跑 -5. **Git blame 保留**:`git log --follow packages/desktop/src/main/service-graph.ts` 能追到原始 commit - -## 不在范围 - -- **不引入 turborepo / nx**:pnpm workspace 已足够,加 task runner 是过度工程 -- **不改代码模块边界**:desktop 内部代码结构本 proposal 不动 -- **不做跨 package 共享代码**:landing 目前不需要 desktop 的类型;如果未来需要再加 `packages/shared/` -- **第三方 runtime reference snapshot 边界**:reference snapshot 已迁出本仓库,monorepo split 保持这个边界 -- **不改 git branching strategy**:单仓单分支 vs 多分支不是本 proposal 问题 - -## 参考文件清单 - -- `landing/package.json`(独立 package 定义) -- `landing/migrations/`(独立 SQL migration) -- `scripts/generate-landing-release-links.mjs`(跨项目脚本) -- `scripts/release-public-cloudflare.mjs`(landing 发布) -- `scripts/release-boss.mjs`(desktop 发布) -- 根 `package.json:1-86`(会被拆分) -- 根 `pnpm-lock.yaml`(workspace 化后会更长但更清晰) - -## 附:为什么现在修 - -**延迟成本**:landing 每加一个 dependency 就让根 `node_modules` 更大;desktop 的 CI 时间持续上升。现在拆 1 天,拖到 landing 翻倍大小就是 3 天+。 - -对 AI coding agent 来说,workspace 化后"这个改动属于哪个 package"一目了然——agent 不再会在 desktop 任务里 accidentally 修 landing 文件。这是隔离 blast radius 的最低成本方式。 - -次要触发:M5 和 M4(scripts 目录混乱)相关——scripts 里的 `release-public-cloudflare.mjs` / `release-boss.mjs` / `release-local.mjs` 混在一起部分就是因为 desktop/landing 不分。拆了 workspace,scripts 也可以按 package 分。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | `pnpm-workspace.yaml` 存在,`pnpm install` 在根目录一次跑通 | Owner | -| G2 | `pnpm --filter desktop build` 产出可签名的 `.app` bundle | Owner | -| G3 | `pnpm --filter landing build` 产出可部署的 Cloudflare Pages 资源 | Owner | -| G4 | CI 按 changed files 触发相应 package 测试 | Owner | -| G5 | git log --follow 在两个 package 内都能追到原始 commit | Linus | - -## 附:迁移后的目录结构草图 - -``` -AgentCompany/ -├── package.json # workspace root -├── pnpm-workspace.yaml -├── pnpm-lock.yaml # hoisted -├── tsconfig.base.json # shared -├── eslint.config.mjs # shared -├── .gitignore -├── CLAUDE.md / AGENTS.md -├── docs/ -├── scripts/ -│ ├── desktop/ # electron-builder / signing / release -│ └── landing/ # cloudflare deploy / release-links -└── packages/ - ├── desktop/ - │ ├── package.json - │ ├── src/ - │ │ ├── main/ - │ │ ├── preload/ - │ │ ├── renderer/ - │ │ └── shared/ - │ ├── tests/ - │ ├── builtin-skills/ - │ ├── electron-vite.config.ts - │ └── tsconfig.json # extends ../../tsconfig.base.json - └── landing/ - ├── package.json - ├── app/ - ├── migrations/ - ├── next.config.js - └── tsconfig.json -``` - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:pnpm workspace,一个仓两个 package。 - -**方案 B(独立仓)**:对当前团队规模不经济;跨仓协调成本高。 - -**方案 C(保持现状 + 更多 gitignore 隔离)**:治标不治本;CI 仍跑全量。 - -方案 A 成本 1 周,收益持续。 - -## 附:release 脚本改造示意 - -```json -// packages/desktop/package.json scripts 片段 -{ - "scripts": { - "build": "electron-vite build && node ../../scripts/desktop/build-desktop.mjs", - "release:local": "node ../../scripts/desktop/release-local.mjs", - "release:boss": "node ../../scripts/desktop/release-boss.mjs" - } -} - -// packages/landing/package.json scripts 片段 -{ - "scripts": { - "build": "next build", - "release": "node ../../scripts/landing/release-cloudflare.mjs" - } -} - -// root package.json -{ - "scripts": { - "release:all": "pnpm --filter desktop release:boss && pnpm --filter landing release" - } -} -``` - -## 附:CI 按 changed files 触发(示意) - -```yaml -# .github/workflows/desktop-ci.yml -on: - pull_request: - paths: - - "packages/desktop/**" - - "pnpm-lock.yaml" - - "tsconfig.base.json" - -# .github/workflows/landing-ci.yml -on: - pull_request: - paths: - - "packages/landing/**" -``` - -desktop PR 不触发 landing CI,反之亦然。 diff --git a/docs/proposals/M7-ceo-mode-state-machine.md b/docs/proposals/M7-ceo-mode-state-machine.md deleted file mode 100644 index 09c32068..00000000 --- a/docs/proposals/M7-ceo-mode-state-machine.md +++ /dev/null @@ -1,270 +0,0 @@ -# Proposal M7: CEO 模式状态机化(resolveCeoMode 单一真源) - -> 来源:问题.md M7(行 260-264) -> 状态:proposed(依赖 B5 + C4) -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:1.5 周 -> Blocking dependencies:B5(eval harness)、C4(initial-user-turn 精简) - -## 问题陈述 - -CEO 当前处于哪个模式,由**两处独立逻辑**各自决定: - -**位置 1**:`src/main/prompt-builder/ceo-modes/` 下 5 个 markdown 文件 -- `awaiting-hire.en.md` -- `awaiting-org.en.md` -- `operating.en.md` -- `proactive-footer.en.md` -- `team-building.en.md` - -加载逻辑在 runtime 靠**字符串匹配**——某段代码根据 company/CEO 状态推出一个 mode 名,然后按文件名拼路径读 markdown。 - -**位置 2**:`src/main/orchestration/initial-user-turn.ts:62-83` -- 独立判断 CEO 是否 "zero active reports" -- 独立判断是否"awaiting hire approval" -- 独立决定发什么 cue - -**两处都在决定 "CEO 现在该做什么",互相不知道对方存在**。结果是:`ceo-modes` 文件可能说当前是 `operating` 模式(有团队在运行),而 `initial-user-turn` 同时决定发 "your team is empty" 的 cue——内部打架。 - -## 根因分析 - -Linus 视角:**同一件事(CEO 当前状态)被两个代码位置各自计算**——这是第一性的违规。状态应该是单一 source of truth。 - -当前设计把 "mode" 当成一个**魔法字符串**在 prompt-builder 和 initial-user-turn 之间传递(甚至不是显式传,而是两边各自推),没有一个函数说"this is where CEO mode is decided"。 - -加载 markdown 的路径也是隐式约定——`ceo-modes/team-building.en.md` 的命名约定没有 schema 保证,漏一个文件、写错一个 mode 名、加新 mode 时忘了建对应文件,都是静默失败。 - -Karpathy 视角:**模式分支是 agent 行为最关键的决策点**——CEO 在 team-building / operating / awaiting-* 下的应答完全不同。这种分支必须**集中**并有 eval 覆盖每个分支。 - -## 设计方案 - -### 单一 resolveCeoMode 函数 - -新建 `src/main/orchestration/ceo-mode.ts`: - -```ts -export type CeoMode = - | "team_building" // 无 active report,需要 hire - | "awaiting_hire" // 已提交 hire approval,等人批 - | "awaiting_org" // 组织架构待确认 - | "operating" // 正常运行态 - ; - -export interface CeoModeContext { - agent: AgentRecord; - company: CompanyRecord; - activeAgents: AgentRecord[]; - pendingApprovals: ApprovalRecord[]; - executionMode: ExecutionMode; -} - -export function resolveCeoMode(ctx: CeoModeContext): CeoMode { - if (ctx.agent.role !== "ceo") { - throw new Error("resolveCeoMode called on non-CEO agent"); - } - - const activeReports = ctx.activeAgents.filter(a => a.ceoId === ctx.agent.id && a.status !== "terminated"); - const pendingHires = ctx.pendingApprovals.filter(a => a.kind === "hire_agent"); - - if (activeReports.length === 0 && pendingHires.length === 0) { - return "team_building"; - } - if (activeReports.length === 0 && pendingHires.length > 0) { - return "awaiting_hire"; - } - if (ctx.company.orgStatus === "pending_review") { - return "awaiting_org"; - } - return "operating"; -} -``` - -**所有**判断 CEO 模式的代码都必须调这个函数。 - -### Prompt-builder 从 mode 映射到片段 - -```ts -// src/main/prompt-builder/ceo-modes/index.ts(新增) -const modeToSlug: Record = { - team_building: "team-building", - awaiting_hire: "awaiting-hire", - awaiting_org: "awaiting-org", - operating: "operating", -}; - -export function loadCeoModePrompt(mode: CeoMode, locale: AppLocale): string { - const slug = modeToSlug[mode]; - // 加载 `ceo-modes/{slug}.{locale}.md` -} -``` - -通过 TypeScript 枚举保证 mode 和 markdown 文件的一一对应——加新 mode 必须加枚举 + 对应 markdown,编译期强制。 - -### initial-user-turn 走 resolveCeoMode - -`src/main/orchestration/initial-user-turn.ts` 不再重复判断 CEO 状态,调 `resolveCeoMode(ctx)`: - -```ts -const mode = resolveCeoMode(modeCtx); -const cue = getCeoModeCue(mode, trigger); -``` - -这样 prompt-builder 里的 markdown 和 initial-user-turn 的 cue **通过同一个 mode 驱动**——永远一致。 - -### proactive-footer 归类 - -当前的 `proactive-footer.en.md` 不是一个 mode——它是所有 CEO 模式共享的 footer。应该: -- 重命名目录结构:`ceo-modes/{mode}.md` 专门装 mode-specific -- 另起 `ceo-shared/proactive-footer.md` 放共享片段 -- 避免把 footer 误当作第 5 个模式 - -## Migration 计划 - -1. **Phase 0(前置)**:B5 eval harness + C4 完成 -2. **Phase 1(2 天)**:实现 `resolveCeoMode` 函数 + 单测(不动 call site) -3. **Phase 2(3 天)**:prompt-builder 从 mode enum 加载 markdown,删除字符串拼接 -4. **Phase 3(3 天)**:initial-user-turn 重构——删除自行判断逻辑,全走 `resolveCeoMode` -5. **Phase 4(3 天)**:eval 对比——相同 CEO 状态下行为一致性 -6. **Phase 5(1 天)**:重组目录——proactive-footer 从 ceo-modes 移出 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| 模式分类漏 corner case | awaiting_hire 和 awaiting_org 同时成立 | resolveCeoMode 函数里明确 priority + 单测覆盖 | -| eval 发现行为偏移 | 新 mode decision 逻辑和旧隐式判断不等价 | 保留旧 initial-user-turn 分支 flag,对比 N 轮 run | -| Markdown 内容过期 | enum 加了新 mode 但没写 markdown | 加载时 assert 文件存在,启动 fail fast | -| Locale 缺失 | `awaiting-hire.zh.md` 不存在但 locale=zh | fallback 到 `.en.md` + telemetry 告警 | - -## 验证标准 - -1. **Typecheck 保证完整性**:新增 mode 必须同时更新 enum + modeToSlug map + markdown 文件,否则编译 fail -2. **Eval 行为对比**:每个 mode 至少 3 种代表性 company 状态,新旧行为 99% 一致 -3. **Call site 归一**:`grep -rn "team_building\|awaiting_hire\|operating" src/main/` 只在 `ceo-mode.ts` 里出现枚举定义,其他地方通过 import 使用 -4. **Markdown coverage**:所有 mode 在所有支持的 locale 下都有文件,启动时校验通过 -5. **Initial-user-turn 简化**:`initial-user-turn.ts` 行数降低(假设从 159 行 → < 100 行) - -## 不在范围 - -- **不重写 ceo-modes 的 prompt 内容**:只是让加载机制严谨,具体文字走 Owner 业务决策 -- **不加新 mode**:当前 4 个 mode 足够(proactive-footer 不是 mode) -- **不改 non-CEO agent 的模式逻辑**:他们没有这种 mode 概念 -- **不做 mode transition 审计 log**:有需要另开 event 表 -- **不做 mode-specific tool gating**:tool 可用性和 mode 解耦(不同 mode 可用相同 tool,只是 prompt 引导不同) - -## 参考文件清单 - -- `src/main/prompt-builder/ceo-modes/awaiting-hire.en.md` -- `src/main/prompt-builder/ceo-modes/awaiting-org.en.md` -- `src/main/prompt-builder/ceo-modes/operating.en.md` -- `src/main/prompt-builder/ceo-modes/proactive-footer.en.md`(将重组) -- `src/main/prompt-builder/ceo-modes/team-building.en.md` -- `src/main/orchestration/initial-user-turn.ts:62-83`(重复逻辑) -- `src/main/prompt-builder/system-prompt.ts`(mode 注入点) -- `src/main/database/agents.ts`(CEO 状态 query) -- `src/main/database/approvals.ts`(pending hire approval query) - -## 附:为什么现在修 - -C4 已经把 initial-user-turn 的"实现细节泄漏"修了——如果不顺便做 M7,就会出现 initial-user-turn 变干净了但还在自行判断 mode 的状态。一次做完,两件事共享同一个 resolveCeoMode 函数,改 prompt 的团队只需要 reason about 一个真源。 - -M7 也是未来扩展 CEO 行为的基础——如果要加 "awaiting_funding" / "pivoting" 之类的新模式,没有 state machine 就是继续堆字符串判断。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | B5 eval harness 可 record CEO 在各 mode 下的 baseline 行为 | Karpathy | -| G2 | `resolveCeoMode` 单测覆盖 4 种 mode × 边缘状态 | Linus | -| G3 | prompt-builder 通过 enum 加载 markdown,启动时验证文件存在 | Owner | -| G4 | initial-user-turn 重构后行为 eval 与 baseline 一致 | Karpathy | -| G5 | proactive-footer 从 ceo-modes 目录移出,路径调整不破坏现有 prompt | Owner | - -## 附:state machine 扩展指南 - -未来加新 mode 的最小改动点: - -1. `src/main/orchestration/ceo-mode.ts` 的 `CeoMode` enum 增加成员 -2. `resolveCeoMode` 函数加对应 if 分支 -3. `ceo-modes/.en.md`(+ 其他 locale)新建 -4. `modeToSlug` 映射加一行 -5. 对新 mode 写单测(至少 1 个 positive + 1 个 negative case) - -TypeScript 会强制 1-4 的完整性——漏一步编译 fail。 - -## 附:反模式对比 - -**Before**(`initial-user-turn.ts:62-83` + `ceo-modes/*.md` 两处各自判断): -```ts -// 位置 1: initial-user-turn.ts -if (activeReports.length === 0) { - return teamBuildingCue; -} - -// 位置 2: prompt-builder/system-prompt.ts (加载 ceo-modes) -const modeFile = loadCeoModeFile(company, agent); // 内部逻辑不一致 -``` - -**After**(单一真源): -```ts -const mode = resolveCeoMode(ctx); -const cue = getCeoModeCue(mode, trigger); -const modeSection = loadCeoModePrompt(mode, locale); -``` - -两处都 derive from mode,保证一致。 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:enum + resolve 函数 + markdown 映射。 - -**方案 B(把 mode 存 DB)**:不必要——mode 完全由当前状态 derive,存 DB 反而要维护一致性。 - -**方案 C(把 markdown 内容放代码里)**:失去给产品经理 / 业务 owner 迭代 prompt 的低成本路径。 - -方案 A 保留 markdown 灵活性同时让加载逻辑类型安全。 - -## 附:mode priority 排序规则 - -`resolveCeoMode` 判断顺序(先匹配即返回): - -1. `team_building`:无 active report + 无 pending hire -2. `awaiting_hire`:无 active report + 有 pending hire -3. `awaiting_org`:有 active report + org 待 review -4. `operating`:默认 - -顺序基于"外部依赖度"——团队空时必须先 team_building,其次考虑组织结构审查,最后才是运行态。单测覆盖所有 transition: - -| from → to | 条件 | 覆盖点 | -|----------|------|-------| -| team_building → awaiting_hire | 提交 hire approval | unit | -| awaiting_hire → team_building | hire approval 被拒 | unit | -| awaiting_hire → operating | hire approval 通过 | unit | -| operating → awaiting_org | org review 触发 | unit | -| awaiting_org → operating | org review 通过 | unit | - -## 附:proactive-footer 重组说明 - -`ceo-modes/proactive-footer.en.md` 当前存在于 ceo-modes 目录但不是 mode。重组: - -``` -Before: -ceo-modes/ -├── awaiting-hire.en.md -├── awaiting-org.en.md -├── operating.en.md -├── proactive-footer.en.md ← 伪 mode -└── team-building.en.md - -After: -ceo-modes/ ← 真 modes -├── awaiting-hire.en.md -├── awaiting-org.en.md -├── operating.en.md -└── team-building.en.md -ceo-shared/ ← 跨 mode 共享片段 -└── proactive-footer.en.md -``` - -`system-prompt.ts` 加载 mode 片段后,独立拼接 `ceo-shared/proactive-footer.en.md`。 diff --git a/docs/proposals/M8-worker-module-consolidation.md b/docs/proposals/M8-worker-module-consolidation.md deleted file mode 100644 index 2382f6af..00000000 --- a/docs/proposals/M8-worker-module-consolidation.md +++ /dev/null @@ -1,250 +0,0 @@ -# Proposal M8: worker/ 13 文件整合为 3 文件(entry / runtime / observability) - -> 来源:问题.md M8(行 266-270)、附录 C(行 396-397) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:1 周 -> Blocking dependencies:无 - -## 问题陈述 - -`src/main/worker/` 当前 13 个文件: - -| 文件 | 行数近似 | 职责 | -|------|---------|------| -| circuit-breaker.ts | 80+ | run 失败熔断 | -| failure-escalation.ts | 60+ | 失败升级通知 | -| log-redactor.ts | 50+ | log 敏感信息遮蔽 | -| pi-agent-factory.ts | 131 | 组装 pi agent | -| run-event-recorder.ts | 100+ | run event 写入 DB | -| run-log-filter.ts | 40+ | log 过滤 | -| worker-crash-recovery.ts | 80+ | 崩溃恢复 | -| worker-entry.ts | 50+ | 进程入口 | -| worker-helpers.ts | 100+ | 杂项 utility | -| worker-message-handler.ts | 150+ | IPC 消息分发 | -| worker-rpc.ts | 60+ | RPC 框架 | -| worker-runner.ts | 239 | 主 run loop | -| worker-types.ts | 80+ | 类型定义 | - -问题: -1. **边界模糊**:`circuit-breaker` / `failure-escalation` / `log-redactor` / `run-log-filter` 四个"辅助"模块互相引用,存在**跨文件 silent dependency**(比如 failure-escalation 读 circuit-breaker 的状态) -2. **helpers 是垃圾筐**:`worker-helpers.ts` 什么都有——典型的 catch-all 反模式 -3. **13 个文件对 ~1200 行总量是过度切分**:平均每个文件 ~90 行,跨文件跳转成本高 -4. **职责不在文件名上**:`worker-entry.ts` / `worker-runner.ts` / `worker-message-handler.ts` 三个都像"入口",实际职责谁是谁需要打开文件才知道 - -## 根因分析 - -Linus 视角(第七条:解法是否最简):**一件事切十三片是过度工程**。 - -正确的切分标准不是"这段代码看起来像独立功能",而是"这段代码的变更频率和变更原因与其他代码是否不同"。当前 worker 的所有文件几乎**同一批人、同一时间、同一原因**被修改——每次 pi-agent-core 升级或 bug fix 都在改多个文件。这表明它们本质是**一个模块**被过早分裂。 - -Karpathy 视角补充:worker 是 agent 跑 run 的核心路径,逻辑密度高——分文件反而让跟踪执行流程更难("log redactor 在 worker-entry 之后还是之前跑的?")。 - -## 设计方案 - -### 新结构:3 文件 + 1 types - -``` -src/main/worker/ -├── worker-types.ts # 保留 (类型定义) -├── worker-entry.ts # 进程入口 + crash recovery + message dispatch -├── worker-runtime.ts # pi agent 组装 + run loop + circuit breaker + failure escalation -└── worker-observability.ts # log redactor + log filter + run-event recorder -``` - -### 职责划分 - -**worker-entry.ts**(原 worker-entry + worker-message-handler + worker-rpc + worker-crash-recovery + worker-helpers 里的入口相关) -- Electron utility process entry point -- 初始化 IPC(与 main 的 duplex channel) -- 接收 inbound messages、分发到 runtime -- 处理崩溃恢复(重启后 resume run state) -- 进程级别 helper - -**worker-runtime.ts**(原 worker-runner + pi-agent-factory + circuit-breaker + failure-escalation) -- 组装 pi agent(hooks / context compactor / cost writer 等) -- 启动和驱动 agent loop -- 失败检测(circuit breaker) -- 失败升级(重试策略 / 通知 main) -- 这些是**紧密耦合**的——一个 run 的生命周期线性经过它们 - -**worker-observability.ts**(原 log-redactor + run-log-filter + run-event-recorder) -- Log 敏感信息遮蔽 -- Log level 过滤 -- Run event 持久化到 DB -- 这些都是"run 执行的副作用输出",职责统一 - -**worker-types.ts**(不动) -- 保留所有跨文件共享的类型 - -### 单文件结构建议 - -每个合并后的文件内部用 section comment 分 region: - -```ts -// worker-runtime.ts - -// ============================================================================ -// pi agent factory -// ============================================================================ -export function createPiAgent(...) { ... } - -// ============================================================================ -// Circuit breaker -// ============================================================================ -class CircuitBreaker { ... } - -// ============================================================================ -// Run loop -// ============================================================================ -export async function runWorker(...) { - const agent = createPiAgent(...); - const breaker = new CircuitBreaker(...); - // ... -} -``` - -这样读者打开一个文件就能线性看完 run 的全生命周期,不用跳 5 个文件。 - -## Migration 计划 - -1. **Phase 1(1 天)**:创建新 3 文件空壳,逐步把内容从 13 个旧文件搬过去 -2. **Phase 2(2 天)**:搬运过程中修 import path——外部消费者(service-graph / orchestration)的 import 从 13 个路径收敛到 3 个 -3. **Phase 3(1 天)**:删除旧 13 个文件 -4. **Phase 4(1 天)**:`pnpm typecheck` + 相关单测跑完 -5. **Phase 5(1 天)**:观察 log output 是否有 regression(redactor / filter 的行为是否保持) - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| 循环 import | 合并后某些函数互相依赖 | 合并过程本就在消除循环,如发现循环则进一步合并或拆新文件 | -| Log redactor 规则失效 | 合并时漏搬某个 regex | 搬前先列完整 redact rule 清单,合并后 diff | -| Circuit breaker 状态丢失 | 重构过程中某状态字段遗漏 | 单测覆盖 circuit breaker 开/合/半开三态 | -| 外部 consumer 的 import 路径 | service-graph 引用 13 个 worker 文件中某些 | 先全改 import,再删旧文件 | - -**回滚路径**:用 `git mv` 做文件合并,所有改动在一个大 PR,如发现问题 revert 一键回到 13 文件结构。 - -## 验证标准 - -1. **Typecheck 全绿**:pnpm typecheck 通过 -2. **Worker 启动正常**:desktop app 启动后能看到 worker utility process 正常上线 -3. **Run 执行完整**:手动跑一个 run,验证 tool call / log / cost 记录都正确 -4. **Log 行为不变**:同样的 agent 输出,redacted log 应和 migration 前字节级一致 -5. **Crash recovery 可用**:kill worker 进程,主进程重启 worker 后能 resume 运行中的 run - -## 不在范围 - -- **不改 worker 行为**:只是文件重组,功能完全一致 -- **不重写 pi-agent-factory 内部逻辑**:hook 注册顺序和参数都保留 -- **不改 IPC 协议**:main ↔ worker 的消息格式不动 -- **不引入新的 utility process**:browser automation 的独立 utility process 走 M9 -- **不拆分 worker 到独立 package**:当前仓库内结构即可 - -## 参考文件清单 - -合并前 13 个文件: -- `src/main/worker/circuit-breaker.ts` -- `src/main/worker/failure-escalation.ts` -- `src/main/worker/log-redactor.ts` -- `src/main/worker/pi-agent-factory.ts` -- `src/main/worker/run-event-recorder.ts` -- `src/main/worker/run-log-filter.ts` -- `src/main/worker/worker-crash-recovery.ts` -- `src/main/worker/worker-entry.ts` -- `src/main/worker/worker-helpers.ts` -- `src/main/worker/worker-message-handler.ts` -- `src/main/worker/worker-rpc.ts` -- `src/main/worker/worker-runner.ts` -- `src/main/worker/worker-types.ts` - -外部消费者(import 路径需更新): -- `src/main/service-graph.ts` -- `src/main/orchestration/scheduler.ts` -- `src/main/orchestration/task-runner.ts` - -## 附:为什么现在修 - -文件数量的治理成本**线性增长**——13 个文件比 3 个文件多 10 倍"哪个文件负责什么"的认知负担。每次新 feature 加 worker 里的 hook 或 recovery 逻辑,都要先判断"应该加到哪个文件"。 - -**AI coding agent 尤其受影响**——agent 写代码前要扫完 13 个文件才知道 worker 现有结构。合并到 3 个文件后,一次读完就能动手。这直接缩短每个 worker 相关任务的 time-to-PR。 - -M8 和 M10(agent-runtime hooks 聚合)有类似 pattern——都是"过度切分的模块要合回来"。两件事可以同一个 sprint 做。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | 新 3 文件结构覆盖旧 13 文件所有导出符号 | Linus | -| G2 | 外部 import 路径全部更新(grep `from "\.\./worker/"` 只出现 3 个模块名) | Linus | -| G3 | worker 启动 / run 执行 / crash recovery 三大路径验证 | Owner | -| G4 | Log output 字节级 diff 与合并前一致 | Karpathy | -| G5 | Lines per file < 800(可读性上限) | Linus | - -## 附:文件内部 region 结构 - -**worker-runtime.ts** 的 section 顺序: - -``` -// ============================================================================ -// Circuit breaker (state machine: closed / open / half-open) -// ============================================================================ - -// ============================================================================ -// Failure escalation (retry policy + incident creation) -// ============================================================================ - -// ============================================================================ -// Pi agent factory (assemble hooks + options) -// ============================================================================ - -// ============================================================================ -// Run loop (main entry: runWorker) -// ============================================================================ -``` - -读者按顺序线性理解一个 run 的生命周期:通过 circuit breaker 检查 → 构造 agent → 进 run loop → 失败时走 escalation。 - -## 附:反模式对比 - -**Before**: -- `worker-runner.ts` 引用 `circuit-breaker.ts`、`failure-escalation.ts`、`pi-agent-factory.ts` -- `pi-agent-factory.ts` 引用 `log-redactor.ts` -- `worker-crash-recovery.ts` 引用 `run-event-recorder.ts` -- 13 文件组成不可见的依赖图 - -**After**: -- 3 文件 + 1 types,依赖方向清晰:`entry.ts → runtime.ts → observability.ts` -- 单向依赖,无循环 -- 新 reader 打开 `runtime.ts` 就能读懂 run 怎么跑 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:合并到 3 文件。 - -**方案 B(保留文件但拆到 5-6 个更合理的模块)**:仍然分散,没解决根本问题。 - -**方案 C(全合到单一 worker.ts 大文件)**:过度合并,单文件过大(>2000 行)不利于 review。 - -方案 A 平衡了"单 responsibility 原则"和"可读性"。 - -## 附:合并映射表 - -| 原文件 | 合并到 | 原职责 | -|-------|-------|-------| -| worker-entry.ts | worker-entry.ts | 进程入口 | -| worker-crash-recovery.ts | worker-entry.ts | Crash 恢复 | -| worker-message-handler.ts | worker-entry.ts | IPC 分发 | -| worker-rpc.ts | worker-entry.ts | RPC 框架 | -| worker-helpers.ts | worker-entry.ts + worker-runtime.ts | 杂项(分拆归属) | -| worker-runner.ts | worker-runtime.ts | Run loop | -| pi-agent-factory.ts | worker-runtime.ts | Agent 组装 | -| circuit-breaker.ts | worker-runtime.ts | 熔断 | -| failure-escalation.ts | worker-runtime.ts | 失败升级 | -| log-redactor.ts | worker-observability.ts | Redact | -| run-log-filter.ts | worker-observability.ts | Filter | -| run-event-recorder.ts | worker-observability.ts | Event 记录 | -| worker-types.ts | worker-types.ts | 不变 | - -合并后 ~1200 行分布:entry ~400, runtime ~500, observability ~200, types ~100。 diff --git a/docs/proposals/M9-browser-automation-utility-process.md b/docs/proposals/M9-browser-automation-utility-process.md deleted file mode 100644 index ad40e1c4..00000000 --- a/docs/proposals/M9-browser-automation-utility-process.md +++ /dev/null @@ -1,268 +0,0 @@ -# Proposal M9: browser / automation 拆出独立 utility process - -> 来源:问题.md M9(行 272-276)、附录 I 第 3 条(行 589-590) -> 状态:proposed -> 提出:Roundtable 2026-04-20(Linus + Karpathy + Steve Jobs) -> Owner: TBD -> 估计工时:3 周 -> Blocking dependencies:C2(RuntimeBus 就绪后,跨进程 dispatch 更容易) - -## 问题陈述 - -`src/main/browser/` 和 `src/main/automation/` 两个子系统目前运行在主进程: -- `browser/` 跑 Electron 的 BrowserWindow / BrowserView,做网页自动化(填表单、点按钮、截图) -- `automation/` 跑 rule engine,触发 browser actions 或其他 side effects - -后果: -1. **Crash blast radius 大**:browser page crash / 内存泄漏直接拖垮 main 进程,整个 desktop app 挂掉 -2. **事件循环阻塞**:自动化脚本跑长时间同步操作(例如等待 CAPTCHA)时,main 进程 UI IPC 都受影响 -3. **Cloudflare / CAPTCHA 等防爬虫对抗**:反爬逻辑跑在 main 进程意味着主程序有"机器人"指纹,可能被下游服务整体封禁 -4. **资源占用不可见**:browser 内存和 CPU 混在 main 进程里,不便于监控 / 限额 -5. **Attack surface**:自动化脚本触达外部网站,一旦被攻击(XSS / sandbox escape)直接污染 main 进程的数据库连接和文件系统权限 - -## 根因分析 - -Linus 视角:**crash blast radius 是进程边界的第一目的**。把 browser 跑在 main 进程 = 把不稳定的组件和稳定的组件绑一起了。Electron 提供 utility process 正是为此——crash 就让它 crash,主进程重启它即可。 - -当前架构把"永远不 crash 的组件(main)"和"经常 crash 的组件(browser automation)"放在同一个进程里——这是 colocation 反模式。 - -Karpathy 视角:agent 跑 browser automation 是典型的 stochastic task——成功率不是 100%。需要**独立的失败域 + 重试机制 + resource cap**。跑在 main 进程无法给 browser 设单独的 memory limit / CPU quota。 - -## 设计方案 - -### 架构 - -``` -Main process -├── Orchestration / DB / IPC to renderer -│ -├──[fork]──> Worker utility process (agent run loop) -│ -├──[fork]──> Browser utility process (browser automation) -│ ├── Electron BrowserWindow / Puppeteer -│ ├── 独立内存 / CPU quota -│ └── 通过 bus dispatch "browserAction.dispatch" 消费 -│ -└──[fork]──> Automation utility process (rule engine) - ├── Rule evaluation loop - ├── Scheduled triggers - └── 通过 bus dispatch 发送到 browser / agent -``` - -### 对 C2 bus 的依赖 - -本 proposal 依赖 C2 的 RuntimeBus——拆进程后跨进程 dispatch 最自然的实现是: -- Main 的 bus 是 hub -- utility process 和 main 之间通过 `process.parentPort.postMessage` 传递 command/event -- Bus 在 main 侧做 multiplexing:根据 command kind 路由到对应 utility process - -这让 C2 的抽象同时覆盖 in-process 和 cross-process 两种 dispatch,**代码层面完全一致**。 - -### Browser utility process 实现 - -新建 `src/main/browser-process/entry.ts`: - -```ts -import { parentPort } from "node:worker_threads"; // 或 utilityProcess API - -const browser = new BrowserAutomationService(...); - -parentPort.on("message", async (msg) => { - if (msg.kind === "browserAction.dispatch") { - try { - const result = await browser.execute(msg.payload); - parentPort.postMessage({ kind: "browserAction.result", runId: msg.runId, result }); - } catch (e) { - parentPort.postMessage({ kind: "browserAction.error", runId: msg.runId, error: serializeError(e) }); - } - } -}); -``` - -### Automation utility process - -rule engine 比 browser 轻量,但同样的道理——独立进程 = 独立故障域。新建 `src/main/automation-process/entry.ts`: - -```ts -const engine = new AutomationRuleEngine(db); - -engine.on("fire", (payload) => { - parentPort.postMessage({ kind: "automation.fired", ...payload }); -}); - -// tick loop -setInterval(() => engine.evaluate(), 1000); -``` - -### DB 访问 - -utility process **不直接访问 DB**——所有 DB 操作通过 bus 让 main 进程的 writer actor 处理(与 B4 的 single-writer actor 配合)。 - -这避免 SQLite 跨进程连接的复杂度(SQLite 支持跨进程但要处理 WAL 同步)。 - -### Resource cap - -- Electron utility process 可设 `memoryLimit`(v27+) -- 配置 `maxOldSpaceSize` 控制 V8 heap -- Main 进程定期 ping utility process,超时自动 kill + restart - -### Crash recovery - -Browser utility process crash 时: -1. Main 收到 `process.exit` 事件 -2. 发"browser 不可用"告警 -3. 根据 restart policy 重启进程 -4. 重启后已在运行的 browser action 状态从 DB 恢复 - -Automation utility process 同理。 - -## Migration 计划 - -1. **Phase 0(前置)**:C2 RuntimeBus 完成 -2. **Phase 1(1 周)**:设计 cross-process bus 协议(message envelope / error serialization / backpressure) -3. **Phase 2(1 周)**:browser 拆进程——browser automation 代码搬到 `browser-process/`,main 侧改为通过 bus dispatch -4. **Phase 3(3 天)**:automation 拆进程——同样方式 -5. **Phase 4(3 天)**:monitoring & restart policy—— main 侧加 utility process health check + telemetry -6. **Phase 5(1 周观察期)**:生产压力测试 / crash 注入测试,确认 blast radius 隔离 - -## 风险与回滚 - -| 风险 | 触发条件 | 回滚方法 | -|------|---------|---------| -| IPC latency 升高 | browserAction 从本地函数调用变成跨进程 | 每次 action 多 1-2ms 可忽略;如果某 action 需要高频通信则重新评估 | -| State 丢失 | utility process crash 时正在执行的 action 状态 | 所有 action 状态进 DB 持久化,crash 后恢复 | -| 开发体验差 | 调试需要 attach 多个进程 | VS Code 多 process debug configuration | -| macOS entitlements | utility process 需要特殊 entitlement 才能跑某些 Electron API | 研究 Apple 文档,提前在 entitlements.plist 加 | - -**回滚路径**:拆进程过程保留旧 in-process 代码路径作为 feature flag(`BROWSER_USE_UTILITY_PROCESS=true/false`),回滚时切 flag。 - -## 验证标准 - -1. **Blast radius 验证**:故意在 browser utility process 内 `process.exit(1)`,main 进程应不受影响,UI 仍可用 -2. **Memory isolation**:browser automation 跑长时间任务,main 进程 memory 稳定不增长 -3. **Restart 自动化**:kill -9 browser process,main 检测到后自动重启,丢失 ≤1 个 in-flight action -4. **Latency baseline**:browserAction.dispatch 的 P99 latency 在可接受区间(< 50ms 额外开销) -5. **Crash rate telemetry**:生产观察一周,browser process crash 数据可见且独立于 main 进程崩溃 - -## 不在范围 - -- **不把 worker 也一起重构**:worker 已经是 utility process(见 worker-entry.ts),本 proposal 只补 browser / automation -- **不实现跨机器 dispatch**:bus 仍是单机进程间,不做分布式 -- **不重构 rule engine 的规则 DSL**:只是搬进程 -- **不做 browser farm**:单个 browser utility process 就够,不是并发 N 个实例 -- **不改 renderer**:renderer 层对 browser / automation 的交互仍走 main → utility process 中转 - -## 参考文件清单 - -- `src/main/browser/`(当前 browser automation 代码) -- `src/main/automation/`(当前 automation rule engine 代码) -- `src/main/automation-service.ts`(当前 rule engine 入口) -- `src/main/browser/browser-action-service.ts`(action 执行) -- `src/main/browser/browser-action-executor.ts`(具体 action) -- `src/main/service-graph.ts:110-113`(browserActionRef / automationRef 的 LateBinding,C2 会改) -- Electron utilityProcess 文档:https://www.electronjs.org/docs/latest/api/utility-process - -## 附:为什么现在修 - -单个 browser page 的崩溃已经是生产痛点——任何 agent 的网页操作触发 chromium crash 都拖垮用户整个 desktop app。随着 agent 被用于更多 web automation 场景(社交登录、paid subscription 填表、CAPTCHA 对抗),crash 频率只会升。 - -C2 做完后,跨进程 bus 成本极低——本 proposal 是把 C2 的 bus 抽象延伸到进程边界,很自然。 - -Jobs 视角:**"app 不能崩"是 desktop 软件的基础承诺**。当前架构把 desktop 稳定性和 agent browser 稳定性绑定了,这违反了承诺。 - -## 附:gating matrix - -| Gate | 条件 | 放行判断人 | -|------|------|----------| -| G1 | C2 RuntimeBus 完成 + 跨进程 dispatch 协议定稿 | Linus | -| G2 | browser utility process 跑 long-running automation 1 小时无 main 进程回压 | Owner | -| G3 | Kill utility process 后 main 进程自动重启,in-flight action 损失 ≤ 1 | Owner | -| G4 | Browser process 内存隔离验证:独立 heap,不与 main 共享 | Linus | -| G5 | macOS entitlements 配置完整,通过 notarization | Owner | - -## 附:跨进程 message envelope - -```ts -interface CrossProcessMessage { - id: string; // correlation id - kind: CommandKind | EventKind; - payload: unknown; // 由 kind 决定 shape - source: "main" | "browser-process" | "automation-process" | "worker"; - timestamp: number; - // Error case - error?: { name: string; message: string; stack?: string }; -} -``` - -序列化走 JSON(Electron utilityProcess 默认);大 payload 用 MessagePort + structured clone。 - -## 附:跨进程 DB 访问禁令 - -Utility process 内禁止直接 `new DatabaseSync(...)` ——所有 DB 操作走 bus dispatch 到 main 的 writer actor(B4)。原因: -1. SQLite WAL 跨进程同步复杂 -2. Main 的 writer actor 保持单 writer 不变式 -3. Utility process crash 不会导致 DB 文件锁残留 - -## 附:反模式对比 - -**Before**: -- Main 进程 import browser automation service -- 浏览器 crash → main 进程 crash → desktop app 关闭 -- 用户 log off,30+ 秒后重新登录才能恢复 - -**After**: -- Main 进程通过 bus dispatch 到 browser utility process -- 浏览器 crash → utility process 独立退出 → main 进程 2 秒内重启它 -- 用户看到 "browser automation recovering",UI 其他部分无感 - -## 附:为什么不选其他方案 - -**方案 A(当前 proposal)**:Electron utilityProcess 隔离。 - -**方案 B(完全拆出 desktop app 外,跑独立 daemon)**:过度工程——用户不希望后台跑多个进程。 - -**方案 C(保留 main 进程但加 try-catch)**:JS 层的 try-catch 无法 catch native crash(chromium renderer crash)。 - -方案 A 是 Electron 官方推荐的隔离路径。 - -## 附:restart policy 细节 - -| 情况 | 行为 | -|-----|------| -| Browser utility process 正常退出(exit 0) | 不重启(可能是主动 stop) | -| 异常退出(exit ≠ 0) | 立即重启,最多 3 次/分钟 | -| 超过 3 次/分钟 | 进入 backoff(冷却 5 分钟) | -| 冷却期间 browserAction.dispatch | 直接返回 `BROWSER_UNAVAILABLE` 错误 | -| 冷却结束 | 自动重启;成功则清 backoff 计数 | -| 连续 3 次 backoff 失败 | 告警 + 停止重启,等用户手动恢复 | - -## 附:resource cap 配置 - -```ts -const browserProcess = utilityProcess.fork(entryPath, args, { - serviceName: "agent-company-browser", - stdio: "pipe", - execArgv: ["--max-old-space-size=2048"], // 2GB heap 上限 -}); -``` - -macOS 的 resource monitor 可以看到 `agent-company-browser` 的 CPU/memory 独立使用,用户也能直接感知 automation 占用。 - -## 附:与 C2 的跨进程扩展 - -C2 的 InProcessRuntimeBus 扩展为支持 cross-process: - -```ts -class CrossProcessRuntimeBus implements RuntimeBus { - constructor(private child: UtilityProcess, private local: InProcessRuntimeBus) {} - - async dispatch(kind, payload) { - if (this.isLocalKind(kind)) { - return this.local.dispatch(kind, payload); - } - return this.sendToChild(kind, payload); - } -} -``` - -消费者代码不变——bus 抽象隐藏了进程边界。 diff --git a/docs/proposals/_BLOCKED-BY-CONSTRAINT.md b/docs/proposals/_BLOCKED-BY-CONSTRAINT.md deleted file mode 100644 index eeec0a79..00000000 --- a/docs/proposals/_BLOCKED-BY-CONSTRAINT.md +++ /dev/null @@ -1,218 +0,0 @@ -# Blocked by Constraint: 执行矩阵与约束冲突分析 - -> 日期:2026-04-20 -> 决策者:Roundtable(Linus Torvalds + Andrej Karpathy + Steve Jobs) -> 作用:诚实记录用户硬约束 vs 问题.md 清单之间的不可能三角,明确今晚实施了什么、延后了什么、因约束冲突无法做什么。 -> -> **2026-04-20 update**:用户放宽 fixture/tests 禁令 — 允许 dev-only `tests/eval/` 目录(不进 production bundle)。**B5 已 unblock**,Karpathy 正在落地 eval harness。mock / fallback / silent-catch 仍全量禁止。详见文末 "Constraint timeline"。 - ---- - -## TL;DR - -用户硬约束:"全部修 + 禁 tests/mock/fallback/logging + 不破坏业务逻辑 + production live + 无 backup"。 - -这是**不可能三角**。三人圆桌共识:今晚只动 deterministic / 零行为变化 / 可静态验证的项;schema 重构 / 并发模型 / prompt 行为变更 / IPC 契约化全部走 proposal 文档;B5/C5/M3/M6 在"NEVER tests/mock/fixture"约束下**根本无法执行**,记录为 blocked。 - ---- - -## 不可能三角 - -| 用户约束 | 冲突的 reviewer 要求 | 结果 | -|---------|-------------------|------| -| NEVER 添加 tests / mock / fixture | B5(LLM 行为 eval harness) | B5 无法实施 | -| NEVER 添加 tests / mock / fixture | C5(pi hook 契约测试,要 fixture) | C5 无法实施 | -| NEVER 添加 tests / mock / fixture | M3(migration 行为 eval baseline) | M3 无法实施 | -| NEVER 添加 tests / mock / fixture | M6(分层测试 + LLM 行为覆盖) | M6 无法实施 | -| NEVER logging / telemetry | B4(writer queue depth 监控) | 部分实施受限 | -| Production live + 无 backup | B2(dual-write migration) | 延后,需要 eval 前置 | -| 不破坏业务逻辑 | C4(改 CEO prompt) | 延后,无 eval 无法验证 | - -**Karpathy 原则**:"没有 eval 的 agent 产品等于闭着眼睛开飞机"——B5 被禁等于**整个 roadmap 的验证基础被抽掉**。后续 B2/B3/B4/C4/C7 的"修完是对是错"都没有机制回答。 - ---- - -## 今晚已提交的 surgical 修复 - -| Commit | 任务 | 本质 | -|--------|------|------| -| `Remove signing cert artifact from repo (local copy kept via .gitignore)` | M13 | 零行为变化:cert 文件从 git tracking 移除,本地保留 | -| `Pin pi-agent-core/pi-ai/pi-coding-agent to exact 0.67.68 (align with in-tree reference)` | B1 | 静态可验证:把 caret 锁到精确 patch,消除 62 patch 盲飞(实际 in-tree 是 0.67.68) | -| `Drop redundant prompt-builder.ts re-export shim` | N1 | 零行为变化:2 行 re-export shim 删除,import path 调整 | -| `Add proposals for deferred root-cause refactors …` | 本次 roundtable 产出 | 文档:14 个 proposal 明确技术债 + 前置依赖 + gating | - -以上四个 commit 全部**不会触发**生产行为变化: -- M13 只动 git index,磁盘文件不删 -- B1 在 caret 允许范围内精确到 patch,lockfile 对齐 in-tree reference -- N1 是纯粹的 import shim 删除,运行时行为字节级一致 -- Proposals 是文档,不引入代码 - ---- - -## 今晚 proposal-only 的项(写了文档,待 eval 就绪后做) - -| 编号 | 问题 | 为什么不今晚做 | -|-----|------|------------| -| B2 | tasks 5 列状态机 → phase + lease 表 | dual-write migration 在无 backup / 无 eval 前提下 = 赌博 | -| B3 | compactor tool_use 切腰斩 | 修起来需要行为 eval 验证"压缩后 pi 仍不 400"——B5 blocked | -| B4 | single-writer actor 并发模型 | 改并发模型应 eval 压力曲线,缺 telemetry 做不了 | -| C1 | AppDatabase 80+ pass-through | 可以做但与 B2 共享 migration 窗口更经济,推迟 | -| C2 | service-graph LateBinding → RuntimeBus | 涉及 4 个服务重构,无行为 eval 无法验证等价性 | -| C3 | compactor tokenizer 精确化 | B3 修好前做 C3 没意义(依赖关系) | -| C4 | initial-user-turn 硬编码 CEO 行为 | 圆桌 2-1:Linus + Karpathy 反对,Jobs 赞成改;共识不动 | -| C5 | pi hook 契约测试 | 需要 fixture,用户禁 fixture → blocked | -| C6 | error taxonomy + silent catch 清扫 | 涉及 248 处 catch 的分类改造,每处可能改行为 | -| C7 | prompt-builder 按 role 条件拼装 | 无 eval 下改 prompt = 随机改 | -| M2 | 104 IPC handler 契约化 | 需要对所有 channel 加 zod schema,改 channel 名有 renderer 兼容影响 | -| M5 | landing/ 与 desktop 拆 workspace | git mv 大量 + CI 重构,production live 下 risky | -| M7 | CEO mode state machine | 依赖 C4 前置 | -| M8 | worker/ 13 文件整合为 3 | 纯 refactor 可做,但 import path 大面积改动有 ripple effect | -| M9 | browser/automation 拆 utility process | 依赖 C2 前置(跨进程 bus) | -| M10 | agent-runtime hooks 聚合 | 依赖 C5 契约测试——blocked by fixture 禁令 | -| M11 | credential-manager unification | 涉及 secret 处理路径变更,需要审计覆盖 | -| M12 | renderer state audit | 依赖 M2(契约化完成才能审 state) | - ---- - -## 因 "NEVER tests/mock/fixture" 约束完全无法执行的项 - -以下四项**无解**,在当前约束下根本无法开始: - -### B5 — LLM 行为 eval harness - -> **2026-04-20 update**: tests 解禁,B5 已 unblock,本日完成 minimal harness scaffold(`tests/eval/` — loader / replay-client / assertion judge / eval-runner / vitest driver / record-fixture CLI);LLM-as-judge 延后到 B5.1(见 `docs/proposals/B5.1-llm-as-judge-followup.md`),等 fixture 累积到 N ≥ 10 再上。 - -**要求**: -- Fixture:录一批 company 初始状态 + pi 请求 → 期望 tool calls 子集 -- Judge:LLM-as-judge 评分(是否 hire / 是否避免写 plan / 回复 message 是否 mark-read) -- Ledger:每次 eval 记 input/output/cache tokens,PR 带 diff 表 - -**冲突**:fixture / mock 全被禁,LLM-as-judge 本质是一个 test,token ledger 需要写 log(用户禁 logging)。 - -**Karpathy 视角**:这是整份清单里唯一真正阻挡团队"知道自己在前进"的问题。没有它,后面 B2/B3/B4/C4/C7 全是玄学。 - -### C5 — pi hook 契约测试 - -> **2026-04-20 update**: tests 解禁,执行依赖 B5 fixture 累积到位;B5 scaffold 已落地(本日),等首批 recorded trace 入库后即可开写 hook 契约 fixture。 - -**要求**:每个 hook 的输入输出 shape 由 golden fixture 验证;升级 pi 前必跑。 - -**冲突**:fixture 被禁。 - -**后果**:下次 pi 升级(B1 已 pin 0.67.68,未来若升 0.68.x)没有机制判断 hook 签名是否兼容——升级仍是赌博。 - -### M3 — migration 行为 eval baseline - -> **2026-04-20 update**: tests 解禁,执行依赖 B5 fixture 累积;B5 scaffold 已落地(本日),migration baseline 在 fixture 足够多之后可以按 schema 版本钉 snapshot。 - -**要求**:48 次 schema 演化需要每次附带行为 eval baseline;每次 migration PR 必须附 eval diff。 - -**冲突**:eval 依赖 B5(blocked)。 - -**后果**:无法回答"v38 → v48 之间 CEO 的平均 hire 数变了吗"这类关键问题。 - -### M6 — 分层测试 + LLM 行为覆盖 - -> **2026-04-20 update**: tests 解禁,执行依赖 B5 fixture 累积;B5 scaffold 已落地(本日),M6 的 LLM 行为覆盖层将直接消费 B5 的 `tests/eval/fixtures/` 而不再另起炉灶。 - -**要求**:集成测试走真 SQLite 临时 db;契约测试走 pi fixture;LLM 行为走 eval harness。 - -**冲突**:fixture 禁令 + logging 禁令。 - -**后果**:当前 55 个 test 文件 10949 行仍是状态机单测,真实行为回归检测零覆盖。任何业务逻辑改动仍靠"手动点击 UI"验证。 - ---- - -## Karpathy 的建议:放宽一个维度 - -Karpathy 在圆桌 explicitly 提出:用户硬约束若能放宽为"**fixture-only eval harness(不进 production bundle)**"——B5 立刻可落地。 - -具体建议: -1. Fixture 和 eval harness 放 `tests/eval/` 或 `__evals__/` 子目录 -2. Build 产物(electron-builder 打包)排除这个目录 -3. fixture 不进入生产 bundle,不会影响用户实际运行时 -4. 只在 dev / CI 跑 eval,记录 regression - -这是**唯一让 B5 能做的路径**。当前硬约束下,C4/C7/M3/M6 所有依赖 eval 的改动都被卡住,路线图没法推进。 - -**强烈建议**:用户重新考虑"NEVER fixtures"是否真的覆盖"生产 bundle 之外的 dev fixture"。如果不覆盖,开一个窄例外,整个 roadmap 解锁。 - ---- - -## 执行矩阵总览 - -| 类别 | 数量 | 举例 | -|------|-----|------| -| 今晚已 commit 的 surgical 修复 | 4 | M13 / B1 / N1 / proposals | -| 写了 proposal 待 eval 就绪后做 | 14 | B2, B3(未显式 proposal), B4, C1, C2, C3(未显式), C4, C6(未显式), C7, M2, M5, M7, M8, M9, M10, M11, M12 | -| 因 "NEVER tests/fixture" blocked | 4 | B5, C5, M3, M6 | -| 其他 minor 可以随手做 | ~8 | N2-N10 多数是注释 / README 级别 | - ---- - -## 圆桌投票记录(关键分歧) - -### 是否今晚动 C4(CEO prompt 硬编码) - -- **Linus**:反对。prompt 行为变化无 eval = 盲飞。 -- **Karpathy**:反对。没有 golden trace,改完不知 CEO 还会不会正常 hire。 -- **Steve Jobs**:赞成。用户视角的"CEO 不该知道 HTTP endpoint"是产品一致性问题,拖延就是累积坏用户体验。 -- **决议**:2-1 不改。写 C4 proposal。 - -### 是否今晚 drop agent_messages.read_at 死列(M1) - -- **Linus**:可以做。schema 干净化。 -- **Karpathy**:反对。read 路径残留风险,one-way door——drop 了如果发现某个地方还在读这列就死。 -- **Jobs**:弃权。 -- **决议**:M1 不动。等 production read path 全静态扫描后再决定。 - -### B1 pin 到 0.67.6 还是 0.67.68 - -- Task 文档写 pin 到 0.67.6,但 in-tree reference 是 0.67.68,lockfile 实际锁在 0.67.6(caret 行为)。 -- **Linus 决策**:pin 到 0.67.68。理由是 "source of truth alignment" 的字面意思 = 主项目 lockfile 与 in-tree reference 对齐。如果真要 0.67.6,下一个 PR 修一个字符即可。 -- Commit message 明确标注 0.67.68。 - ---- - -## 若约束放宽后的优先级(Karpathy 推荐顺序) - -一旦用户放宽"fixture-only eval"禁令: - -1. **立刻做 B5**(搭 eval harness + 3-5 个 critical behavior fixture) -2. 做 B3(compactor tool_use),用 B5 验证压缩后不再 400 -3. 做 C4 + M7(CEO prompt 精简 + mode state machine),用 B5 验证行为一致 -4. 做 C7(prompt 条件拼装),用 B5 A/B 验证 -5. B2 + B4 + C1 一批 migration -6. 剩余 C / M 按依赖链推 - ---- - -## 一句话:今晚的诚实结论 - -今晚交付了 3 个 zero-risk 的 surgical commit(cert / version pin / shim 删除)+ 14 个 technical debt proposal。**用户约束下 B5/C5/M3/M6 四大关键项无法开始**,整个 product 的可度量性依赖用户放宽一个 fixture 维度的例外。在此之前,后续所有 proposal 的实施都处于"设计已定 / 验证手段缺失"的悬停状态。 - -Linus 最后一句:**"先让数据结构对,其它 6 步会一起变简单"——但前提是你能证明改完是对的。现在我们连那个证明机制都没有。** - ---- - -## Constraint timeline - -| 日期 | 变化 | 影响 | -|------|------|------| -| 2026-04-20 (initial) | 用户硬约束:NEVER tests / mock / fixture / logging / fallback;production live;无 backup。 | B5 / C5 / M3 / M6 全部 blocked;14 项 proposal 仅写文档。 | -| 2026-04-20 (update) | 用户放宽 tests 禁令:允许 dev-only `tests/eval/` 目录,build 产物排除。mock / fallback / silent-catch 仍全量禁止。 | **B5 unblock** — Karpathy 开始搭 eval harness;C5 / M3 / M6 仍受 mock 禁令影响,需二次评估;B2 / B3 / B4 / C4 / C7 的验证路径打开,可进入排期。 | - -### 当前仍 blocked 的项 - -| 项 | 剩余阻塞 | 下一步 | -|----|---------|------| -| C5 — pi hook 契约测试 | 需要 golden fixture;若 `tests/eval/` 视为"非 mock 的真实快照"则可落地。 | 待 B5 harness 形态定稿后复盘。 | -| M3 — migration 行为 eval baseline | 依赖 B5 稳定运行 + schema 历史回放能力。 | B5 落地后补 baseline capture。 | -| M6 — 分层测试 + LLM 行为覆盖 | 契约层仍受 mock 禁令影响;eval 层 B5 解锁后可启动。 | 分两批推进:行为层(B5 内)先上,契约层待约束再议。 | - -### 继续保持的约束 - -- No production mocks / fallbacks / silent catches — 仅 dev `tests/eval/` 例外。 -- No runtime logging / telemetry beyond existing electron-log usage. -- No dual-write migrations without backup path。 -- `electron-builder.yml` 采用 whitelist `files:` 模式(`out/**` + `package.json` + 指定 assets),`tests/eval/` 本就不在白名单内,无需新增排除规则。 diff --git a/docs/rebuild/05-design-system-and-flows.md b/docs/rebuild/05-design-system-and-flows.md deleted file mode 100644 index 845eb0a6..00000000 --- a/docs/rebuild/05-design-system-and-flows.md +++ /dev/null @@ -1,321 +0,0 @@ -# Phase 5 — Design System & Desktop Flows - -> Visual + interaction system for the rebuild. Anchors: desktop-native, two-mode (AI CEO / AI Co-Founder), thread-runtime first, knowledge-backed. No web-dashboard-in-a-shell affordances. - ---- - -## 1. Design intent - -A control-plane for an autonomous company. Calm. Information-dense. Keyboard-first. Pause moments are intentional — when AI Co-Founder mode pauses for review, the UI **feels** like a checkpoint, not a delay. - -The aesthetic baseline already lives in `landing/` and `screenshots/Dashboard.jpeg`: dusty navy (`#4a5d7a`), graphite text, off-white surfaces, restrained accent. We keep that palette and tighten the IA. - -## 2. Information architecture - -### 2.1 Top-level navigation (left rail) - -``` -┌─────────────────────────────────────┐ -│ ⌂ Dashboard │ -│ 📥 Inbox ⓘ │ -│ 🧵 Threads │ -│ ✓ Tasks & Approvals │ -│ 💼 Workspaces │ -│ 📚 Knowledge │ -│ ── │ -│ ⚙ Settings │ -│ 📊 Diagnostics │ -└─────────────────────────────────────┘ -``` - -Sidebar collapses to icons at < 1100 px. Active item shows a subtle vertical accent bar. - -### 2.2 Top bar - -Per company: company picker · execution-mode pill (AI CEO / AI Co-Founder) · provider chip with active connector + cost-this-month · search · profile. - -The mode pill is interactive: clicking opens a small panel explaining the difference, with a switch. - -### 2.3 Onboarding (first run) - -Welcome opens the flow. The setup panel then runs 7 sections: - -1. **Requirements** — checks Node.js because CLI runtimes call the local API through `node -e`. -2. **Providers** — connects at least one runtime. -3. **Company** — captures company name, description, and workspace. -4. **Team Models** — enables the models available to the CEO and workers. -5. **Mode** — defaults to `ai_ceo`; `ai_cofounder` keeps key decisions human-reviewed. -6. **Mission** — captures the first goal and acceptance description. -7. **Launch** — creates the company, CEO agent, workspace, kickoff task, and initial run handoff. - -The user lands in Control Center after launch. - -### 2.4 Dashboard - -Top: 4 KPI tiles (Active agents, Tasks in review, Spend month-to-date, Waiting-on-you). -Below: 3 columns — -- "What's happening now" (live runs with brief status) -- "Decisions waiting for you" (approval queue mirrors Inbox) -- "Recent deliverables" (documents/work-products with reviewer) - -Empty states explain what each panel will hold once activity begins. - -### 2.5 Inbox - -A single ordered feed of `inbox_items`: - -| Type | Source | Action | -|---|---|---| -| Wait-on-you (approval) | `thread_wait_states` `waiting_for='human'` + linked approval | Approve / Deny inline | -| @mention | `agent_messages.body` mention scan | Reply | -| Subscribed thread update | `thread_subscriptions` + `conversation_events` | Open | -| Deliverable for review | `tasks.requires_user_review` true | Open task | - -Counts shown in sidebar mirror the unread/wait totals. - -### 2.6 Threads - -A two-pane view: left = thread list (filter: All / Subscribed / Wait / Recent); right = thread transcript with composer. - -Transcript items: agent messages, tool executions (collapsible), tool results (collapsible), human posts, wait-state markers ("Waiting on @you to approve `bash` call …"). - -Composer: posts a `user` message into the active thread → triggers `wakeup_request` for the assigned agent. - -### 2.7 Tasks & Approvals - -Existing task/approval surfaces preserved; added: - -- "Pending tool approvals" section grouped by run (each item shows tool, args summary, "Approve in thread" deep link). - -### 2.8 Workspaces - -Existing surface preserved. Adds workspace lock indicator and a "Reveal in Finder/Explorer/Files" button (uses `openPath`). - -### 2.9 Knowledge - -Existing surface preserved. Adds "Inject into agent" affordance — moves a knowledge entry into the prompt-builder context for the next run. - -### 2.10 Settings - -Sub-pages: - -``` -Settings - • Profile - • Providers ← new (the key addition) - • Execution defaults (mode default, thinking level, retry counts) - • Budgets - • Workspaces - • Skills - • Updates - • Advanced (logs path, profile dir, vault info) -``` - -### 2.11 Diagnostics - -Read-only: -- Recent runs with status colours -- Recent IPC errors -- Vault backend label (e.g. "macOS Keychain" or "encrypted file") -- Current pi-mono package versions -- Open log directory button - -## 3. Settings → Providers panel (the central new surface) - -### 3.1 Layout - -``` -┌──────────────────────────────────────────────────────────────────────┐ -│ Providers │ -│ Search [ ] View: [Configured ▾] [+ Add provider]│ -│ │ -│ ── Configured (4) ──────────────────────────────────────────────── │ -│ ● Claude Pro/Max OAuth · claude.pro@gmail.com [Re-login][⋯] │ -│ ● Anthropic API Key · sk-ant-…abcd [Edit] [⋯] │ -│ ● AWS Bedrock AWS · profile=prod region=us-east-1 [Edit] │ -│ ! Gemini CLI OAuth · refresh failed [Re-login] │ -│ │ -│ ── Available (21) ─────────────────────────────────────────────── │ -│ ○ ChatGPT Plus/Pro (Codex) OAuth [Login] │ -│ ○ GitHub Copilot OAuth [Login] │ -│ ○ Antigravity OAuth [Login] │ -│ ○ OpenAI API Key [Add] │ -│ … │ -└──────────────────────────────────────────────────────────────────────┘ -``` - -Status dot colours: -- `●` green — `active` -- `◐` amber — `expired` (refresh failed) -- `!` red — `error` -- `○` neutral — `not configured` - -### 3.2 Forms - -Five hand-written forms (no universal generator): - -1. **OAuthRow** — "Login" button, optional GHE domain prompt for GitHub Copilot (renders `OAuthPromptDialog`), shows progress (`onProgress` messages) inline as a tiny status line. -2. **ApiKeyForm** — single password input (masked) + "Reveal" toggle + dropdown "Source: Inline value | Env var name". Save button. -3. **AzureForm** — fields: `baseUrl`, `resourceName`, `apiVersion`, `deploymentMap` (key/value editor), `apiKey`. Save button. -4. **AwsForm** — radio: "AWS profile" / "IAM keys" / "Bearer token", each revealing fields. Region (default `us-east-1`). Advanced toggles for `forceCache`, `endpointUrl`, `skipAuth`, `forceHttp1`. -5. **VertexForm** — fields: `project`, `location`, `credentialsPath` (file picker, optional), "Use ADC" checkbox. - -Each form has a "Test connection" button that performs `streamSimple(... { maxTokens: 1 })` against the connector's default model with a 1-character prompt. Outcome: ✅ "OK — used $0.0001" / ❌ "". - -### 3.3 OAuthPromptDialog - -Modal triggered by `oauth:prompt-request` (e.g. GHE domain) and `oauth:manual-code-request` (fallback when callback server is blocked): - -``` -┌─────────────────────────────────────┐ -│ GitHub Copilot │ -│ │ -│ Enter your GitHub Enterprise domain. │ -│ Leave blank for github.com. │ -│ │ -│ [github.com_______________________] │ -│ │ -│ [Cancel] [Submit →] │ -└─────────────────────────────────────┘ -``` - -## 4. Mode UX - -Mode pill in top bar: - -- **AI CEO** — solid green pill. Tooltip: "Tools execute without review. Approvals only for explicit policy gates." -- **AI Co-Founder** — outlined navy pill. Tooltip: "Agents pause at write-side tools (bash, edit, write). You approve in Inbox." - -Switching modes is per-company. The switch action writes `companies.execution_mode` and a confirmation toast. - -### Pause state in a thread - -When a run pauses at `beforeToolCall`, the thread shows: - -``` -┌───────────────────────────────────────────┐ -│ ⟳ engineer-01 wants to run │ -│ │ -│ [bash] npm install │ -│ in workspaces/web-frontend │ -│ │ -│ [Approve] [Deny] [Approve & don't ask]│ -└───────────────────────────────────────────┘ -``` - -"Approve & don't ask" sets a per-task auto-approval for the same tool with the same arg shape (writes `agent_permissions.permissions_json`). - -## 5. Visual system - -### 5.1 Tokens (Tailwind config) - -``` -colors: - navy.700 #2c3a4f - navy.600 #4a5d7a ← brand accent - navy.500 #6f8198 - graphite #1f1f23 ← primary text - ash #56575a ← secondary text - fog #efeff1 ← surface alt - paper #f8f8f9 ← surface - accent #c98c5a ← warm accent (warnings, awaiting human) - ok #4a8d6f - warn #c79a45 - err #b75252 - -font: - sans Inter, ui-sans-serif - mono "JetBrains Mono", ui-monospace - -radius: - sm 4px / md 8px / lg 12px - -shadow: - card 0 1px 2px rgba(0,0,0,0.06), 0 0 0 1px rgba(0,0,0,0.04) -``` - -Dark mode: invert paper/fog/graphite axis; navy.600 preserved as accent. - -### 5.2 Spacing scale - -`4 / 8 / 12 / 16 / 24 / 32 / 48 / 64` px. No off-grid spacing. - -### 5.3 Components reused - -`src/renderer/components/ui/` already exposes primitives, layout, feedback, hooks. We extend it (no rewrite) with: - -- `` -- `` -- `` (Azure deployment map, custom env) -- `` -- `` - -### 5.4 Density + responsive - -- Default density: comfortable. Toggle to compact in Settings → Profile. -- Window min size: `1024 × 720`. Sidebar collapses < 1100. Right panels collapse < 1280. -- Drag-and-drop affordances: - - Knowledge entries → agent context (drag onto agent card). - - Files into Workspaces (already supported by underlying tooling; UI affordance added). - -### 5.5 Keyboard - -| Shortcut | Action | -|---|---| -| `⌘/Ctrl + K` | Quick open (companies, threads, tasks) | -| `⌘/Ctrl + 1..9` | Switch sidebar item | -| `⌘/Ctrl + Enter` | Submit composer / Approve highlighted item | -| `Esc` | Close dialogs | -| `?` | Show shortcuts overlay | - -## 6. Empty + loading + error states (mandatory per screen) - -Every new screen ships: - -- Empty illustration + 1-line explanation + 1-CTA. -- Loading: skeleton blocks (no spinners except > 2 s). -- Error: a `` with an action button (retry / open logs). - -No placeholder copy. No "Coming soon" text on any provider — every provider has either an active form or an inactive form with a clear "Configure" path. - -## 7. Microcopy rules - -- Lead with verbs ("Approve", "Deny", "Re-login"). -- Status text uses past tense ("Refreshed 2 min ago"). -- Cost expressed as `$0.012` (3 decimals when < $1, otherwise 2). -- Token counts use grouping `12,345`. -- Times use locale-aware format with absolute hover tooltip. - -## 8. Thread runtime UX bindings - -| Renderer concept | Binding | -|---|---| -| "Wait card" in thread | `thread_wait_states` row resolved == null | -| "Read receipt" | (not in this rebuild) | -| "Subscribed" badge | `thread_subscriptions` row exists | -| "Mention" highlight | `agent_messages.body` mentions parsed at render time (existing helper) | -| "Inject knowledge" | calls `agentCompany.addThreadEvent` with `event_type: 'knowledge_injection'`, then `wakeup_request` | - -## 9. Onboarding mode-explainer copy - -``` -AI CEO -The CEO agent runs without pausing. Tools execute autonomously. -Best for: research sprints, content batches, long-running automation. - -AI Co-Founder -The CEO agent pauses before any tool that writes to your filesystem, -modifies code, or runs a shell command. You approve in your Inbox. -Best for: code in your real workspaces, anything you'd want to review first. - -You can switch any company between modes from the top bar. -``` - -## 10. Done criteria for Phase 5 - -- Every screen is named. -- Every form is a dedicated component. -- Every state (empty/loading/error) has a rule. -- Every status surface has a token. -- The Providers panel is fully specified per the contract. -- The mode UX is concrete, not aspirational. diff --git a/docs/screenshots/AI-Internal-Realtime-Message.jpeg b/docs/screenshots/AI-Internal-Realtime-Message.jpeg deleted file mode 100644 index bd8235e937b81f17f86897e95a5ef5b45f4a4c5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 770540 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 `AFt2h(3Z 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
$hs0w2@OQM@d8p3ebni!TdEa}k3PYO^o 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�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

yRu$Qw{b>gn@K06DwXYsMUDw7 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 diff --git a/docs/screenshots/Approval-by-Human.jpeg b/docs/screenshots/Approval-by-Human.jpeg deleted file mode 100644 index d5e459ff41eb178b7f1992f8fe3f54059b6fd14c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233031 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 z 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≈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 diff --git a/docs/screenshots/Auto-OrgChart-Team.jpeg b/docs/screenshots/Auto-OrgChart-Team.jpeg deleted file mode 100644 index 156ed2ad0ca7a4326f4ca21dd2975d23471fe38f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344657 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

5pr=l+n#XU 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
Zq?O7bI9KxDlsbM2A_)>B`MauYP{-MzH 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 atsTOJaMpA7rlb92~h8a}-Ekzfp+a=GAbq{^9A1 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
t;T?a;BZz03>2so~&1lfN^S1`cqkV<{wQ;x=a@F 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%0DkXt8P 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 z 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 FzX11Csg(c# diff --git a/docs/screenshots/Document-Center.jpeg b/docs/screenshots/Document-Center.jpeg deleted file mode 100644 index a40bfb894813e501048b2450b961737ae9465621..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221097 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 dP}5bMEV<#1(RPpT2`>!t#ak{{WhM$7}!q diff --git a/docs/screenshots/Onboarding.jpeg b/docs/screenshots/Onboarding.jpeg deleted file mode 100644 index d80dee0d7aa38ab6d7acf09c26ce4b7930e100e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 620378 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

IiL@{h9dwK>PRu0;QXA2dY!i`^ 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 MethodDefinition[key.name!=/^(createHireRequest|rollbackConfigRevision|queryAll)$/]", - message: - "C1: do not add new methods to AppDatabase. Put the implementation on the owning `database/.ts` and invoke via `db..(...)`. Only `createHireRequest`, `rollbackConfigRevision`, and `queryAll` are grandfathered; adding another requires a proposal and an explicit eslint-disable.", - }, - ], - }, - }, - { - // C-01 — keep task state writes behind the database domain modules. - // - // `tasks.status` and the same-row runtime lock columns are the single - // source of truth. Callers outside the database task/run modules must - // use `db.tasks.*` / `db.runs.*` helpers instead of issuing ad hoc SQL. - files: ["src/main/**/*.ts"], - ignores: [ - "src/main/database/migrations/**/*.ts", - "src/main/database/task-checkout.ts", - "src/main/database-base.ts", - "src/main/database/tasks-crud.ts", - "src/main/database/tasks-status.ts", - "src/main/database/tasks-update.ts", - "src/main/database/runs.ts", - ], - rules: { - "no-restricted-syntax": [ - "error", - { - // Plain string literals: any `UPDATE tasks SET ...status = ...` - // regardless of column ordering. The previous variant only - // caught `SET status` as the first column, letting writes - // like `SET checkout_run_id = ..., status = 'todo'` slip - // through silently. - selector: - "Literal[value=/\\b[Uu][Pp][Dd][Aa][Tt][Ee]\\s+tasks\\s+[Ss][Ee][Tt]\\s[^;]*\\bstatus\\s*=/]", - message: - "C-01: write task.status through the database task/run helpers.", - }, - { - selector: - "TemplateElement[value.raw=/\\b[Uu][Pp][Dd][Aa][Tt][Ee]\\s+tasks\\s+[Ss][Ee][Tt]\\s[^;]*\\bstatus\\s*=/]", - message: - "C-01: write task.status through the database task/run helpers.", - }, - { - // Dynamic-SQL bypass: `UPDATE tasks SET ${...}` where the - // first interpolation is a JS-built column list. The literal - // head ends with `SET ` (trailing space) and `status` never - // shows up in the template itself. Match the head-only shape - // so dynamic task-state SQL stays inside the database task/run - // modules instead of leaking to orchestration or renderer code. - selector: - "TemplateElement[value.raw=/\\b[Uu][Pp][Dd][Aa][Tt][Ee]\\s+tasks\\s+[Ss][Ee][Tt]\\s*$/]", - message: - "C-01: write task.status through the database task/run helpers.", - }, - ], - }, - } ); diff --git a/landing/.gitignore b/landing/.gitignore deleted file mode 100644 index 8fec6031..00000000 --- a/landing/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.next/ -.wrangler/ -out/ -node_modules/ -npm-debug.log* diff --git a/landing/README.md b/landing/README.md deleted file mode 100644 index b179faed..00000000 --- a/landing/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# AgentCompany Landing - -Next.js landing page for the AgentCompany desktop release lane. - -## Copy Sources - -| Surface | Source | -|---|---| -| Download cards | `landing/components/release-links.generated.ts` | -| Platform FAQ | `landing/lib/platform-support.ts` | -| Hero, How It Works, software JSON-LD features | `landing/lib/product-narrative.ts` | -| Runtime download URLs | generated from `scripts/generate-landing-release-links.mjs` | - -The public story mirrors the first-run desktop flow: Welcome, Requirements, Providers, Company, Team Models, Mode, Mission, Launch. diff --git a/landing/_headers b/landing/_headers deleted file mode 100644 index 27e6349e..00000000 --- a/landing/_headers +++ /dev/null @@ -1,21 +0,0 @@ -/* - Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none' - Permissions-Policy: camera=(), microphone=(), geolocation=() - Referrer-Policy: strict-origin-when-cross-origin - X-Content-Type-Options: nosniff - X-Frame-Options: DENY - -/screenshots/* - Cache-Control: public, max-age=31536000, immutable - -/assets/* - Cache-Control: public, max-age=31536000, immutable - -/_next/static/* - Cache-Control: public, max-age=31536000, immutable - -/favicon.ico - Cache-Control: public, max-age=31536000, immutable - -/icon.png - Cache-Control: public, max-age=31536000, immutable diff --git a/landing/app/globals.css b/landing/app/globals.css deleted file mode 100644 index 7948109b..00000000 --- a/landing/app/globals.css +++ /dev/null @@ -1,128 +0,0 @@ -@import "tailwindcss"; - -@theme { - --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - --font-serif: "Space Grotesk", "Inter", ui-sans-serif, system-ui, sans-serif; - --font-mono: "Space Mono", ui-monospace, SFMono-Regular, monospace; -} - -/* ── Light Theme (Cohere) ── */ -:root { - --bg: #ffffff; - --bg-subtle: #fafafa; - --panel: #ffffff; - --panel-soft: #fafafa; - --text: #000000; - --text-secondary: #212121; - --muted: #93939f; - --muted-strong: #565650; - --accent: #1863dc; - --accent-hover: #1352b8; - --accent-soft: rgba(24, 99, 220, 0.06); - --text-on-accent: #ffffff; - --cta: #000000; - --cta-hover: #212121; - --cta-soft: rgba(0, 0, 0, 0.04); - --text-on-cta: #ffffff; - --text-on-cta-muted: rgba(255, 255, 255, 0.75); - --text-on-cta-faint: rgba(255, 255, 255, 0.60); - --border: rgba(0, 0, 0, 0.06); - --border-cool: #d9d9dd; - --glow-warm: rgba(24, 99, 220, 0.04); - --glow-accent: rgba(24, 99, 220, 0.03); - --section-alt: rgba(0, 0, 0, 0.015); -} - -/* ── Dark Theme (Cohere) ── */ -.dark { - --bg: #17171c; - --bg-subtle: #1e1e24; - --panel: #212126; - --panel-soft: #2a2a30; - --text: #fafafa; - --text-secondary: #d9d9dd; - --muted: #93939f; - --muted-strong: #b8b8b2; - --accent: #1863dc; - --accent-hover: #2070e8; - --accent-soft: rgba(24, 99, 220, 0.12); - --text-on-accent: #ffffff; - --cta: #fafafa; - --cta-hover: #e5e5e5; - --cta-soft: rgba(250, 250, 250, 0.06); - --text-on-cta: #17171c; - --text-on-cta-muted: rgba(23, 23, 28, 0.75); - --text-on-cta-faint: rgba(23, 23, 28, 0.60); - --border: rgba(250, 250, 250, 0.08); - --border-cool: #333338; - --glow-warm: rgba(24, 99, 220, 0.06); - --glow-accent: rgba(24, 99, 220, 0.04); - --section-alt: rgba(24, 99, 220, 0.025); -} - -/* ── Base ── */ -html { - scroll-behavior: smooth; -} - -body { - background-color: var(--bg); - color: var(--text); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-rendering: optimizeLegibility; - line-height: 1.65; -} - -::selection { - background-color: var(--accent); - color: var(--text-on-accent); -} - -:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; -} - -:focus:not(:focus-visible) { - outline: none; -} - -/* ── Scrollbar ── */ -::-webkit-scrollbar { - width: 6px; - height: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: var(--border); - border-radius: 3px; -} - -::-webkit-scrollbar-thumb:hover { - background: var(--muted); -} - -* { - scrollbar-width: thin; - scrollbar-color: var(--border) transparent; -} - -/* ── Reduced Motion ── */ -@media (prefers-reduced-motion: reduce) { - html { - scroll-behavior: auto; - } - - *, - *::before, - *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } -} diff --git a/landing/app/layout.tsx b/landing/app/layout.tsx deleted file mode 100644 index dc2d4df6..00000000 --- a/landing/app/layout.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import type { Metadata } from "next"; -import "./globals.css"; -import { ThemeProvider } from "../components/theme-provider"; -import { - landingHowItWorksNarrative, - landingStructuredDataNarrative, -} from "../lib/product-narrative"; -import { platformSupportSummary } from "../lib/platform-support"; - -const description = - "Local-first desktop control plane for autonomous AI companies. Set a goal, let an AI CEO assemble specialists, delegate work, and deliver code, research, content, and operations from your desktop."; - -export const metadata: Metadata = { - metadataBase: new URL("https://agent-company.dev"), - title: "AgentCompany - Launch an Autonomous AI Company from Your Desktop", - description, - keywords: [ - "AI company", - "autonomous AI agents", - "AI automation", - "multi-agent system", - "AI CEO", - "AI agent orchestration", - "autonomous agents desktop app", - "AI task delegation", - "AI team management", - "AI code generation", - "AI content generation", - "AI research automation", - "self-organizing AI", - "AI workforce", - "Claude Code", - "Codex CLI", - "Gemini CLI", - "multi-agent framework", - "AI company builder", - ], - openGraph: { - title: "AgentCompany - Launch an Autonomous AI Company from Your Desktop", - description, - url: "https://agent-company.dev/", - siteName: "AgentCompany", - locale: "en_US", - images: [ - { - url: "/screenshots/Dashboard.jpeg", - width: 1920, - height: 1080, - alt: "AgentCompany dashboard showing autonomous AI agents managing a company", - }, - ], - type: "website", - }, - twitter: { - card: "summary_large_image", - title: "AgentCompany - Launch an Autonomous AI Company from Your Desktop", - description, - images: ["/screenshots/Dashboard.jpeg"], - }, - robots: { - index: true, - follow: true, - }, - icons: { - icon: "/favicon.ico", - apple: "/icon.png", - }, -}; - -const themeScript = ` -(function(){try{var t=localStorage.getItem("agentcompany-theme");if(t==="dark"||(!t&&window.matchMedia("(prefers-color-scheme:dark)").matches)){document.documentElement.classList.add("dark")}}catch(e){}})(); -`; - -const softwareJsonLd = { - "@context": "https://schema.org", - "@type": "SoftwareApplication", - name: "AgentCompany", - applicationCategory: "BusinessApplication", - operatingSystem: "macOS, Windows, Linux", - url: "https://agent-company.dev", - downloadUrl: "https://agent-company.dev/#download", - screenshot: "https://agent-company.dev/screenshots/Dashboard.jpeg", - softwareVersion: landingStructuredDataNarrative.softwareVersion, - description, - featureList: landingStructuredDataNarrative.featureList, - author: { "@type": "Organization", name: "AgentCompany", url: "https://agent-company.dev" }, -}; - -const organizationJsonLd = { - "@context": "https://schema.org", - "@type": "Organization", - name: "AgentCompany", - url: "https://agent-company.dev", - logo: "https://agent-company.dev/icon.png", -}; - -const howToJsonLd = { - "@context": "https://schema.org", - "@type": "HowTo", - name: "How to Launch an Autonomous AI Company with AgentCompany", - description: "Complete the AgentCompany desktop first-run flow and queue the first mission.", - step: landingHowItWorksNarrative.steps.map((step) => ({ - "@type": "HowToStep", - position: step.number, - name: step.title, - text: step.description, - })), -}; - -const faqJsonLd = { - "@context": "https://schema.org", - "@type": "FAQPage", - mainEntity: [ - { - "@type": "Question", - name: "What is AgentCompany?", - acceptedAnswer: { - "@type": "Answer", - text: "AgentCompany is a local-first desktop application for launching and operating autonomous AI companies. You define the mission, an AI CEO organizes the team, delegates work, and coordinates delivery across engineering, design, research, and operations.", - }, - }, - { - "@type": "Question", - name: "How do I download AgentCompany?", - acceptedAnswer: { - "@type": "Answer", - text: platformSupportSummary.downloadAnswer, - }, - }, - { - "@type": "Question", - name: "What platforms does AgentCompany support?", - acceptedAnswer: { - "@type": "Answer", - text: platformSupportSummary.platformAnswer, - }, - }, - { - "@type": "Question", - name: "What AI models can AgentCompany use?", - acceptedAnswer: { - "@type": "Answer", - text: "AgentCompany supports multiple AI runtimes as first-class connectors: Claude Code, Codex CLI, and Gemini CLI. You can connect your preferred provider during setup.", - }, - }, - { - "@type": "Question", - name: "How does the AI CEO work?", - acceptedAnswer: { - "@type": "Answer", - text: "When you create a company with a goal, the AI CEO agent analyzes the objective, creates the necessary departments, hires specialized agents for each role, builds an org chart, and delegates tasks. The CEO monitors progress, handles blockers, and coordinates cross-department work.", - }, - }, - { - "@type": "Question", - name: "Is my data private? Does it leave my machine?", - acceptedAnswer: { - "@type": "Answer", - text: "AgentCompany is local-first. All data is stored in a local SQLite database on your machine. Secrets are encrypted via an OS-level keychain. The only external communication is between your machine and your AI provider's API.", - }, - }, - { - "@type": "Question", - name: "What can an AI company actually deliver?", - acceptedAnswer: { - "@type": "Answer", - text: "AI companies built with AgentCompany can produce code, content, research, business documents, and more. The deliverables depend on the goal you set and the AI runtime you connect.", - }, - }, - { - "@type": "Question", - name: "How are updates delivered?", - acceptedAnswer: { - "@type": "Answer", - text: "Desktop updates are published to a Cloudflare-hosted release lane. macOS builds include the signed update metadata required for in-app update checks, while Windows and Linux builds are delivered from the same release host for manual installation.", - }, - }, - ], -}; - -export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { - return ( - - - - - - - - - - -

- -
-
-
-
- - -
-
FOR AUTONOMOUS AI TEAMS
-
- Launch an
AI company. -
-
- Describe your mission. A CEO agent recruits the team, - delegates work, and delivers real results. -
-
- -
-
ENTERPRISE · LOCAL-FIRST · 26 PROVIDERS
-
agent-company.dev→
-
-
-
- - -
-
-
01 · DESCRIBE
-
- Describe your mission. -
- -
-
-
COMPANY MISSION · PLAIN ENGLISH
-
- Build a marketing agency that ships weekly content, tracks KPIs, and auto-reports to stakeholders. -
-
-
⌘ + ↵ TO SUBMIT
-
Create Company
-
-
-
-
-
- - -
-
-
02 · ASSEMBLE
-
- A CEO agent recruits the team. -
- -
- - - - - - - - - -
-
CEO
-
-
Chief Executive
-
AUTONOMOUS · CLAUDE OPUS
-
-
-
-
MK
-
-
Marketing Lead
-
HIRED · 00:03
-
-
-
-
CW
-
-
Content Writer
-
HIRED · 00:05
-
-
-
-
DA
-
-
Data Analyst
-
HIRED · 00:07
-
-
-
-
OP
-
-
Ops Manager
-
HIRED · 00:09
-
-
-
-
-
- - -
-
-
-
-
03 · EXECUTE
-
- A team that actually works. -
- -
-
-
-
COMMAND DECK
-
Live company dashboard
-
-
-
-
COLLABORATION
-
Real-time agent messages
-
-
-
-
ORCHESTRATION
-
Self-assigning task queue
-
-
-
-
DELIVERABLES
-
AI-generated document center
-
-
-
-
- - -
-
-
-
04 · APPROVE
-
- You stay in control. -
-
- Gate sensitive moves behind human approval. Hiring, budget, - outbound messages — every critical decision waits for your sign-off. -
-
-
AI CEO · full autonomy
-
AI CO-FOUNDER · ask first
-
AUDIT TRAIL · every decision
-
-
-
-
- -
-
- ✓ - Approved by founder -
-
-
-
- - -
-
-
-
READY TO LAUNCH?
-
- Start your
AI company today. -
-
-
-
26
-
AI PROVIDERS
-
-
-
-
13,674+
-
DOWNLOADS
-
-
-
-
100%
-
LOCAL-FIRST
-
-
-
agent-company.dev →
-
-
- -
AgentCompany
-
-
- - -
-
-
- - - - diff --git a/promo-video/snapshots/frame-00-at-0.5s.png b/promo-video/snapshots/frame-00-at-0.5s.png deleted file mode 100644 index 8425d7cbac0c41ff0531f26552af8b78f206491c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157916 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 Dchjq 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

tRl|g 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 diff --git a/promo-video/snapshots/frame-01-at-5.0s.png b/promo-video/snapshots/frame-01-at-5.0s.png deleted file mode 100644 index dbafe92bc4f7c7ce9963c9ad09b148b00c9001a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216017 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͔(j@ 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 dNR3t3V$mm)Yp`;P*S1D~8Z` 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�ks*JIVrD%pxr(ia5mlHTE7Y9mG;P?j$+2m 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 z zN0yTn2|NxR=~tHrvx?Nq{@}Ooium3nzxgG0ZMIQREco8O%k`Ug|1PD4Xc%+BmDk40 zvSM+1}`It_rL8b1LS^N^3#KwKuca z)^%Gy^jdtmt<$hDFq$&FFpd>d@`~0cD_L|K+|N&sSdF`)+04FPePP#N)DgZMYhI{u zd%DhL=Y>(n-TS1`aENf1Ydce(7iUSxef2&GygSV9+wF8FJ@GEPOA7OMf!_HZ>DYR9 zyocwm#WZ_)6QpWddS9+~9GDO1vO8@|HA!ShMrhPIKd-EX_s|rmxxh?nV`GDbN0zTv zq|=+o-xfq!3CA&0?*`8_6R#$@1ShvWW!D=4hZs8hcdjLbir3g{2LUhlNsI|Rqek9C z$)v{spRZ%wdMFjixIEkF*#}1>K`3x|pZ}R6oSFb`tU%nt{M#e}ssF!WR4VOxCh%etOHjMX@-Qi$e>hd!X>w7SX8jy&GQ zCZy)uq@seG{vrwedxghgWp}HMhBu~6yVfzu^Ss(-Z74?xo;rrrqzA$R!1H3~Lyd8( z#G=hb+WbB1+{*ZIq8bV$KvC_%LJFk_rT_>cri1E9OAQ6>Z<)f3$ zMkdyeOpAnp5cw-F&631A8x=DoFKcx2HEfMat98Q)`{e=T-*4Eox8beToUTq)@ARdJ zK!8`kQKA#w3SYjzN{}RAHC2U6`jl_`=fhgZ^%qUt;Sf7+CJW|;)qgf>H#vgMc3dD_ zmv3ChKz9X@GOV$l!nLpW-_%uB>p>D)9!nM9;cJmjS0^UUeC70aah*aFDuf; zNhhbi3Z%ej;wEx@gyS14?yuh(VATG#ReCiymeLj=7- zbNgv*nPkLMC@}0z+$j|?Z8V_%YB*M6rQ@c^q z`GQ@oQ0w!{=-Y@)%l=d!qw7pMOoo>w^U*^u-}cale%x~Q$WrI6-y74lyiZJvA>b&X z5s+K<%@itYC$j+F9*CcsARNQw~2}I;fze7LPNR>%dC$U(QKLG)*t%ODyGwdrcrsdA@kY5} zwm|%%8&0=75yQDh{MiZXP}&`4kq6}I(i>CNZJ)`B-+HSJHWu$&}g(V2S0@)yp^e6HDNf8`$Bd)2j8O0Dhq@J24|X;#Qn90RuMa(b}?zj62to8~f>83s%$Lj~ZQnm%Aq-F`8a##385 zyZw#n$$$R_LtN%Ya%is6&o6U9oHOrUpydS5P;b9oy^KKkxj+1g^X1A25Odh6K+IKzd`C>GE2Q|Jh6=t-z*`%u*!R!7cG z4j}dTpQ}S3@8&MCn&$CCF32VDWW?+MRAAEN2-Al?$!(JKJlh+a5b+)jUuy8<^Yxec zW+wx(51~cL8jlFb@7!V1V6)Vi*t>kLCYmd3%orWX3D^4Oe*`IArwUuWm~RWYI9@Hn zBV!yZH401}W@;y(5s0UgOLT9SjABOabaRg8sxS!5v<8X$?_?{aWy&TTL+xVtbt7JA zGhMb6f(Sa*h|@rdh~J-{1Wo7<^(MqhVj-|C>iV;w-nL@C}aavbg+d952cyYSZcz$f&pZZENXiq#v*a!Z; z51TpZ*NqW#<7xonn4Pn6N)K1T)obD3!BFMnfu{iz=ER# z*)iea5HvJr(6lD%vu&h83_HSe+>f>){_0i>YyT6NzdQ%%N1s)p_yGkLH5}(6sb4h# z1`Ohsi)2(+%u#$yXZI9O{*O_r!|(6@fN@?WDXZ@{AWxcmlHhBgn3dR}dvMucJ|0>f zElTg$+dHWGi)i`bH^ge_vE7CpOu=)E-s9+K|2Lg|jOGT)l z8LDePl$?mACpM~Ug%RIH%U{(U%(#UJ9Ghn6zzOfJ7Bx~IRtXnE+H9{^&Z%S(mPQnSj^P9$o?tPs@_g;n#t)+jE*+#Ns6w>oo zkh{hvUoJ^Nqg;9crI8!60+qP$b#C|UT-k1rDPd;$tMzM$XU~XS52l@HJWp+iQ>JU3 z{MJ?PO)~@r8%^xRWSf!)le50=FAIK{D7MjXV#R*tdV;!)kamr|dbO=lUyerNWyh1Y zsu1V5uZgCWp&(YWs>@uo&UyTr$&s0zGB2pj<)qShf`>5;^X! zLRq#(N7`7}_m8qtLu_&U!5u6W(m zt}#P^i^Ceq$uF-ED|H-03DbLJO~k*tX&69KOUJ95GX?oB-0DNr|L2!G6eLcuU9obh z=R}IDKj9r6Zg;Y5PLy|wir3a!e|_?`7M@)P+Dq$dPm&JYZC0Y|%B&%@KY!EqF*7Hp zX@^m>Zne1gn~8moT`zPWK`V~ioEJJ^(lABHkPEn1En?Bh#P0rl7_x-beU!!}DF&ZM_^}D{pVAFUGI{_z?;q3)7WenP<(=`rx zu_~x7V?Z-@JASe6&FS!5FZ_BqhgQ-IVl>#S8_yhxnJn!QHwWGNaO-$ubkuQbXS^%! zGbz?zsSisgDs!9%G(1G~4yqfihDI&Q`hZdAtQKIC&jdhf2G#s%o0#({z~U&+vA=>d zRBr)5#EuMgWXNS9hwwS4-U@bP#g8x~JT*PpwlL+1Q4XwaL9bYvi={*;Ny+8qIksw; zT#lkJ2hI6$vp=G1#B4mGzP+LGxx^!b7C+|82sg#WL=W-Rlz} z#L`K7>RYupq6t$#?srMGI#*1@KX2-sOPDi+>&e67-(hk#Hv+#6DdWD@Bfbr;ODPo5gmG{$dX6ryFyijFVn9R`ry^B z3yfs-9%rs6qf!5eTt^O=B)ZUA&(zThYgEv<|NWLM{SSUNG91VcF}@#p%5aC)#Ls3 zyobsD0W)R4e=c66S<1BSw)hdAbdx#PeG1o6>UOiP--}fBEoNmXElQHM`D+xVooOw` z(A)GL6DqNkj7mO@Hb<_tDn3paog4vgmZR?RperWNA;LOYcdw$Ha!5~GP}KhZ;EYHu z(dO-u+zg)_rXeS4Im~LeY3JeeEbaG^iDU^oCOJ&1mPrWy;Wo~a|QhiZop>CNSp<Pe`;9M!JkJ2V+BcZ&Fx^P*YF5&Euy$u1fl<&q z19KHU59<2B|lVxebOKS z6b&~`I1T^#;XDC0WBqbw+)(0NUHf-oUUDPPfX`>tEZQ|F4GK6iqX#LG9OcZ?aU4wV zzN+?!QM-uhh3N{tV@I3fd!DRUHXg4qG>-j@8hE$p)xXXeejxzRXy4@lZZgtLjA~z- z8z&j?Kc{im-E|$*?pl4t*;Ui}o$L4%^iHfjOPcaSrdpXH$)9y%MxkcHIA8Qko7=jN zyS#Pz;m3L`Ax#^YkJsm!>Gg)b`e$o((IvU3{`gvaa2KCOK+BKygpY^byt2rk{Oz%eJXoPCO|xCj?wi@y_}V^Ua#3zSc5pxk7mW zT)+PsYL601_PM(aU$Q{&v8m-p$PiO}+LNBATWtY_!i#Y=8hP5a75cN{CseB+MD_fv zj~N5rlMMSH3z?q)R6cFSW4Wdy@p@WUWwcj=OOnl?^K2k zDms!|P~4GXFAD zOIWxW;9LaJ<%FhZGJ@?dacuE*hxW0U#}$;LdD`os05+uR)zogfVn*q$->umA6!rl1 zv5~6KeI|xUenUfHux>c|BSwQHVe?Qai|2UIn(vw;PKg7p`w24s6Av9vRz_B&I2xs{Pbq?69K5DE^tjgYM)`-+m4viW;?H|x?W?h#j$FwZ5!Xp>v^q7gHoXJq$n zrPcI@#7(o3yz-VJjc{8R{#Wa@JU)1CY5t`a2_a8>M!Eepcu{h8&hiABO0O(2oo11h zv+aqCmME*~3C##I56yv9oDlk@w+1Q_BemdcqCsP6Pw^>1Q2vfGHUi6 zEZYn1#0YBb1jm&jiKs2w+cmBbb~H$u96&MIH#xr)X4+TZb>6YHUsQ51-UU( zUmF?Ha^ge!R(*pXxXv+{B<7(0pfyNQYBgO0B;!ZdZuw22pi*D~svW)j{r!77Z{_)~X2w~)C`oJ54lIEI z$z!=J(pz8@z$|5M<$Kv-RMJh?$*HU)kKE1Y7HU=rA=9p_1#)~_AODQTgzR{i@_Qu$ zyX<%fw@%1jSv49CEc82OqL=d@QW$XQ%9zwkAFc7dUoI;|I~2TuX=L6jF)zl!hYWGu z2U+uV)X3ZB_4`ej_T~f=SFjyoiemje5U zTLe0TD53yyo5NK0HagMV&S54oL00kZk{OyvEnqExBp}xg`Ba;AE|g zRwnjZ;iCX$l+SDBIn=8_GQrcoBErJL+2km03WQ@4;9S8by#IQ!aYk6=SbQK<;>VQ)X=kVnh>5EOH9~6CMW73xp5nMg0 z<5sZfKjD+B{@k=XMjX?0U3O2=gAgIpC-ALQ(p)Ud`X6PZb@|P?k~V5h_@+oEO?&sD z+at0sC2BIJr$uHRB!4vhO(T0jb-23>UEt?s7XW35c5RxK$I1grtWey6y@l)kxXHTQ zD0csT>fqh=)ZwRTWmoCks2BGlzhy^6=Z&)m{MMNDI4J+ zqZiI?c<*!Jz0U@~5BKjyKfb1H<lDBbP-I` z3`u+8)XbU{`5#yxKLn;01|oCd4;kf@DKhZZfXq9}$x2krPG6X|n=PEFmU{Q=skqBxy5j}Lp|LgV|K&?n}gfjmT*_m31rJSuiCn|LH}y!4Qm zyI==5ixDYa9&4s~L$h*Jt#3}z;FYCqzlx~BOnQ9@$KzJS$^N?1mpl8iE=85I9+OHq z8oZ~Fw;Hvy?5bw%reP==_MuXvsgzHuG6jKQma`4o<29vBZZB1nU%r=b3x|ng1|+%} zS1gU68e9`I!#5DieCEwqeH!KNlv21rot2xb6=Z{mP*JoW!27VqK%^-1K+xdF&69Ka zlT_d%W3x@w?p2Y}_gDcG8bbsB_0Y8a&!?-V?4wxxxS)BARnFVVYdqgoxlSMx3hW+T zmI{LIk{KqzhB>XYmpt#7lGkZN+3wSA&&CtJ@OinI7q5aW33SEK!V}KkvIFxezSMj2 zil>8ef@albofI%M%hIVrtt)$IkYVD3*jL4zn-3A(&@L%Ya$idEBgr)9Os$%oNwvr^ zxvWc9{_*;O)uJ~-wm+d_R%CsgZ(audpEh-Od_Gds$^|44CRTdV;k^nRu@bYl2V{Q8 z63pe;5vRA=pN_4c7J&3wdxj8QNuYo6DYd1Dxutm~Xw^*w32Y|mEkhWdck*6f8CgnZ zx15_T+FYuibZnz4Ag9>X4{PwXCOBLn&mHo5Fx`~rboNS{Y{Jd9)%|b;I^eSH=uX+l z4|I|z2rhfBXqX}KT!r!$)0~~4oq)b!t0=zv-JiI|%4zI=iP<16ll$zh`ulL^M46Af zJrOY)D}2!lMfX!rLJh>NSuE&G{R~KX7DnGI;8fX2yH&_0@L&lP-dKjB9+-XWeGzDu z^?#f3BFTs3)2D^Uct`4ozLG2#P!g4>VH0EkrHiomyC#hi)&Z?=;&-lEk(Fm8hh1wa zBH=|lyUDQ5HgKtK!qWBO6!j!{PtORCwd$*0@Y=~bQ{=6A%Fey*L+1QG1a$69sbN*S z&fzlwExBI60V;TwOk8Fc|B(60+msfqK8eKLan`5F!PB^M{D|2lrVul3&nn_EE(pVfuX_Xnv5c^YFRsCZcWw_o)?fmNs zx|Tgmt9l8@bJQ#bNv^t--!?VBtFy;Qjx4aLC_zv~4;P1stHkN%1tEgxT&W$D4b3B^&=NE1QTjl4Z`N)K7-W!P^;Q{5Cc#lrjAV`KKVnNi2S6{$P zfWqDe%f-Jt0tW)As#h9Mk`t8VsVjJ^uRgI$oB}ErMuC#9WcH^4jEwZH#|`CJ%(ZJT z(ENtwfqfOfsHD51D6T`|n=1Zlr%OUrI-Aif;^-yF*RB5j;j{D|@k{d6KEf4MX}z3x z@NqM7m;2q6vXLU_&CbBXoVn64Y!aOOes0n$;=M0Byip0@0)b*}w=9wT9*#N=`tUaA zkM&on2iF9a;sngaYJfWe96nSTB+B4#%h}oaI{c>VxLRHI3AzEeS0S2^?1U;16FkHe z(MOvwN`qo{@32ben+tyou)D{@tpRLaBgYoYmIauREo@W2A?8$gQL;BrsYms+Ls78? zG7G}UO<;2r2NV21Ryaxd|3ek*ea@6%=Ne~C`e}7i`R@8Cvw7n`EfV7lpsEaoU{Kt- zi5|W#jMW!l9d3LaX)}c7&HPyg^;9+Ad00hl9F0R+h*e*}p6WJpwv;^ZNj+Bh)Cw%O75awN6Gww5X3T zDK)vLVb=gd_xxvmXBj<4b6r!S`YH}`x1@3PGGmwA-yksYrtBMQxFSX`1>}>x)ln$$ z@JUzmi=r9bq=ALH6?S{p{-p&F<@?geqN zsIuxcUkm%qdEWy|lAti7!&kkz7_o{6~o2mKbToxExy(U0BBd}bmOl|#U60JaU}HMDjAFQ z*9+?gna3ADf~^H)2;Tb);))pgvO4&#I#I!CQ2aT6m;D1t$)5Y(xF zcGSaxF4^4Q-{T*96hNc-<+?qjBS2V2a|@_}y31o{CI z6TzaUnSU@Uj=2Q%h{li4GJ0qD$k&#pLJT!^`xEARoi6Iid8$l9``IHzbSOmY}`Zokwg?=#`BR>5{9^Di}MuwKd_uHN}fvhOuw^!gWvMwO&Fc#T98_aO;>R=Qnw>3K5M-7|XGz3(DIPr|kdDE`=>6Pz;N zz2P>J&@-2T%e5389&)EyG$$5=U*H19f#*-=$=Q2OR?A0qG{GuGC#U?II9I-WB$A{8 z|4`8bvDuW(KYXdFGcz~1Xvt4pxF0WPp{t@_+rx}ThEROVmA#(}^&w^HC|`lE;EV9>CCN{agaMOFJm=BeH? zhM}1(!Eh}feR-1)?pgV@ST?iYCqJQ(0wKXH_nf@Ecz

VHYon>K^akdtIw_Qy~DL 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 A$N&HU diff --git a/promo-video/snapshots/frame-03-at-11.5s.png b/promo-video/snapshots/frame-03-at-11.5s.png deleted file mode 100644 index ef31f11e603e2e63775587c07da278ad2e8e1ed0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81984 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 diff --git a/promo-video/snapshots/frame-04-at-17.0s.png b/promo-video/snapshots/frame-04-at-17.0s.png deleted file mode 100644 index f3d0163743c41f904c95907347e2c61335597b6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 756485 zcmY(qWn7bg+`nz25+Z^~qoR}`jBZp)>4uTQfYC_zP?1ndx=XrabdB7oF}g!)bPgCX zwm-k?{$Ka~x}Tm8&L`*h^*xWz@qT}PsjDiG5z`Uhx^;`}^Cwx&Telv3yLIcH$iq7~ zPry~WRJU$Dx%FB0gSJ=NZmV6wZc}->C`FFXznvw^X12N#f{Nm}YV?cScmBy_`;|hU zBU<%MUr{~Hr2NxOc}2JgAj}b1U-1TpCNnQvZ5@NQ0}^-)84eCDZ+}GdOkEPQ5=E6d zpvfJ!VjE4*GwaOP2~v|7MVt>c61VDCvbuvdWBj+)D;<_CwpxG-C0Z-N!LnKdrX@6> z{!$pvy`kB`$zxYsQCf{NuF$t4;Cxk`U*o*Cs4tO_gDJT%tw1)se;$CtkavQ=rxhTsX2Rp|7uLg^3vcx^h=i4Ek_$rU5xx_qt1Uhg za3h3FExx!S)rnbKe55DH05fa9FFBc1Shs!*I{{R5Zk8o*9&Ye{c8F^pDja%T>2uh$&#<)eBF@51UbkI1Jrm&1)c5!_Ofe>v!z zb&DHgl&P!&;{CIO2Hv;?cSpyS#BBnKcN`6|+I3IlpR6wpg5vWnag>q-Yf>LQU#Fh@ z>i2igE}RpWJ5m}jLUySa&(FMcto*OqLuECTFO1tbkxbqPHgoTIc3n$GONSlRf-yN{ zNrX5&BH(JN{SU3ZYf4a!S6Q3MpkoI7XjzNalqmZK8 zr%c(v5;yKSQByN+yQ{wX88VTMx;kbV(yi#DBok3{e^tC6RS~DkZ(4Nol){_*#GK0o zn?G#ot5Zoz>dn;Tjc!G#0rX4e(WD&;E6Y^gJF?6C6fygM-tFI2P!H)UB_CBt9^&6C z&6yEbMiZruO;PCS@U!R-6-PE!qkJfIbBcn$rrC9*(UpHa9c~~d=9l8-(7h$bm(K0h z4N1k4)c098)haVI`cfpUD!`Ng%C80A{ z!&LO`(9u5~u-#s*Ap<|5`yqnW!#F5(-g?scv;YeXEPL*Xb(>{A%oI5aC{07b{w2F# z$ex6J-LN^1BAs|%+AtPEJoeye7iEnmW1hB@yahvdq$%_VlXlT6l(`Z@oUixcFt@ZP zMJofIh3)Z4lW&SYIK$YC_@`bRl%WO#ntiPns4ERezbj-qHZqY=L+3@16Tf?YG*8r{wGa*ohIzI;tOiaVZgr#jjgSrzKJ%16a9b^ChjmOJ8V+3H#e|=d zpZqBad4^6hD5_;Hz{79{YhB*eg3_@U5~d`(ZSGy8!2x03D@!BnFGhsd=tRae|Gf{9 zNq>-kiTWdQY>Q6}L`}u2aQiyaFuHCAoW8?WxjzjPJ<{4cXbQXN|8neiO91sI zw}-E1eG7_|dBQ*N(bkvwHOUXlPu&c-W8*AG@uH221*AF0^3-OcBuPb`#Xzj(J_|c! z8~^*L?rf2ZKMG$j}f8 z6G2bw{h1w5O1m&3t-Vv;@XK&P^IRjhyKtGZ5V9rC-SbglrbdGu4sr8431Ieq(=%p4 z@^Qd-Sa|cUfu=o}N;g3@q zv-3JbY0IMJUxKM4tCk5{Pb=EHH4OuUMZqiOXBL7m4nL4G4aeO`CwHu7*e4qb4!L7| z#}B@8=hq++qI$t~^WO$f`~{s2wLXORii9$Lq6G}RP_H&gGrfd8QkW75cjaBlkX8`o zr4qKp)LAp8Ox7|HxmY0_rod4uYuBJsQA_$%TU5!v_X9NDV*A4{CTTN`ZjB!>zGy5w zmcb}`Q{$sWPshH7|JIWDW$L>S>uE^0I!nA4t?IqIbx9`?<(OCBp}zC(s6>2h@UnTl z9AjBF;xYN*GtozfH`|;Az>uZ`Ye}vWa!w_N`&2Fm?V};TIgZB&=M{tn8Tq8>`5N^* z6*L|xJJIxtXlb5%6S4?X+YKc09A)$U9g1vP@A*PdGI&Xv`A_CCp>_!bbM@OuL!ug` z#g9GXf7NjXDhk+VnqG=9*i+?~6{+)-+74rj9}5oIsU-&Z5zja@>sgCGgR}r>N z{+T$4Cc*4;i^p@fmhKA2(>@zfxN?FSbB#ppmRerCLjI3NJ@RM&qBxzOL+5^VVF-KR z#@GW1s6(!old@f(*m-iKbc*d(5Q=Tr*>!5dRC^Pio<2EBi2FqtP?U1TNo|hfHRw)p zzxnaI9f1Mr&W>;RUoxq_9&yE)VyCv>;`@%3Q83qux!UBihclE5z!ODGmq)#?W7cj;DzkeZPjmn(5nN#F?}mzIo#Uhr?kUbILZ+sF^5dMLP_)$S1KwZ7Q_ zcj;y-IG}K$pl)z)%-iZSrBbtHl(*}Xf-g7;<=>qGk139H2e1DuyCB9L@AinkPoO`+ zEz5BttQ~&j@(A>4mOBH;UpQZ9xF5x-jZmk4rJb>Bu09@MU!_Yp<8Hq!f)F!ZuMa~= z-L1AsQglc{nz_P_U{~JS;^gv55oW&RY5X>Xk|BzjLHW^^IK+@ot=yyJhb*xx&m(jK zi}Ll)l;h{dz?0O0h=ah%1O;*ikm~`|oCZ$DL|no~M{7tfEF}I!Ja*w~-lIdA%XMoNXq_#t;$f)#ho)RM4{VQ|Y?lvV%!0xNao2obz8 ze1NHB=Hf9ycG-b?z%_qJ86LAb-U&EvMa?Eucg1Gt+fW#?B64RqpEBqv4F!rJpVjM3 z#uf0~Z^nAV`!cLsuQU(*g&^Vf+@zrX)}4}mQO7Q#Ja>^%u|fu~FTc)PQQ1CH8}H<7 zbwe{PbFEBg zoP=nw0;Nqe4d|AZwtZ_0?0sbn2BvzuX|>Yva=G>wGWDz_xe!J8{$-<%UsVRtq@Ner z>^a=?4$}Y4Ef{>P6oAL5UD6LLktFA0X(iM4Do@aQhog%nF0@YHoDO+xJ5;22OoiKN z0|?KYs!Xz)(2!+1f+-{c3dx8Z;7QkmWwSaxiwS4|2sJM6d+z8eZ!;#&=+;Y__7}*_ zDZ&4`OD(%d$fPffhX=jMIJP$}8Ip4&cbOY6v6IGK9x5DcZx=A-eY&u7$onf`L|TT{ zc>G>WxIKw~+!X-bc|_+LL*A!(8PKjuw?xh6(~Rt#REd$k{E=85clKGhX#d3+V{UMm zHZ##)ZV$jpd1g1PqLxjZKsCq2(v!p+0nJB_-n~%Qn}V9<5I0W@iq%LGvs1RJIm^R6 zm}^#DbP-(K4p>a@`G;Cq9fPqoAtCUU81^n=5;;c~cLFKTrts{2JiRhFgnt1MGK`GT_kX7HrL?UG(g z2_FD?mr?PtysWR)SFaR*e;+Et1^St^b#!R%JV?a{%lLZ!hPL)$9<`ez#C%cRckYhG zaeOJI3D%&@uBQPc9=S5?S&CS-A$mm?13F&jRJj#e`EfG?Edpiv<>57bR|-;nZvDI0 z;cc;>m~*ZJE`X6&qV$Qrplf5y*Mm>?=Nmf$z$uje#Mbmgo?dYX#{X-oQ$birgd@zc z=T0slh#nRUdUZAGOy6G$^1D1XyiAf|(C|CayNIjpR+6Y(syNyrVQgCLe8a9jwv%V{=N^u8 z`2v0pYUdS@!Q|)B4|1sOazRD_YUcA_AB=F096bMWCbeoME3*gb2@m(S^v}O7A5hSF zja&idn{j)UR)3CL3Gd`}UV4!JdPPTH2d(bp5}tW8R9rLXiXvV=|In^JHimJ{EBpBe zhGY`LKCtuGA2ZcKFL?CNTH&R;>w+YX2CP7u9^i=iRUR&F0$~Und|4%?)tjmE zH`dW|RRf&0ev2yW7%t-YrJ4Q(ogJ-O-@Zn3?)pnk_CmY*6Eiy?f!?Pu@wrvC{}kYA ziaI8Lg4tJ{tONyk(@G1oJbqF$_|xy~m=pI`q`n9SP{F-SpWvGkJAbWb$#1;^A>$7V zfoo1%(?vlsC}fh0UYVq9Y@_vCK_I{it;J{8z}%S8SL1H{v$a}JMHr}4@TEx^$Q|w_ zW^Fh{;;xImn>*%-H(3r7d1Ei~+YSb=N!{ zX&>G{K37Zn2P@r0Qp4DMvXx+7g^`mA91l)~!I@Hn4Q2z0J7ar8u{?3x3N}dcxQe|C zU%}~86(P(j&1;|2AWz%o1=rPFY4t_=#E>QjlV4@TlFvuloZe6Rqbnp;{?`R~M57Pr zC{DLL(lvJa*!!?=cl`}`&E?Iy=edVyax&MYc-Q!tocQmPt|Ht_1FQN>9?4#D97^Qy zcU(juanbPw%(j182*y^(=|lSb{@fR$`Oy>*CjN!8I_gWm|J+s-K!KtH+j#w-)kjr+`68` z!ySFK2veHlki-?fciQqBP1bR-;of1jABJ)cp88I;q!8$WQurhM7G}q1ye{mJG~4H5 zdg4&aK8Ajq%l&8A6JW-1td$~e(|5h_OrM#?Yi|E1klUusE=evmZRcrbS?Xw-h!{l?1pn7y&n%$EAs zaU2&bIZ}G_OQxooF`$8`jI`x~jh;Qk79sC>)Re=zzR@w(R6UU%-+W(QW%V&k@b^wb zZ|cBMVBYj4jfJ_2C3wRbTp9jdg*0aO?LWMrqH5VC3=vHx56{UniXLppRZbnWlV6W+2SE7|-TC&fM!xjd zzupOdE=zDROf|l`$P8Fz9RBmD!Rll<_AKu(OI_tAab*Q#p130 zKF;Y<wC`De`FDrxUl9fzAQSoNGrq&DjMn6&%ZdB=^#H)r zf3=N`jw@Q5T6bG`L>Ix@IQ^=r6$K0fj}28cp5Kx0Qh;3TQf35kh@m?s!z^*12n54^ z#YKs$R@5ma;;&LbFm-y_FTgO}`mZ6r%zx`wS_H*toRsw*xq0^y@n!LG79ICcTfoG( z)6fQ**Nmo(eqUAx9#ZYu2rKbN!xki=j{MK(Oa})9y=X?<8pYLp zba&8ISEi{ihu8(A0k1d^r{PZ>bwj=u%{S188kp`>EpI;8;RGFO{d3}K`X=W44=Z@U zYaX!W={|T)bPJ7qU&Cw`=AB95>g~aMIdaW=g{D(NY+MnDZLG7y=Ai(QKN0=5)h@by{HE3$msdu_W^>OV|p2PgzI%*^CGf4 z;!(JWY$ap)PE?&!3II)-iy;;fN55_vG<%OJK;5hTxxEQB6T)Abj<91n{oEg5fd)8B z@Xw8%#17Nf7<8t6DKy2fmhiT|rBpTo6?8*}c$@f=JTGzDq z+J+NJv0H&(H5hsfI>4YH?>cj=EcVl^2u%))0PoqEteqk8 zo`?TDr4_SV{Tf#Gfp}JG3_H9~LLJe5x!i!D5I#!g3JhsQeXYtW&q}BH9!J5SQvHlP zrKdMM+R$pbVOyo$c;|^!^Eb=`UHRJ+V?H$2_@N0@BrxLBlfYiSaVhJ2RjeTTKm%zg zw0HV-GiW9CsPDe5)T16aIr8l~@LT~su6866>A?h5rR~DNnE^PNljB?=k!!u4O2;*4VrA|y zcJ}khDcdz(-P~$gCz~pp-j8j} ze){!yAkueYsa5@;DZ)~e{}iq@PBC@34bn#13fhDM&J?ewGVPGPew>44i?#-j#=hde z+$tnvxz8-fGv`$Icu!8Vz~y;%G35Hv_2TKyeNkRx7+(3*Ykg{l6Pu@>!j}Awm0!2k z-kMVm5gPb_t(j~^7L(i^JI2;?W=B|6wDnF>$j-~6#^mi+)agxoz9z$;{utmcDY6f4 z-3u&7F|GkQxk|1)s8u51SbSK#Fw#S} zS`S1VW%f(3f+;YRect!)(oaL_V6Vg;M5~t=gG_qSrD?6*FJoaXQ9dMPajWehXXW{- z^lRzt&yPV8=}K(B3AM?oPiMW=-;oTs`v9oyq)(kcq%$vn;+W%n%T$|0jA?Ie21^Wm z{n8)>YQxU(al)vuk6pr}(=8|Nm(rm)V!3K_W0LGJtaGqi43g53c5nd{Fp zSz9?S{rF-Ven$#s#b(|yVS!+fn^ob+cOw=nK0LKuaej6fbW?x|=F6V`$;(VWzWuFuuw_wDsMx#jrh?ahC`k|t34(data$1XBR5wH zZmU+JT5idrzcefs`sg?f$=`j>DDLHI5`VT&l+EcHH4|(T0!F^gi(!E9yku@k97@{% zfq;dJyFB?DajyQ8XDu}$I^}xP%WSqj`ptJ2-#rh|BoP5MIyNh?I-*A?s5ntprs?_^~A0C@%$w(?EzTzyNnnDud|PsmTK za+(8|%OXZ)*l*gCNFb#t;ew^!>pG7nU+DR2ViOo651V9M!$X793 zWLBR^Ps!0q09Js50 z?zsKqV|?YvUCQOebHgCy4QJ0z**H4$7WXoizAie!a=VQ=)EXF|^Tq>O-#*uHn`X#0 z@k9u+?L{Q9@taaftQmsm*H$Meir>T$+0IR9zDqmW!xQQg{f6Ps5R#yz&9i7c?vuBb z${^b@$JCC4<%kJE@Ilo-uL(aLZ}o`9rqSC|^{~8ENvMU-hNpfx*2kdy2( zJ&4od7df%J0={&aQSJL}!VTr3tQY=u8NHSvl{j<04OJ>ODR_>+UABzB-8U4>B%b=6 zH6E|n_EN{txk9Hl=B>Q)-es#c`9zfoFR6?~9;ydKdv~hX&ICB;rOUXH?Ak_@@Zqj2 zm{j?$*3h?Ecgu!wo5A;OdUSw+KTjR0b;maXcNMgZK$h)s&QX;q*qoPE0Fs91rbb*z z(?!8D80E|YEMsrdV5=JAI+sPyd@W$K@7vXJ*87(a!iJLgCrJxww%xg^zv2v)vMNao zbxk9_^?;IzSOYet|Tx3`~C^hDZDw?Iu#!>s~+VbmLD343L>;kYVbDGrXba5`J z@18Pa^uNVXxS9(1=WSZXl|C=A|7wIb=$7Q!BmEK+#+ooUql3CD3Iz!nt;)ggbxm9S z#EM8h9DdzaX*E7l|2OSu@xD*+Bbs0<>&2RyzLp+J@hD(HOSrXzL!IIYDKk!%>VM@z zd>y4Il5OC@Oi=B=s{URm$(C9dw7bbiY;5D{<@{|j!FUOn-mG$v-Ll?vME*J5b^ffs zVX~(T++zKK>7s)}lPd12#cs}rAEGJlb^@4%psOKAxYqgt@8hvQhWC{|-V<2cy?H%-i}$5o(xUB9>}@-#9|yIeF|`5v$FKzL`#Q zwIag5iC3VBt|L;T>C+h1ZHB+^tV#2NdH+hvh;#T5R(E+F^qx{=6~v#c~I7~P(hI*6+X=MLcMhyI>dovXa6GkX0|wp z7?4>=&{@giR0x~VS+}=X;@FYWP1ZTG#phFGXALD^{~?fZ%(V`tI0xFj+5Ttn?)q3r zt9{Bng?T8-9;ROdzWtk@@bW*?kXSd*T>Ll!*F2aKeNn_$lphW`@_U5YBwv&{-c<9R zdUXOlVp(W}BGUMTa8U++-w6fh>6Zc75ePskxmT(u8Z)~h^}z0or1qoTc%iY%l2^XF z*S9iOEiI?hxv@;45x?gwq&p(Vv!Q}KjL=U<8}DpWy1UJ7!V9S2x-}1#WWwR;=aJD4 z_!nw@nEAjvFa}ei+dZbLWXWvv)mdkyYs`>7N(<;+11p2W6QCm#twn|w)U3&;9xGIo zp#Ziv9P)6Nuo%C?I$$klmhKd}m3N(+l(zwl__2Ff2Kj+T$+yL2rZB(kx>}}Tp;s#8 zhiV%ExRa36&(LTaWi2M|d8y5!AW)Ug=k4&9Ti>PHXhC0S4`&L>crkIJ7EH;UuB$dw zi&54#r9fyT#Z}cU`I3lWjB;0mlxzPjD=beHeBaLI%h*)|-=OZZ){mp@^wjA}8+=?j z?w8be7x*{Q)nNZofe+WiBnE{9hOtUE8K8&|H3z5@ByFwJQQnzVLTrN`Tmp3r_W!oK z4GVJqj|teWvVeP@9!A^(U52?3QX_?I@;GZcRxUmb?`)g*2La+@?SCe|Vm}?%_83Dr zq2c2bT`c4`Z}(D|RJeUtTs(>=(2~^NoUG)W?<;}sO@Z!pfF+;pw}S9+1*OpIRsH`@ zO2mQpXcc~PBW`%0hU;UnR#nQmAh{>$0N-QDuuc4mhH@k#{D-!@nOBV5duK6C30~4f zsfyD4-qVO=|M;bEy0-CE*s7N5-Fw1pYh1?Qz*KQGrlt-i zj;haNI2n1zj*NA!r>sNqNN<6Z{k9l$SJKxitUPT+4fOW&_H8Qo)j|GwK7%F5L*2XH zx$n=4XVKy{6?8Qll@cD_JL*ULm$Jie>|%$+44RQGPXHv z>Z|HLY-ogU%3wh#{^j+uFO$a;Lo+_8>H=Qr`FRxzMNP%`;7qzU%1>L+lB%eBkeC0~@5pzdvLxz*P!*}*SFX{wsS9<@n04btIa*TKJeyAGHDX803| zZ|_hzSILXDxmderVCaq5OPccfO>PjgtG9(=Wt9@rylWIN(j+vGT; zN0S9uT0n@Sek}=QRkUsyO?3_LaL!@_Q+`! zAVQFzkaDQ?epDnWt3>H>+COJ0Vs#F)mVV(~DSv!gYY=!d zZYBq-mx^A^)|U9bF=__g*-N(;`6xsbKTU-w6@cHbI_|oB;~53ox1$b= z?s2Q)i9gra$jn7nA(pDG`IYIL~}CIXqx2x1*8F@uB5CDVQ-B55WUp%_%R4E;n68e z*qC+fc{8!m$m&|$7iuH@%=i~YfY42;R?U-dBp+rY~1Aq~|1n-Z!g#s#Eu5&I2JVk*7_2XUv0|0w}Jj$eYB7 zt+h(B!&oFO->*5#y(HUgsY#}~gpGehenHU-`n2SS2>Rp>K6rsSaFap9Ea%2k&L!>U zt{oCmL7(;l`fwS2YbH6;;??Ne-ei6D@+UngedD2&RH3)T+eH&fD`A&}C6nU|gre(R zWL3Xbe+6TV@CL*O{%;p5KDHpI{@C`Q>(W=GkJ>ANy7_patCKC|O#hkaqr(ki`a#^$ zP+`=^Ew5j7PQ?4y``#{&(uNuT#Vbg?%?3_3jX}Nj~4e+Xd)_xRrysY?n$86s23HyA}XB* z0i{uV@hmJ)>mBNC_=tdhIj-1vYneGKfVMT{;oXB+p`9@luEnlkm&DJPKcE`1KOC>T5u_!#PgK2B{lGZ%3$7=*Z4jM``DRaZ%Xx972K#%jrBAqdHlc#4BS zYLaz@FBH&sv$0igZLN-_cycgeH(!~O6>vW%fQf{9R%+R(L|D*!?St>5yAKS+HaCb; z`;Xz0FRTkk1booW#Cu4oxgq6;EeJ)h8*z+F81P02#jHJdOGWxJM z!18Cc-4f!s7z>HQ2y6VHCi#`^gut5*B1OQ9ne#FSwdBu|{*E(u<_5FhO0%V);4Iq$ z=w1F7My=rU zP8yL2LHox442Z9E?DocemQ{d_qCNS2ccVKn+sl`1)RE2HJ8v;my41H38eCSuK(n~@#77MZ!eeFm6!JGO!bTGU8MGvo$k0COSHUEXv&SUG3c1J2E28F=p zj#FZBoQj~qp@}yvhk3m^jx?;4k>56PZGP#EPx-5_L+(O6G|V9$COj4&Ho|VlE%0W69Kg3EK)EGTfAB!tjgxbXLCeM880BF2)oxwlAYE6qSm*V-bZNp)K zABo8Hl8lgP@%B1hpwSf`_b{O2t*c74hLZyJKneeM?qvUYkpj-nyr4bcw`C~g{ChPs z?bH$bFOE=igeGPQt>ddF(fn;pEhjIQe{^VuEzRUx?bD%#l1$&H#ykl}dr}19gjR2% za=v7GlT6>A#O`q0p{O_>ec)WI7>Iu+kN7j1L#*QB@?-JE?|R*Sz4!+@8)a|PD^vFJ z>bXrH94)r~iV*zIjU=9hGA~0R2;s zC|Op#Ou$C4+uZ4X{%)yCz6{ucT@lbCxZ8e_^o5sc$WSfd=T%FMIwQDYq2#ABIj`j) zOFb5{5&j1A^Wq&SaR!4M`?h1~=Eo1}B1o*#Y1$6bfYY)iv)Q(obtXD_KMBS0=TlVYnl+*7}OYqNq@*O{`=x zRE5NNEND)^UkAM%vQeE^rzVa(4eyURtLeBsVDo~lQg>1EVGb<9dLBoGnQ%rPcvV`q zPQe9;=;6K5r(`k?q@M4(*xAAw7F>z>`|Te!N~)+Ui{3@6WSftJD=1hjt2Rly)W=o| zEB{XV>&sraQyC(1Ugv+|k-xu$#T^BmHEECWW{@GE&U#<3hVWbkLtWwZS%I&+Z{Q_Uj z!Op+)B|N5esqA*DbbeU#8>qZ`&X6cYo;(t(70DH0B#_p-h2wMO1(wIP7ax!dUe9^)zb;@fHT5VF7~@;~2W6jH z6l^nHZ$4w-%_e$TK<#c^HZyloz(-VotH*H{yh)Y5a&>Z0n;O_sRGxC#U{racyEU0l zth46>s5n6y{O&v$oW=CM-=wclM&0Zhj6dz$G|gQW*T`NY|4dt&5}ht8frAK;ZBO0g z7E{Oy)!6;+X4SIBio`Tc*YWJ|*|$+bGXO-Y-HsDbIk#PR|4s-yXrc z{hStapPvceNg24o z#HyvbZxD;+_^Xt{T$fkcyaB$vsA&;?7v(YMtP@G?aiLqygpxl?e=5w?7{;Suji05+ z2Bu$3EV;`_Pdr}CWahgmUW6QL51rk);hC?Q087w}clq``1p|T*)XG9R{)T4Vny0rL^DkH zV!9y2IxNI|!XwntG_S73^e*dob5v@>4KZAAuRgjAPQ>_doGJsQ1!2`J199g&TR}WZ z5szr}xeCIgZ-j_=iG_$+e}nXsh6XjnpS~mORsUh_8K4MtSij=qPh^c}>d#&b(o_Yo zvuSwIp4P3ZQn6T7y_mp-YKTrA-c@OX8~6QO)pnZUb>S`>(Ai>I7?Ve9Kf0^?TOoPH z{XT!1z8eWbpEETjGndN|AcR9bYwI!h9vW|CcZIG^>x=Bqu5jJ-J`j+94Lz=JKIoAn zSsw)J&{#$Tfk11c0#O?#E;Z4*FSScE&b7nyf@OT$xO%4UaF2!w0cHJhWv?>OLt2$) zPFJi5{AV*R)FV6W$^RrHR7(XX(<3u8-paIGpfA=!-p%X(x0umQvJ2p2;(mD+1&Zc# z;H$X)DluDK&8O=j?Xs2D!f#ObqN^zBs+-4oo}X(#gsKjrTcT$9uyW?(9Hk^LDNA#g zrf5JMcg-_lUS(|vU0uQ(u%Z;9J;NyEgCuBFn>#8FJK{Z z9tOSTrPnW&T+2-PR*z`**y^q*WdaxxMKFPHZ>rId0ozpI_L9}!NKU{u3OrOqaJn#b zn@N`TMDMkpK0WN1HLAES3igxlNF2+|qXzhgE^TL6YqmtL*PjVYnlD}O`S=;!+x20f8zZ`gy!M9fnq_w?hdq$J^A{b@3LPaLe6j;Y? zZU{lwdRTd24%|3WTE>aV`pH3FXTr6ra5HIW4sFoBJv|d+uvUUgYiA^1v0_>Tiv*{3 z0iqs7`RnzOn*sXn-0H*z4(E*VAAJM@R>1U|i=kz7x|8X3$ zwFUHL{kp)DEjZPM*579pP*#7eO9D$a|_w-s0yRJqgrq5RMnFAUE>RU1RHEsg@+{JJ3ti=GO zCY^aumiUc)6793ML3g|&8*u(U=MSI5c?6tp&$6J8ZB{jcBb4RxoJngCWJVbn(>syD zjWTB@B7g@Bg2|Rq@(O_GmI@_NBh6Kd3|&$I)>9>RD!60%F)=-}=jG25Rmi(JC)QqL ziZZK@U1LPX>#yBZ!r+xg+p0~BGCui=>9)u=izJ{5NzWjc^xN}lM7v9>Xg_B_UrK)| zdb`N<6t|6a$7`12){|Y2ek#+l{Hss{WDkybq9T+o5^chXsh&_;M-7M&$|UA z+Ayja;YE|e*yxafVv!^7wuam}waJ_0cJ@*&pPo*Ra7J*9O#}Lj0TXAgWJ|*)Zz*3! z(al|2F+jxUS}&)H@$-73{JxV0_XwWN<%lwfOC3%A|aD0Nono|1UC>g3(EH>^}iPTv!c#M6{){hPm1e zXG}W(BsxN#uieR-txvDz4zgDJAB|y2CsKu(7C0{LI_{MV&Cxe>K9GMa(&p1wt*;9a zs$2Y^?W4U+j>2XbQXT53n?m)U( z_3)#AQ&+An5?Pq+93#Acna&L^Ii!Au^LT$Av~WqBUgD=I#bwm4J5Nnpu=-4{?`(7} z9oOS#EWtMmTOGFC6@uThGr0WPcos$&)(;vXg*MSEwX(A|_HcVT1@7@Z4$;r9I(I5y zR~q^Y-Od6+>ohy+0bl>Q7SQ~l=?U2(cE<0ZEK)np3@^PFzWF>$&z@9MI0c*e^rR~~ zla;#~pQ5u>+eYkXO)o<@_WiFyfbYk5mZOFy>6!^WK1Id?&g;D?6dS}xo zTxKZ_=8a}H8O7`9&t$)->EOU?M=C*_ZJj%CUH zynzTRdKRzvMEJ$wQTIj4BX<$^Q4(g=_KnHUK4!Wko)F5;nOvAoHtfy23sSSZB-}+ zFh*A4lk<^WlSWh~cE>yFU8a)ni$e0p9gU>cI4f3|%~hxaiL7#uO6FcFjt=ywyXDuL zpPVX<@xKNv%8f*2lHe|`PzeL`2pwq3^P5uE-q3q{S=$M~8v7QD>kh`bB=_ z4T>NG_pX(TGw;G5V{0Dr&&hmXOl+@6Y3rb;-UaFI^>OP`2irVtWSF|0BVpj2c`lgf zLE4D5NHf0afm67zbT>uRf2X3tH%??v$CypI<=okFYCsp z9hi7`Y*@nj)v9{$XI2XcZ{Q<`pj_o~J0j&kw;AZ-$k}}yBWC#qHt?@g$!~^$}3{b7Xc5-|*L#cscWF z7!r|NtciDAo#Tr&Fs8$`(%w5|V%q*?DT+DO=+jr0yTEudeae*Eps~P}5yeerLFA+# zIYbnvt8X9OUNC#Tu@4>;n=^?y$);(RBvU*7ox^a7!dyQ083jAK+B9@W3Qo3@7Ssg$}>$ z-1j*5$h_%{mN#9?| zP~DImKiHvw)+J86YN}qqutAhKvP*1dNiBRa*>uSmfTE=>DL8((nA(A{#9s7H3cq|* zGDU+;zO!Hd#|^H}r5<)c6&YL83B*g7@jNdW<{KjGWB`}{BkriYHs_E z>`g)dk0DGn=|w$0$Ii^aj6=;Up4SCMqC`}B(#gAd3(`{uE>N^2VWRsIMwA0lcA(xV zV;hDbAx=Tp5sf9(L!E}>2a41K>s$N8mLn+h<}^#!o3?Ed_KXKNnf%PxcnS4hFbbV1lbsOdJ}hONo#GPkF); zPAEU^cCFF?@3yOc)sw1E4dq-Y+opLQDHj!2Xao%asqw%e>eTNqD$T~FUDX%RFKhq& zvdDduuhN+y*zCDlcT)TGaleP&5h>R4OB}a0|CiJ%v}0A>SKJk`c!s{MT|e)J^8B-; zw8u9A2+hUN=BLk&Za(wo@z^2$>5h;55u|yXcd>n`Rm2PSN!yAVH$I})_#jZIl#5}m z=Qd)XGy>G!OfDB_BSJJ+V{h5fj0X9d-QCwYF z)%G9IoYgloy0dTkQkCkMY0L%bCFAPV&6x=pP)o>T_1o^#43OaeKUBSiL(^>^_AQrz zN{Mu*PpfFA#rQT?w zP#w6NI91TZS?2%48yuUy`rS!rL?s=6dj@fQv)+4Zr*t`^Xy~kQ2|-hcj1|ERX}Zr8 zDG|U2H}#Qp)zln{Xb~)%eY4m~7XJLfmznjX!GSYcUYK0(=dc=}I>ouk3bQW6yf6Bi z@z?AcGJ;uWV`(-#7K|S!4z#NlG;i|rl&9skghEWWEong_yMG8ti58E z<0VuhvGt;@5e~bGlcN#rxFZn-d62qXfIuXH`JTa<8m5Isd1rMt?WPy>m4wPshjZ(u%R~e}{##Jjt_L_+c6}B6wa#+i(d*S}EV|j_?e>ik$?Q-94 zjfanKsC35AXDBl>U)SmS-iIChPB;oHWKeo?T^nTb$XxMSyr@$7AxZ61|eW79ubbu5}H3JryK4=OkYGctu)h6W@C~SP!tME@)pz znDLTeWgD#}Qr$h+d$)sIPm$ynJ(II%4qS2Q74#^cnZZ0fqEqVt6G@Y5=adlH8E0DU zQUNfxXHqEe+MBubqSKWdwA572rO*-bdvR0;nSqa5P5X@ z0HZ9rdUwzv{5>@)&$R$1yC*i}l-!=evGJByMZQ4AFmFvBPyMVQraA=6E7PHOmF(l0 zu#qjqRZ!Gp{nm+H_MwN^(&;45U3RgUBvKD+V>><%nh}6L<^_*^ z(NjfeTa!lm6-A~d5sHE6Ann*vLRHaKoa+R=Kce3iw#&<-xtUI;$u##4&Xn~@QJ7eV zR*ZC1Q?z+rE`T|xX720}Ph!&S?Su6bBb?tlx5&cT7$5E!TZTh?*`^-NfA-T6@z9Y5 zyXKx*zp`QfxI+B`_+W@hYNzv4*$!UCK>uP2i*RZeSe%ijYVLrMT(j$!H0Qw?yYf)Z z=H0K)O#28mI=WF+hZtn)t0sl2cS*g2u7>&(Mpm?({1)V#CY3?x-J3O zoG$U`;Rz#LiCK<*ZRsql@_!hr3+g~=g8sili6^eyIxSFT5~HvgCDRB$q3w(k&ktbQ zp%f0)7vwAZm(}!_6toI;Bh0z9@+4})&Z`{yLo^Ngn&{ALfSzJKg+ydS>BaS^RfU1_ ze2|^1cEOL0QmWl~*k3fUOMuTWao%XLdeuJV{kKMvD;L#btwk*S-x>+^#(TFn-}F}{ z$YXIs6qqA#dwrY((l-8ZxCfuJ6Kuy!p2g|>cz1kCLm7Es8$$FSp)oxJFaBb)Zu>8z za9iX;>tUt0^HNOL5l?&H9~x6?A!j3U(Qo?x+6A3w%1-)qN$N%6l~%gpUF<}mPrq4m zkEe?*DD_@cO7mps)Q?M0{O}|dP1A44i^b2Y9gzgtLVbe(Fihz9QweLF-Fb)VE4!z* zb!_(%U3^lg^_D-sD}WA%HO9A2a@ZIFpZ(N;F+}k`%O;&VspXNDD44FA&~L1X)<+s4 zr<1YqeG(qYGH7p={mYgK8iSu(+5j(|*BZ%BKM+lsCnYT7<1}zj3+KD_M*k9?%hqzg zW|sb-eq5=`)R%Aa?GP#O(&d1Xk2?V7qs-V?$+MmcbVv?ZZ4>W0FA!8u1@)miY7$%x z8m_-5nX4)}YW|W5PuIq>0sGoGlufB*c%hk9@L`BxZhx8k2p;g(-8^^g!pFN_!#GX^ z>9L;Sda8wT{_!{fj$f~ZM|811b8u{RmZ-vG@$Nzfm*u5-X|&>uglVK)APK(^dpg=% z#D3?;3Z4}rah%gloz)p~8YRuT>|$yT2ZJNbBXI94<4iQ{JBZ0R)d

h#iuFDeGU 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 Xy=Z+T66qiP@D6BW0lAy zTKS!eh4gP$ofHf`5j1$UxeiVe1EKA2Tq&{=b-;zGQ8qLsBY?GSzf9PjIvY3)93;0$}M1^0;-j}s3@Ao5Fg z__zO&kR(I4IN-rk@s!$|X7x8WtJ>CgV~kT!6FmMM#t6b$WgYC|k;-@uJK_q#9w|@0 zGgMI&T7Z(DXHcQ_e7=bTjv^m6xeh7}T9s*hEqCOT9gqX&Mw2PT78sHj}7)$){8ek z%A=3bzBB~*mj~X;u6+&Lsj^RYFl`aP!MR!`(4adNwP?v=X4rjeh}=W}gmm1yxKUrY z%y8e@-Ig&tXfVK7T9JKsh*sb^z2Xz0unoVX6VdEUfuhR&_cgy|Fk(j_g7mxEb7MGW zW93)>v@j;XYY#%msN=+gn{@Y^R z-e2D>VIy8yWXVGqEGB@vQg{JddPmIkn}FzrWbOI*R90*1J%-b9MtM5wq@fy(Yyf%0=Z>9$H9ATR(Dl z<=!NX{sG9*3@_+Z%ML-}&mh4c?au4fPJ!d>LQI#_B|X`j_x+^zo^;Cm%yj79uVG+@ z>__EHK%Hv^&OjaCHF@Qi98wuqpAJDkQtLOrwYlKaL*3E_3$jKZfmN(~4Gm>m`~ zXymOk_^B&ZUvzJ`B3YWHY<=9{CE${H4%f!f0BikrD7*TN$C|Q-fO2LJ-8@=fUcd-@ z!@)b|qx2{F6UH9K;(K;3O?wgKre+!zdk3;)Jhp=z`sH~nGEY;N zpAEKEB;)97HuQ4`Dhc^lYjms{cW>H?GH3exAHgfLUpzA%xmnlLwv)R_ehHj2&Xt7c zT^mWnK^K9q8v!iu!xO2Z6GICy<;4gcRfqu(exz?(?!LV{ZXgW$_|!m2UbKb~R~kEC zw>XK$?m8=|4Jq{&qK9B-tMUXTj$yN4uXlBaU?g8??=^RbdkAQXO+^{+gb$uzHY}Us z+v0y@`XaJ=RP*s_6pep{zSJDwN3T9p7MRV0%R}^E#1fbPtb5)2pn)~bkEl!XHP%Mx zB;^49wl}QFR54DfqwS*Jqzd5Kn8_`f@hc?%conl=%Dv*)t}(N)DFtcoBA@9dF;sGW zkL#2sjS*>OHZ}G3t#28`)^z~fg^NwP%PII0OYC4l0Qk)W^v&c_pM{i-*IFIico$>_9U@Z$8a7*&0xI!7jOV7Ye znc8mhZyTWf`il?N2Qmj^q9cY32AMZOBVtUDPTsT{6S;CtMH;@L>u>Kl*U5-ZkdwG! z$4#OEP5tG#qBRmQjZ5eOHf8hu8Z7A-75n@~=3MY0$gDi-0&(2xb&fW}i0?gYcEh9V zx^&bdOEcF`WIxi8SKki57h)QdSuSt_DwCNGP*4orRMgFlxa4lfT>7p(7vfw(bh=hM zcSqRH5lVI{ly<$q=Z0vl&P!hyB)ggkp`vO*RjvwvM;eELurpy zRx|5YO@Q@|H|7;%5al~E1P+94F!%UzGm7i!QT?g*?kg$@fl7+q0}T_`O~9tlx~H@M z#%X4b+VNiLj+a2uwu|)s#{z!(b|EjDv_&Bv7Zcg6Z^W*UpP!1DT%_|u2NHaI^CNbw z=XTob=#20XAT+w{_LR89wKQu>4p*U%c6aj%*Y6otc;_nu0k4na9gkA8R|mBT1j~~j z{>+Md%K%+f_>gR<{a304puTA$ZW!h+N{IEpSOr8qdP3S8xr_)g_xy ztQ59QkAce@`O8IMoOS;aL0Ispiz;eK>5iMK$$2Q6kYl$$bxZ9kk?(=V^Zv~NzH7ZhQ)sl6UeSEavKZ06!Qh-;-dL%vLOio<^r>IVgOQAqS(}kK>)udZ z&mR+4p`vH+UJZQP*BF<{f3ZX2GDUl%$lZYHPR1N-790X)7^e%~w^v(&B8to``#!lH zG4*RRCpzre)b*4WjwS>Pp?+iijijYLuad6kSkc2K37E3q86jMQ>WiQiy;lgS|5nZ7>h{c-7sl`yJ>q!oXlAe1G3-{!>@k=6YNl0&k&((^3oG zSFjSA4YD@t0I~A{o=1n+uc8E@2TbT^W1_ZnJJlbvd;%wF3VPd}fkPbOT$2S`r{#iU zIwEzGh&pKe6Z;_g;wiK)(JKbvHXF1ulc{8qZIbsg5ljevQkY_Uz&>!Yun-5E|IfTBrJ zrB7ROn1DTK|C{q_x~*LuDW5ClZsg;Ho!QR>l!+*tCa2-5T0R)=QKK~1d{Ak3vd8`x z=MLq+Jn1~mybUOIg-SRbt;_x9)RlA))8t`(=ykydIIoEfEYl0Y5&_fG`K2paeZhH? zJE(1d7EB#!+#7%VNCrtwhd}#4@UAb~;MCo(O!G7Sg|5?yOtPjQXs#{oV25@8tdTwz zJG+L+{2qp`LZA7_Z(34ylmDjip(oTEh7PiD$*hlP3s?N3p z{(+T`MGQ{JhZ=1tutqb8$tuZzZQoE$nW!8fDO;T54|(#P*A~UqBq+q}Lg-;j$!t^G`|suDQ|d$y9Ye?YKCHIkd~L;7n%>QfxbnfO!}VGw zyoG;Ayelb;XCxViOuU6PbZS`}Ru&(AkgO5T(u2}QNZGn%xW8rp_JZ*9O*yjerOW(3 zrrt6v>TvDiRZ$TEkxoHcx{*dn0qJhZp^@$xgHGvg0qKsR2I(ON>28>zyJ2R|?ERj7 zo%5aR;sekBW&In0ro$CM6yKl#=BFZ+FuDa~hred}%fK zF54X}(&H?gtjeN?4)}3|_?)mnKA*$*MS({TeXtw9pCFFOS7;+-$5mAyKzh{%RWWC0 zf{Aka-TN*{UDbw_kDkMzv$Y?tMXWED=C$ExCZ2kpN_n@ic3$Z?5*3uhbX~{A@twrZ zNT#!kE>ah6euKcSzV&p6yZrW9t#N$xN9gC5ccI}m!Kya)x;ZZNX&eA!#?=E=&V8I- z&#U13Bj|dlNcxj00X7pgM(;3c_eOX1A}1yb^*tTj)MnQhP09V}{=;Zl+cMqKaiiwO z?PS9n@kJn}qk=HeqdVT|QoC<9U72{6BD8NOv&K$_A$tWWa+ioqTs?`!#pFOn+pn!ML zn#tes!)T)D^^-mtefdr6M2dyAY%u;ZKrP0~#hx7;-qzG5*aHxhq%_341(FC$)C3DF z4t!o}fR)kMD-68A%#W4vjZPc*frs=SZmLHMEvrx-oM-<-9|r7Y$!``~?3)Kbw@x&y z2>Am;|B=PTR8ldd-$`g?ap}{ax9ml@f>$(qDZ|t81(b|uRvr^$rb{*q;5?AjRBye7 zN?zizXl(NFeyFiE^t>wLH&78z!;kX&t`EnRek34~roA_~N8xplB@kCbA@qY%l6*L) zsL7S+^D6}SCI@q+CaPD*f0THeJW=ZP#-(6tE#a^OKajO)e+~90_M)}($LX3uMR7{vcj63(5>Vu)ho7S*y{Ks* zHa~RaxAv|CHP3L#sO_T1?#pa_Fjl!0EpV`7j02$ax9ae|Wi_`f%oSJkXlmJTEH~%%RlE zXc4engUG`+|CCG`_}(T=nC5CKe72$-K})VXUy9h=GE#4Ci#QC#Xo&hJ!u}_rFAvkS zkK`uws0uO56s~dCn+a+7&Vkm~8E6jAmou2IXo`5K1#cKxWhTEB!R#*u#6mC~y~_TL zcJD~?&@nGH2BuyohhX^tAN@R!=q{#Z%jy0DB%7@{qZ{_8`S+`yc|4u#Vc|IUdmk6y zy05hJrT7T;ZCHD44xkS~c9(SJ_N#d^9aQRu-A7Z`5d1;C0$#B@oiXzlQ;5`42YBO* z{T?E%_^YM(qN2>UX-O9XQ+*FIk{#0+4`ekMiQZ{}m7IXEUR7id+=FS8U13)&#YB=p zqosXGy_qXt-~7N2Su`$I_-+2ArafyvIk^=0(dYTcEQJH-T?Lsg>x0pV`#nND!MHJ2 zc1`x`p@;<{zL=J8$fvIKnxDU$vj8J$BkGBEjYktKBFA`Pye;?{OD|q=RpbUkVm|hz zonUucQAqmeMacmqg=lx{P2!T>GLTdDoVJuCx^Ia0E%=wpO=iS~jRl>x+P*a4Dz`mN z{kSHO7p&C2JTt<0l!T4i9W?L@zYyJ7F$$slqnvwasO$TOy~BpD0Z+TP!~X?~zB+8; zC7G@s#_Aa4Wp+_w6RoksQy z{AFdt8VWQ1#Ck@%=sUKz@$vq_=zHvIS;aGPPV__=>ixKpUTNqp9VC z)BI`TNpsp5Z}q)J%ex_JmqIy?33)ik@u^3Imyl+QV&kHiRR z&#kiP2A}E8R3YPzN)dB4(>1FS+a8>mTagG>_nh$X1fJ|pwPa3?KR4MmmnqGNrf**R zb5#2G+l%ky6DH+5jD&|r+Uv~Gov%pmpPip)v>mz1r*fWdUim9m32w2;|3=Efp3c+n zfSKx&8t&$&I)j#@Q2Lr`PeFp{P2Qi#L6)UV&p|+S-wyFfYg-=k3^k{7URkWU?Zb-@g0D6LFLk>sn1#gDw3D~+|6C52-~m!GyU6nLkBJ>C^N5S>G%wJh%TYAv6~PXz zFle%82tJtEC5KY|o3=ilHGwZL=BXxHO#JYCFzDYX%WpU%o^-SLy_G}BmpkCZb`9L-RZx9c~h=X5ZG({pW9K3e$B?iYc8pHOP!b^R4h>_G7wVYMUxd+YqV#_`OjAN3XE&G#Re4c>AHE`gIdzz zFndVSXZP>a_ON`fzjy2DM-df7g+SYMyTr1DO=rb^k$mJcsv%lJPF3QwaY!1_@td?C zmH-*#G=1+i;tb%Xl~W0JFJnG_{T5c)RlzNoC{<*@|LaVYC07YUUR1i^7WxOeJT{}% zkUe4z_+mWgR9Din9j)BPmTTX8lJ59SfYDEw&n9k|cgb=i_8;tt%%_apnA{l1CjQ=` z9siYmHQ>$YlE$S0mS3K0`0R;ehC+tbVfUA@AHU9df8kwpHyBOr4i+^38?wTzWpTFc z+l?*qe19h7;R~#W%EtEnTFj>ib9hG0%{oQnVy~>XBc9n!g4u;Y<Hk`On}g2ZfQ(8JeC#h(Mdt za*6WV7nHQkyp#U0)W>)|eiw!IYBApTQ{$8`s{AdTBSh;;`iaBA4kBXstoet!78xb8 zC*hauwKuhX$%8wFP#e8=jYWOhE{C&kC#hP#iA9e+c1n(@#x=~+d5j91PlmFz6!ixF zSRt}RaQC5Y z8^%bDZ3gVv+a_vZ^UNMcQSJN6%GSeI5<}8sYN@|crb`}-wfsivXtt#bMgXXXv<1sW z8MiCrTT@c2D%r?QI0x%%_2$nb$|ZXxrS^;+nh-FxywDTnNnKJ^oGR#Ho{>$-Y?^hw za-JwQVHvo<(3&b+s)(C63+3N4L2xL$R)&Tg%Vt)SkFh}z4ust2H#jq($qC|8T0K7i zRxg7NNoW%E)?hVyv?O>TE_mDrDKjo)n!45I=Qn>v8m=d`JJhPrDLMGDTWj_>UNw1W zB#mPV=~Fb~&}CPlxOw}hty&K~f=#ENkE=VNvlW}+si3`mw|Ye0d!OV2%9qe;gNGhCJUzyKTVqpirCT%64k*mUva*KBA` zlk3b$ki`j7oc3$EOciSo1EN0dCsN-LoF%nMfI2BEhj&71NurC;!9CHmE?LVNEDIpu*p zHUL^jMm*U6PPsf!h3K7v=}0&*0vKG;$WU!o~> zUS|MTmQ@-$&8=qT1B^0PMJ7U>Foi}p%+Nj3tu1_k{H&Td#v?VUo-2u)sUgS6pgl;B z)g+HI2|HACrE{F8 zY$sW>=nMuoyZ(McoE+XBE_3WN~ z2@44a7^;7s^3d}7`<=9hA~Yb1zIjS4ibva5z~fSfrN=R)B4k~-H9$`|nexb}UU*`D zGb=g8&|OT zg@Tm}Z7uf&7)JrlPo7FkUjBE`n`(vgiSxkMWRW!@qDn+;Q~gQ(RkN{3Q`{{-=4LJw z9p2adxTD0#d+y?e9X2*uXr`)_9KRQka9Y?W8cy;zFIlt*KW^yYyg;9j@qOve*8$k) zpg|lv2Syq%rfPTHf-P^6F=7miA?vR61#bl{&~&;-=n|<|SUHKG*D&PJYWD#cXNxWP7lf zr!i0boPRKVKwAmah~D0T;dftF4DqPF<)Z^ogz*P-my_Lfk+=OI-iu1rcVW-af=P*cIF|RR< z*sPtOrjjT-^l0|n_w1{sc;~Lg_JdhkL*Z34U>cwFERd)b+G5snq&;R` zK-8rBwVR#Wqe&(N_#ZDfbZ{h$H)kWDCy=6W6YIQY8+_qJEiT?~n`3Ywq)cqN{A~ku z;L%nLa|pPowBLk|e|A*Y4O1VDyMmk4O?fM#2U3y-a2m2RC$i+1+Z9M)J{q%s`~()6 zo8FCg8dd$ZGxLVK@j(*T6U|sn<}Z8rxqEkHeaxPZ!UNw9bvz0%V>9pD!3EEy)-jSI zmK|QJyic19{{zr+Z&<%lTh4^Ohn0-%>8OYuT2e+T@ss#`l=OOxc?NaIcgVfgTAkJ& z7b<9ZGt&4Y-6I*SYn`p6=a*v9(if?^^aKM-o*Tr3EwnZDXZ{;8qrar`DtYdIXWLi~ z*z@F^W2|r_X;5I}+M}SCJ<5DkE~72qj+PPEO=^_)5I=TmDUH-j)6nHDXV0;Gin$f_ zMdUZi@?AOhMM~`mII4vI$9@ov0s^$tiYcUIcc5L}CrAz_-!DqhuSTc%?8$}{GRFBx zWUDz2c2)?NW?0C$Hpg2F>T76a-megPK=cGnK&54cc@;!#fSa4;*uwI0QM?Y;V2 z0x@-_9C&z$@nhbo`GoRc&oYSToAx;B!U|aV^zju-)=Bt3p62LU5}Q)(ieCD|GL*RT z6^2Wbv3c_-5+*Ib>m^$h#figzm2P6Fi&q&NP|>2;mOEb}kEe%Oiobd|4Jzd^JG6>_ zW?Eu_YnZoE#^Xj4Zso^oy)Lo*X#eJBq%S%soINIEc+6#9HZ?NvaWu_7?R+X~X6@l* z)vS5&s~pNNMfe^kD01vX`wF%A2LiwM*N+`N-&WyObDhCvJv6VqUFLEfe_f`Ihn;Kj zCUb(Bq_J3=(@5>ZtkPn=XF}s!2-%dbOt7k`#IC?9bJBfOoYpt0>wP?iLvm520+qc~ zU+|U=(mOU(^`t?#V8~&`d}VXEgF!=`75W095SiWemgO_N-i21M@aJzI8fTGggv40j z{6%c51r$kiK}F~KEV+OS+`Q`;a(?uqFgWDmYq?Ja>(+)cWn9H~e0I0~Hzh}%rECB_ zOOt%(ZlEgpoSV9c5G#xFHH;=!Alu^>`h;NUOsoAJx2KO9p`50eryJQ zXiR$I=V9p|p&#L(YMtjEm474WJCXe3yqan0woMDhunlS%3B8Qy^9I+cEHALhyJ5Qe zjl$J6)$2at=4y-J(0dSu@^gBuJ(J}(1OZg!$eb&7RV>4f`8Yx?5y6@k_KQz=H`+zQ zwv<#}tMYwjJgUGD{4Rv9b^H5#!!&y(bw<>FzrVlmB#^D#)YxbD8Mi98ni82a#1mxy z$7~T#nM^O5{0mEd@1?6oS_OUIWckaAoC-FaW6cE1djA>?oUpdXEILo_Nv(7_W-h<~ zW~nLTjAG|ddy{C)B{~+@VABz4`~T0M)TgPxaS>n2_k#8R{Yt$oo2lFz6fo~fi3`OQ ziL->#xHW}yPM?E0`601x|1lzt^nO~m*Z{T1ciQWl{?CY*{x;kNlc?p_ETMDY$z%U~ zI!ha4P+dMe^zSSKeEWo!_gxthX5+M(kCO1(&QJV+ad>P!!ZGW#&>mnQ=<wS5F#`QxqIQ+54#?zcTiRWp94ZJpaQHuvh1Q>t6a~ z|IySOoaHr`E&^2J{es-$V%cOI6>H{ocU*s$sxN|mS%0D`46lD;;_dh@Aettoq56~f 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

0M^n$1~Bf`6-BDI2;_W5 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 mRM|p9>5PJa2 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%0AJk~SWqq%s*~+q^+|lAom`(bIz@ViRX@Y-; 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 >x^Q{9I8d; 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 - expectedExts.some((ext) => f.endsWith(ext)), -); - -if (foundArtifacts.length === 0) { - console.error( - `[build-all] ERROR: No ${PLATFORM_NAMES[currentPlatform]} artifacts found in ${releaseDir}. ` + - `Expected files with extensions: ${expectedExts.join(", ")}`, - ); - process.exit(1); -} - -console.log(`\n[build-all] SUCCESS: ${PLATFORM_NAMES[currentPlatform]} build artifacts:`); -for (const artifact of foundArtifacts) { - console.log(` - ${artifact}`); -} - -// Step 4: Report remaining platforms -const otherPlatforms = Object.entries(PLATFORM_NAMES) - .filter(([key]) => key !== currentPlatform) - .map(([, name]) => name); - -if (otherPlatforms.length > 0) { - console.log(`\n[build-all] NOTE: Build on these platforms for full D-07 coverage:`); - for (const name of otherPlatforms) { - console.log(` - ${name}: run 'pnpm build:current' on a ${name} host`); - } -} - -console.log("\n[build-all] Done."); diff --git a/scripts/build-desktop.mjs b/scripts/build-desktop.mjs deleted file mode 100644 index e384667d..00000000 --- a/scripts/build-desktop.mjs +++ /dev/null @@ -1,93 +0,0 @@ -import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; -import { prepareBuildEnv, resolvePublishMode } from "./build/prepare-env.mjs"; -import { resolveBuildVersion, writeRuntimeBuilderConfig } from "./build/emit-builder-config.mjs"; -import { buildElectronBuilderArgs, runElectronBuilder } from "./build/run-electron-builder.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const packageJsonPath = join(rootDir, "package.json"); -const buildDir = join(rootDir, "build"); -const runtimeConfigPath = join(buildDir, "electron-builder.runtime.json"); -const localElectronDistPath = join(rootDir, "node_modules", "electron", "dist"); -const customMacSignPath = join(__dirname, "electron-builder-mac-sign.mjs"); - -const extraArgs = process.argv.slice(2); -const prepared = prepareBuildEnv(process.env, extraArgs); -const publishMode = resolvePublishMode(prepared.env); - -await rm(buildDir, { recursive: true, force: true }); -await mkdir(buildDir, { recursive: true }); - -const buildVersion = await resolveBuildVersion(packageJsonPath, prepared.env.AGENTCOMPANY_BUILD_VERSION); -await writeRuntimeBuilderConfig({ - rootDir, - buildDir, - runtimeConfigPath, - buildVersion, - extraArgs, - prepared, - customMacSignPath, - localElectronDistPath, -}); -prepared.env.AGENTCOMPANY_BUILD_VERSION = buildVersion; -prepared.env.npm_package_version = buildVersion; -console.log(`[build-desktop] Cleaned ${buildDir} and staged build version ${buildVersion}.`); - -const builderArgs = buildElectronBuilderArgs({ - runtimeConfigPath, - extraArgs, - publishMode, - prepared, -}); - -// electron-builder with `extraMetadata` mutates the source package.json in -// place during packaging and restores it when it finishes. If the process is -// killed mid-flight (CI timeout, Ctrl-C, OOM, parent task cancellation) the -// restore step never fires and the source tree is left with a stripped -// scripts block — every subsequent `pnpm` command then fails until someone -// notices the drift and runs `git checkout`. The snapshot + signal-safe -// restore below is idempotent: on a clean exit electron-builder's own -// restore already wrote the original bytes back and this is a no-op; on -// any abnormal termination we guarantee the working tree is clean. -const packageJsonSnapshot = await readFile(packageJsonPath); -let packageJsonRestored = false; -async function restorePackageJsonIfNeeded() { - if (packageJsonRestored) return; - packageJsonRestored = true; - try { - const current = await readFile(packageJsonPath); - if (current.equals(packageJsonSnapshot)) return; - await writeFile(packageJsonPath, packageJsonSnapshot); - console.log("[build-desktop] Restored package.json from snapshot after builder left it mutated."); - } catch (error) { - console.error(`[build-desktop] Failed to restore package.json snapshot: ${error instanceof Error ? error.message : String(error)}`); - } -} - -const signals = ["SIGINT", "SIGTERM", "SIGHUP"]; -const signalHandlers = new Map(); -for (const signal of signals) { - const handler = () => { - void restorePackageJsonIfNeeded().finally(() => { - process.kill(process.pid, signal); - }); - }; - signalHandlers.set(signal, handler); - process.once(signal, handler); -} - -try { - const result = await runElectronBuilder(builderArgs, prepared.env); - await restorePackageJsonIfNeeded(); - for (const [signal, handler] of signalHandlers) process.off(signal, handler); - if (result.signal) { - process.kill(process.pid, result.signal); - } else { - process.exit(result.code); - } -} catch (error) { - await restorePackageJsonIfNeeded(); - throw error; -} diff --git a/scripts/build/emit-builder-config.mjs b/scripts/build/emit-builder-config.mjs deleted file mode 100644 index 69dece20..00000000 --- a/scripts/build/emit-builder-config.mjs +++ /dev/null @@ -1,117 +0,0 @@ -import { readFile, writeFile } from "node:fs/promises"; -import { join } from "node:path"; - -function validateBuildVersion(currentVersion) { - const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(currentVersion); - if (!match) { - throw new Error(`[build-desktop] Unsupported package version format: ${currentVersion}`); - } - return currentVersion; -} - -export async function resolveBuildVersion(packageJsonPath, override) { - if (override?.trim()) return validateBuildVersion(override.trim()); - const raw = await readFile(packageJsonPath, "utf8"); - const pkg = JSON.parse(raw); - return validateBuildVersion(pkg.version); -} - -export function hasExplicitArchArg(args) { - return args.some((arg) => - arg === "--arm64" || - arg === "--x64" || - arg === "--ia32" || - arg === "--universal" || - arg.startsWith("--arm64=") || - arg.startsWith("--x64=") || - arg.startsWith("--ia32=") || - arg.startsWith("--universal="), - ); -} - -function resolveCurrentMacArch(env, extraArgs) { - if (process.platform !== "darwin" || env.AGENTCOMPANY_MAC_ALL_ARCHES === "true" || hasExplicitArchArg(extraArgs)) { - return null; - } - return process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : null; -} - -export async function writeRuntimeBuilderConfig({ - rootDir, - buildDir, - runtimeConfigPath, - buildVersion, - extraArgs, - prepared, - customMacSignPath, - localElectronDistPath, -}) { - const { env, resolvedUpdateUrl, hasR2PublishConfig, hasMacSigningMaterial, strictRelease, isDirBuild, explicitElectronDistPath, r2 } = prepared; - const forcedMacArch = resolveCurrentMacArch(env, extraArgs); - const isUnsignedLocalMacBuild = ( - process.platform === "darwin" && - !hasMacSigningMaterial && - env.AGENTCOMPANY_ENABLE_LOCAL_DMG !== "true" - ); - - const releaseDir = join(buildDir, "release"); - const runtimeConfig = { - extends: join(rootDir, "electron-builder.yml"), - directories: { output: releaseDir }, - extraMetadata: { version: buildVersion }, - }; - - if (explicitElectronDistPath) { - runtimeConfig.electronDist = explicitElectronDistPath; - } else if (isDirBuild) { - runtimeConfig.electronDist = localElectronDistPath; - } - - if (hasR2PublishConfig) { - runtimeConfig.publish = [{ - provider: "s3", - bucket: r2.bucket, - endpoint: r2.endpoint, - region: r2.region, - path: r2.path || undefined, - acl: null, - publishAutoUpdate: true, - }]; - } else if (resolvedUpdateUrl) { - runtimeConfig.publish = [{ provider: "generic", url: resolvedUpdateUrl }]; - } - - if (isUnsignedLocalMacBuild) { - if (strictRelease) { - throw new Error("[build-desktop] Strict release mode requires macOS signing/notarization material."); - } - runtimeConfig.mac = { hardenedRuntime: false, identity: null }; - if (!isDirBuild) { - runtimeConfig.mac.target = forcedMacArch - ? [{ target: "zip", arch: [forcedMacArch] }] - : ["zip"]; - } - } else if (process.platform === "darwin" && !hasMacSigningMaterial) { - runtimeConfig.mac = { hardenedRuntime: false, identity: null }; - } else if (process.platform === "darwin") { - runtimeConfig.mac = { hardenedRuntime: true }; - if (hasMacSigningMaterial) { - runtimeConfig.mac.sign = customMacSignPath; - } - } - - if (process.platform === "darwin" && !isDirBuild && forcedMacArch && !isUnsignedLocalMacBuild) { - runtimeConfig.mac ??= {}; - runtimeConfig.mac.target = [ - { target: "dmg", arch: [forcedMacArch] }, - { target: "zip", arch: [forcedMacArch] }, - ]; - } - - if (strictRelease && !resolvedUpdateUrl) { - throw new Error("[build-desktop] Strict release mode requires AGENTCOMPANY_UPDATE_URL or an R2 public URL to be configured."); - } - - await writeFile(runtimeConfigPath, `${JSON.stringify(runtimeConfig, null, 2)}\n`, "utf8"); - return { forcedMacArch, isUnsignedLocalMacBuild }; -} diff --git a/scripts/build/prepare-env.mjs b/scripts/build/prepare-env.mjs deleted file mode 100644 index d9d76570..00000000 --- a/scripts/build/prepare-env.mjs +++ /dev/null @@ -1,93 +0,0 @@ -function normalizeBaseUrl(url) { - return url.replace(/\/+$/, ""); -} - -function normalizePublishPath(targetPath) { - return targetPath.replace(/^\/+|\/+$/g, ""); -} - -export function prepareBuildEnv(sourceEnv, extraArgs) { - const env = { ...sourceEnv }; - const noDeprecationFlag = "--no-deprecation"; - const requestedUpdateUrl = env.AGENTCOMPANY_UPDATE_URL?.trim() ?? ""; - const strictRelease = env.AGENTCOMPANY_STRICT_RELEASE === "true"; - const hasMacSigningMaterial = Boolean( - env.CSC_LINK?.trim() || - env.CSC_NAME?.trim() || - env.APPLE_API_KEY?.trim(), - ); - const isDirBuild = extraArgs.includes("--dir"); - const r2AccountId = env.AGENTCOMPANY_R2_ACCOUNT_ID?.trim() ?? env.R2_ACCOUNT_ID?.trim() ?? ""; - const r2Bucket = env.AGENTCOMPANY_R2_BUCKET?.trim() ?? env.R2_BUCKET?.trim() ?? ""; - const r2PublicUrl = env.AGENTCOMPANY_R2_PUBLIC_URL?.trim() ?? env.R2_PUBLIC_BASE_URL?.trim() ?? ""; - const r2Path = env.AGENTCOMPANY_R2_PATH?.trim() ?? env.AGENTCOMPANY_RELEASE_PREFIX?.trim() ?? "desktop"; - const r2Region = env.AGENTCOMPANY_R2_REGION?.trim() || "auto"; - const r2Endpoint = env.AGENTCOMPANY_R2_ENDPOINT?.trim() || (r2AccountId ? `https://${r2AccountId}.r2.cloudflarestorage.com` : ""); - - const resolvedUpdateUrl = (() => { - if (requestedUpdateUrl && !requestedUpdateUrl.includes("example.invalid")) { - return normalizeBaseUrl(requestedUpdateUrl); - } - if (!r2PublicUrl) return ""; - const baseUrl = normalizeBaseUrl(r2PublicUrl); - const publishPath = normalizePublishPath(r2Path); - return publishPath ? `${baseUrl}/${publishPath}` : baseUrl; - })(); - - const hasR2PublishConfig = Boolean( - r2Bucket && - r2Endpoint && - resolvedUpdateUrl && - (env.AGENTCOMPANY_R2_ACCESS_KEY_ID?.trim() || env.R2_ACCESS_KEY_ID?.trim() || env.AWS_ACCESS_KEY_ID?.trim()) && - (env.AGENTCOMPANY_R2_SECRET_ACCESS_KEY?.trim() || env.R2_SECRET_ACCESS_KEY?.trim() || env.AWS_SECRET_ACCESS_KEY?.trim()), - ); - - if (!env.AWS_ACCESS_KEY_ID && (env.AGENTCOMPANY_R2_ACCESS_KEY_ID?.trim() || env.R2_ACCESS_KEY_ID?.trim())) { - env.AWS_ACCESS_KEY_ID = env.AGENTCOMPANY_R2_ACCESS_KEY_ID?.trim() || env.R2_ACCESS_KEY_ID?.trim(); - } - if (!env.AWS_SECRET_ACCESS_KEY && (env.AGENTCOMPANY_R2_SECRET_ACCESS_KEY?.trim() || env.R2_SECRET_ACCESS_KEY?.trim())) { - env.AWS_SECRET_ACCESS_KEY = env.AGENTCOMPANY_R2_SECRET_ACCESS_KEY?.trim() || env.R2_SECRET_ACCESS_KEY?.trim(); - } - if (!env.AWS_REGION) env.AWS_REGION = r2Region; - if (!env.AWS_DEFAULT_REGION) env.AWS_DEFAULT_REGION = env.AWS_REGION; - if (!env.AWS_EC2_METADATA_DISABLED) env.AWS_EC2_METADATA_DISABLED = "true"; - if (!env.AGENTCOMPANY_UPDATE_URL && resolvedUpdateUrl) { - env.AGENTCOMPANY_UPDATE_URL = resolvedUpdateUrl; - } - - if (env.CSC_IDENTITY_AUTO_DISCOVERY === undefined) { - env.CSC_IDENTITY_AUTO_DISCOVERY = hasMacSigningMaterial ? "true" : "false"; - } - - const existingNodeOptions = env.NODE_OPTIONS?.trim(); - if (!existingNodeOptions) { - env.NODE_OPTIONS = noDeprecationFlag; - } else if (!existingNodeOptions.includes(noDeprecationFlag)) { - env.NODE_OPTIONS = `${existingNodeOptions} ${noDeprecationFlag}`; - } - - return { - env, - resolvedUpdateUrl, - hasR2PublishConfig, - hasMacSigningMaterial, - strictRelease, - isDirBuild, - explicitElectronDistPath: env.AGENTCOMPANY_ELECTRON_DIST?.trim() || "", - r2: { bucket: r2Bucket, endpoint: r2Endpoint, region: r2Region, path: normalizePublishPath(r2Path) }, - }; -} - -export function resolvePublishMode(env) { - const allowedPublishModes = new Set(["always", "never", "onTag", "onTagOrDraft"]); - const requested = env.AGENTCOMPANY_ELECTRON_PUBLISH?.trim(); - if (!requested) return "never"; - if (!allowedPublishModes.has(requested)) { - console.warn( - `[build-desktop] Ignoring invalid AGENTCOMPANY_ELECTRON_PUBLISH="${requested}". ` + - "Falling back to --publish never.", - ); - return "never"; - } - return requested; -} diff --git a/scripts/build/run-electron-builder.mjs b/scripts/build/run-electron-builder.mjs deleted file mode 100644 index d4f22cb5..00000000 --- a/scripts/build/run-electron-builder.mjs +++ /dev/null @@ -1,94 +0,0 @@ -import { spawn } from "node:child_process"; -import { hasExplicitArchArg } from "./emit-builder-config.mjs"; - -const filteredUnsignedMacWarningSnippets = [ - "skipped macOS code signing reason=identity explicitly is set to null", - "arm64 requires signing, but identity is set to null and signing is being skipped", -]; - -function resolveCurrentPlatformArg() { - switch (process.platform) { - case "darwin": return "--mac"; - case "win32": return "--win"; - default: return "--linux"; - } -} - -function resolveCurrentArchArg() { - switch (process.arch) { - case "arm64": return "--arm64"; - case "x64": return "--x64"; - default: return null; - } -} - -function shouldSuppressBuildLine(line) { - return filteredUnsignedMacWarningSnippets.some((snippet) => line.includes(snippet)); -} - -function forwardChildOutput(stream, writer) { - if (!stream) return; - let pending = ""; - stream.on("data", (chunk) => { - pending += chunk.toString(); - const lines = pending.split(/\r?\n/); - pending = lines.pop() ?? ""; - for (const line of lines) { - if (!shouldSuppressBuildLine(line)) writer.write(`${line}\n`); - } - }); - stream.on("end", () => { - if (!pending) return; - if (!shouldSuppressBuildLine(pending)) writer.write(`${pending}\n`); - }); -} - -export function buildElectronBuilderArgs({ runtimeConfigPath, extraArgs, publishMode, prepared }) { - const explicitPublishArg = extraArgs.some((arg) => arg === "--publish" || arg.startsWith("--publish=")); - const explicitPlatformArg = extraArgs.some((arg) => - arg === "--mac" || arg === "--win" || arg === "--linux" || - arg === "-m" || arg === "-w" || arg === "-l" || - arg.startsWith("--mac=") || arg.startsWith("--win=") || arg.startsWith("--linux="), - ); - const explicitArchArg = hasExplicitArchArg(extraArgs); - const { env, hasR2PublishConfig, resolvedUpdateUrl, hasMacSigningMaterial, isDirBuild } = prepared; - const shouldForceLocalMacZip = ( - process.platform === "darwin" && - !hasMacSigningMaterial && - env.AGENTCOMPANY_ENABLE_LOCAL_DMG !== "true" && - !explicitPlatformArg && - !isDirBuild - ); - - if (publishMode !== "never" && !hasR2PublishConfig && !resolvedUpdateUrl) { - throw new Error( - "[build-desktop] Publishing requires either AGENTCOMPANY_UPDATE_URL (generic feed only) " + - "or full Cloudflare R2 publish configuration.", - ); - } - - const args = ["exec", "electron-builder", "--config", runtimeConfigPath]; - if (!explicitPublishArg) args.push("--publish", publishMode); - if (!explicitPlatformArg) args.push(resolveCurrentPlatformArg()); - if (!explicitArchArg) { - const currentArchArg = resolveCurrentArchArg(); - if (currentArchArg) args.push(currentArchArg); - } - if (shouldForceLocalMacZip) args.push("zip"); - args.push(...extraArgs); - return args; -} - -export function runElectronBuilder(builderArgs, env) { - return new Promise((resolve, reject) => { - const child = spawn("pnpm", builderArgs, { - stdio: ["ignore", "pipe", "pipe"], - env, - shell: process.platform === "win32", - }); - forwardChildOutput(child.stdout, process.stdout); - forwardChildOutput(child.stderr, process.stderr); - child.on("error", reject); - child.on("close", (code, signal) => resolve({ code: code ?? 1, signal })); - }); -} diff --git a/scripts/codemod/README.md b/scripts/codemod/README.md deleted file mode 100644 index f0a999a0..00000000 --- a/scripts/codemod/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# scripts/codemod/ - -One-shot and reusable codemods for mechanical refactors. Kept in the repo -so the next person doing a similar migration has a working starting -point instead of re-deriving it from scratch. - -## remove-appdatabase-passthrough.mjs - -Rewrites `db.(...)` → `db..(...)` for every -pass-through method that used to live on `AppDatabase` / `AppDatabaseBase` -and now lives on a sub-module field. - -### Usage - -```bash -# Full rewrite across src/**, tests/**: -node scripts/codemod/remove-appdatabase-passthrough.mjs - -# Dry run (print what would change, don't write): -node scripts/codemod/remove-appdatabase-passthrough.mjs --dry-run - -# Restrict to one or more modules: -node scripts/codemod/remove-appdatabase-passthrough.mjs --modules=tasks,agents -``` - -The script walks `git ls-files 'src/**/*.ts' 'src/**/*.tsx' 'tests/**/*.ts'` -(so it respects `.gitignore`), excludes the three files that define the -pass-throughs themselves (`src/main/database.ts`, -`src/main/database-base.ts`, `src/main/database/**`), and applies the -regex `(^|[^\w.])((?:[\w$]+\.)*)db\.()\(` → `$1$2db..(`. - -### C1 migration evidence (coverage proof) - -The `METHOD_TO_MODULE` map in the script was derived mechanically from -two source-of-truth files as they existed at the start of C1: - -1. `src/main/database.ts` (pre-C1) — defined pass-through methods on - `AppDatabase` that delegated to domain modules. -2. `src/main/database-base.ts` (pre-C1) — defined pass-through methods - on the base class that delegated to sub-module fields. - -Every pass-through method name from those two files was copied into the -map with its owning sub-module field name. Two composite methods -(`createHireRequest`, `rollbackConfigRevision`) are intentionally left -unmapped because they span multiple modules and live on `AppDatabase` -itself; rewriting them would break caller semantics. - -The completeness of the map is proven by two independent signals, not -by inspection alone: - -- **Typecheck after C1 part 3/3** (commit `ee1734e`): `pnpm typecheck` - is clean. If the map had missed any pass-through, call sites would - still read `db.(...)` against a deleted method, and the - TypeScript compiler would surface it as `Property '' does - not exist on type 'AppDatabase'`. Typecheck passing = no orphaned - call sites. -- **Test suite green after C1 part 3/3**: 524 tests pass. If the - codemod had silently mis-mapped a method (e.g. routed `saveGoal` to - `documentsMod` instead of `entityCrud`), the runtime would throw - `TypeError: db.documentsMod.saveGoal is not a function` on the - exercising test. All 524 tests green = map entries are semantically - correct, not just syntactically in scope. - -Taken together, typecheck-clean + 524 tests green = the map is -complete and correct across every live call site at the time of C1. - -### When to use this script in the future - -If a future refactor re-introduces a pass-through on `AppDatabase` for -temporary back-compat, and you want to remove it again, you have two -options: - -1. Add the method to `METHOD_TO_MODULE` in this script and run it. -2. If the new pass-through follows a different shape (e.g. a method - that moved to a different module entirely), copy this script as a - template and adjust the map. The regex structure is reusable. - -The ESLint rule in `eslint.config.mjs` blocks new pass-throughs from -landing in the first place. See `CONTRIBUTING.md` at the repo root for -the rule and the guidance on when to invoke the codemod. - -### C1 commit recipe and revert ordering - -C1 landed as three commits. The final one (`ee1734e`) did two things in -the same commit — removed the remaining pass-throughs AND simplified the -vault binding layer. In retrospect the vault simplification should have -been a separate fourth commit so each concern could revert independently; -in practice the commits are already published, so the recipe below -records the actual state. - -Commits (oldest first): - -1. `e352a69` — codemod-driven rewrite of `tasks` + `agents` pass-throughs -2. (C1 part 2/3) — rewrite of remaining domain-module pass-throughs -3. `ee1734e` — remove final pass-throughs + add ESLint guard + simplify - vault binding - -**Sequential revert** (not independent): to unwind C1 cleanly you revert -in reverse order: 3 → 2 → 1. Reverting commit 2 or 1 without first -reverting 3 will leave the ESLint guard still active, which will then -fail on the re-introduced pass-throughs. The "net simplification" part -of `ee1734e` that touched the vault layer comes along for the ride; it -does not have its own revert handle. - -If that bundling is ever a problem, the fix is not to rewrite history -(already published) but to issue a targeted revert of only the vault -hunks of `ee1734e` via `git revert -n ee1734e && git checkout --patch -HEAD -- `. diff --git a/scripts/codemod/remove-appdatabase-passthrough.mjs b/scripts/codemod/remove-appdatabase-passthrough.mjs deleted file mode 100644 index 00bc986d..00000000 --- a/scripts/codemod/remove-appdatabase-passthrough.mjs +++ /dev/null @@ -1,412 +0,0 @@ -#!/usr/bin/env node -/** - * Codemod: rewrite `db.(` → `db..(` - * for all AppDatabase pass-through methods removed by the C1 refactor. - * - * Regex-based (no ts-morph dep). Operates on a fixed method→module map - * derived mechanically from src/main/database.ts and - * src/main/database-base.ts. Only rewrites `db.(...)` with a - * word-boundary before `db`; never touches `db..(...)`. - * - * Usage: - * node scripts/codemod/remove-appdatabase-passthrough.mjs \ - * --modules=tasks,agents \ - * [--dry-run] - * - * The --modules flag restricts rewrites to passthroughs owned by those - * sub-module fields; omitting it rewrites every passthrough in the map. - */ - -import { readFileSync, writeFileSync } from "node:fs"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; -import { execSync } from "node:child_process"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const REPO_ROOT = join(__dirname, "..", ".."); - -// Canonical map: passthrough method name → AppDatabaseBase field name -// Source: src/main/database.ts + src/main/database-base.ts as of C1 start. -const METHOD_TO_MODULE = { - // activityMod - listComments: "activityMod", - addActivity: "activityMod", - addComment: "activityMod", - listRecentTaskComments: "activityMod", - // messages - sendAgentMessage: "messages", - getAgentMessage: "messages", - listAgentMessages: "messages", - searchMessages: "messages", - markMessageReadForReader: "messages", - listAgentInboxUnread: "messages", - // social - saveSocialAccount: "social", - deleteSocialAccount: "social", - listSocialAccounts: "social", - getSocialAccount: "social", - saveBrowserAction: "social", - updateBrowserAction: "social", - listBrowserActions: "social", - getBrowserAction: "social", - getBrowserActionByApprovalId: "social", - // skills - upsertCompanySkill: "skills", - listCompanySkills: "skills", - getCompanySkill: "skills", - deleteCompanySkill: "skills", - assignSkillToAgent: "skills", - removeSkillFromAgent: "skills", - listAgentSkillAssignments: "skills", - listSkillAgentAssignments: "skills", - updateCompanySkillMetadata: "skills", - // budget - saveBudgetPolicy: "budget", - deleteBudgetPolicy: "budget", - listBudgetPolicies: "budget", - getBudgetPolicy: "budget", - getActivePoliciesForRun: "budget", - getCalendarMonthWindow: "budget", - getSpentInWindow: "budget", - upsertBudgetIncident: "budget", - listBudgetIncidents: "budget", - resolveBudgetIncident: "budget", - resolveIncidentsForPolicy: "budget", - resolveWarnIncidentsForPolicy: "budget", - autoCloseExpiredIncidents: "budget", - // entityCrud - saveGoal: "entityCrud", - listGoals: "entityCrud", - getGoalForUpdate: "entityCrud", - saveProject: "entityCrud", - listProjects: "entityCrud", - getProjectForUpdate: "entityCrud", - saveSecret: "entityCrud", - resolveSecretEnv: "entityCrud", - deleteGoal: "entityCrud", - deleteProject: "entityCrud", - deleteSecret: "entityCrud", - countActiveGoalsForCompany: "entityCrud", - // createHireRequest is a multi-module composite that lives on - // AppDatabase itself (spans agents + approvalsMod). Do not rewrite. - // rollbackConfigRevision is the same (spans documents + entityCrud). - // documentsMod - saveDocument: "documentsMod", - listImportantDocsForReview: "documentsMod", - listDocuments: "documentsMod", - getDocumentForUpdate: "documentsMod", - updateDocumentStatus: "documentsMod", - deleteDocument: "documentsMod", - createDocumentRevision: "documentsMod", - getDocumentLatestRevisionId: "documentsMod", - listDocumentRevisions: "documentsMod", - createWorkProduct: "documentsMod", - updateWorkProduct: "documentsMod", - listWorkProductsForTask: "documentsMod", - listWorkProductsForCompany: "documentsMod", - findWorkProductByExternalId: "documentsMod", - resolveWorkProductTarget: "documentsMod", - deleteWorkProduct: "documentsMod", - archiveWorkProductsByExternalPaths: "documentsMod", - linkDocumentToTask: "documentsMod", - unlinkDocumentFromTask: "documentsMod", - listDocumentsForTask: "documentsMod", - listConfigRevisions: "documentsMod", - getConfigRevision: "documentsMod", - rollbackConfigRevision: "documentsMod", - recordConfigRevision: "documentsMod", - // knowledgeMod - saveMeeting: "knowledgeMod", - deleteMeeting: "knowledgeMod", - listMeetings: "knowledgeMod", - getMeeting: "knowledgeMod", - saveKnowledgeEntry: "knowledgeMod", - deleteKnowledgeEntry: "knowledgeMod", - listKnowledgeEntries: "knowledgeMod", - saveSprint: "knowledgeMod", - deleteSprint: "knowledgeMod", - listSprints: "knowledgeMod", - collectRunDeliverableSignals: "knowledgeMod", - // automationMod - saveAutomationRule: "automationMod", - deleteAutomationRule: "automationMod", - listAutomationRuleNames: "automationMod", - toggleAutomationRule: "automationMod", - recordAutomationExecution: "automationMod", - getAutomationLog: "automationMod", - listActiveAutomationRules: "automationMod", - saveWorkflow: "automationMod", - getWorkflowRecord: "automationMod", - updateWorkflowExecution: "automationMod", - deleteWorkflow: "automationMod", - listTriggerableWorkflows: "automationMod", - // wakeup - enqueueWakeupRequest: "wakeup", - promoteWakeupRequests: "wakeup", - listWakeupRequests: "wakeup", - getPreferredWakeTrigger: "wakeup", - completePendingWakeupRequests: "wakeup", - purgeExpiredWakeupRequests: "wakeup", - // backupMod - exportBackup: "backupMod", - createAutomaticBackup: "backupMod", - restoreFromBackup: "backupMod", - // threads - createThread: "threads", - listThreads: "threads", - getThread: "threads", - addThreadEvent: "threads", - listThreadEvents: "threads", - setThreadWaitState: "threads", - resolveThreadWaitState: "threads", - listThreadWaitStates: "threads", - hasUnresolvedWaitStateForAgent: "threads", - addParticipant: "threads", - listParticipants: "threads", - removeParticipant: "threads", - subscribe: "threads", - unsubscribe: "threads", - listSubscriptions: "threads", - listSubscribedThreads: "threads", - // settings - getCurrentCompanyId: "settings", - setCurrentCompany: "settings", - hasCompany: "settings", - belongsToCompany: "settings", - updateSettings: "settings", - getLogRetentionDays: "settings", - purgeExpiredRunLogs: "settings", - canOpenPath: "settings", - getDisabledModels: "settings", - setDisabledModels: "settings", - hasModelPoolSettings: "settings", - getLastBudgetResetMonth: "settings", - setLastBudgetResetMonth: "settings", - // snap - listSnapshot: "snap", - listRendererSnapshot: "snap", - // company - saveCompany: "company", - deleteCompany: "company", - getCompanyStatus: "company", - getCompanyBasic: "company", - getCompanyExecutionMode: "company", - getCompanyApprovalSettings: "company", - listActiveCompanyIds: "company", - getCompanyMetrics: "company", - getStandupReport: "company", - getDashboardSnapshot: "company", - // connectorsCrud - saveConnector: "connectorsCrud", - updateConnectorHealth: "connectorsCrud", - getConnector: "connectorsCrud", - findConnector: "connectorsCrud", - // agents (note: getAgent/findAgent live on entityCrud) - saveAgent: "agents", - deleteAgent: "agents", - getAgent: "entityCrud", - findAgent: "entityCrud", - setHeartbeat: "agents", - markHeartbeatAt: "agents", - resetMonthlyBudgets: "agents", - listHeartbeatEligibleAgents: "agents", - getChainOfCommand: "agents", - getDirectReports: "agents", - getCeoForCompany: "agents", - listActiveAgentsForCompany: "agents", - listAgentsForApi: "agents", - listDirectReportsForStandup: "agents", - listReportStatusesForStandup: "agents", - listExistingAgentsForHireCheck: "agents", - hasAgentAssignedTasks: "agents", - updateAgentStatus: "agents", - isAgentPendingApproval: "agents", - findMentionedAgentIds: "agents", - getIdleAgentsForDepartment: "agents", - getManagerForAgent: "agents", - getAgentPermissions: "agents", - setAgentPermission: "agents", - hasAgentPermission: "agents", - getRuntimeState: "agents", - setRuntimeState: "agents", - getHeartbeatPolicy: "agents", - setHeartbeatPolicy: "agents", - countActiveRunsForAgent: "agents", - listDepartmentAgentIds: "agents", - listCompanyBroadcastAgentIds: "agents", - listIncidentPingableAgentIds: "agents", - findAgentName: "agents", - listAgentNamesByIds: "agents", - listActiveAgentIdsFromIds: "agents", - // tasks (note: getTask lives on entityCrud) - saveTask: "tasks", - getTask: "entityCrud", - deleteTask: "tasks", - getSessionById: "tasks", - incrementSessionUsage: "tasks", - archiveSession: "tasks", - createNewSession: "tasks", - ensureAgentSession: "tasks", - setAgentSessionId: "tasks", - getRecentRunsForTask: "tasks", - getRecentActivityForTask: "tasks", - checkoutTask: "tasks", - releaseTaskLock: "tasks", - renewTaskLease: "tasks", - listAgentTasks: "tasks", - listTasksByStatuses: "tasks", - listAssigneeTasksForStandup: "tasks", - listTasksForAssignees: "tasks", - listReviewTasksForManager: "tasks", - countActiveTasksForCompany: "tasks", - countAdvancingTasksForCompany: "tasks", - listChildTasks: "tasks", - advanceTaskStatus: "tasks", - setTaskRequiresUserReview: "tasks", - hasPendingDeliverableReviews: "tasks", - hasAgentPendingDeliverableReview: "tasks", - hasAgentTaskAwaitingReview: "tasks", - autoAssignTask: "tasks", - getTaskRetryCount: "tasks", - incrementTaskRetryCount: "tasks", - resetTaskRetryCount: "tasks", - retryInterruptedTask: "tasks", - dismissInterruptedTask: "tasks", - markInterruptedTaskFailed: "tasks", - setTaskType: "tasks", - listProjectTaskAssigneeIds: "tasks", - listReviewTasksForSweep: "tasks", - getTaskType: "tasks", - // runs - getRun: "runs", - getRunAuthState: "runs", - createRun: "runs", - appendRunLog: "runs", - readRunLog: "runs", - readRunLogChunk: "runs", - markRunStatus: "runs", - finishRun: "runs", - recordCostEntry: "runs", - hasActiveRun: "runs", - listQueuedRuns: "runs", - getInterruptedRunsForRecovery: "runs", - appendRunEvent: "runs", - listRunEvents: "runs", - listRunEventsAfter: "runs", - updateRunActor: "runs", - // approvalsMod - requestApproval: "approvalsMod", - decideApproval: "approvalsMod", - getApprovalRecord: "approvalsMod", - findApprovalById: "approvalsMod", - deleteApproval: "approvalsMod", - getBlockingApproval: "approvalsMod", - resubmitApproval: "approvalsMod", - addApprovalComment: "approvalsMod", - listApprovalComments: "approvalsMod", - linkTaskToApproval: "approvalsMod", - unlinkTaskFromApproval: "approvalsMod", - listApprovalsForTask: "approvalsMod", - listTasksForApproval: "approvalsMod", - linkManyTasksToApproval: "approvalsMod", - listAgentPendingApprovals: "approvalsMod", - listAgentResolvedApprovals: "approvalsMod", - listPendingHireApprovalPayloads: "approvalsMod", - listApprovalsForApi: "approvalsMod", - findPendingApprovalForTask: "approvalsMod", - hasPendingReviewApprovalForAgent: "approvalsMod", - listCompanyApprovalsByType: "approvalsMod", - // workspacesMod - saveWorkspace: "workspacesMod", - getWorkspace: "workspacesMod", - getProjectPrimaryWorkspace: "workspacesMod", - listWorkspaceLocalPaths: "workspacesMod", - deleteWorkspace: "workspacesMod", - acquireWorkspaceLock: "workspacesMod", - claimWorkspaceLock: "workspacesMod", - releaseWorkspaceLock: "workspacesMod", - releaseAllWorkspaceLocks: "workspacesMod", - releaseStaleWorkspaceLocks: "workspacesMod", - isWorkspaceLocked: "workspacesMod", -}; - -const args = process.argv.slice(2); -const dryRun = args.includes("--dry-run"); -const modulesArg = args.find((a) => a.startsWith("--modules=")); -const methodsArg = args.find((a) => a.startsWith("--methods=")); -const includedModules = modulesArg - ? new Set(modulesArg.split("=")[1].split(",")) - : null; -const extraMethods = methodsArg - ? new Set(methodsArg.split("=")[1].split(",")) - : new Set(); - -const targetMethods = Object.entries(METHOD_TO_MODULE) - .filter(([name, mod]) => { - if (!includedModules) return true; - if (includedModules.has(mod)) return true; - if (extraMethods.has(name)) return true; - return false; - }) - .map(([m]) => m); - -if (targetMethods.length === 0) { - console.error("No methods matched module filter."); - process.exit(2); -} - -// Collect files via git ls-files (fast, respects .gitignore) -const filesOut = execSync("git ls-files 'src/**/*.ts' 'src/**/*.tsx' 'tests/**/*.ts'", { - cwd: REPO_ROOT, - encoding: "utf8", -}); -const files = filesOut - .split("\n") - .filter(Boolean) - .filter((f) => !f.startsWith("src/main/database.ts")) - .filter((f) => !f.startsWith("src/main/database-base.ts")) - .filter((f) => !f.startsWith("src/main/database/")); - -// Build one giant alternation regex, non-capturing, then use a back-reference -// group only for the method name so we can look up the module. -const methodAlt = targetMethods - .sort((a, b) => b.length - a.length) // longest-first to avoid partial shadow - .join("|"); - -// Match `db.(`. The qualifier must end with -// a `.` so `adb.saveTask(` (same token) is not matched. Examples that -// DO match: `db.saveTask(`, `this.db.saveTask(`, `shared.db.saveTask(`, -// `ctx.db.saveTask(`. The pre-anchor `(^|[^\w.])` keeps us from -// splitting an identifier token containing `db` somewhere in the middle. -const pattern = new RegExp( - `(^|[^\\w.])((?:[\\w$]+\\.)*)db\\.(${methodAlt})\\(`, - "g", -); - -let totalReplacements = 0; -let changedFiles = 0; -const perFile = {}; - -for (const relPath of files) { - const abs = join(REPO_ROOT, relPath); - const src = readFileSync(abs, "utf8"); - let count = 0; - const out = src.replace(pattern, (match, pre, qualifier, method) => { - const mod = METHOD_TO_MODULE[method]; - if (!mod) return match; - count += 1; - return `${pre}${qualifier}db.${mod}.${method}(`; - }); - if (count > 0) { - perFile[relPath] = count; - totalReplacements += count; - changedFiles += 1; - if (!dryRun) writeFileSync(abs, out); - } -} - -const hdr = dryRun ? "DRY RUN" : "APPLIED"; -console.log(`${hdr}: ${totalReplacements} rewrites across ${changedFiles} files`); -for (const [f, n] of Object.entries(perFile).sort((a, b) => b[1] - a[1])) { - console.log(` ${n}\t${f}`); -} diff --git a/scripts/electron-builder-mac-sign.mjs b/scripts/electron-builder-mac-sign.mjs deleted file mode 100644 index d72b7105..00000000 --- a/scripts/electron-builder-mac-sign.mjs +++ /dev/null @@ -1,132 +0,0 @@ -import { spawn } from "node:child_process"; -import { readdir } from "node:fs/promises"; -import { extname } from "node:path"; - -async function runCommand(command, args, capture = false) { - return await new Promise((resolve, reject) => { - const child = spawn(command, args, { - stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit", - }); - let stdout = ""; - let stderr = ""; - - if (capture) { - child.stdout.on("data", (chunk) => { - stdout += chunk.toString(); - }); - child.stderr.on("data", (chunk) => { - stderr += chunk.toString(); - }); - } - - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve({ stdout, stderr }); - return; - } - reject(new Error(stderr || stdout || `${command} failed with exit code ${code ?? 1}`)); - }); - }); -} - -async function runCodesign(args) { - await runCommand("/usr/bin/codesign", args, false); -} - -function buildCodesignArgs(targetPath, identity, keychain, fileOptions = {}) { - const args = [ - "--sign", identity, - "--force", - ]; - - if (keychain) { - args.push("--keychain", keychain); - } - if (fileOptions.timestamp !== false) { - args.push("--timestamp"); - } - if (fileOptions.hardenedRuntime) { - args.push("--options", "runtime"); - } - if (fileOptions.entitlements) { - args.push("--entitlements", fileOptions.entitlements); - } - if (Array.isArray(fileOptions.additionalArguments) && fileOptions.additionalArguments.length > 0) { - args.push(...fileOptions.additionalArguments); - } - - args.push(targetPath); - return args; -} - -async function isMachBinary(filePath) { - const extension = extname(filePath); - if (extension === ".dylib" || extension === ".node") { - return true; - } - - const { stdout } = await runCommand("/usr/bin/file", ["-b", filePath], true); - return stdout.includes("Mach-O"); -} - -async function collectSignTargets(rootPath) { - const bundleTargets = []; - const binaryTargets = []; - - async function walk(currentPath) { - const entries = await readdir(currentPath, { withFileTypes: true }); - for (const entry of entries) { - const fullPath = `${currentPath}/${entry.name}`; - - if (entry.isSymbolicLink()) { - continue; - } - - if (entry.isDirectory()) { - if ( - entry.name.endsWith(".app") || - entry.name.endsWith(".framework") || - entry.name.endsWith(".xpc") || - entry.name.endsWith(".appex") || - entry.name.endsWith(".plugin") - ) { - bundleTargets.push(fullPath); - } - await walk(fullPath); - continue; - } - - if (await isMachBinary(fullPath)) { - binaryTargets.push(fullPath); - } - } - } - - await walk(rootPath); - - bundleTargets.sort((left, right) => right.length - left.length); - binaryTargets.sort((left, right) => right.length - left.length); - - return { bundleTargets, binaryTargets }; -} - -async function signTarget(targetPath, context) { - const fileOptions = context.optionsForFile?.(targetPath) ?? {}; - const args = buildCodesignArgs(targetPath, context.identity, context.keychain, fileOptions); - await runCodesign(args); -} - -export default async function sign(context) { - const { bundleTargets, binaryTargets } = await collectSignTargets(context.app); - - for (const target of binaryTargets) { - await signTarget(target, context); - } - - for (const target of bundleTargets) { - await signTarget(target, context); - } - - await signTarget(context.app, context); -} diff --git a/AgentCompany-New/scripts/ensure-electron.cjs b/scripts/ensure-electron.cjs similarity index 100% rename from AgentCompany-New/scripts/ensure-electron.cjs rename to scripts/ensure-electron.cjs diff --git a/scripts/generate-landing-release-links.mjs b/scripts/generate-landing-release-links.mjs deleted file mode 100644 index face9b1e..00000000 --- a/scripts/generate-landing-release-links.mjs +++ /dev/null @@ -1,241 +0,0 @@ -import { readdir, writeFile } from "node:fs/promises"; -import { existsSync } from "node:fs"; -import { join } from "node:path"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; - -const rootDir = process.cwd(); -const localReleaseDir = join(rootDir, "local-release"); -const outputPath = join(rootDir, "landing", "components", "release-links.generated.ts"); - -function normalizeBaseUrl(url) { - return url.replace(/\/+$/, ""); -} - -function normalizePathSegment(pathValue) { - return pathValue.replace(/^\/+|\/+$/g, ""); -} - -function resolveUpdateBaseUrl() { - const explicit = process.env.AGENTCOMPANY_UPDATE_URL?.trim(); - if (explicit) return normalizeBaseUrl(explicit); - - const publicBaseUrl = - process.env.AGENTCOMPANY_R2_PUBLIC_URL?.trim() || - process.env.R2_PUBLIC_BASE_URL?.trim(); - const prefix = process.env.AGENTCOMPANY_RELEASE_PREFIX?.trim() || "AC"; - - if (!publicBaseUrl) { - throw new Error("Missing AGENTCOMPANY_UPDATE_URL / R2 public URL while generating landing release links."); - } - - const normalizedBase = normalizeBaseUrl(publicBaseUrl); - const normalizedPrefix = normalizePathSegment(prefix); - return `${normalizedBase}/${normalizedPrefix}`; -} - -function ensureSingle(files, predicate, label) { - const matches = files.filter(predicate); - if (matches.length !== 1) { - throw new Error(`Expected exactly one ${label} artifact, found ${matches.length}: ${matches.join(", ")}`); - } - return matches[0]; -} - -function extractVersion(fileNames) { - const versions = new Set( - fileNames - .map((fileName) => fileName.match(/(\d+\.\d+\.\d+)/)?.[1] ?? null) - .filter(Boolean), - ); - - if (versions.size !== 1) { - throw new Error(`Expected exactly one release version across artifacts, found: ${[...versions].join(", ")}`); - } - - return [...versions][0]; -} - -function urlFor(baseUrl, fileName) { - return `${baseUrl}/${encodeURIComponent(fileName)}`; -} - -async function main() { - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - - if (!existsSync(localReleaseDir)) { - throw new Error(`Local release directory not found: ${localReleaseDir}`); - } - - const baseUrl = resolveUpdateBaseUrl(); - const macFiles = (await readdir(join(localReleaseDir, "mac"))).filter((name) => !name.startsWith(".")); - const winFiles = (await readdir(join(localReleaseDir, "win"))).filter((name) => !name.startsWith(".")); - const linuxFiles = (await readdir(join(localReleaseDir, "linux"))).filter((name) => !name.startsWith(".")); - - const macArm64Dmg = ensureSingle(macFiles, (name) => name.endsWith(".dmg") && name.includes("arm64"), "macOS Apple Silicon .dmg"); - const macIntelDmg = ensureSingle(macFiles, (name) => name.endsWith(".dmg") && !name.includes("arm64"), "macOS Intel .dmg"); - const windowsUniversalInstaller = ensureSingle( - winFiles, - (name) => name.endsWith(".exe") && name.includes("Setup"), - "Windows universal installer", - ); - const linuxX64AppImage = ensureSingle( - linuxFiles, - (name) => name.endsWith(".AppImage") && !name.includes("arm64"), - "Linux x64 AppImage", - ); - const linuxArm64AppImage = ensureSingle( - linuxFiles, - (name) => name.endsWith(".AppImage") && name.includes("arm64"), - "Linux arm64 AppImage", - ); - const linuxX64Deb = ensureSingle( - linuxFiles, - (name) => name.endsWith(".deb") && name.includes("amd64"), - "Linux x64 .deb", - ); - const linuxArm64Deb = ensureSingle( - linuxFiles, - (name) => name.endsWith(".deb") && name.includes("arm64"), - "Linux arm64 .deb", - ); - const linuxX64Rpm = ensureSingle( - linuxFiles, - (name) => name.endsWith(".rpm") && (name.includes("x86_64") || name.includes("amd64")), - "Linux x64 .rpm", - ); - const linuxArm64Rpm = ensureSingle( - linuxFiles, - (name) => name.endsWith(".rpm") && (name.includes("aarch64") || name.includes("arm64")), - "Linux arm64 .rpm", - ); - - const version = extractVersion([ - macArm64Dmg, - macIntelDmg, - windowsUniversalInstaller, - linuxX64AppImage, - linuxArm64AppImage, - linuxX64Deb, - linuxArm64Deb, - linuxX64Rpm, - linuxArm64Rpm, - ]); - - const content = `export type PlatformDownloadAsset = { - architectures: ReleaseArchitecture[]; - id: string; - label: string; - href: string; - note: string; -}; - -export type ReleaseArchitecture = "arm64" | "x64" | "x86"; - -export type PlatformDownload = { - id: "macos" | "windows" | "linux"; - packageDescription: string; - title: string; - note: string; - assets: PlatformDownloadAsset[]; -}; - -export const releaseVersion = "${version}"; - -export const platformDownloads: PlatformDownload[] = [ - { - id: "macos", - packageDescription: "signed and notarized DMG builds", - title: "macOS", - note: "Signed + notarized DMG builds", - assets: [ - { - architectures: ["arm64"], - id: "macos-arm64-dmg", - label: "Apple Silicon DMG", - href: "${urlFor(baseUrl, macArm64Dmg)}", - note: "arm64", - }, - { - architectures: ["x64"], - id: "macos-x64-dmg", - label: "Intel Mac DMG", - href: "${urlFor(baseUrl, macIntelDmg)}", - note: "x64", - }, - ], - }, - { - id: "windows", - packageDescription: "an NSIS installer build", - title: "Windows", - note: "NSIS installer builds", - assets: [ - { - architectures: ["arm64", "x64"], - id: "windows-universal-installer", - label: "Windows Universal Installer", - href: "${urlFor(baseUrl, windowsUniversalInstaller)}", - note: "arm64 + x64", - }, - ], - }, - { - id: "linux", - packageDescription: "AppImage, DEB, and RPM builds", - title: "Linux", - note: "AppImage, DEB, and RPM builds", - assets: [ - { - architectures: ["x64"], - id: "linux-x64-appimage", - label: "Linux x64 AppImage", - href: "${urlFor(baseUrl, linuxX64AppImage)}", - note: "x64", - }, - { - architectures: ["x64"], - id: "linux-x64-deb", - label: "Linux x64 DEB", - href: "${urlFor(baseUrl, linuxX64Deb)}", - note: "x64", - }, - { - architectures: ["x64"], - id: "linux-x64-rpm", - label: "Linux x64 RPM", - href: "${urlFor(baseUrl, linuxX64Rpm)}", - note: "x64", - }, - { - architectures: ["arm64"], - id: "linux-arm64-appimage", - label: "Linux ARM64 AppImage", - href: "${urlFor(baseUrl, linuxArm64AppImage)}", - note: "arm64", - }, - { - architectures: ["arm64"], - id: "linux-arm64-deb", - label: "Linux ARM64 DEB", - href: "${urlFor(baseUrl, linuxArm64Deb)}", - note: "arm64", - }, - { - architectures: ["arm64"], - id: "linux-arm64-rpm", - label: "Linux ARM64 RPM", - href: "${urlFor(baseUrl, linuxArm64Rpm)}", - note: "arm64", - }, - ], - }, -]; -`; - - await writeFile(outputPath, content, "utf8"); - console.log(`[generate-landing-release-links] wrote ${outputPath}`); - console.log(`[generate-landing-release-links] version ${version}`); -} - -await main(); diff --git a/scripts/icons/generate-icons.py b/scripts/icons/generate-icons.py deleted file mode 100644 index 6e5c4702..00000000 --- a/scripts/icons/generate-icons.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python3 -"""Generate AgentCompany icons from SVG sources using cairosvg. - -Two icon families: - - Web (circle bg): icon.svg → landing favicon + website logo - - App (square bg): icon-app.svg → Electron app icon (Apple HIG, OS applies mask) - - Tray: rendered from logo.svg for menu bar / notification area -""" - -from __future__ import annotations - -import io -import os -import shutil -import subprocess -import sys -from pathlib import Path - -# ── macOS-only build helper (uses iconutil and Homebrew cairo) ──────── -if sys.platform != "darwin": - sys.exit( - "generate-icons.py is a macOS-only build helper (requires iconutil + " - "Homebrew cairo). Icons are pre-generated and committed under assets/." - ) - -# ── Ensure cairo library is discoverable on macOS (Homebrew) ────────── -for _lib_dir in ("/opt/homebrew/opt/cairo/lib", "/usr/local/opt/cairo/lib"): - if Path(_lib_dir).exists(): - os.environ["DYLD_LIBRARY_PATH"] = ( - _lib_dir + ":" + os.environ.get("DYLD_LIBRARY_PATH", "") - ) - break - -import cairosvg # noqa: E402 — must come after DYLD_LIBRARY_PATH setup -from PIL import Image # noqa: E402 - -ROOT = Path(__file__).resolve().parents[2] -ASSETS = ROOT / "assets" -LANDING = ROOT / "landing" / "public" -ICONSET = ASSETS / "icon.iconset" -LOGO_SVG = ROOT / "logo.svg" - -# SVG sources -WEB_SVG = ASSETS / "icon.svg" # circle bg — web favicon -APP_SVG = ASSETS / "icon-app.svg" # square bg — Electron (Apple HIG) - -SIZE = 1024 - - -# ── Helpers ─────────────────────────────────────────────────────────── - -def svg_to_image(svg_path: Path, width: int, height: int | None = None) -> Image.Image: - """Render an SVG to a Pillow RGBA Image at the given size.""" - h = height or width - png_data = cairosvg.svg2png( - url=str(svg_path), output_width=width, output_height=h, - ) - return Image.open(io.BytesIO(png_data)).convert("RGBA") - - -def svg_bytes_to_image(svg_bytes: bytes, width: int, height: int | None = None) -> Image.Image: - """Render SVG bytes to a Pillow RGBA Image.""" - h = height or width - png_data = cairosvg.svg2png( - bytestring=svg_bytes, output_width=width, output_height=h, - ) - return Image.open(io.BytesIO(png_data)).convert("RGBA") - - -# ── Web icons (circle background) ──────────────────────────────────── - -def generate_web_icons() -> None: - """Generate favicon.ico and icon.png for the landing site (circle bg).""" - print("Generating web icons from icon.svg (circle bg)…") - master = svg_to_image(WEB_SVG, SIZE) - - # PNG for apple-touch-icon / og - web_png = LANDING / "icon.png" - master.save(web_png, format="PNG") - print(f" → {web_png}") - - # Copy SVG to landing - shutil.copy2(WEB_SVG, LANDING / "icon.svg") - print(f" → {LANDING / 'icon.svg'}") - - # ICO with multiple sizes for favicon - favicon = LANDING / "favicon.ico" - master.save( - favicon, format="ICO", - sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)], - ) - print(f" → {favicon}") - - -# ── App icons (square background, Apple HIG) ───────────────────────── - -def generate_app_icons() -> None: - """Generate Electron app icons: PNG, ICO, ICNS (square bg, Apple HIG).""" - print("Generating app icons from icon-app.svg (square bg, Apple HIG)…") - master = svg_to_image(APP_SVG, SIZE) - - # Main PNG - png_path = ASSETS / "icon.png" - master.save(png_path, format="PNG") - print(f" → {png_path}") - - # Windows ICO - ico_path = ASSETS / "icon.ico" - master.save( - ico_path, format="ICO", - sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)], - ) - print(f" → {ico_path}") - - # macOS ICNS via iconutil - generate_icns(master) - - -def generate_icns(master: Image.Image) -> None: - """Generate .icns from a master image using macOS iconutil.""" - if ICONSET.exists(): - shutil.rmtree(ICONSET) - ICONSET.mkdir(parents=True, exist_ok=True) - - for size in (16, 32, 64, 128, 256, 512): - master.resize((size, size), Image.Resampling.LANCZOS).save( - ICONSET / f"icon_{size}x{size}.png", format="PNG", - ) - master.resize((size * 2, size * 2), Image.Resampling.LANCZOS).save( - ICONSET / f"icon_{size}x{size}@2x.png", format="PNG", - ) - - icns_path = ASSETS / "icon.icns" - subprocess.run( - ["iconutil", "-c", "icns", str(ICONSET), "-o", str(icns_path)], - check=True, - ) - shutil.rmtree(ICONSET) - print(f" → {icns_path}") - - -# ── Tray / notification area icons ─────────────────────────────────── - -def generate_tray_icons() -> None: - """Generate tray icons following Apple HIG for menu bar. - - - Color (Windows/Linux): square bg with logo, 32×32 and 64×64 - - Template (macOS): monochrome black logo on transparent, 22×22 and 44×44 - """ - print("Generating tray icons…") - - # Color tray icons — render app icon (square bg) at small sizes - for name, size in [("tray-icon.png", 32), ("tray-icon@2x.png", 64)]: - img = svg_to_image(APP_SVG, size) - img.save(ASSETS / name, format="PNG") - print(f" → {ASSETS / name}") - - # macOS template icons — black logo silhouette on transparent - # Read logo.svg paths, render as black on transparent - logo_svg = LOGO_SVG.read_text() - - for name, size in [("tray-iconTemplate.png", 22), ("tray-iconTemplate@2x.png", 44)]: - # Create SVG with black fill, sized to target - template_svg = _make_template_svg(logo_svg, size) - img = svg_bytes_to_image(template_svg.encode("utf-8"), size) - img.save(ASSETS / name, format="PNG") - print(f" → {ASSETS / name}") - - -def _make_template_svg(logo_svg_content: str, target_size: int) -> str: - """Create a macOS template SVG: black logo silhouette on transparent bg.""" - # Logo viewBox is 0 0 122 126 — scale to fit target with padding - padding = max(2, int(target_size * 0.1)) - available = target_size - 2 * padding - # Scale to fit height (taller dimension) - scale = available / 126 - logo_w = 122 * scale - # Center horizontally - offset_x = (target_size - logo_w) / 2 - offset_y = padding - - return f""" - - - - -""" - - -# ── Main ────────────────────────────────────────────────────────────── - -def main() -> None: - ASSETS.mkdir(parents=True, exist_ok=True) - LANDING.mkdir(parents=True, exist_ok=True) - - generate_web_icons() - generate_app_icons() - generate_tray_icons() - - print("\nDone! All icons generated.") - - -if __name__ == "__main__": - main() diff --git a/scripts/patch-electron-name.sh b/scripts/patch-electron-name.sh deleted file mode 100755 index 68be43dc..00000000 --- a/scripts/patch-electron-name.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# Patch the Electron.app bundle name so macOS shows "AgentCompany" -# in the dock and menu bar during development. -# This runs as a postinstall hook and is safe to re-run. - -set -euo pipefail - -APP_NAME="AgentCompany" - -# Find the Electron.app Info.plist (works with pnpm hoisted or nested) -PLIST=$(find node_modules -path "*/electron/dist/Electron.app/Contents/Info.plist" -maxdepth 8 2>/dev/null | head -1) - -if [ -z "$PLIST" ]; then - echo "[patch-electron-name] Electron.app not found, skipping." - exit 0 -fi - -# Also find helper plists -HELPERS_DIR=$(dirname "$PLIST")/../Frameworks -MAIN_PLIST="$PLIST" - -echo "[patch-electron-name] Patching $MAIN_PLIST" -/usr/libexec/PlistBuddy -c "Set :CFBundleName $APP_NAME" "$MAIN_PLIST" 2>/dev/null || true -/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $APP_NAME" "$MAIN_PLIST" 2>/dev/null || true - -# Patch helper apps too (they show in Activity Monitor) -for HELPER in "$HELPERS_DIR"/Electron\ Helper*.app/Contents/Info.plist; do - if [ -f "$HELPER" ]; then - HELPER_NAME=$(basename "$(dirname "$(dirname "$HELPER")")" .app | sed "s/Electron Helper/$APP_NAME Helper/") - /usr/libexec/PlistBuddy -c "Set :CFBundleName $HELPER_NAME" "$HELPER" 2>/dev/null || true - fi -done - -echo "[patch-electron-name] Done — dock and menu bar will show \"$APP_NAME\"." diff --git a/scripts/postinstall.mjs b/scripts/postinstall.mjs deleted file mode 100644 index 826fb808..00000000 --- a/scripts/postinstall.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import { existsSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { spawnSync } from "node:child_process"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const patchScriptPath = join(__dirname, "patch-electron-name.sh"); - -if (process.platform !== "darwin") { - console.log("[postinstall] Skipping macOS Electron plist patch on non-darwin host."); - process.exit(0); -} - -if (!existsSync(patchScriptPath)) { - console.log("[postinstall] No Electron name patch script found."); - process.exit(0); -} - -const result = spawnSync("bash", [patchScriptPath], { - cwd: dirname(__dirname), - stdio: "inherit", -}); - -if (result.error) { - console.error(`[postinstall] Electron name patch failed: ${result.error.message}`); - process.exit(1); -} - -if ((result.status ?? 0) !== 0) { - console.error(`[postinstall] Electron name patch exited with status ${result.status}.`); - process.exit(result.status ?? 1); -} - -process.exit(0); diff --git a/scripts/release-boss.mjs b/scripts/release-boss.mjs deleted file mode 100644 index 229e051b..00000000 --- a/scripts/release-boss.mjs +++ /dev/null @@ -1,246 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile, mkdir, cp, readdir } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; -import { createRunner } from "./release/lib/process.mjs"; -import { createWorkflowHelpers } from "./release/lib/workflow.mjs"; -import { createSnapshotHelpers } from "./release/lib/snapshot.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const packageJsonPath = join(rootDir, "package.json"); -const bossOutDir = join(rootDir, "boss-build", "build", "out"); -const remoteBossWorkflowFile = ".github/workflows/remote-boss-platforms.yml"; -const remoteBossWorkflowName = "remote-boss-platforms.yml"; -const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/; -const syncExcludes = [ - ".git", - "node_modules/", - ".pnpm-store/", - "build/", - "local-release/", - "out/", - ".omx/", - ".omc/", - ".claude/", - "landing/.next/", - "landing/out/", - "landing/node_modules/", - ".DS_Store", - ".env.release.local", - "CertificateSigningRequest.certSigningRequest", - "Certificates.p12", - "developerID_application.cer", -]; -const bossSnapshotIncludes = [ - remoteBossWorkflowFile, - "boss-build/boss-runtime.json", - "boss-build/build-boss-edition.mjs", - "boss-build/electron-builder-boss.yml", -]; - -const run = createRunner(rootDir); -const { - getGitHubHttpAuthHeader, - getRepoInfo, - assertRemoteWorkflowExists, - waitForWorkflowRun, - waitForWorkflowCompletion, - downloadRemoteAssets, - cleanupRemoteTransportRelease, -} = createWorkflowHelpers(run); -const { - createSnapshotBranch, - cleanupRemoteBranch, - cleanupLocalWorktree, -} = createSnapshotHelpers(run, getGitHubHttpAuthHeader); - -function parseArgs(argv) { - const options = { - version: null, - deleteRemoteBranch: false, - keepTransportRelease: false, - }; - - for (const arg of argv) { - if (arg.startsWith("--version=")) { - options.version = arg.slice("--version=".length).trim(); - continue; - } - if (arg === "--delete-remote-branch") { - options.deleteRemoteBranch = true; - continue; - } - if (arg === "--keep-transport-release") { - options.keepTransportRelease = true; - continue; - } - if (arg === "--help") { - printHelp(); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - - return options; -} - -function printHelp() { - console.log(`Usage: node scripts/release-boss.mjs [options] - -Options: - --version=x.y.z Explicit version. Defaults to current package version. - --delete-remote-branch Delete the GitHub snapshot branch after success. - --keep-transport-release Keep the temporary draft GitHub release after success. - --help Show this help. -`); -} - -async function readPackageJson() { - return JSON.parse(await readFile(packageJsonPath, "utf8")); -} - -async function forceStageBossSnapshotFiles(tempDir) { - const stagedPaths = bossSnapshotIncludes - .filter((relativePath) => existsSync(join(tempDir, relativePath))); - - if (stagedPaths.length === 0) { - throw new Error("Boss snapshot is missing required boss-build source files after syncing the workspace."); - } - - await run("git", ["-C", tempDir, "add", "--force", ...stagedPaths]); -} - -async function ensureRemoteBuildPrerequisites(repo) { - if (process.platform !== "darwin") { - throw new Error("Boss release currently expects to run on macOS for the local Boss DMG build."); - } - if (!existsSync(join(rootDir, remoteBossWorkflowFile))) { - throw new Error(`Required workflow file missing locally: ${remoteBossWorkflowFile}`); - } - await assertRemoteWorkflowExists( - repo, - remoteBossWorkflowFile, - `Remote workflow ${remoteBossWorkflowFile} was not found on ${repo.defaultBranch}. ` + - "Commit and push this Boss automation workflow before using scripts/release-boss.mjs.", - ); - await run("gh", ["auth", "status"], { capture: true }); -} - -function buildSnapshotCommitMessage(version) { - return [ - `Package Boss build ${version} from the current workspace snapshot`, - "", - "Constraint: Boss Windows artifacts are built on a native GitHub runner from a temporary snapshot branch", - "Rejected: Build Boss Windows locally on Apple Silicon | docker/wine packaging is not stable on this host", - "Confidence: medium", - "Scope-risk: narrow", - "Directive: This snapshot branch is transport-only and should be deleted after the Boss build is recovered locally", - "Tested: local Boss mac build stages before snapshot creation", - "Not-tested: remote Boss Windows packaging before workflow execution", - ].join("\n"); -} - -async function dispatchRemoteBossWorkflow(repo, branchName, version, releaseTag, releaseTitle) { - await run("gh", [ - "workflow", - "run", - remoteBossWorkflowName, - "--repo", - repo.nameWithOwner, - "--ref", - branchName, - "-f", - `version=${version}`, - "-f", - `release_tag=${releaseTag}`, - "-f", - `release_title=${releaseTitle}`, - ]); -} - -async function stageBossRemoteAssets(downloadRoot) { - await mkdir(bossOutDir, { recursive: true }); - const files = await readdir(downloadRoot); - for (const fileName of files) { - if (fileName.endsWith(".exe") || fileName.endsWith(".blockmap")) { - await cp(join(downloadRoot, fileName), join(bossOutDir, fileName)); - } - } -} - -async function buildBossMac(version) { - await run("node", ["boss-build/build-boss-edition.mjs", `--platform=mac`, `--version=${version}`]); -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - - const repo = await getRepoInfo(); - await ensureRemoteBuildPrerequisites(repo); - await run("pnpm", ["audit:deps"]); - - const currentVersion = (await readPackageJson()).version; - const nextVersion = options.version ?? currentVersion; - if (!versionPattern.test(nextVersion)) { - throw new Error(`Invalid version: ${nextVersion}`); - } - - const timestamp = Date.now(); - const releaseTag = `boss-transport-${nextVersion}-${timestamp}`; - const branchName = `boss-build-${nextVersion.replace(/\./g, "-")}-${timestamp}`; - const releaseTitle = `Boss Release ${nextVersion}`; - - const tempDir = await createSnapshotBranch({ - repo, - branchName, - rootDir, - syncExcludes, - commitMessage: buildSnapshotCommitMessage(nextVersion), - afterRsync: forceStageBossSnapshotFiles, - }); - let cleanupPending = true; - - try { - await dispatchRemoteBossWorkflow(repo, branchName, nextVersion, releaseTag, releaseTitle); - await buildBossMac(nextVersion); - const runSummary = await waitForWorkflowRun(repo, remoteBossWorkflowName, branchName, 60_000); - const runInfo = await waitForWorkflowCompletion(repo, runSummary.databaseId, 30 * 60 * 1000); - if (runInfo.conclusion !== "success") { - throw new Error(`Boss remote workflow failed: ${runInfo.url}`); - } - const downloadRoot = await downloadRemoteAssets(repo, releaseTag); - await mkdir(bossOutDir, { recursive: true }); - await stageBossRemoteAssets(downloadRoot); - - if (!options.keepTransportRelease) { - await cleanupRemoteTransportRelease(repo, releaseTag); - } - if (options.deleteRemoteBranch) { - await cleanupRemoteBranch(repo, branchName); - } - await cleanupLocalWorktree(tempDir); - cleanupPending = false; - - console.log(JSON.stringify({ - version: nextVersion, - remoteBranch: branchName, - remoteWorkflowRun: runInfo.url, - bossOutDir, - releaseTag, - }, null, 2)); - } finally { - if (cleanupPending) { - try { - await cleanupLocalWorktree(tempDir); - } catch { - // no-op during best-effort temp cleanup - } - } - } -} - -await main(); diff --git a/scripts/release-local-mac.mjs b/scripts/release-local-mac.mjs deleted file mode 100644 index e1cf97af..00000000 --- a/scripts/release-local-mac.mjs +++ /dev/null @@ -1,200 +0,0 @@ -import { spawn } from "node:child_process"; -import { readFile, writeFile, mkdir, rm, readdir } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { prepareR2ReleaseHost, purgeReleasePrefix, uploadReleaseFiles } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const packageJsonPath = join(rootDir, "package.json"); -const buildReleaseDir = join(rootDir, "build", "release"); -const localReleaseDir = join(rootDir, "local-release"); -const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/; - -function parseArgs(argv) { - const options = { version: null, skipBoss: false, bump: true }; - for (const arg of argv) { - if (arg.startsWith("--version=")) { - options.version = arg.slice("--version=".length).trim(); - options.bump = false; - continue; - } - if (arg === "--no-bump") { - options.bump = false; - continue; - } - if (arg === "--skip-boss") { - options.skipBoss = true; - continue; - } - if (arg === "--help") { - console.log(`Usage: node scripts/release-local-mac.mjs [options] - -Options: - --version=x.y.z Explicit version (disables auto-bump). - --no-bump Use current package.json version without bumping. - --skip-boss Build public Mac only; skip Boss DMG. - --help Show this help. -`); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - return options; -} - -async function readPackageJson() { - return JSON.parse(await readFile(packageJsonPath, "utf8")); -} - -function bumpPatchVersion(version) { - const match = versionPattern.exec(version); - if (!match) throw new Error(`Unsupported package version format: ${version}`); - const [, major, minor, patch] = match; - return `${major}.${minor}.${Number.parseInt(patch, 10) + 1}`; -} - -async function updatePackageVersion(nextVersion) { - const pkg = await readPackageJson(); - pkg.version = nextVersion; - await writeFile(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8"); -} - -function hasMacSigningCredential() { - return Boolean(process.env.CSC_LINK?.trim() || process.env.CSC_NAME?.trim()); -} - -function hasMacNotarizationCredential() { - return Boolean( - (process.env.APPLE_ID?.trim() && - process.env.APPLE_APP_SPECIFIC_PASSWORD?.trim() && - process.env.APPLE_TEAM_ID?.trim()) || - (process.env.APPLE_API_KEY?.trim() && - process.env.APPLE_API_KEY_ID?.trim() && - process.env.APPLE_API_ISSUER?.trim()), - ); -} - -function validatePreflight() { - if (process.platform !== "darwin") { - throw new Error("release:local-mac must run on macOS for signed Mac builds."); - } - if (!hasMacSigningCredential() || !hasMacNotarizationCredential()) { - throw new Error( - "Missing Mac signing/notarization credentials. Set CSC_LINK (or CSC_NAME) and " + - "APPLE_ID/APPLE_APP_SPECIFIC_PASSWORD/APPLE_TEAM_ID or the APPLE_API_KEY trio.", - ); - } -} - -async function run(command, args, env = process.env) { - await new Promise((resolve, reject) => { - const child = spawn(command, args, { - cwd: rootDir, - env, - stdio: "inherit", - shell: process.platform === "win32", - }); - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve(); - return; - } - reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); -} - -async function buildPublicMac() { - const env = { - ...process.env, - AGENTCOMPANY_ELECTRON_PUBLISH: "never", - AGENTCOMPANY_ENABLE_LOCAL_DMG: "true", - CSC_IDENTITY_AUTO_DISCOVERY: "true", - }; - await run("pnpm", ["exec", "electron-vite", "build"], env); - await run("node", ["scripts/build-desktop.mjs", "--mac", "--arm64", "--x64"], env); -} - -async function stageMac() { - const destination = join(localReleaseDir, "mac"); - await rm(destination, { recursive: true, force: true }); - await mkdir(localReleaseDir, { recursive: true }); - await run("cp", ["-R", buildReleaseDir, destination]); - console.log(`[release-local-mac] staged mac artifacts in ${destination}`); - return destination; -} - -async function buildBossMac(version) { - await run("node", ["boss-build/build-boss-edition.mjs", `--platform=mac`, `--version=${version}`]); -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - process.env.AGENTCOMPANY_ELECTRON_PUBLISH = "never"; - - validatePreflight(); - await run("pnpm", ["audit:deps"]); - - const currentVersion = (await readPackageJson()).version; - const nextVersion = options.version ?? (options.bump ? bumpPatchVersion(currentVersion) : currentVersion); - if (!versionPattern.test(nextVersion)) throw new Error(`Invalid version: ${nextVersion}`); - if (nextVersion !== currentVersion) await updatePackageVersion(nextVersion); - - await rm(localReleaseDir, { recursive: true, force: true }); - await rm(buildReleaseDir, { recursive: true, force: true }); - - const r2 = await prepareR2ReleaseHost({ rootDir }); - console.log(`[release-local-mac] update URL: ${process.env.AGENTCOMPANY_UPDATE_URL}`); - console.log(`[release-local-mac] version: ${nextVersion}`); - - // Purge only Mac artifacts — Win/Linux (from the Windows release script) stay put. - await purgeReleasePrefix({ - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - keep: ["win", "linux", "other"], - }); - - await buildPublicMac(); - await stageMac(); - await uploadReleaseFiles({ - rootDir, - releaseDir: buildReleaseDir, - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - - if (!options.skipBoss) { - await buildBossMac(nextVersion); - } - - await mkdir(localReleaseDir, { recursive: true }); - await writeFile( - join(localReleaseDir, "manifest.json"), - JSON.stringify({ - generatedAt: new Date().toISOString(), - command: "release:local-mac", - version: nextVersion, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - }, null, 2), - "utf8", - ); - - const bossFiles = options.skipBoss - ? [] - : (await readdir(join(rootDir, "boss-build", "build", "out")).catch(() => [])) - .filter((name) => name.endsWith(".dmg") || name.endsWith(".zip")); - - console.log(JSON.stringify({ - version: nextVersion, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - macStagedIn: join(localReleaseDir, "mac"), - bossArtifacts: bossFiles, - }, null, 2)); -} - -await main(); diff --git a/scripts/release-local-winlinux.mjs b/scripts/release-local-winlinux.mjs deleted file mode 100644 index 0a50a960..00000000 --- a/scripts/release-local-winlinux.mjs +++ /dev/null @@ -1,223 +0,0 @@ -import { spawn } from "node:child_process"; -import { readFile, writeFile, mkdir, rm, readdir } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { prepareR2ReleaseHost, purgeReleasePrefix, uploadReleaseFiles } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const packageJsonPath = join(rootDir, "package.json"); -const buildReleaseDir = join(rootDir, "build", "release"); -const localReleaseDir = join(rootDir, "local-release"); -const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/; - -function parseArgs(argv) { - const options = { version: null, skipBoss: false, only: null }; - for (const arg of argv) { - if (arg.startsWith("--version=")) { - options.version = arg.slice("--version=".length).trim(); - continue; - } - if (arg === "--skip-boss") { - options.skipBoss = true; - continue; - } - if (arg === "--win-only") { - options.only = "win"; - continue; - } - if (arg === "--linux-only") { - options.only = "linux"; - continue; - } - if (arg === "--help") { - console.log(`Usage: node scripts/release-local-winlinux.mjs [options] - -Options: - --version=x.y.z Override version (defaults to current package.json). - --win-only Build and upload Windows only. - --linux-only Build and upload Linux only. - --skip-boss Skip Boss Windows EXE build. - --help Show this help. - -Environment: - On Windows host: Windows builds run natively via electron-builder. - On any host: Linux builds run through Docker + electronuserland/builder image. -`); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - return options; -} - -async function readPackageJson() { - return JSON.parse(await readFile(packageJsonPath, "utf8")); -} - -async function run(command, args, env = process.env) { - await new Promise((resolve, reject) => { - const child = spawn(command, args, { - cwd: rootDir, - env, - stdio: "inherit", - shell: process.platform === "win32", - }); - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve(); - return; - } - reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); -} - -function hasDockerInstalled() { - return new Promise((resolve) => { - const child = spawn("docker", ["--version"], { stdio: "ignore" }); - child.on("error", () => resolve(false)); - child.on("close", (code) => resolve(code === 0)); - }); -} - -async function buildPublicWinNative() { - const env = { - ...process.env, - AGENTCOMPANY_ELECTRON_PUBLISH: "never", - CSC_LINK: process.env.WIN_CSC_LINK ?? "", - CSC_KEY_PASSWORD: process.env.WIN_CSC_KEY_PASSWORD ?? "", - }; - await run("pnpm", ["exec", "electron-vite", "build"], env); - await run("node", ["scripts/build-desktop.mjs", "--win", "nsis", "--x64"], env); - await run("node", ["scripts/build-desktop.mjs", "--win", "nsis", "--arm64"], env); -} - -async function buildPublicLinuxDocker() { - if (!(await hasDockerInstalled())) { - throw new Error("Docker is required for Linux builds. Install Docker Desktop and retry."); - } - // Reuse the existing Docker-based Linux build path from release-local.mjs by - // shelling into it with --platforms=linux --no-upload. That keeps one source - // of truth for the container mounts. - await run("node", [ - "scripts/release-local.mjs", - "--platforms=linux", - "--no-upload", - "--skip-verify", - ]); -} - -async function stage(platform) { - const destination = join(localReleaseDir, platform); - await rm(destination, { recursive: true, force: true }); - await mkdir(localReleaseDir, { recursive: true }); - await run(process.platform === "win32" ? "xcopy" : "cp", process.platform === "win32" - ? [buildReleaseDir, destination, "/E", "/I", "/Y"] - : ["-R", buildReleaseDir, destination]); - console.log(`[release-local-winlinux] staged ${platform} artifacts in ${destination}`); - return destination; -} - -async function buildBossWin(version) { - if (process.platform !== "win32") { - throw new Error("Boss Windows EXE build must run on Windows (electron-builder --win native)."); - } - await run("node", ["boss-build/build-boss-edition.mjs", `--platform=win`, `--version=${version}`]); -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - process.env.AGENTCOMPANY_ELECTRON_PUBLISH = "never"; - - const pkgVersion = (await readPackageJson()).version; - const nextVersion = options.version ?? pkgVersion; - if (!versionPattern.test(nextVersion)) throw new Error(`Invalid version: ${nextVersion}`); - if (nextVersion !== pkgVersion) { - console.log(`[release-local-winlinux] version override: ${pkgVersion} -> ${nextVersion}`); - } - await run("pnpm", ["audit:deps"]); - - await rm(localReleaseDir, { recursive: true, force: true }); - await rm(buildReleaseDir, { recursive: true, force: true }); - - const r2 = await prepareR2ReleaseHost({ rootDir }); - console.log(`[release-local-winlinux] update URL: ${process.env.AGENTCOMPANY_UPDATE_URL}`); - console.log(`[release-local-winlinux] version: ${nextVersion}`); - - // Purge only Win+Linux artifacts — Mac files (owned by release-local-mac) stay put. - const keepClasses = options.only === "win" - ? ["mac", "linux", "other"] - : options.only === "linux" - ? ["mac", "win", "other"] - : ["mac", "other"]; - await purgeReleasePrefix({ - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - keep: keepClasses, - }); - - if (options.only !== "linux") { - if (process.platform !== "win32") { - throw new Error( - "release:local-winlinux Windows builds must run on a Windows host. " + - "Use --linux-only on non-Windows machines, or run the full command on the Windows box.", - ); - } - await buildPublicWinNative(); - await stage("win"); - await uploadReleaseFiles({ - rootDir, - releaseDir: join(localReleaseDir, "win"), - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - } - - if (options.only !== "win") { - await buildPublicLinuxDocker(); - // release-local.mjs already staged into local-release/linux when it ran. - // Upload from there so we do not wipe the staged tree. - await uploadReleaseFiles({ - rootDir, - releaseDir: join(localReleaseDir, "linux"), - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - } - - if (!options.skipBoss && options.only !== "linux" && process.platform === "win32") { - await buildBossWin(nextVersion); - } - - await mkdir(localReleaseDir, { recursive: true }); - await writeFile( - join(localReleaseDir, "manifest.json"), - JSON.stringify({ - generatedAt: new Date().toISOString(), - command: "release:local-winlinux", - version: nextVersion, - only: options.only, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - }, null, 2), - "utf8", - ); - - const bossFiles = options.skipBoss || process.platform !== "win32" - ? [] - : (await readdir(join(rootDir, "boss-build", "build", "out")).catch(() => [])) - .filter((name) => name.endsWith(".exe")); - - console.log(JSON.stringify({ - version: nextVersion, - only: options.only, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - bossArtifacts: bossFiles, - }, null, 2)); -} - -await main(); diff --git a/scripts/release-local.mjs b/scripts/release-local.mjs deleted file mode 100644 index 0d231cab..00000000 --- a/scripts/release-local.mjs +++ /dev/null @@ -1,306 +0,0 @@ -import { spawn } from "node:child_process"; -import { createHash } from "node:crypto"; -import { cp, mkdir, rm, writeFile } from "node:fs/promises"; -import os from "node:os"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { prepareR2ReleaseHost, uploadReleaseFiles } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const buildReleaseDir = join(rootDir, "build", "release"); -const localReleaseDir = join(rootDir, "local-release"); -const pnpmVersion = "10.24.0"; -const checkoutHash = createHash("sha1").update(rootDir).digest("hex").slice(0, 10); -const dockerNodeModulesVolume = `agentcompany-node-modules-${checkoutHash}`; - -function parseArgs(argv) { - const options = { - skipVerify: false, - upload: true, - platforms: ["mac", "win", "linux"], - }; - for (const arg of argv) { - if (arg === "--skip-verify") { - options.skipVerify = true; - continue; - } - if (arg === "--no-upload") { - options.upload = false; - continue; - } - if (arg.startsWith("--platforms=")) { - options.platforms = arg.slice("--platforms=".length) - .split(",") - .map((platform) => platform.trim()) - .filter(Boolean); - continue; - } - if (arg === "--help") { - printHelp(); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - return options; -} - -function printHelp() { - console.log(`Usage: node scripts/release-local.mjs [options] - -Options: - --platforms=mac,win,linux Comma-separated platform list (default: all) - --skip-verify Skip dependency audit and pnpm verify before release builds - --no-upload Build artifacts locally without publishing - --help Show this help - -Environment loading: - - .env.release - - .env.release.local - - existing shell environment (takes precedence) -`); -} - -function hasDockerInstalled() { - return spawnAndAwaitExitCode("docker", ["--version"]); -} - -function spawnAndAwaitExitCode(command, args) { - return new Promise((resolve) => { - const child = spawn(command, args, { stdio: "ignore" }); - child.on("error", () => resolve(false)); - child.on("close", (code) => resolve(code === 0)); - }); -} - -function hasMacSigningCredential() { - return Boolean(process.env.CSC_LINK?.trim() || process.env.CSC_NAME?.trim()); -} - -function hasMacNotarizationCredential() { - return Boolean( - (process.env.APPLE_ID?.trim() && - process.env.APPLE_APP_SPECIFIC_PASSWORD?.trim() && - process.env.APPLE_TEAM_ID?.trim()) || - (process.env.APPLE_API_KEY?.trim() && - process.env.APPLE_API_KEY_ID?.trim() && - process.env.APPLE_API_ISSUER?.trim()), - ); -} - -async function validatePreflight(platforms, upload) { - if (platforms.includes("mac") && process.platform !== "darwin") { - throw new Error("Signed macOS release builds must run on macOS."); - } - if (platforms.includes("mac") && (!hasMacSigningCredential() || !hasMacNotarizationCredential())) { - throw new Error( - "Signed macOS release requires signing credentials (CSC_LINK or CSC_NAME) and notarization credentials " + - "(APPLE_ID/APPLE_APP_SPECIFIC_PASSWORD/APPLE_TEAM_ID or APPLE_API_KEY trio).", - ); - } - if ((platforms.includes("win") || platforms.includes("linux")) && !(await hasDockerInstalled())) { - throw new Error("Docker is required to build Windows/Linux locally from this macOS host."); - } - if (!upload) { - return; - } -} - -async function run(command, args, env = process.env) { - await new Promise((resolve, reject) => { - const child = spawn(command, args, { - cwd: rootDir, - env, - stdio: "inherit", - shell: process.platform === "win32", - }); - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve(); - return; - } - reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); -} - -async function stageRelease(platform) { - const destination = join(localReleaseDir, platform); - await rm(destination, { recursive: true, force: true }); - await mkdir(localReleaseDir, { recursive: true }); - await cp(buildReleaseDir, destination, { recursive: true }); - console.log(`[release-local] staged ${platform} artifacts in ${destination}`); -} - -function makeDockerEnv(platform) { - const env = { - AGENTCOMPANY_ELECTRON_PUBLISH: "never", - AGENTCOMPANY_UPDATE_URL: process.env.AGENTCOMPANY_UPDATE_URL ?? "", - AGENTCOMPANY_ELECTRON_DIST: "/root/.cache/electron", - }; - if (platform === "win") { - env.CSC_LINK = process.env.WIN_CSC_LINK ?? ""; - env.CSC_KEY_PASSWORD = process.env.WIN_CSC_KEY_PASSWORD ?? ""; - } - return env; -} - -function getDockerBuildCommands(platform) { - if (platform === "win") { - return [ - "node scripts/build-desktop.mjs --win nsis --x64", - "node scripts/build-desktop.mjs --win nsis --arm64", - ]; - } - return [ - "node scripts/build-desktop.mjs --linux AppImage deb rpm --x64", - "node scripts/build-desktop.mjs --linux AppImage deb rpm --arm64", - ]; -} - -// Paths under rootDir that the container needs. Credentials, env files, docs, -// screenshots, and other host-only state are deliberately -// excluded to keep secrets out of the Wine/Linux builder image. -const containerSourceMounts = [ - { host: "src", mode: "ro" }, - { host: "scripts", mode: "ro" }, - { host: "assets", mode: "ro" }, - { host: "builtin-skills", mode: "ro" }, - { host: "electron-builder.yml", mode: "ro" }, - { host: "package.json", mode: "ro" }, - { host: "pnpm-lock.yaml", mode: "ro" }, - { host: "electron.vite.config.ts", mode: "ro" }, - { host: "tsconfig.json", mode: "ro" }, - { host: "tsconfig.base.json", mode: "ro" }, - { host: "tsconfig.check.json", mode: "ro" }, - { host: "eslint.config.mjs", mode: "ro" }, -]; - -// Writable host paths — electron-vite writes to out/, electron-builder writes to build/. -const containerOutputMounts = [ - { host: "out" }, - { host: "build" }, -]; - -async function runDockerBuild(platform) { - const isWindows = platform === "win"; - const image = isWindows ? "electronuserland/builder:wine" : "electronuserland/builder"; - const env = makeDockerEnv(platform); - const cacheDir = join(os.homedir(), ".cache"); - const command = [ - "corepack enable", - `corepack prepare pnpm@${pnpmVersion} --activate`, - "pnpm install --frozen-lockfile", - "pnpm exec electron-vite build", - ...getDockerBuildCommands(platform), - ].join(" && "); - // Ensure host-side output dirs exist before binding (docker would otherwise create - // them as root-owned on Linux hosts). - for (const mount of containerOutputMounts) { - await mkdir(join(rootDir, mount.host), { recursive: true }); - } - const dockerArgs = [ - "run", - "--rm", - "--platform", "linux/amd64", - ]; - for (const mount of containerSourceMounts) { - dockerArgs.push("-v", `${join(rootDir, mount.host)}:/project/${mount.host}:${mount.mode}`); - } - for (const mount of containerOutputMounts) { - dockerArgs.push("-v", `${join(rootDir, mount.host)}:/project/${mount.host}`); - } - dockerArgs.push( - "-v", `${dockerNodeModulesVolume}:/project/node_modules`, - "-v", `${join(cacheDir, "electron")}:/root/.cache/electron`, - "-v", `${join(cacheDir, "electron-builder")}:/root/.cache/electron-builder`, - "-w", "/project", - ); - for (const [key, value] of Object.entries(env)) { - dockerArgs.push("-e", `${key}=${value}`); - } - dockerArgs.push(image, "/bin/bash", "-lc", command); - await run("docker", dockerArgs); -} - -async function buildMac() { - const env = { - ...process.env, - AGENTCOMPANY_ELECTRON_PUBLISH: "never", - AGENTCOMPANY_ENABLE_LOCAL_DMG: "true", - CSC_IDENTITY_AUTO_DISCOVERY: "true", - }; - await run("pnpm", ["exec", "electron-vite", "build"], env); - await run("node", ["scripts/build-desktop.mjs", "--mac", "--arm64", "--x64"], env); - await stageRelease("mac"); -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - process.env.AGENTCOMPANY_ELECTRON_PUBLISH = "never"; - const r2 = options.upload ? await prepareR2ReleaseHost({ rootDir }) : null; - await validatePreflight(options.platforms, options.upload); - - console.log(`[release-local] update URL: ${process.env.AGENTCOMPANY_UPDATE_URL}`); - console.log(`[release-local] upload mode: ${options.upload ? "enabled" : "disabled"}`); - console.log(`[release-local] platforms: ${options.platforms.join(", ")}`); - - await rm(localReleaseDir, { recursive: true, force: true }); - if (!options.skipVerify) { - await run("pnpm", ["audit:deps"]); - await run("pnpm", ["verify"]); - } - if (options.platforms.includes("mac")) { - await buildMac(); - if (r2) { - await uploadReleaseFiles({ - rootDir, - releaseDir: buildReleaseDir, - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - } - } - if (options.platforms.includes("win")) { - await runDockerBuild("win"); - await stageRelease("win"); - if (r2) { - await uploadReleaseFiles({ - rootDir, - releaseDir: buildReleaseDir, - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - } - } - if (options.platforms.includes("linux")) { - await runDockerBuild("linux"); - await stageRelease("linux"); - if (r2) { - await uploadReleaseFiles({ - rootDir, - releaseDir: buildReleaseDir, - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - } - } - await mkdir(localReleaseDir, { recursive: true }); - await writeFile( - join(localReleaseDir, "manifest.json"), - JSON.stringify({ - generatedAt: new Date().toISOString(), - platforms: options.platforms, - uploadEnabled: options.upload, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - }, null, 2), - "utf8", - ); - console.log(`[release-local] complete. Local artifact staging: ${localReleaseDir}`); -} - -await main(); diff --git a/scripts/release-local/r2.mjs b/scripts/release-local/r2.mjs deleted file mode 100644 index dd02b45f..00000000 --- a/scripts/release-local/r2.mjs +++ /dev/null @@ -1,262 +0,0 @@ -import { readdir } from "node:fs/promises"; -import { createReadStream } from "node:fs"; -import { join } from "node:path"; -import { spawn } from "node:child_process"; -import { DeleteObjectsCommand, ListObjectsV2Command, S3Client } from "@aws-sdk/client-s3"; -import { Upload } from "@aws-sdk/lib-storage"; - -const defaultBucket = "agentcompany-updates"; -const defaultPrefix = "AC"; -const ignoredReleaseFiles = new Set(["builder-debug.yml"]); - -function normalizeBaseUrl(url) { - return url.replace(/\/+$/, ""); -} - -function normalizePathSegment(pathValue) { - return pathValue.replace(/^\/+|\/+$/g, ""); -} - -function guessContentType(fileName) { - if (fileName.endsWith(".yml")) return "text/yaml; charset=utf-8"; - if (fileName.endsWith(".blockmap")) return "application/octet-stream"; - if (fileName.endsWith(".zip")) return "application/zip"; - if (fileName.endsWith(".dmg")) return "application/x-apple-diskimage"; - if (fileName.endsWith(".exe")) return "application/vnd.microsoft.portable-executable"; - if (fileName.endsWith(".AppImage")) return "application/octet-stream"; - if (fileName.endsWith(".deb")) return "application/vnd.debian.binary-package"; - if (fileName.endsWith(".rpm")) return "application/x-rpm"; - if (fileName.endsWith(".snap")) return "application/vnd.snap"; - return "application/octet-stream"; -} - -async function runWrangler(args, cwd, capture = false) { - return await new Promise((resolve, reject) => { - const child = spawn("npx", ["wrangler", ...args], { - cwd, - stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit", - shell: process.platform === "win32", - }); - let stdout = ""; - let stderr = ""; - if (capture) { - child.stdout.on("data", (chunk) => { - stdout += chunk.toString(); - }); - child.stderr.on("data", (chunk) => { - stderr += chunk.toString(); - }); - } - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve({ stdout, stderr }); - return; - } - reject(new Error(stderr || stdout || `wrangler ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); -} - -function resolveUpdateUrl(publicBaseUrl, releasePrefix) { - const baseUrl = normalizeBaseUrl(publicBaseUrl); - const prefix = normalizePathSegment(releasePrefix); - return prefix ? `${baseUrl}/${prefix}` : baseUrl; -} - -function hasS3Credentials() { - return Boolean( - process.env.R2_ACCESS_KEY_ID?.trim() && - process.env.R2_SECRET_ACCESS_KEY?.trim(), - ); -} - -export async function prepareR2ReleaseHost({ rootDir }) { - const prefix = normalizePathSegment(process.env.AGENTCOMPANY_RELEASE_PREFIX?.trim() || defaultPrefix); - const s3Mode = hasS3Credentials(); - - let accountId = process.env.R2_ACCOUNT_ID?.trim() - || process.env.AGENTCOMPANY_R2_ACCOUNT_ID?.trim() - || ""; - if (!accountId) { - if (s3Mode) { - throw new Error("R2 S3 credentials set but R2_ACCOUNT_ID missing. Add it to .env.release.local."); - } - const whoami = JSON.parse((await runWrangler(["whoami", "--json"], rootDir, true)).stdout); - accountId = whoami.accounts?.[0]?.id; - } - if (!accountId) { - throw new Error("Unable to resolve Cloudflare account ID. Set R2_ACCOUNT_ID in .env.release.local."); - } - - const bucket = process.env.R2_BUCKET?.trim() - || process.env.AGENTCOMPANY_R2_BUCKET?.trim() - || defaultBucket; - - // Skip wrangler bucket-info/create when S3 creds are available: wrangler's - // OAuth may be logged into a different Cloudflare account (see Win host - // where the OAuth account has no R2 enabled). S3 API operations later in - // the flow cover the real bucket existence check. - if (!s3Mode) { - try { - await runWrangler(["r2", "bucket", "info", bucket, "--json"], rootDir, true); - } catch (error) { - if (!String(error).includes("does not exist")) { - throw error; - } - await runWrangler(["r2", "bucket", "create", bucket], rootDir, false); - } - } - - let publicBaseUrl = process.env.R2_PUBLIC_BASE_URL?.trim() - || process.env.AGENTCOMPANY_R2_PUBLIC_URL?.trim() - || ""; - - if (!publicBaseUrl) { - if (s3Mode) { - throw new Error( - "R2 S3 credentials set but R2_PUBLIC_BASE_URL missing. Add it to .env.release.local " + - "(e.g. R2_PUBLIC_BASE_URL=https://pub-.r2.dev).", - ); - } - const devUrlState = await runWrangler(["r2", "bucket", "dev-url", "get", bucket], rootDir, true) - .then((result) => result.stdout) - .catch(() => ""); - if (!devUrlState.includes("https://")) { - await runWrangler(["r2", "bucket", "dev-url", "enable", bucket], rootDir, false); - } - const enabledOutput = (await runWrangler(["r2", "bucket", "dev-url", "get", bucket], rootDir, true)).stdout; - const match = enabledOutput.match(/https:\/\/[^\s']+\.r2\.dev/); - if (!match) { - throw new Error("Unable to resolve R2 public dev URL from wrangler."); - } - publicBaseUrl = match[0]; - } - - process.env.R2_ACCOUNT_ID = accountId; - process.env.AGENTCOMPANY_R2_ACCOUNT_ID = accountId; - process.env.R2_BUCKET = bucket; - process.env.AGENTCOMPANY_R2_BUCKET = bucket; - process.env.R2_PUBLIC_BASE_URL = publicBaseUrl; - process.env.AGENTCOMPANY_R2_PUBLIC_URL = publicBaseUrl; - process.env.AGENTCOMPANY_RELEASE_PREFIX = prefix; - process.env.AGENTCOMPANY_R2_PATH = prefix; - process.env.AGENTCOMPANY_UPDATE_URL = process.env.AGENTCOMPANY_UPDATE_URL?.trim() - || resolveUpdateUrl(publicBaseUrl, prefix); - - return { - accountId, - bucket, - publicBaseUrl, - releasePrefix: prefix, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL, - }; -} - -function createS3ClientForLargeUploads() { - const accessKeyId = process.env.R2_ACCESS_KEY_ID?.trim(); - const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY?.trim(); - const endpoint = process.env.R2_S3_ENDPOINT?.trim() - || (process.env.R2_ACCOUNT_ID ? `https://${process.env.R2_ACCOUNT_ID.trim()}.r2.cloudflarestorage.com` : ""); - if (!accessKeyId || !secretAccessKey || !endpoint) { - throw new Error( - "Large file (>290 MiB) requires R2 S3 credentials. Set R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, and R2_S3_ENDPOINT (or R2_ACCOUNT_ID) in .env.release.local.", - ); - } - return new S3Client({ - region: "auto", - endpoint, - credentials: { accessKeyId, secretAccessKey }, - forcePathStyle: false, - }); -} - -async function uploadViaS3Multipart({ bucket, key, filePath, fileName }) { - const client = createS3ClientForLargeUploads(); - const upload = new Upload({ - client, - params: { - Bucket: bucket, - Key: key, - Body: createReadStream(filePath), - ContentType: guessContentType(fileName), - CacheControl: fileName.endsWith(".yml") ? "no-cache" : "public, max-age=31536000, immutable", - }, - partSize: 64 * 1024 * 1024, - queueSize: 4, - }); - upload.on("httpUploadProgress", (p) => { - if (p.loaded && p.total) { - process.stdout.write(`\r[s3-multipart] ${key} ${(p.loaded / p.total * 100).toFixed(1)}%`); - } - }); - await upload.done(); - process.stdout.write(`\n[s3-multipart] ${key} uploaded\n`); -} - -export function classifyReleaseArtifact(fileName) { - if (fileName === "latest-mac.yml") return "mac"; - if (/\.dmg(\.blockmap)?$/.test(fileName)) return "mac"; - if (/-mac\.zip(\.blockmap)?$/.test(fileName)) return "mac"; - if (fileName === "latest.yml") return "win"; - if (/\.exe(\.blockmap)?$/.test(fileName)) return "win"; - if (fileName === "latest-linux.yml") return "linux"; - if (/\.(AppImage|deb|rpm|snap)$/.test(fileName)) return "linux"; - return "other"; -} - -export async function purgeReleasePrefix({ bucket, releasePrefix, keep }) { - const client = createS3ClientForLargeUploads(); - const prefix = `${normalizePathSegment(releasePrefix)}/`; - const keepClass = new Set(Array.isArray(keep) ? keep : []); - let continuationToken; - let total = 0; - let skipped = 0; - do { - const list = await client.send(new ListObjectsV2Command({ - Bucket: bucket, - Prefix: prefix, - ContinuationToken: continuationToken, - })); - const candidates = list.Contents ?? []; - const toDelete = []; - for (const obj of candidates) { - const baseName = obj.Key.slice(prefix.length); - if (keepClass.has(classifyReleaseArtifact(baseName))) { - skipped += 1; - continue; - } - toDelete.push({ Key: obj.Key }); - } - if (toDelete.length > 0) { - await client.send(new DeleteObjectsCommand({ - Bucket: bucket, - Delete: { Objects: toDelete, Quiet: true }, - })); - total += toDelete.length; - } - continuationToken = list.IsTruncated ? list.NextContinuationToken : undefined; - } while (continuationToken); - console.log( - `[r2-purge] deleted ${total} object(s) under ${bucket}/${prefix}` + - (skipped > 0 ? ` (kept ${skipped} in classes: ${[...keepClass].join(",")})` : ""), - ); -} - -export async function uploadReleaseFiles({ rootDir, releaseDir, bucket, releasePrefix }) { - const files = (await readdir(releaseDir, { withFileTypes: true })) - .filter((entry) => entry.isFile() && !ignoredReleaseFiles.has(entry.name)) - .map((entry) => entry.name); - - for (const fileName of files) { - const key = `${normalizePathSegment(releasePrefix)}/${fileName}`; - const filePath = join(releaseDir, fileName); - // Always use the S3 multipart path: wrangler's OAuth token commonly lacks - // the r2 scope, which returns 401 on `r2 object put`. The S3 credentials - // (R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY) bypass that mismatch and - // handle every file size uniformly. `rootDir` is kept in the signature - // for call-site compatibility even though the S3 path does not need it. - void rootDir; - await uploadViaS3Multipart({ bucket, key, filePath, fileName }); - } -} diff --git a/scripts/release-public-cloudflare.mjs b/scripts/release-public-cloudflare.mjs deleted file mode 100644 index d5674a1c..00000000 --- a/scripts/release-public-cloudflare.mjs +++ /dev/null @@ -1,350 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile, rm, writeFile, mkdir, cp, readdir } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { prepareR2ReleaseHost, purgeReleasePrefix, uploadReleaseFiles } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; -import { createRunner } from "./release/lib/process.mjs"; -import { createWorkflowHelpers } from "./release/lib/workflow.mjs"; -import { createSnapshotHelpers } from "./release/lib/snapshot.mjs"; -import { applyD1Migrations } from "./release/lib/d1-migrations.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const packageJsonPath = join(rootDir, "package.json"); -const landingDir = join(rootDir, "landing"); -const localReleaseDir = join(rootDir, "local-release"); -const remoteWorkflowFile = ".github/workflows/remote-release-platforms.yml"; -const remoteWorkflowName = "remote-release-platforms.yml"; -const pagesProjectName = "agentcompany"; -const pagesBranch = "main"; -const versionPattern = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/; -const syncExcludes = [ - ".git", - "node_modules/", - ".pnpm-store/", - "build/", - "local-release/", - "out/", - ".omx/", - ".omc/", - ".claude/", - "landing/.next/", - "landing/out/", - "landing/node_modules/", - ".DS_Store", - ".env.release.local", - "CertificateSigningRequest.certSigningRequest", - "Certificates.p12", - "developerID_application.cer", -]; - -const run = createRunner(rootDir); -const { - getGitHubHttpAuthHeader, - getRepoInfo, - assertRemoteWorkflowExists, - waitForWorkflowRun, - waitForWorkflowCompletion, - downloadRemoteAssets, - cleanupRemoteTransportRelease, -} = createWorkflowHelpers(run); -const { - createSnapshotBranch, - cleanupRemoteBranch, - cleanupLocalWorktree, -} = createSnapshotHelpers(run, getGitHubHttpAuthHeader); - -function parseArgs(argv) { - const options = { - version: null, - skipVerify: false, - deleteRemoteBranch: false, - keepTransportRelease: false, - }; - - for (const arg of argv) { - if (arg.startsWith("--version=")) { - options.version = arg.slice("--version=".length).trim(); - continue; - } - if (arg === "--skip-verify") { - options.skipVerify = true; - continue; - } - if (arg === "--delete-remote-branch") { - options.deleteRemoteBranch = true; - continue; - } - if (arg === "--keep-transport-release") { - options.keepTransportRelease = true; - continue; - } - if (arg === "--help") { - printHelp(); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - - return options; -} - -function printHelp() { - console.log(`Usage: node scripts/release-cloudflare.mjs [options] - -Options: - --version=x.y.z Explicit version. Defaults to current patch + 1. - --skip-verify Skip local dependency audit and pnpm verify before packaging. - --delete-remote-branch Delete the GitHub snapshot branch after success. - --keep-transport-release Keep the temporary draft GitHub release after success. - --help Show this help. -`); -} - -async function readPackageJson() { - return JSON.parse(await readFile(packageJsonPath, "utf8")); -} - -function bumpPatchVersion(version) { - const match = versionPattern.exec(version); - if (!match) { - throw new Error(`Unsupported package version format: ${version}`); - } - const [, major, minor, patch] = match; - return `${major}.${minor}.${Number.parseInt(patch, 10) + 1}`; -} - -async function updatePackageVersion(nextVersion) { - const pkg = await readPackageJson(); - pkg.version = nextVersion; - await writeFile(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8"); -} - -async function ensureRemoteBuildPrerequisites(repo) { - if (process.platform !== "darwin") { - throw new Error("This release script currently expects to run on macOS for the signed macOS build."); - } - if (!existsSync(join(rootDir, remoteWorkflowFile))) { - throw new Error(`Required workflow file missing locally: ${remoteWorkflowFile}`); - } - await assertRemoteWorkflowExists( - repo, - remoteWorkflowFile, - `Remote workflow ${remoteWorkflowFile} was not found on ${repo.defaultBranch}. ` + - "Commit and push this automation workflow before using scripts/release-cloudflare.mjs.", - ); - await run("gh", ["auth", "status"], { capture: true }); - await run("npx", ["wrangler", "whoami", "--json"], { capture: true }); -} - -async function resetReleaseStaging() { - await rm(localReleaseDir, { recursive: true, force: true }); - await rm(join(rootDir, "build", "release"), { recursive: true, force: true }); -} - -async function buildMacAndUpload() { - await run("node", ["scripts/release-local.mjs", "--platforms=mac", "--skip-verify"]); -} - -function buildSnapshotCommitMessage(version) { - return [ - `Package release ${version} from the current workspace snapshot`, - "", - "Constraint: Windows and Linux artifacts are built on native GitHub runners from a temporary snapshot branch", - "Rejected: Build Windows/Linux locally on Apple Silicon | docker/wine packaging is not stable on this host", - "Confidence: medium", - "Scope-risk: moderate", - "Directive: This snapshot branch is transport-only and should be deleted after the release completes", - "Tested: local verify/build stages before snapshot creation", - "Not-tested: remote packaging before workflow execution", - ].join("\n"); -} - -async function dispatchRemoteWorkflow(repo, branchName, releaseTag, releaseTitle) { - await run("gh", [ - "workflow", - "run", - remoteWorkflowName, - "--repo", - repo.nameWithOwner, - "--ref", - branchName, - "-f", - `release_tag=${releaseTag}`, - "-f", - `release_title=${releaseTitle}`, - ]); -} - -async function stageRemoteAssets(downloadRoot) { - const winDir = join(localReleaseDir, "win"); - const linuxDir = join(localReleaseDir, "linux"); - await rm(winDir, { recursive: true, force: true }); - await rm(linuxDir, { recursive: true, force: true }); - await mkdir(winDir, { recursive: true }); - await mkdir(linuxDir, { recursive: true }); - - const files = await readdir(downloadRoot); - for (const fileName of files) { - const sourcePath = join(downloadRoot, fileName); - if (fileName.endsWith(".exe") || fileName.endsWith(".blockmap") || fileName === "latest.yml") { - await cp(sourcePath, join(winDir, fileName)); - continue; - } - if ( - fileName.endsWith(".AppImage") || - fileName.endsWith(".deb") || - fileName.endsWith(".rpm") || - fileName === "latest-linux.yml" - ) { - await cp(sourcePath, join(linuxDir, fileName)); - } - } -} - -async function uploadWinAndLinuxToR2() { - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - const r2 = await prepareR2ReleaseHost({ rootDir }); - await uploadReleaseFiles({ - rootDir, - releaseDir: join(localReleaseDir, "win"), - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); - await uploadReleaseFiles({ - rootDir, - releaseDir: join(localReleaseDir, "linux"), - bucket: r2.bucket, - releasePrefix: r2.releasePrefix, - }); -} - -async function applyLandingMigrations() { - await applyD1Migrations({ landingDir, run }); -} - -async function buildAndDeployLanding() { - if (!existsSync(join(landingDir, "node_modules"))) { - await run("npm", ["ci"], { cwd: landingDir }); - } - await run("npm", ["run", "build"], { cwd: landingDir }); - const deploy = await run( - "npx", - ["wrangler", "pages", "deploy", "out", "--project-name", pagesProjectName, "--branch", pagesBranch, "--commit-dirty=true"], - { cwd: landingDir, capture: true }, - ); - const output = `${deploy.stdout}\n${deploy.stderr}`; - const urlMatch = output.match(/https:\/\/[^\s]+\.agentcompany\.pages\.dev/); - return urlMatch?.[0] ?? null; -} - -async function verifyPublishedAssets(version, deployUrl) { - const releaseLinksSource = await readFile(join(landingDir, "components", "release-links.generated.ts"), "utf8"); - const requiredFragments = [ - `AgentCompany-0.4.150-arm64.dmg`.replace("0.4.150", version), - `AgentCompany.Setup.${version}.exe`, - `agent-company-${version}.aarch64.rpm`, - `agent-company_${version}_arm64.deb`, - ]; - for (const fragment of requiredFragments) { - if (!releaseLinksSource.includes(fragment)) { - throw new Error(`Missing expected release asset in generated links: ${fragment}`); - } - } - - if (deployUrl) { - const { stdout } = await run("curl", ["-L", "--silent", "-A", "Mozilla/5.0", deployUrl], { capture: true }); - if (!stdout.includes(version)) { - throw new Error(`Deployed landing preview ${deployUrl} does not contain version ${version}.`); - } - } -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - - const repo = await getRepoInfo(); - await ensureRemoteBuildPrerequisites(repo); - - const currentVersion = (await readPackageJson()).version; - const nextVersion = options.version ?? bumpPatchVersion(currentVersion); - if (!versionPattern.test(nextVersion)) { - throw new Error(`Invalid version: ${nextVersion}`); - } - - await updatePackageVersion(nextVersion); - await resetReleaseStaging(); - - if (!options.skipVerify) { - await run("pnpm", ["audit:deps"]); - await run("pnpm", ["verify"]); - } - - const r2Host = await prepareR2ReleaseHost({ rootDir }); - await purgeReleasePrefix({ bucket: r2Host.bucket, releasePrefix: r2Host.releasePrefix }); - - await buildMacAndUpload(); - - const timestamp = Date.now(); - const releaseTag = `transport-${nextVersion}-${timestamp}`; - const branchName = `release-build-${nextVersion.replace(/\./g, "-")}-${timestamp}`; - const releaseTitle = `Remote Release ${nextVersion}`; - - const tempDir = await createSnapshotBranch({ - repo, - branchName, - rootDir, - syncExcludes, - commitMessage: buildSnapshotCommitMessage(nextVersion), - }); - let cleanupPending = true; - - try { - await dispatchRemoteWorkflow(repo, branchName, releaseTag, releaseTitle); - const runSummary = await waitForWorkflowRun(repo, remoteWorkflowName, branchName, 60_000); - const runInfo = await waitForWorkflowCompletion(repo, runSummary.databaseId, 45 * 60 * 1000); - if (runInfo.conclusion !== "success") { - throw new Error(`Remote workflow failed: ${runInfo.url}`); - } - - const downloadRoot = await downloadRemoteAssets(repo, releaseTag); - await stageRemoteAssets(downloadRoot); - await uploadWinAndLinuxToR2(); - await run("node", ["scripts/generate-landing-release-links.mjs"]); - await applyLandingMigrations(); - const deployUrl = await buildAndDeployLanding(); - await verifyPublishedAssets(nextVersion, deployUrl); - - if (!options.keepTransportRelease) { - await cleanupRemoteTransportRelease(repo, releaseTag); - } - if (options.deleteRemoteBranch) { - await cleanupRemoteBranch(repo, branchName); - } - await cleanupLocalWorktree(tempDir); - cleanupPending = false; - - console.log(JSON.stringify({ - version: nextVersion, - remoteBranch: branchName, - remoteWorkflowRun: runInfo.url, - releaseTag, - deployUrl, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null, - }, null, 2)); - } finally { - if (cleanupPending) { - try { - await cleanupLocalWorktree(tempDir); - } catch { - // no-op during best-effort temp cleanup - } - } - } -} - -await main(); diff --git a/scripts/release-website.mjs b/scripts/release-website.mjs deleted file mode 100644 index 198fdc29..00000000 --- a/scripts/release-website.mjs +++ /dev/null @@ -1,126 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { spawn } from "node:child_process"; -import { prepareR2ReleaseHost } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; -import { applyD1Migrations } from "./release/lib/d1-migrations.mjs"; -import { createRunner } from "./release/lib/process.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const landingDir = join(rootDir, "landing"); -const packageJsonPath = join(rootDir, "package.json"); -const pagesProjectName = "agentcompany"; -const pagesBranch = "main"; - -const run = createRunner(rootDir); - -function parseArgs(argv) { - const options = { skipVerify: false }; - for (const arg of argv) { - if (arg === "--skip-verify") { - options.skipVerify = true; - continue; - } - if (arg === "--help") { - console.log(`Usage: node scripts/release-website.mjs [options] - -Options: - --skip-verify Do not assert the deployed page includes the current version. - --help Show this help. -`); - process.exit(0); - } - throw new Error(`Unknown argument: ${arg}`); - } - return options; -} - -async function readPackageJson() { - return JSON.parse(await readFile(packageJsonPath, "utf8")); -} - -async function runPlain(command, args, cwd = rootDir) { - await new Promise((resolve, reject) => { - const child = spawn(command, args, { - cwd, - stdio: "inherit", - shell: process.platform === "win32", - }); - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve(); - return; - } - reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); -} - -async function buildAndDeployLanding() { - if (!existsSync(join(landingDir, "node_modules"))) { - await runPlain("npm", ["ci"], landingDir); - } - await runPlain("npm", ["run", "build"], landingDir); - const deploy = await run( - "npx", - ["wrangler", "pages", "deploy", "out", "--project-name", pagesProjectName, "--branch", pagesBranch, "--commit-dirty=true"], - { cwd: landingDir, capture: true }, - ); - const output = `${deploy.stdout}\n${deploy.stderr}`; - const urlMatch = output.match(/https:\/\/[^\s]+\.agentcompany\.pages\.dev/); - return urlMatch?.[0] ?? null; -} - -async function verifyPublishedAssets(version, deployUrl) { - const linksSource = await readFile(join(landingDir, "components", "release-links.generated.ts"), "utf8"); - const required = [ - `AgentCompany-${version}-arm64.dmg`, - `AgentCompany.Setup.${version}.exe`, - `agent-company-${version}.aarch64.rpm`, - `agent-company_${version}_arm64.deb`, - ]; - const missing = required.filter((frag) => !linksSource.includes(frag)); - if (missing.length > 0) { - throw new Error( - `Missing expected release assets in generated links (did you run release:local-mac and release:local-winlinux first?):\n ${missing.join("\n ")}`, - ); - } - if (deployUrl) { - const { stdout } = await run("curl", ["-L", "--silent", "-A", "Mozilla/5.0", deployUrl], { capture: true }); - if (!stdout.includes(version)) { - throw new Error(`Deployed landing preview ${deployUrl} does not contain version ${version}.`); - } - } -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - - await prepareR2ReleaseHost({ rootDir }); - await runPlain("pnpm", ["audit:deps"]); - - const version = (await readPackageJson()).version; - console.log(`[release-website] regenerating landing for version ${version}`); - - await runPlain("node", ["scripts/generate-landing-release-links.mjs"]); - await applyD1Migrations({ landingDir, run }); - const deployUrl = await buildAndDeployLanding(); - - if (!options.skipVerify) { - await verifyPublishedAssets(version, deployUrl); - } - - console.log(JSON.stringify({ - version, - deployUrl, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null, - }, null, 2)); -} - -await main(); diff --git a/scripts/release/lib/d1-migrations.mjs b/scripts/release/lib/d1-migrations.mjs deleted file mode 100644 index a4d3d8dc..00000000 --- a/scripts/release/lib/d1-migrations.mjs +++ /dev/null @@ -1,129 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile, readdir } from "node:fs/promises"; -import { join } from "node:path"; - -const databaseNamePattern = /^[A-Za-z0-9_-]+$/; -const migrationFilePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*\.sql$/; - -function stripTomlComment(line) { - let inString = false; - let escaped = false; - for (let i = 0; i < line.length; i += 1) { - const char = line[i]; - if (escaped) { - escaped = false; - continue; - } - if (char === "\\") { - escaped = true; - continue; - } - if (char === "\"") { - inString = !inString; - continue; - } - if (char === "#" && !inString) { - return line.slice(0, i); - } - } - return line; -} - -function parseTomlString(value, key) { - const trimmed = value.trim(); - if (!trimmed.startsWith("\"") || !trimmed.endsWith("\"")) { - throw new Error(`wrangler.toml key "${key}" must be a quoted string.`); - } - try { - return JSON.parse(trimmed); - } catch (error) { - const detail = error instanceof Error ? error.message : String(error); - throw new Error(`wrangler.toml key "${key}" has invalid string syntax: ${detail}`); - } -} - -function parseAssignment(line) { - const equals = line.indexOf("="); - if (equals === -1) return null; - const key = line.slice(0, equals).trim(); - const value = line.slice(equals + 1).trim(); - if (!key) return null; - return { key, value }; -} - -export function validateD1DatabaseName(databaseName) { - if (!databaseNamePattern.test(databaseName)) { - throw new Error( - `Invalid Cloudflare D1 database_name "${databaseName}". Use only letters, numbers, underscores, and hyphens.`, - ); - } - return databaseName; -} - -export function validateD1MigrationFileName(fileName) { - if (!migrationFilePattern.test(fileName)) { - throw new Error( - `Invalid D1 migration file name "${fileName}". Use a plain .sql file name with letters, numbers, dots, underscores, and hyphens.`, - ); - } - return fileName; -} - -export function parseD1DatabaseName(wranglerToml) { - let inD1Database = false; - for (const rawLine of wranglerToml.split(/\r?\n/)) { - const line = stripTomlComment(rawLine).trim(); - if (!line) continue; - if (line.startsWith("[[")) { - inD1Database = line === "[[d1_databases]]"; - continue; - } - if (line.startsWith("[")) { - inD1Database = false; - continue; - } - if (!inD1Database) continue; - const assignment = parseAssignment(line); - if (!assignment || assignment.key !== "database_name") continue; - return validateD1DatabaseName( - parseTomlString(assignment.value, assignment.key), - ); - } - throw new Error("landing/wrangler.toml does not define [[d1_databases]].database_name."); -} - -export async function listD1MigrationFiles(migrationsDir) { - return (await readdir(migrationsDir)) - .filter((fileName) => fileName.endsWith(".sql")) - .map(validateD1MigrationFileName) - .sort(); -} - -export async function applyD1Migrations({ landingDir, run }) { - const migrationsDir = join(landingDir, "migrations"); - if (!existsSync(migrationsDir)) { - return { databaseName: null, applied: 0 }; - } - - const wranglerToml = await readFile(join(landingDir, "wrangler.toml"), "utf8"); - const databaseName = parseD1DatabaseName(wranglerToml); - const migrationFiles = await listD1MigrationFiles(migrationsDir); - - for (const fileName of migrationFiles) { - await run( - "npx", - [ - "wrangler", - "d1", - "execute", - databaseName, - "--remote", - "--file", - `migrations/${fileName}`, - ], - { cwd: landingDir, input: "y\n" }, - ); - } - - return { databaseName, applied: migrationFiles.length }; -} diff --git a/scripts/release/lib/dotenv.mjs b/scripts/release/lib/dotenv.mjs deleted file mode 100644 index 138ecb16..00000000 --- a/scripts/release/lib/dotenv.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile } from "node:fs/promises"; - -export async function loadEnvFile(filePath) { - if (!existsSync(filePath)) return; - const content = await readFile(filePath, "utf8"); - for (const rawLine of content.split(/\r?\n/)) { - const line = rawLine.trim(); - if (!line || line.startsWith("#")) continue; - const separatorIndex = line.indexOf("="); - if (separatorIndex <= 0) continue; - const key = line.slice(0, separatorIndex).trim(); - if (!key || process.env[key]) continue; - const rawValue = line.slice(separatorIndex + 1).trim(); - if (!rawValue) continue; - process.env[key] = rawValue.replace(/^['"]|['"]$/g, ""); - } -} diff --git a/scripts/release/lib/process.mjs b/scripts/release/lib/process.mjs deleted file mode 100644 index 48e93dff..00000000 --- a/scripts/release/lib/process.mjs +++ /dev/null @@ -1,46 +0,0 @@ -import { spawn } from "node:child_process"; - -export function createRunner(rootDir) { - return function run(command, args, options = {}) { - const { - cwd = rootDir, - env = process.env, - input = null, - capture = false, - } = options; - - return new Promise((resolve, reject) => { - const child = spawn(command, args, { - cwd, - env, - stdio: capture ? ["pipe", "pipe", "pipe"] : ["pipe", "inherit", "inherit"], - shell: process.platform === "win32", - }); - - let stdout = ""; - let stderr = ""; - if (capture) { - child.stdout.on("data", (chunk) => { - stdout += chunk.toString(); - }); - child.stderr.on("data", (chunk) => { - stderr += chunk.toString(); - }); - } - - if (input) { - child.stdin.write(input); - } - child.stdin.end(); - - child.on("error", reject); - child.on("close", (code) => { - if (code === 0) { - resolve({ stdout, stderr }); - return; - } - reject(new Error(stderr || stdout || `${command} ${args.join(" ")} failed with exit code ${code ?? 1}`)); - }); - }); - }; -} diff --git a/scripts/release/lib/snapshot.mjs b/scripts/release/lib/snapshot.mjs deleted file mode 100644 index 0024d7b9..00000000 --- a/scripts/release/lib/snapshot.mjs +++ /dev/null @@ -1,77 +0,0 @@ -import { mkdtemp } from "node:fs/promises"; -import os from "node:os"; -import { join } from "node:path"; - -export function createSnapshotHelpers(run, getGitHubHttpAuthHeader) { - async function createSnapshotBranch({ - repo, - branchName, - rootDir, - syncExcludes, - commitMessage, - afterRsync, - }) { - const tempDir = await mkdtemp(join(os.tmpdir(), "agentcompany-release-")); - const auth = await getGitHubHttpAuthHeader(); - await run("git", [ - "-c", - `http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth}`, - "fetch", - `https://github.com/${repo.nameWithOwner}.git`, - repo.defaultBranch, - ]); - await run("git", ["worktree", "add", "--detach", tempDir, "FETCH_HEAD"]); - await run("git", ["-C", tempDir, "checkout", "-b", branchName]); - - const rsyncArgs = ["-a", "--delete"]; - for (const pattern of syncExcludes) { - rsyncArgs.push("--exclude", pattern); - } - rsyncArgs.push(`${rootDir}/`, `${tempDir}/`); - await run("rsync", rsyncArgs); - - await run("git", ["-C", tempDir, "add", "-A"]); - if (afterRsync) { - await afterRsync(tempDir); - } - const diffStatus = await run("git", ["-C", tempDir, "diff", "--cached", "--quiet"], { capture: true }) - .then(() => false) - .catch(() => true); - - if (!diffStatus) { - throw new Error("Snapshot branch has no staged changes after syncing the workspace."); - } - - await run("git", ["-C", tempDir, "commit", "-m", commitMessage]); - - await run( - "git", - [ - "-C", - tempDir, - "-c", - `http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth}`, - "push", - `https://github.com/${repo.nameWithOwner}.git`, - branchName, - ], - ); - - return tempDir; - } - - async function cleanupRemoteBranch(repo, branchName) { - await run("gh", ["api", "-X", "DELETE", `repos/${repo.nameWithOwner}/git/refs/heads/${branchName}`]); - } - - async function cleanupLocalWorktree(tempDir) { - await run("git", ["worktree", "remove", "--force", tempDir]); - await run("git", ["worktree", "prune"]); - } - - return { - createSnapshotBranch, - cleanupRemoteBranch, - cleanupLocalWorktree, - }; -} diff --git a/scripts/release/lib/workflow.mjs b/scripts/release/lib/workflow.mjs deleted file mode 100644 index 060addd7..00000000 --- a/scripts/release/lib/workflow.mjs +++ /dev/null @@ -1,116 +0,0 @@ -import { mkdtemp } from "node:fs/promises"; -import os from "node:os"; -import { join } from "node:path"; - -export function createWorkflowHelpers(run) { - async function ghJson(args) { - const { stdout } = await run("gh", args, { capture: true }); - return JSON.parse(stdout); - } - - async function getGitHubHttpAuthHeader() { - const tokenResult = await run("gh", ["auth", "token"], { capture: true }); - const token = tokenResult.stdout.trim(); - if (!token) { - throw new Error("Unable to read a GitHub token from gh auth."); - } - return Buffer.from(`x-access-token:${token}`).toString("base64"); - } - - async function getRepoInfo() { - const info = await ghJson(["repo", "view", "--json", "nameWithOwner,defaultBranchRef"]); - const defaultBranch = info.defaultBranchRef?.name; - if (!info.nameWithOwner || !defaultBranch) { - throw new Error("Unable to resolve GitHub repository name/default branch from gh."); - } - return { - nameWithOwner: info.nameWithOwner, - defaultBranch, - }; - } - - async function assertRemoteWorkflowExists(repo, workflowFile, errorMessage) { - try { - await run("gh", [ - "api", - `repos/${repo.nameWithOwner}/contents/${workflowFile}?ref=${repo.defaultBranch}`, - ], { capture: true }); - } catch { - throw new Error(errorMessage); - } - } - - async function waitForWorkflowRun(repo, workflowName, branchName, timeoutMs) { - const startedAt = Date.now(); - while (Date.now() - startedAt < timeoutMs) { - const runs = await ghJson([ - "run", - "list", - "--repo", - repo.nameWithOwner, - "--workflow", - workflowName, - "--branch", - branchName, - "--limit", - "1", - "--json", - "databaseId,status,conclusion,url,displayTitle", - ]); - if (runs.length > 0) { - return runs[0]; - } - await new Promise((resolve) => setTimeout(resolve, 5000)); - } - throw new Error(`Timed out waiting for workflow ${workflowName} on branch ${branchName}.`); - } - - async function waitForWorkflowCompletion(repo, runId, timeoutMs) { - const startedAt = Date.now(); - while (Date.now() - startedAt < timeoutMs) { - const runInfo = await ghJson([ - "run", - "view", - String(runId), - "--repo", - repo.nameWithOwner, - "--json", - "status,conclusion,url", - ]); - if (runInfo.status === "completed") { - return runInfo; - } - await new Promise((resolve) => setTimeout(resolve, 15000)); - } - throw new Error(`Timed out waiting for workflow run ${runId} to complete.`); - } - - async function downloadRemoteAssets(repo, releaseTag) { - const downloadRoot = await mkdtemp(join(os.tmpdir(), "agentcompany-transport-")); - await run("gh", [ - "release", - "download", - releaseTag, - "--repo", - repo.nameWithOwner, - "-D", - downloadRoot, - ]); - return downloadRoot; - } - - async function cleanupRemoteTransportRelease(repo, releaseTag) { - await run("gh", ["release", "delete", releaseTag, "--repo", repo.nameWithOwner, "--yes"]); - } - - return { - ghJson, - getGitHubHttpAuthHeader, - getRepoInfo, - assertRemoteWorkflowExists, - waitForWorkflowRun, - waitForWorkflowCompletion, - downloadRemoteAssets, - cleanupRemoteTransportRelease, - }; -} diff --git a/scripts/resume-release-public.mjs b/scripts/resume-release-public.mjs deleted file mode 100644 index 5f3e3d94..00000000 --- a/scripts/resume-release-public.mjs +++ /dev/null @@ -1,103 +0,0 @@ -import { existsSync } from "node:fs"; -import { readFile } from "node:fs/promises"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; -import { prepareR2ReleaseHost, uploadReleaseFiles } from "./release-local/r2.mjs"; -import { loadEnvFile } from "./release/lib/dotenv.mjs"; -import { createRunner } from "./release/lib/process.mjs"; -import { createWorkflowHelpers } from "./release/lib/workflow.mjs"; -import { applyD1Migrations } from "./release/lib/d1-migrations.mjs"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const rootDir = join(__dirname, ".."); -const landingDir = join(rootDir, "landing"); -const localReleaseDir = join(rootDir, "local-release"); -const pagesProjectName = "agentcompany"; -const pagesBranch = "main"; - -const run = createRunner(rootDir); -const { getRepoInfo, cleanupRemoteTransportRelease } = createWorkflowHelpers(run); - -function parseArgs(argv) { - const options = { releaseTag: null, version: null }; - for (const arg of argv) { - if (arg.startsWith("--release-tag=")) options.releaseTag = arg.slice("--release-tag=".length).trim(); - else if (arg.startsWith("--version=")) options.version = arg.slice("--version=".length).trim(); - else throw new Error(`Unknown argument: ${arg}`); - } - if (!options.releaseTag || !options.version) { - throw new Error("Usage: node scripts/resume-release-public.mjs --release-tag= --version="); - } - return options; -} - -async function uploadWinAndLinuxToR2() { - const r2 = await prepareR2ReleaseHost({ rootDir }); - await uploadReleaseFiles({ rootDir, releaseDir: join(localReleaseDir, "win"), bucket: r2.bucket, releasePrefix: r2.releasePrefix }); - await uploadReleaseFiles({ rootDir, releaseDir: join(localReleaseDir, "linux"), bucket: r2.bucket, releasePrefix: r2.releasePrefix }); -} - -async function applyLandingMigrations() { - await applyD1Migrations({ landingDir, run }); -} - -async function buildAndDeployLanding() { - if (!existsSync(join(landingDir, "node_modules"))) { - await run("npm", ["ci"], { cwd: landingDir }); - } - await run("npm", ["run", "build"], { cwd: landingDir }); - const deploy = await run( - "npx", - ["wrangler", "pages", "deploy", "out", "--project-name", pagesProjectName, "--branch", pagesBranch, "--commit-dirty=true"], - { cwd: landingDir, capture: true }, - ); - const output = `${deploy.stdout}\n${deploy.stderr}`; - const urlMatch = output.match(/https:\/\/[^\s]+\.agentcompany\.pages\.dev/); - return urlMatch?.[0] ?? null; -} - -async function verifyPublishedAssets(version, deployUrl) { - const releaseLinksSource = await readFile(join(landingDir, "components", "release-links.generated.ts"), "utf8"); - const requiredFragments = [ - `AgentCompany-${version}-arm64.dmg`, - `AgentCompany.Setup.${version}.exe`, - `agent-company-${version}.aarch64.rpm`, - `agent-company_${version}_arm64.deb`, - ]; - for (const fragment of requiredFragments) { - if (!releaseLinksSource.includes(fragment)) { - throw new Error(`Missing expected release asset in generated links: ${fragment}`); - } - } - if (deployUrl) { - const { stdout } = await run("curl", ["-L", "--silent", "-A", "Mozilla/5.0", deployUrl], { capture: true }); - if (!stdout.includes(version)) { - throw new Error(`Deployed landing preview ${deployUrl} does not contain version ${version}.`); - } - } -} - -async function main() { - const options = parseArgs(process.argv.slice(2)); - await loadEnvFile(join(rootDir, ".env.release.local")); - await loadEnvFile(join(rootDir, ".env.release")); - - const repo = await getRepoInfo(); - await run("pnpm", ["audit:deps"]); - - await uploadWinAndLinuxToR2(); - await run("node", ["scripts/generate-landing-release-links.mjs"]); - await applyLandingMigrations(); - const deployUrl = await buildAndDeployLanding(); - await verifyPublishedAssets(options.version, deployUrl); - await cleanupRemoteTransportRelease(repo, options.releaseTag); - - console.log(JSON.stringify({ - version: options.version, - releaseTag: options.releaseTag, - deployUrl, - updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null, - }, null, 2)); -} - -await main(); diff --git a/src/main/agent-auth.ts b/src/main/agent-auth.ts deleted file mode 100644 index 333e50a8..00000000 --- a/src/main/agent-auth.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { createHmac, randomBytes, timingSafeEqual } from "node:crypto"; -import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; -import { FatalError } from "./errors/index.js"; - -let signingKey: Buffer | null = null; -const TOKEN_TTL_MS = 48 * 60 * 60 * 1000; // 48 hours -const SIGNING_KEY_BYTES = 32; - -// Once-per-process warning when a malformed token shape is seen. Helps -// diagnose schema breaks after upgrades. -let loggedMalformedTokenWarning = false; - -interface TokenValidationLogContext { - runId?: string | null; - companyId?: string | null; - requestId?: string | null; -} - -function safeAuthLogField(value: string | null | undefined): string { - return typeof value === "string" && /^[A-Za-z0-9._:-]{1,160}$/.test(value) ? value : "unknown"; -} - -function warnMalformedTokenOnce(reason: string, context: TokenValidationLogContext | undefined) { - if (loggedMalformedTokenWarning) return; - loggedMalformedTokenWarning = true; - - console.warn( - "[agent-auth] token shape invalid: " + - `reason=${safeAuthLogField(reason)} ` + - `runId=${safeAuthLogField(context?.runId)} ` + - `companyId=${safeAuthLogField(context?.companyId)} ` + - `requestId=${safeAuthLogField(context?.requestId)}`, - ); -} - -interface TokenPayload { - agentId: string; - companyId: string; - runId: string; - iat: number; - exp: number; -} - -function sign(payload: TokenPayload): string { - const key = getSigningKey(); - const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url"); - const body = Buffer.from(JSON.stringify(payload)).toString("base64url"); - const signature = createHmac("sha256", key) - .update(`${header}.${body}`) - .digest("base64url"); - return `${header}.${body}.${signature}`; -} - -function verify(token: string, context?: TokenValidationLogContext): TokenPayload | null { - const key = getSigningKey(); - const parts = token.split("."); - if (parts.length !== 3) return null; - const [header, body, signature] = parts as [string, string, string]; - - const expectedSignature = createHmac("sha256", key) - .update(`${header}.${body}`) - .digest("base64url"); - - const sigBuffer = Buffer.from(signature, "base64url"); - const expectedBuffer = Buffer.from(expectedSignature, "base64url"); - if (sigBuffer.length !== expectedBuffer.length || !timingSafeEqual(sigBuffer, expectedBuffer)) { - return null; - } - - try { - const payload = JSON.parse(Buffer.from(body, "base64url").toString()) as TokenPayload; - if (Date.now() > payload.exp) return null; - return payload; - } catch { - warnMalformedTokenOnce("payload_json_parse_failed", context); - return null; - } -} - -function getSigningKey() { - if (!signingKey) { - throw new Error("Agent token signing key was used before initialization."); - } - return signingKey; -} - -export function initializeAgentTokenSigningKey(profileDir: string) { - mkdirSync(profileDir, { recursive: true }); - const keyPath = join(profileDir, "agent-api-signing.key"); - let key: Buffer; - try { - key = readFileSync(keyPath); - } catch (error) { - if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; - key = randomBytes(SIGNING_KEY_BYTES); - writeFileSync(keyPath, key, { mode: 0o600, flag: "wx" }); - } - if (key.length !== SIGNING_KEY_BYTES) { - throw new FatalError({ - code: "agent_auth.signing_key.invalid", - message: `Agent token signing key must be ${SIGNING_KEY_BYTES} bytes.`, - context: { keyPath, actualBytes: key.length }, - }); - } - chmodSync(keyPath, 0o600); - signingKey = key; -} - -export function createAgentToken(agentId: string, companyId: string, runId: string): string { - const now = Date.now(); - return sign({ agentId, companyId, runId, iat: now, exp: now + TOKEN_TTL_MS }); -} - -export function validateAgentToken(token: string, context?: TokenValidationLogContext): TokenPayload | null { - return verify(token, context); -} - -export type { TokenPayload, TokenValidationLogContext }; diff --git a/src/main/agent-permissions.ts b/src/main/agent-permissions.ts deleted file mode 100644 index c9e93fc2..00000000 --- a/src/main/agent-permissions.ts +++ /dev/null @@ -1,321 +0,0 @@ -import type { AppDatabase } from "./database"; -import type { TaskRecord } from "@shared/types"; - -function safeGetAgent(db: AppDatabase, agentId: string | null | undefined) { - if (!agentId) { - return null; - } - try { - return db.core.entity.getAgent(agentId); - } catch (error) { - if (error instanceof Error && error.message.startsWith("Agent not found:")) { - return null; - } - throw error; - } -} - -const MANAGEMENT_KEYWORDS = [ - "chief", - "cto", - "cmo", - "coo", - "cfo", - "vp", - "vice president", - "head", - "director", - "manager", - "lead", -]; - -/** Regex union for MANAGEMENT_KEYWORDS with `\b`-anchored matching so short - * tokens like "vp" or "cmo" do not false-match inside "vpc" or "economical". */ -const MANAGEMENT_KEYWORD_PATTERN = new RegExp( - `\\b(?:${MANAGEMENT_KEYWORDS.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`, - "i", -); - -export function hasManagementAuthority(agent: { role: string; title: string; department: string | null }) { - if (agent.department === "hr") { - return true; - } - - const text = `${agent.role} ${agent.title}`; - return MANAGEMENT_KEYWORD_PATTERN.test(text); -} - -function hasOrganizationPermission(db: AppDatabase, agentId: string) { - return db.core.agents.hasAgentPermission(agentId, "organization_manage"); -} - -function managesAgent(db: AppDatabase, managerId: string, targetAgentId: string): boolean { - if (managerId === targetAgentId) { - return true; - } - return db.core.agents.getChainOfCommand(targetAgentId).some((agent) => agent.id === managerId); -} - -export function canControlAgent(db: AppDatabase, companyId: string, actorAgentId: string, targetAgentId: string): boolean { - const actor = safeGetAgent(db, actorAgentId); - const target = safeGetAgent(db, targetAgentId); - if (!actor || !target) { - return false; - } - if (actor.companyId !== companyId || target.companyId !== companyId) { - return false; - } - if (actor.id === target.id) { - return true; - } - if (canManageOrganization(db, companyId, actorAgentId)) { - return true; - } - return managesAgent(db, actorAgentId, targetAgentId); -} - -export function canManageOrganization(db: AppDatabase, companyId: string, agentId: string): boolean { - const agent = safeGetAgent(db, agentId); - if (!agent || agent.companyId !== companyId) { - return false; - } - if (!agent.reportsTo) { - return true; - } - if (hasOrganizationPermission(db, agentId)) { - return true; - } - return agent.department === "hr"; -} - -export function canRequestHire(db: AppDatabase, companyId: string, agentId: string): boolean { - const agent = safeGetAgent(db, agentId); - if (!agent || agent.companyId !== companyId) { - return false; - } - if (canManageOrganization(db, companyId, agentId)) { - return true; - } - if (db.core.agents.getDirectReports(agentId, companyId).length > 0) { - return true; - } - return hasManagementAuthority(agent); -} - -const CEO_ROLE_PATTERN = /^(chief executive officer|ceo)$/i; -const CEO_TITLE_PATTERN = /^ceo$/i; - -/** - * True only when the agent is a top-level CEO — CEO-equivalent role/title - * AND no internal manager (`reportsTo === null`, i.e. reports to the Board). - * - * Intentionally orthogonal to {@link canRequestHire}: hiring authority spans - * managers, directors, VPs, HR, etc., but the `approve_ceo_strategy` flow is - * the CEO's alone. Using `reportsTo === null` by itself is too loose (a VP - * with no manager would slip through) and using a keyword list by itself is - * too loose (a "VP" matches the management keywords). Requiring both pins - * the predicate to a genuine CEO even when someone inserts a virtual - * superior above an executive. - */ -export function canFileCeoStrategy(db: AppDatabase, companyId: string, agentId: string): boolean { - const agent = safeGetAgent(db, agentId); - if (!agent || agent.companyId !== companyId) { - return false; - } - if (agent.reportsTo !== null) { - return false; - } - return CEO_ROLE_PATTERN.test(agent.role.trim()) || CEO_TITLE_PATTERN.test(agent.title.trim()); -} - -function getDepartmentLeadCandidateId( - db: AppDatabase, - companyId: string, - department: string, - excludeAgentId: string | null, -): string | null { - const candidates = db.queryAll<{ - id: string; - role: string; - title: string; - department: string | null; - createdAt: string; - }>( - `select id, role, title, department, created_at as createdAt - from agents - where company_id = ? - and department = ? - and status not in ('terminated', 'pending_approval')`, - companyId, - department, - ); - - const ranked = candidates - .filter((candidate) => candidate.id !== excludeAgentId) - .map((candidate) => ({ - id: candidate.id, - hasReports: db.core.agents.getDirectReports(candidate.id, companyId).length > 0, - leadershipScore: hasManagementAuthority(candidate) ? 1 : 0, - chainDepth: db.core.agents.getChainOfCommand(candidate.id).length, - createdAt: candidate.createdAt, - })) - .filter((candidate) => candidate.hasReports || candidate.leadershipScore > 0) - .sort((left, right) => { - if (left.hasReports !== right.hasReports) return left.hasReports ? -1 : 1; - if (left.leadershipScore !== right.leadershipScore) return right.leadershipScore - left.leadershipScore; - if (left.chainDepth !== right.chainDepth) return left.chainDepth - right.chainDepth; - return left.createdAt.localeCompare(right.createdAt); - }); - - return ranked[0]?.id ?? null; -} - -export function resolveHireReportsTo( - db: AppDatabase, - companyId: string, - requestedByAgentId: string | null | undefined, - explicitReportsTo: string | null | undefined, - department: string | null | undefined, -): string | null { - if (explicitReportsTo !== undefined) { - return explicitReportsTo; - } - - const requester = requestedByAgentId ? safeGetAgent(db, requestedByAgentId) : null; - if (requester && requester.companyId !== companyId) { - return null; - } - - if (!department) { - return requester?.id ?? db.core.agents.getCeoForCompany(companyId)?.id ?? null; - } - - if (requester && (requester.department === department || !requester.reportsTo)) { - return requester.id; - } - - const departmentLeadId = getDepartmentLeadCandidateId(db, companyId, department, requester?.id ?? null); - if (departmentLeadId) { - return departmentLeadId; - } - - if (requester) { - return requester.id; - } - - return db.core.agents.getCeoForCompany(companyId)?.id ?? null; -} - -function normalizeComparableText(value: string): string { - return value - .trim() - .toLowerCase() - .replace(/[\s_\-()[\]{}]+/g, " ") - .replace(/\s+/g, " "); -} - -function isAllowedRoleAcronym(value: string): boolean { - return /^[A-Z]{2,5}$/.test(value.trim()); -} - -export function getHireNameValidationError(input: { - name: string; - role: string; - title: string; -}): string | null { - const normalizedName = normalizeComparableText(input.name); - if (!normalizedName) { - return "Hire requests require a real display name."; - } - const normalizedRole = normalizeComparableText(input.role); - const normalizedTitle = normalizeComparableText(input.title); - if (normalizedName === normalizedRole && !isAllowedRoleAcronym(input.name)) { - return "Hire name must be a real display name, not just the role."; - } - if ( - normalizedTitle.length > 0 && - normalizedName === normalizedTitle && - !isAllowedRoleAcronym(input.name) - ) { - return "Hire name must be a real display name, not just the title."; - } - return null; -} - -export function getHireRoutingValidationError( - db: AppDatabase, - companyId: string, - requestedByAgentId: string | null | undefined, - reportsTo: string | null | undefined, - department: string | null | undefined, -): string | null { - const requester = requestedByAgentId ? safeGetAgent(db, requestedByAgentId) : null; - const manager = reportsTo ? safeGetAgent(db, reportsTo) : null; - const requestedDepartment = department ?? null; - - if (requester && requester.companyId !== companyId) { - return "Requesting agent does not belong to the current company."; - } - if (!requestedDepartment) { - return null; - } - if (reportsTo != null && !manager) { - return "Selected manager not found."; - } - if (manager && manager.companyId !== companyId) { - return "Selected manager does not belong to the current company."; - } - - if ( - manager && - manager.reportsTo != null && - manager.department !== requestedDepartment - ) { - return "Selected manager must belong to the same department as the new hire, unless they are a top-level executive."; - } - - return null; -} - -export function canAssignTask(db: AppDatabase, companyId: string, actorAgentId: string, targetAgentId: string | null): boolean { - if (!targetAgentId || targetAgentId === actorAgentId) { - return true; - } - if (!db.core.settings.belongsToCompany("agents", targetAgentId, companyId)) { - return false; - } - if (canManageOrganization(db, companyId, actorAgentId)) { - return true; - } - return managesAgent(db, actorAgentId, targetAgentId); -} - -export function canUpdateTask(db: AppDatabase, companyId: string, actorAgentId: string, task: TaskRecord): boolean { - if (task.companyId !== companyId) { - return false; - } - if (task.assigneeAgentId === actorAgentId) { - return true; - } - if (!task.assigneeAgentId) { - return canManageOrganization(db, companyId, actorAgentId); - } - if (canManageOrganization(db, companyId, actorAgentId)) { - return true; - } - return managesAgent(db, actorAgentId, task.assigneeAgentId); -} - -export function canManageGoal(db: AppDatabase, companyId: string, actorAgentId: string, ownerAgentId: string | null): boolean { - if (canManageOrganization(db, companyId, actorAgentId)) { - return true; - } - return Boolean(ownerAgentId && ownerAgentId === actorAgentId); -} - -export function canManageProject(db: AppDatabase, companyId: string, actorAgentId: string, leadAgentId: string | null): boolean { - if (canManageOrganization(db, companyId, actorAgentId)) { - return true; - } - return Boolean(leadAgentId && leadAgentId === actorAgentId); -} diff --git a/src/main/agent-role-helpers.ts b/src/main/agent-role-helpers.ts deleted file mode 100644 index 3f6fc7ae..00000000 --- a/src/main/agent-role-helpers.ts +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Role-classification helpers used across prompt construction and skill - * auto-assignment. Historical keyword match remains here for backfill and - * UI-free fallback; typed `agent.roleLevel` is the source of truth once the - * column is populated. - * - * Matching uses word-boundary tokenization instead of substring search, - * so "lead" does not match "cleaner" or "leaderboard". - */ -import type { AgentRoleLevel, TaskDomain, TaskTier } from "@shared/types"; -import { isLeadershipLevel } from "@shared/types"; - -export const LEADERSHIP_ROLE_KEYWORDS = [ - "chief", - "cto", - "cmo", - "coo", - "cfo", - "ceo", - "vp", - "vice", - "president", - "head", - "director", - "manager", - "lead", -] as const; - -function tokenize(text: string): string[] { - // Unicode-safe tokenization. Matches runs of letters/numbers across - // scripts so a Chinese title like "高级架构师" yields ["高级架构师"] - // rather than being stripped. English tokens still tokenize on word - // boundaries as before. - return text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? []; -} - -/** - * Check whether a keyword appears in the role/title text. For Latin - * keywords we use whole-token equality (so "lead" does not match - * "leaderboard"). For CJK keywords we fall back to substring containment - * because CJK text has no explicit word boundaries — "架构师" is a - * legitimate substring of "高级架构师" and should match. - */ -function matchesKeyword(loweredText: string, tokens: Set, keyword: string): boolean { - if (/[\u4e00-\u9fff]/.test(keyword)) { - return loweredText.includes(keyword); - } - return tokens.has(keyword); -} - -export function roleMatchesLeadershipKeywords(role: string, title?: string | null): boolean { - const tokens = new Set(tokenize(`${role} ${title ?? ""}`)); - return LEADERSHIP_ROLE_KEYWORDS.some((keyword) => tokens.has(keyword)); -} - -/** - * One-shot inference from free-text role/title strings. Used when creating or - * backfilling an agent so `roleLevel` can be stored once and re-read cheaply. - * The most specific token wins; order here is most-senior → least. - */ -export function inferRoleLevel(role: string, title?: string | null): AgentRoleLevel { - const tokens = new Set(tokenize(`${role} ${title ?? ""}`)); - if (tokens.has("ceo") || tokens.has("cto") || tokens.has("cmo") || tokens.has("coo") || tokens.has("cfo") || tokens.has("chief")) { - return "c_suite"; - } - if (tokens.has("vp") || tokens.has("vice") || tokens.has("president")) return "vp"; - if (tokens.has("director") || tokens.has("head")) return "director"; - if (tokens.has("manager")) return "manager"; - if (tokens.has("lead")) return "lead"; - return "ic"; -} - -/** Canonical leadership check: typed enum wins, fallback to keyword match. */ -export function agentIsLeader(agent: { roleLevel?: AgentRoleLevel | null; role: string; title: string | null }): boolean { - if (agent.roleLevel) return isLeadershipLevel(agent.roleLevel); - return roleMatchesLeadershipKeywords(agent.role, agent.title); -} - -export interface TaskProfile { - domain: TaskDomain; - requiredTier: TaskTier; -} - -/** - * Ordered keyword → domain table. First match wins; order matters because - * role strings can contain multiple cues ("research engineer" is primarily - * a researcher, not a coder). English keywords match on whole-token - * equality; CJK keywords (Chinese here) match on substring containment. - * The list is intentionally narrow — anything unmatched falls through to - * the role-level heuristic below. - */ -const DOMAIN_KEYWORDS: Array<{ keyword: string; domain: TaskDomain }> = [ - // ── Reasoning-heavy ── - // English - { keyword: "architect", domain: "reasoning" }, - { keyword: "reviewer", domain: "reasoning" }, - { keyword: "auditor", domain: "reasoning" }, - { keyword: "analyst", domain: "reasoning" }, - { keyword: "researcher", domain: "reasoning" }, - { keyword: "scientist", domain: "reasoning" }, - { keyword: "mathematician", domain: "reasoning" }, - { keyword: "economist", domain: "reasoning" }, - { keyword: "strategist", domain: "reasoning" }, - { keyword: "cto", domain: "reasoning" }, - { keyword: "cfo", domain: "reasoning" }, - // Chinese (CJK keywords match via substring, so "高级架构师" hits 架构师) - { keyword: "架构师", domain: "reasoning" }, - { keyword: "审查员", domain: "reasoning" }, - { keyword: "审计", domain: "reasoning" }, - { keyword: "分析师", domain: "reasoning" }, - { keyword: "研究员", domain: "reasoning" }, - { keyword: "科学家", domain: "reasoning" }, - { keyword: "数学家", domain: "reasoning" }, - { keyword: "经济学家", domain: "reasoning" }, - { keyword: "策略师", domain: "reasoning" }, - { keyword: "首席技术", domain: "reasoning" }, - { keyword: "首席财务", domain: "reasoning" }, - - // ── Coding-heavy ── - { keyword: "engineer", domain: "coding" }, - { keyword: "developer", domain: "coding" }, - { keyword: "coder", domain: "coding" }, - { keyword: "programmer", domain: "coding" }, - { keyword: "devops", domain: "coding" }, - { keyword: "sre", domain: "coding" }, - { keyword: "工程师", domain: "coding" }, - { keyword: "开发", domain: "coding" }, - { keyword: "程序员", domain: "coding" }, - { keyword: "研发", domain: "coding" }, - { keyword: "运维", domain: "coding" }, - - // ── Writing-heavy: copy / marketing / content / design / PM / HR ── - { keyword: "writer", domain: "writing" }, - { keyword: "copywriter", domain: "writing" }, - { keyword: "marketer", domain: "writing" }, - { keyword: "marketing", domain: "writing" }, - { keyword: "content", domain: "writing" }, - { keyword: "editor", domain: "writing" }, - { keyword: "pm", domain: "writing" }, - { keyword: "designer", domain: "writing" }, - { keyword: "hr", domain: "writing" }, - { keyword: "撰稿", domain: "writing" }, - { keyword: "文案", domain: "writing" }, - { keyword: "市场", domain: "writing" }, - { keyword: "营销", domain: "writing" }, - { keyword: "内容", domain: "writing" }, - { keyword: "编辑", domain: "writing" }, - { keyword: "设计师", domain: "writing" }, - { keyword: "产品经理", domain: "writing" }, - { keyword: "运营", domain: "writing" }, - { keyword: "人力资源", domain: "writing" }, - { keyword: "人事", domain: "writing" }, -]; - -/** - * Keyword cues that hard-pin a role to the trivial tier regardless of the - * role-level enum. A data-entry clerk whose `roleLevel` is `ic` runs on a - * trivial-tier model even if the free-text title is long; an "intern - * director" (yes, these exist) gets reviewed by their title before their - * level. Mixed English + Chinese cues. - */ -const TRIVIAL_KEYWORDS = [ - "intern", - "assistant", - "clerk", - "entry", - "junior", - "associate", - "实习", - "助理", - "初级", - "见习", - "文员", -] as const; - -/** - * Map a role string + optional title to (domain, requiredTier). Both the - * domain and the tier are conservative defaults — the picker will still - * fall back to the CEO model if no enabled candidate clears the bar, so - * under-classifying here is always safe. - * - * The CEO / c_suite cases are handled by the caller (the dispatcher has - * access to `agent.roleLevel` and knows to pin CEO to the user-chosen - * model). This function treats every input as a subordinate. - */ -export function inferTaskProfile( - role: string, - title: string | null | undefined, - roleLevel?: AgentRoleLevel | null, -): TaskProfile { - const loweredText = `${role} ${title ?? ""}`.toLowerCase(); - const tokens = new Set(tokenize(loweredText)); - - // 1. Domain by keyword — first match wins. - let domain: TaskDomain = "writing"; - for (const entry of DOMAIN_KEYWORDS) { - if (matchesKeyword(loweredText, tokens, entry.keyword)) { - domain = entry.domain; - break; - } - } - - // 2. Tier is pinned trivial by explicit cues; otherwise rides role level. - const trivialOverride = TRIVIAL_KEYWORDS.some((kw) => matchesKeyword(loweredText, tokens, kw)); - let tier: TaskTier; - if (trivialOverride) { - tier = "trivial"; - } else { - switch (roleLevel) { - case "c_suite": - case "vp": - case "director": - tier = "hard"; - break; - case "manager": - case "lead": - tier = "standard"; - break; - case "ic": - case null: - case undefined: - default: - tier = "standard"; - break; - } - } - - return { domain, requiredTier: tier }; -} diff --git a/src/main/agent-runtime/agent-event-projection.ts b/src/main/agent-runtime/agent-event-projection.ts deleted file mode 100644 index ddb8003f..00000000 --- a/src/main/agent-runtime/agent-event-projection.ts +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Pure projection helpers for pi AgentEvent → human-readable console log. - * - * Extracted from runtime-bridge.ts to keep the bridge under the 400-line - * cap. These functions never touch DB, IPC, or filesystem — they are - * deterministic text transforms and must stay that way. New event - * types are added here; the bridge pipes the result into its run-log - * stream. - * - * The `@mariozechner/pi-agent-core` `AgentEvent` union is the - * canonical shape we project. - */ - -export type AgentEventLogChunk = { stream: "stdout" | "stderr"; chunk: string }; - -/** - * Extract plain text from a pi AgentMessage's content array. User - * messages carry `content: [{ type: "text", text: "..." }]`; other - * content types (image, tool_result, thinking) are filtered out. - */ -export function extractMessageText(message: { content?: unknown }): string { - const content = message.content; - if (typeof content === "string") return content; - if (!Array.isArray(content)) return ""; - const parts: string[] = []; - for (const block of content) { - if (block && typeof block === "object" && (block as { type?: string }).type === "text") { - const text = (block as { text?: string }).text; - if (typeof text === "string") parts.push(text); - } - } - return parts.join(""); -} - -/** - * Compact JSON preview used in tool-execution log lines. Falls back to a - * sentinel when the value cannot be serialised (circular refs etc.). - */ -export function summariseJson(value: unknown, maxLength: number): string { - if (value === undefined || value === null) return ""; - try { - const json = typeof value === "string" ? value : JSON.stringify(value); - if (json.length <= maxLength) return json; - return `${json.slice(0, maxLength - 3)}...`; - } catch { - return ""; - } -} - -/** - * Best-effort textual rendering of a pi message's content for thread - * rows. Handles text, thinking, and toolCall blocks; returns an empty - * string for purely structural payloads so the thread view does not - * show noise. - */ -export function extractTextBody(content: unknown): string { - if (typeof content === "string") return content; - if (!Array.isArray(content)) return ""; - const parts: string[] = []; - for (const block of content) { - if (!block || typeof block !== "object") continue; - const obj = block as { type?: string; text?: string; thinking?: string; name?: string }; - if (obj.type === "text" && typeof obj.text === "string") parts.push(obj.text); - else if (obj.type === "thinking" && typeof obj.thinking === "string") parts.push(`[thinking] ${obj.thinking}`); - else if (obj.type === "toolCall" && typeof obj.name === "string") parts.push(`[tool:${obj.name}]`); - } - return parts.join("\n").trim(); -} - -/** - * Project a pi AgentEvent to a single console log chunk. Returns null - * for events that should not appear in the log (e.g., streaming - * deltas whose content is already rendered upstream). - */ -export function projectAgentEventToLogChunk( - event: { type: string } & Record, -): AgentEventLogChunk | null { - switch (event.type) { - case "agent_start": - return { stream: "stdout", chunk: "\n[agent:start]\n" }; - case "turn_start": - return { stream: "stdout", chunk: "\n" }; - case "turn_end": - return { stream: "stdout", chunk: "\n" }; - case "message_start": { - const message = event.message as { role?: string; content?: unknown } | undefined; - if (message?.role === "user") { - const body = extractMessageText(message); - if (!body) return null; - return { stream: "stdout", chunk: `[user] ${body}\n` }; - } - return null; - } - case "message_update": { - const inner = event.assistantMessageEvent as - | ({ type?: string; delta?: string; content?: string } & Record) - | undefined; - if (!inner) return null; - if (inner.type === "text_delta" && typeof inner.delta === "string" && inner.delta.length > 0) { - return { stream: "stdout", chunk: inner.delta }; - } - if (inner.type === "thinking_delta" && typeof inner.delta === "string" && inner.delta.length > 0) { - return { stream: "stdout", chunk: inner.delta }; - } - return null; - } - case "message_end": { - return { stream: "stdout", chunk: "\n" }; - } - case "tool_execution_start": { - const toolName = typeof event.toolName === "string" ? event.toolName : "tool"; - const argsPreview = summariseJson(event.args, 200); - return { stream: "stdout", chunk: `\n[tool:${toolName}] ${argsPreview}\n` }; - } - case "tool_execution_end": { - const toolName = typeof event.toolName === "string" ? event.toolName : "tool"; - const isError = event.isError === true; - const resultPreview = summariseJson(event.result, 300); - const tag = isError ? "tool:error" : "tool:done"; - return { stream: isError ? "stderr" : "stdout", chunk: `[${tag}:${toolName}] ${resultPreview}\n` }; - } - case "agent_end": - return { stream: "stdout", chunk: "\n[agent:end]\n" }; - default: - return null; - } -} diff --git a/src/main/agent-runtime/agent-hooks.ts b/src/main/agent-runtime/agent-hooks.ts deleted file mode 100644 index 838002c9..00000000 --- a/src/main/agent-runtime/agent-hooks.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Aggregated factory for the pi-agent-core runtime hooks - * installed by `pi-agent-factory.createPiAgent`. - * - * Before this module the factory wired `beforeToolCall` and - * `transformContext` as inline closures, each re-establishing - * its own RPC envelope shape and its own error policy. A new hook (or - * a signature change in pi) meant touching the factory in multiple places, - * and the "what does each hook do on failure?" matrix lived only in - * reader memory. - * - * `buildAgentHooks` collapses the wiring into a single object whose - * shape mirrors the subset of `AgentOptions` that we populate. The - * factory spreads the result into `new Agent({...})`, so the agent - * contract is still the pi-defined one. Tool policy stays routed - * through `WorkerRpcClient`; context compaction runs inside the worker - * so the full transcript never crosses the worker-main boundary. - * - * The signatures below are pinned to pi via `pi-hook-contract`: any - * drift in `AgentOptions.beforeToolCall` / `transformContext` breaks - * the build on the contract file, so the - * aggregation cannot silently drift from upstream. - */ - -import type { - AgentMessage, - AgentOptions, - BeforeToolCallResult, -} from "@mariozechner/pi-agent-core"; -import type { - BeforeToolCallRpcPayload, - BeforeToolCallRpcResult, -} from "./hook-rpc"; -import type { WorkerRpcClient } from "../worker/entry/rpc"; -import { - compactMessagesIfNeeded, - type CompactionTelemetry, -} from "./context-compactor"; - -export interface ContextCompactionTelemetry extends CompactionTelemetry { - runId: string; - emittedAt: string; -} - -/** - * Inputs the aggregator needs to produce a hook bundle. `rpc` is the - * worker-side RPC client that ships policy hook invocations back to - * main. `runId` is the routing key main uses to look up the per-run - * `ActiveRunContext` in `RuntimeBridge`. - */ -export interface AgentHooksDeps { - runId: string; - rpc: WorkerRpcClient; - onContextCompaction?: (telemetry: ContextCompactionTelemetry) => void; -} - -/** - * Subset of `AgentOptions` the aggregator populates. Exposed as an - * explicit interface so the factory call site keeps a stable shape - * even when pi adds further option slots — anything not in here stays - * the factory's own responsibility. - */ -export interface AgentHookBundle { - beforeToolCall: NonNullable; - transformContext: NonNullable; -} - -/** - * Build the pi-agent-core hooks as a single bundle. - * - * Each hook's behavior matches the pre-aggregation inline closures in - * `pi-agent-factory`: - * - * - `beforeToolCall`: fail-closed RPC. A thrown error travels up into - * pi's loop and surfaces as a tool-error result — destructive tools - * must never silently bypass main's approval gate. - * - `transformContext`: worker-local compaction. The transcript stays - * inside the worker; main receives telemetry only. - */ -export function buildAgentHooks(deps: AgentHooksDeps): AgentHookBundle { - const { runId, rpc, onContextCompaction } = deps; - - const beforeToolCall: AgentHookBundle["beforeToolCall"] = async ( - ctx, - ): Promise => { - const payload: BeforeToolCallRpcPayload = { - toolName: ctx.toolCall.name, - toolCallId: ctx.toolCall.id, - args: ctx.args, - }; - const response = await rpc.invoke(runId, "beforeToolCall", payload); - if (!response.ok) { - // RPC failure must fail closed for destructive tools: main is - // the source of truth for approval state, and silently running - // without it would bypass the gate. The loop converts the thrown - // error into a tool-error result and surfaces it to the agent. - throw new Error(`beforeToolCall RPC failed: ${response.error}`); - } - const result = response.result as BeforeToolCallRpcResult; - if (!result.block) return undefined; - return { block: true, reason: result.reason ?? undefined }; - }; - - const transformContext: AgentHookBundle["transformContext"] = async ( - messages, - ): Promise => { - try { - const outcome = compactMessagesIfNeeded(messages); - if (outcome.changed && outcome.messages) { - if (outcome.telemetry) { - onContextCompaction?.({ - ...outcome.telemetry, - runId, - emittedAt: new Date().toISOString(), - }); - } - return outcome.messages; - } - return messages; - } catch (error) { - throw new Error( - `transformContext compaction failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - }; - - return { beforeToolCall, transformContext }; -} diff --git a/src/main/agent-runtime/agent-message-schema.ts b/src/main/agent-runtime/agent-message-schema.ts deleted file mode 100644 index 0f7407ac..00000000 --- a/src/main/agent-runtime/agent-message-schema.ts +++ /dev/null @@ -1,100 +0,0 @@ -import type { AgentMessage } from "@mariozechner/pi-agent-core"; - -const AGENT_MESSAGE_SCHEMA_VERSION = 1; -const ALLOWED_AGENT_MESSAGE_ROLES = new Set(["user", "assistant", "toolResult"]); - -interface PersistedAgentMessageEnvelope { - schemaVersion: 1; - kind: "agent_message"; - message: AgentMessage; - persistedAt: string; -} - -interface SessionEntryPayloadRow { - id: string; - payloadJson: string; -} - -function formatMessageError(prefix: string, message: string): Error { - return new Error(`${prefix}: ${message}`); -} - -function assertRecord(value: unknown, prefix: string): asserts value is Record { - if (!value || typeof value !== "object" || Array.isArray(value)) { - throw formatMessageError(prefix, "expected an object"); - } -} - -function normalizeAgentMessageForSession( - input: AgentMessage, - prefix = "Invalid AgentMessage", - options: { requireTimestamp: boolean } = { requireTimestamp: true }, -): AgentMessage { - assertRecord(input, prefix); - const role = input.role; - if (typeof role !== "string" || !ALLOWED_AGENT_MESSAGE_ROLES.has(role)) { - throw formatMessageError(prefix, `invalid role ${typeof role === "string" ? JSON.stringify(role) : ""}`); - } - const content = (input as { content?: unknown }).content; - if (typeof content !== "string" && !Array.isArray(content)) { - throw formatMessageError(prefix, "content must be a string or an array"); - } - const timestamp = (input as { timestamp?: unknown }).timestamp; - if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) { - if (options.requireTimestamp) { - throw formatMessageError(prefix, "timestamp must be a finite number"); - } - return { - ...input, - timestamp: Date.now(), - } as AgentMessage; - } - return input; -} - -export function validateNewAgentMessageForSession(input: AgentMessage, prefix = "Invalid AgentMessage"): AgentMessage { - return normalizeAgentMessageForSession(input, prefix, { requireTimestamp: true }); -} - -function normalizeLegacyAgentMessageForSession(input: AgentMessage, prefix = "Invalid legacy AgentMessage"): AgentMessage { - return normalizeAgentMessageForSession(input, prefix, { requireTimestamp: false }); -} - -export function encodeAgentMessageForSession(message: AgentMessage, persistedAt = new Date().toISOString()): string { - const normalized = validateNewAgentMessageForSession(message); - const envelope: PersistedAgentMessageEnvelope = { - schemaVersion: AGENT_MESSAGE_SCHEMA_VERSION, - kind: "agent_message", - message: normalized, - persistedAt, - }; - return JSON.stringify(envelope); -} - -export function decodeAgentMessageFromSessionEntry(row: SessionEntryPayloadRow): AgentMessage { - let parsed: unknown; - try { - parsed = JSON.parse(row.payloadJson); - } catch (error) { - throw new Error( - `Invalid session entry ${row.id} payload JSON: ${error instanceof Error ? error.message : String(error)}`, - ); - } - assertRecord(parsed, `Invalid session entry ${row.id}`); - - if (parsed.schemaVersion === AGENT_MESSAGE_SCHEMA_VERSION || parsed.kind === "agent_message") { - if (parsed.schemaVersion !== AGENT_MESSAGE_SCHEMA_VERSION || parsed.kind !== "agent_message") { - throw new Error(`Invalid session entry ${row.id}: unsupported AgentMessage envelope`); - } - return validateNewAgentMessageForSession( - parsed.message as AgentMessage, - `Invalid session entry ${row.id} AgentMessage`, - ); - } - - return normalizeLegacyAgentMessageForSession(parsed as unknown as AgentMessage, `Invalid legacy session entry ${row.id}`); -} - -export function getAgentMessageRole(message: AgentMessage): string { - return validateNewAgentMessageForSession(message).role as string; -} diff --git a/src/main/agent-runtime/artifact-baseline.ts b/src/main/agent-runtime/artifact-baseline.ts deleted file mode 100644 index 9dbbbf26..00000000 --- a/src/main/agent-runtime/artifact-baseline.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { relative, resolve } from "node:path"; -import { readdirSync, statSync } from "node:fs"; -import { isGitRepo } from "./artifact-git"; -import { logArtifactFsError, type Logger } from "./artifact-logging"; -import type { WorkspaceBaseline } from "./artifact-types"; - -const MAX_BASELINE_ENTRIES = 20_000; - -export const BASELINE_SKIP_DIR_NAMES: ReadonlySet = new Set([ - ".git", - "node_modules", - ".next", - "dist", - "build", - "out", - ".cache", - ".pnpm-store", -]); - -/** - * Capture a run-start mtime baseline only for non-git workspaces. - * Git workspaces use `git status` as the authoritative diff source. - */ -export function captureBaselineIfRequired( - workspacePath: string | null, - logger?: Logger, -): WorkspaceBaseline | null { - if (!workspacePath) return null; - if (isGitRepo(workspacePath)) return null; - try { - if (!statSync(workspacePath).isDirectory()) return null; - } catch (error) { - logArtifactFsError( - logger, - error, - "artifact.fs.workspace_stat_failed", - "Failed to stat workspace before artifact baseline capture.", - { workspacePath }, - ); - return null; - } - - const mtimeByRelPath = new Map(); - const stack: string[] = [workspacePath]; - let truncated = false; - while (stack.length > 0) { - if (mtimeByRelPath.size >= MAX_BASELINE_ENTRIES) { - truncated = true; - break; - } - const dir = stack.pop(); - if (!dir) break; - let entries: { name: string; isDirectory: () => boolean; isSymbolicLink: () => boolean }[]; - try { - entries = readdirSync(dir, { withFileTypes: true }); - } catch (error) { - logArtifactFsError( - logger, - error, - "artifact.fs.baseline_readdir_failed", - "Failed to read workspace directory during artifact baseline capture.", - { workspacePath, dir }, - ); - continue; - } - for (const entry of entries) { - const abs = resolve(dir, entry.name); - if (entry.isSymbolicLink()) continue; - if (entry.isDirectory()) { - if (BASELINE_SKIP_DIR_NAMES.has(entry.name)) continue; - stack.push(abs); - continue; - } - try { - const stat = statSync(abs); - if (!stat.isFile()) continue; - const rel = relative(workspacePath, abs); - if (rel.length === 0) continue; - mtimeByRelPath.set(rel, stat.mtimeMs); - } catch (error) { - logArtifactFsError( - logger, - error, - "artifact.fs.baseline_stat_failed", - "Failed to stat workspace file during artifact baseline capture.", - { workspacePath, absPath: abs }, - ); - continue; - } - if (mtimeByRelPath.size >= MAX_BASELINE_ENTRIES) { - truncated = true; - break; - } - } - } - return { mtimeByRelPath, capturedAt: Date.now(), truncated }; -} diff --git a/src/main/agent-runtime/artifact-change-detector.ts b/src/main/agent-runtime/artifact-change-detector.ts deleted file mode 100644 index b46dc5a9..00000000 --- a/src/main/agent-runtime/artifact-change-detector.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { execFileSync } from "node:child_process"; -import { readdirSync, statSync } from "node:fs"; -import { relative, resolve } from "node:path"; -import { BASELINE_SKIP_DIR_NAMES } from "./artifact-baseline"; -import { isGitRepo } from "./artifact-git"; -import { logArtifactFsError } from "./artifact-logging"; -import type { ArtifactProjectorRunContext, ChangeSet, GitChangeSet, WorkspaceBaseline } from "./artifact-types"; - -export function collectChangedPaths(ctx: ArtifactProjectorRunContext): ChangeSet { - if (!ctx.workspacePath) { - return { source: "none", changed: [], deleted: [], skipReason: "no_workspace" }; - } - if (isGitRepo(ctx.workspacePath)) { - try { - const gitSet = listChangedRelPaths(ctx.workspacePath); - return { source: "git", changed: gitSet.changed, deleted: gitSet.deleted }; - } catch (error) { - logArtifactFsError( - ctx.logger, - error, - "artifact.fs.git_status_failed", - "Failed to read git status during artifact projection.", - { workspacePath: ctx.workspacePath, runId: ctx.runId }, - ); - return { source: "none", changed: [], deleted: [], skipReason: "git_status_failed" }; - } - } - if (ctx.workspaceBaseline) { - const diff = diffAgainstBaseline(ctx.workspacePath, ctx.workspaceBaseline, ctx.logger); - return { - source: "baseline", - changed: diff.changed, - deleted: diff.deleted, - coverageTruncated: ctx.workspaceBaseline.truncated, - }; - } - return { source: "none", changed: [], deleted: [], skipReason: "no_baseline" }; -} - -function diffAgainstBaseline( - workspacePath: string, - baseline: WorkspaceBaseline, - logger: ArtifactProjectorRunContext["logger"], -): GitChangeSet { - const changed: string[] = []; - const seenRels = new Set(); - const stack: string[] = [workspacePath]; - while (stack.length > 0) { - const dir = stack.pop(); - if (!dir) break; - let entries: { name: string; isDirectory: () => boolean; isSymbolicLink: () => boolean }[]; - try { - entries = readdirSync(dir, { withFileTypes: true }); - } catch (error) { - logArtifactFsError( - logger, - error, - "artifact.fs.diff_readdir_failed", - "Failed to read workspace directory during artifact diff.", - { workspacePath, dir }, - ); - continue; - } - for (const entry of entries) { - if (entry.isSymbolicLink()) continue; - const abs = resolve(dir, entry.name); - if (entry.isDirectory()) { - if (BASELINE_SKIP_DIR_NAMES.has(entry.name)) continue; - stack.push(abs); - continue; - } - let mtimeMs: number; - try { - const stat = statSync(abs); - if (!stat.isFile()) continue; - mtimeMs = stat.mtimeMs; - } catch (error) { - logArtifactFsError( - logger, - error, - "artifact.fs.diff_stat_failed", - "Failed to stat workspace file during artifact diff.", - { workspacePath, absPath: abs }, - ); - continue; - } - const rel = relative(workspacePath, abs); - if (rel.length === 0) continue; - seenRels.add(rel); - const previous = baseline.mtimeByRelPath.get(rel); - if (previous === undefined) { - if (!baseline.truncated) changed.push(rel); - continue; - } - if (mtimeMs > previous) changed.push(rel); - } - } - const deleted: string[] = []; - for (const rel of baseline.mtimeByRelPath.keys()) { - if (!seenRels.has(rel)) deleted.push(rel); - } - return { changed, deleted }; -} - -function listChangedRelPaths(workspacePath: string): GitChangeSet { - const raw = execFileSync("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], { - cwd: workspacePath, - timeout: 5_000, - encoding: "utf8", - maxBuffer: 1024 * 1024, - }); - if (!raw) return { changed: [], deleted: [] }; - const entries = raw.split("\0").filter(Boolean); - const changed: string[] = []; - const deleted: string[] = []; - for (let i = 0; i < entries.length; i++) { - const entry = entries[i]; - if (entry.length < 3) continue; - const indexStatus = entry[0]; - const worktreeStatus = entry[1]; - const rest = entry.slice(3); - if (indexStatus === "!" && worktreeStatus === "!") continue; - const isRename = indexStatus === "R" || worktreeStatus === "R"; - if (representsDeletion(indexStatus, worktreeStatus)) { - deleted.push(rest); - if (isRename) i += 1; - continue; - } - changed.push(rest); - if (isRename) i += 1; - } - return { changed, deleted }; -} - -function representsDeletion(indexStatus: string, worktreeStatus: string): boolean { - if (worktreeStatus === "D") return true; - if (indexStatus === "D" && worktreeStatus === " ") return true; - return false; -} diff --git a/src/main/agent-runtime/artifact-git.ts b/src/main/agent-runtime/artifact-git.ts deleted file mode 100644 index 3cd1b62f..00000000 --- a/src/main/agent-runtime/artifact-git.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { spawnSync } from "node:child_process"; - -/** - * Ask git whether `workspacePath` sits inside a working tree. This - * covers a plain clone, linked worktree, and submodule. - */ -export function isGitRepo(workspacePath: string): boolean { - const result = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], { - cwd: workspacePath, - timeout: 2_000, - stdio: ["ignore", "ignore", "ignore"], - }); - return result.status === 0; -} diff --git a/src/main/agent-runtime/artifact-logging.ts b/src/main/agent-runtime/artifact-logging.ts deleted file mode 100644 index 99386989..00000000 --- a/src/main/agent-runtime/artifact-logging.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { logAppError, type Logger } from "../errors/index.js"; - -const DEFAULT_ARTIFACT_LOGGER: Logger = console; - -export type { Logger }; - -export function logArtifactFsError( - logger: Logger | undefined, - error: unknown, - code: string, - message: string, - context: Record, -): void { - logAppError( - logger ?? DEFAULT_ARTIFACT_LOGGER, - error, - { - kind: "recoverable", - code, - message, - context, - }, - "warn", - ); -} diff --git a/src/main/agent-runtime/artifact-path-filter.ts b/src/main/agent-runtime/artifact-path-filter.ts deleted file mode 100644 index 64b78a08..00000000 --- a/src/main/agent-runtime/artifact-path-filter.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { isAbsolute, relative } from "node:path"; - -/** Paths we never register because they are tool output or build/cache state. */ -const IGNORED_PATH_SEGMENTS: readonly string[] = [ - "/.git/", - "/node_modules/", - "/.next/", - "/dist/", - "/build/", - "/out/", - "/.cache/", - "/.pnpm-store/", - "/.DS_Store", -]; - -const IGNORED_EXACT_NAMES: ReadonlySet = new Set([ - ".DS_Store", - "package-lock.json", - "pnpm-lock.yaml", - "yarn.lock", - ".gitignore", -]); - -const IGNORED_EXTENSIONS: ReadonlySet = new Set([ - ".lock", - ".log", - ".map", - ".min.js", - ".min.css", -]); - -/** Returns true when the path is inside the workspace and passes the artifact filter. */ -export function isRegistrablePath(absPath: string, workspacePath: string): boolean { - const rel = relative(workspacePath, absPath); - if (rel.startsWith("..") || isAbsolute(rel)) return false; - const probePath = `/${rel}/`; - if (IGNORED_PATH_SEGMENTS.some((seg) => probePath.includes(seg))) return false; - const lastSlash = rel.lastIndexOf("/"); - const basename = lastSlash >= 0 ? rel.slice(lastSlash + 1) : rel; - if (IGNORED_EXACT_NAMES.has(basename)) return false; - const dot = basename.lastIndexOf("."); - if (dot > 0) { - const ext = basename.slice(dot).toLowerCase(); - if (IGNORED_EXTENSIONS.has(ext)) return false; - const prevDot = basename.lastIndexOf(".", dot - 1); - if (prevDot > 0) { - const compound = basename.slice(prevDot).toLowerCase(); - if (IGNORED_EXTENSIONS.has(compound)) return false; - } - } - return true; -} diff --git a/src/main/agent-runtime/artifact-projection-events.ts b/src/main/agent-runtime/artifact-projection-events.ts deleted file mode 100644 index f478d983..00000000 --- a/src/main/agent-runtime/artifact-projection-events.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type { AppDatabase } from "@main/database"; -import type { ProjectionOutcome } from "./artifact-types"; - -export type ArtifactProjectionPhase = "completion_reconcile"; - -export interface ArtifactProjectionEventInput { - companyId: string; - runId: string; - agentId: string; - phase: ArtifactProjectionPhase; - workspaceId: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - outcomes: ProjectionOutcome[]; -} - -export interface ArtifactProjectionFailureInput { - companyId: string; - runId: string; - agentId: string; - phase: ArtifactProjectionPhase; - workspaceId: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - errorMessage: string; -} - -interface ProjectionCounts { - inserted: number; - updated: number; - retired: number; - skipped: number; -} - -function countOutcomes(outcomes: ProjectionOutcome[]): ProjectionCounts { - const counts: ProjectionCounts = { - inserted: 0, - updated: 0, - retired: 0, - skipped: 0, - }; - for (const outcome of outcomes) { - counts[outcome.kind] += 1; - } - return counts; -} - -function summarizeOutcomes(phase: ArtifactProjectionPhase, counts: ProjectionCounts): string { - return [ - `Artifact projection ${phase} acknowledged`, - `${counts.inserted} inserted`, - `${counts.updated} updated`, - `${counts.retired} retired`, - `${counts.skipped} skipped`, - ].join("; "); -} - -export function appendArtifactProjectionEvent( - db: AppDatabase, - input: ArtifactProjectionEventInput, -): ProjectionCounts { - const counts = countOutcomes(input.outcomes); - db.core.runs.appendRunEvent({ - companyId: input.companyId, - runId: input.runId, - agentId: input.agentId, - eventType: "artifact_projection", - level: "info", - message: summarizeOutcomes(input.phase, counts), - payload: { - phase: input.phase, - workspaceId: input.workspaceId, - workspaceMode: input.workspaceMode, - counts, - outcomes: input.outcomes, - }, - }); - return counts; -} - -export function appendArtifactProjectionFailureEvent( - db: AppDatabase, - input: ArtifactProjectionFailureInput, -): void { - db.core.runs.appendRunEvent({ - companyId: input.companyId, - runId: input.runId, - agentId: input.agentId, - eventType: "artifact_projection", - level: "error", - message: `Artifact projection ${input.phase} failed: ${input.errorMessage}`, - payload: { - phase: input.phase, - workspaceId: input.workspaceId, - workspaceMode: input.workspaceMode, - errorMessage: input.errorMessage, - }, - }); -} diff --git a/src/main/agent-runtime/artifact-projector.ts b/src/main/agent-runtime/artifact-projector.ts deleted file mode 100644 index fbea01b2..00000000 --- a/src/main/agent-runtime/artifact-projector.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { AppDatabase } from "@main/database"; -import { collectChangedPaths } from "./artifact-change-detector"; -import { - projectChangedPaths, - retireDeletedArtifacts, -} from "./artifact-work-products"; -import type { - ArtifactProjectorRunContext, - ChangeSet, - ProjectionOutcome, -} from "./artifact-types"; - -export { captureBaselineIfRequired } from "./artifact-baseline"; -export type { - ArtifactProjectorRunContext, - ProjectionOutcome, - WorkspaceBaseline, -} from "./artifact-types"; - -/** - * End-of-run filesystem artifact protocol. - * - * Completion reconciliation projects changed and deleted workspace - * paths into `work_products`, so the desktop UI can surface what the - * agent produced without relying on the agent to POST documents. - * - * Projection is idempotent through the natural identity - * `(companyId, workspaceId, provider="filesystem", externalId=)`. - * Git workspaces use `git status`; non-git workspaces use a run-start - * mtime baseline captured by `captureBaselineIfRequired`. - */ - -/** - * End-of-run reconciliation sweep. This is the single artifact - * projection boundary for files produced or removed during a run. - */ -export function reconcileWorkspaceArtifacts( - db: AppDatabase, - ctx: ArtifactProjectorRunContext, -): ProjectionOutcome[] { - return projectCollectedChanges(db, ctx, collectChangedPaths(ctx)); -} - -function projectCollectedChanges( - db: AppDatabase, - ctx: ArtifactProjectorRunContext, - change: ChangeSet, -): ProjectionOutcome[] { - if (change.source === "none") { - return [{ kind: "skipped", reason: change.skipReason ?? "no_changes" }]; - } - const outcomes: ProjectionOutcome[] = []; - if (change.changed.length === 0 && change.deleted.length === 0) { - outcomes.push({ kind: "skipped", reason: "no_changes" }); - } else { - outcomes.push(...projectChangedPaths(db, ctx, change.changed)); - outcomes.push(...retireDeletedArtifacts(db, ctx, change.deleted)); - } - if (change.coverageTruncated) { - outcomes.push({ kind: "skipped", reason: "baseline_truncated" }); - } - return outcomes; -} diff --git a/src/main/agent-runtime/artifact-types.ts b/src/main/agent-runtime/artifact-types.ts deleted file mode 100644 index cf9c2e1f..00000000 --- a/src/main/agent-runtime/artifact-types.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { Logger } from "./artifact-logging"; - -export type ArtifactProjectorRunContext = { - runId: string; - agentId: string; - companyId: string; - taskId: string | null; - workspaceId: string | null; - workspacePath: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - logger?: Logger; - /** - * mtime snapshot captured at run start for workspaces that are NOT - * a git repo. Diff-against-baseline is how completion reconciliation - * finds files the agent wrote without a `.git` to fall back on. - */ - workspaceBaseline: WorkspaceBaseline | null; -}; - -export interface WorkspaceBaseline { - /** Relative path -> mtimeMs at capture. */ - mtimeByRelPath: Map; - /** Unix ms at which the baseline was taken. */ - capturedAt: number; - /** True when the walker stopped early because the cap was hit; the baseline is still usable for captured paths. */ - truncated: boolean; -} - -export type ProjectionOutcome = - | { kind: "skipped"; reason: string } - | { kind: "inserted"; workProductId: string; relativePath: string } - | { kind: "updated"; workProductId: string; relativePath: string } - | { kind: "retired"; workProductId: string; relativePath: string }; - -export interface GitChangeSet { - changed: string[]; - deleted: string[]; -} - -export type ChangeSource = "git" | "baseline" | "none"; - -export interface ChangeSet { - source: ChangeSource; - /** Paths, relative to the workspace root, that currently exist on disk with a new or advanced mtime. */ - changed: string[]; - /** Paths, relative to the workspace root, that the detector reports as removed during the run. */ - deleted: string[]; - /** Reason the source chose to skip, meaningful when source is "none". */ - skipReason?: string; - /** - * True when the baseline walker stopped before sampling the whole - * tree. Callers surface it as a `baseline_truncated` skip outcome. - */ - coverageTruncated?: boolean; -} diff --git a/src/main/agent-runtime/artifact-work-products.ts b/src/main/agent-runtime/artifact-work-products.ts deleted file mode 100644 index b3963ce5..00000000 --- a/src/main/agent-runtime/artifact-work-products.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { statSync } from "node:fs"; -import { relative, resolve } from "node:path"; -import type { AppDatabase } from "@main/database"; -import { logArtifactFsError } from "./artifact-logging"; -import { isRegistrablePath } from "./artifact-path-filter"; -import type { ArtifactProjectorRunContext, ProjectionOutcome } from "./artifact-types"; - -export function projectChangedPaths( - db: AppDatabase, - ctx: ArtifactProjectorRunContext, - changed: string[], -): ProjectionOutcome[] { - const workspacePath = ctx.workspacePath; - if (!workspacePath) return [{ kind: "skipped", reason: "no_workspace" }]; - const outcomes: ProjectionOutcome[] = []; - for (const rel of changed) { - const absPath = resolve(workspacePath, rel); - if (!isRegistrablePath(absPath, workspacePath)) { - outcomes.push({ kind: "skipped", reason: "path_ignored" }); - continue; - } - outcomes.push(upsertFilesystemArtifact(db, ctx, workspacePath, absPath)); - } - return outcomes; -} - -export function retireDeletedArtifacts( - db: AppDatabase, - ctx: ArtifactProjectorRunContext, - deleted: string[], -): ProjectionOutcome[] { - if (deleted.length === 0) return []; - const resolvedWorkspaceId = - ctx.workspaceId ?? - (ctx.workspacePath - ? db.core.workspaces.findWorkspaceIdByLocalPath(ctx.companyId, ctx.workspacePath) - : null); - const archived = db.core.documents.archiveWorkProductsByExternalPaths({ - companyId: ctx.companyId, - workspaceId: resolvedWorkspaceId, - provider: "filesystem", - paths: deleted, - lastTouchedByRunId: ctx.runId, - }); - return archived.map(({ id, externalId }) => ({ - kind: "retired", - workProductId: id, - relativePath: externalId, - })); -} - -function upsertFilesystemArtifact( - db: AppDatabase, - ctx: ArtifactProjectorRunContext, - workspacePath: string, - absPath: string, -): ProjectionOutcome { - const relativePath = relative(workspacePath, absPath); - let stat: ReturnType; - try { - stat = statSync(absPath); - } catch (error) { - logArtifactFsError( - ctx.logger, - error, - "artifact.fs.path_stat_failed", - "Failed to stat filesystem artifact before projection.", - { - workspacePath, - absPath, - runId: ctx.runId, - }, - ); - return { kind: "skipped", reason: "path_missing" }; - } - if (!stat.isFile()) { - return { kind: "skipped", reason: "not_a_regular_file" }; - } - - const lastSlash = relativePath.lastIndexOf("/"); - const title = lastSlash >= 0 ? relativePath.slice(lastSlash + 1) : relativePath; - const provider = "filesystem"; - const resolvedWorkspaceId = - ctx.workspaceId ?? db.core.workspaces.findWorkspaceIdByLocalPath(ctx.companyId, workspacePath); - const existing = db.core.documents.findWorkProductByExternalId( - ctx.companyId, - provider, - relativePath, - resolvedWorkspaceId, - ); - if (existing) { - const patch: Parameters[2] = { - title, - status: "active", - lastTouchedByRunId: ctx.runId, - }; - if (resolvedWorkspaceId) patch.workspaceId = resolvedWorkspaceId; - db.core.documents.updateWorkProduct(existing.id, ctx.companyId, patch); - return { kind: "updated", workProductId: existing.id, relativePath }; - } - const workProductId = db.core.documents.createWorkProduct({ - companyId: ctx.companyId, - taskId: ctx.taskId, - workspaceId: resolvedWorkspaceId, - type: "file", - provider, - externalId: relativePath, - title, - url: null, - createdByRunId: ctx.runId, - }); - return { kind: "inserted", workProductId, relativePath }; -} diff --git a/src/main/agent-runtime/context-compactor.ts b/src/main/agent-runtime/context-compactor.ts deleted file mode 100644 index 3162d14e..00000000 --- a/src/main/agent-runtime/context-compactor.ts +++ /dev/null @@ -1,328 +0,0 @@ -/** - * Deterministic pi context compactor. - * - * pi's `transformContext` hook runs before each LLM call and returns - * the message list that will actually be sent. A long-running agent - * can accumulate hundreds of messages — if we forward every one on - * every call we pay per-token for the whole history, and large models - * throttle when the context approaches their window. - * - * This compactor keeps the hook pure and provider-free: no LLM - * round-trip, no mutation, no IO. It counts transcript text with a - * local tiktoken-compatible encoder, keeps recent traffic verbatim, and - * collapses older messages into a single "context summary" user turn - * that preserves the assistant's narrative plus tool-call headlines. - * - * Triggering only when the estimate clears the threshold means short - * runs pay nothing; long runs see roughly constant per-call cost once - * they cross the threshold. - */ - -import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import { getEncoding } from "js-tiktoken"; - -/** Token-budget threshold that triggers compaction. */ -const COMPACTION_TRIGGER_TOKENS = 120_000; -/** - * Number of recent messages preserved verbatim. The tail must include - * the current turn plus enough context for the agent to answer without - * losing mid-stream state (tool-call pairs, user intent). - */ -const RECENT_MESSAGE_TAIL = 20; -const CONTEXT_ENCODING = getEncoding("cl100k_base"); -const CHAT_MESSAGE_OVERHEAD_TOKENS = 4; -/** Per-assistant-message summary cap to keep the compacted turn readable. */ -const MAX_SUMMARY_CHARS_PER_MESSAGE = 160; -const MAX_TOOL_RESULT_LINES = 12; -const MAX_TOOL_RESULT_FACTS = 10; -const MAX_FACT_VALUE_CHARS = 120; - -interface MessageLike { - role?: string; - content?: unknown; - timestamp?: number; - toolCallId?: string; - details?: unknown; -} - -export interface CompactionOutcome { - changed: boolean; - messages: AgentMessage[] | null; - telemetry: CompactionTelemetry | null; -} - -export interface CompactionTelemetry { - estimatedTokens: number; - originalMessageCount: number; - compactedMessageCount: number; - compactedOlderMessageCount: number; - retainedRecentMessageCount: number; -} - -/** - * Returns a compacted message list when the incoming transcript - * exceeds the budget, or `{ changed: false }` when no compaction is - * needed. The transformContext hook forwards the result verbatim. - * - * Cutoff must land on a user-turn boundary so we never orphan a - * `toolResult` from its originating assistant `toolCall`. pi-ai's - * message shape pairs assistant-with-toolCall blocks against standalone - * `{ role: "toolResult", toolCallId }` messages — cutting mid-pair - * would leave the provider with a dangling id and crash the next call. - * When no safe boundary exists within reach, we decline to compact and - * let the upstream token budget handle it. - */ -export function compactMessagesIfNeeded(messages: AgentMessage[]): CompactionOutcome { - const estimatedTokens = estimateTokens(messages); - if (estimatedTokens < COMPACTION_TRIGGER_TOKENS) { - return { changed: false, messages: null, telemetry: null }; - } - if (messages.length <= RECENT_MESSAGE_TAIL + 1) { - return { changed: false, messages: null, telemetry: null }; - } - - const desiredCutoff = messages.length - RECENT_MESSAGE_TAIL; - const cutoff = findSafeCutoff(messages, desiredCutoff); - if (cutoff === null) { - return { changed: false, messages: null, telemetry: null }; - } - - const older = messages.slice(0, cutoff); - const recent = messages.slice(cutoff); - - const summaryText = buildSummaryText(older); - const summary: AgentMessage = { - role: "user", - content: [{ type: "text", text: summaryText }], - timestamp: Date.now(), - } as AgentMessage; - - const compactedMessages = [summary, ...recent]; - return { - changed: true, - messages: compactedMessages, - telemetry: { - estimatedTokens, - originalMessageCount: messages.length, - compactedMessageCount: compactedMessages.length, - compactedOlderMessageCount: older.length, - retainedRecentMessageCount: recent.length, - }, - }; -} - -/** - * Walk back from `desiredCutoff` until we find an index where the - * message at that position starts a clean user turn. A user turn is - * identifiable by `role === "user"`; anything else (`assistant`, - * `toolResult`, or custom app message) can reference or be referenced - * by neighbouring messages and must stay grouped. - * - * Returns `null` when no safe boundary exists in [1, desiredCutoff] — - * e.g. an entirely tool-chained transcript. Returning null signals "do - * not compact"; callers must pass the transcript through unchanged. - */ -function findSafeCutoff(messages: AgentMessage[], desiredCutoff: number): number | null { - for (let i = desiredCutoff; i >= 1; i--) { - const raw = messages[i] as MessageLike | undefined; - if (raw && raw.role === "user") { - return i; - } - } - return null; -} - -function estimateTokens(messages: AgentMessage[]): number { - let total = 0; - for (const message of messages) { - total += estimateMessageTokens(message); - } - return total; -} - -function estimateMessageTokens(message: AgentMessage): number { - const raw = extractTextForEstimate(message as MessageLike); - if (raw.length === 0) return CHAT_MESSAGE_OVERHEAD_TOKENS; - return CONTEXT_ENCODING.encode(raw).length + CHAT_MESSAGE_OVERHEAD_TOKENS; -} - -function extractTextForEstimate(message: MessageLike): string { - const content = message.content; - if (typeof content === "string") return content; - if (!Array.isArray(content)) return ""; - const parts: string[] = []; - for (const block of content) { - if (!block || typeof block !== "object") continue; - const obj = block as { type?: string; text?: string; thinking?: string; name?: string }; - if (typeof obj.text === "string") parts.push(obj.text); - else if (typeof obj.thinking === "string") parts.push(obj.thinking); - else if (obj.type === "toolCall" && typeof obj.name === "string") parts.push(`tool:${obj.name}`); - } - return parts.join(" "); -} - -function buildSummaryText(older: AgentMessage[]): string { - const lines: string[] = [ - "[Context summary — older turns compacted to stay within the token budget]", - "", - ]; - const firstUserText = findFirstUserPrompt(older); - if (firstUserText) { - lines.push(`Original task: ${truncate(firstUserText, 200)}`); - lines.push(""); - } - const assistantPoints = collectAssistantHighlights(older); - if (assistantPoints.length > 0) { - lines.push("Key turns:"); - for (const point of assistantPoints) { - lines.push(`- ${point}`); - } - } - const toolResultFacts = collectToolResultFacts(older); - if (toolResultFacts.length > 0) { - lines.push(""); - lines.push("Tool results:"); - for (const fact of toolResultFacts) { - lines.push(`- ${fact}`); - } - } - lines.push(""); - lines.push(`(${older.length} earlier message${older.length === 1 ? "" : "s"} compacted.)`); - return lines.join("\n"); -} - -function findFirstUserPrompt(messages: AgentMessage[]): string | null { - for (const message of messages) { - const raw = message as MessageLike; - if (raw.role !== "user") continue; - const text = extractTextForEstimate(raw).trim(); - if (text.length > 0) return text; - } - return null; -} - -function collectAssistantHighlights(messages: AgentMessage[]): string[] { - const highlights: string[] = []; - for (const message of messages) { - const raw = message as MessageLike; - if (raw.role !== "assistant") continue; - const text = extractTextForEstimate(raw).trim(); - if (text.length === 0) continue; - highlights.push(truncate(firstSentence(text), MAX_SUMMARY_CHARS_PER_MESSAGE)); - if (highlights.length >= 12) break; - } - return highlights; -} - -function collectToolResultFacts(messages: AgentMessage[]): string[] { - const toolNamesById = collectToolNamesById(messages); - const facts: string[] = []; - for (const message of messages) { - const raw = message as MessageLike; - if (raw.role !== "toolResult") continue; - const toolCallId = raw.toolCallId ?? "unknown"; - const toolName = toolNamesById.get(toolCallId) ?? "tool"; - const resultFacts = collectFactsFromToolResult(raw); - const factText = - resultFacts.length > 0 - ? resultFacts.slice(0, MAX_TOOL_RESULT_FACTS).join("; ") - : `result=${truncate(firstSentence(extractTextForEstimate(raw)), MAX_FACT_VALUE_CHARS)}`; - facts.push(`${toolName} ${toolCallId}: ${factText}`); - if (facts.length >= MAX_TOOL_RESULT_LINES) break; - } - return facts; -} - -function collectToolNamesById(messages: AgentMessage[]): Map { - const names = new Map(); - for (const message of messages) { - const raw = message as MessageLike; - if (raw.role !== "assistant" || !Array.isArray(raw.content)) continue; - for (const block of raw.content) { - if (!block || typeof block !== "object") continue; - const obj = block as { type?: string; id?: string; name?: string }; - if (obj.type === "toolCall" && typeof obj.id === "string" && typeof obj.name === "string") { - names.set(obj.id, obj.name); - } - } - } - return names; -} - -function collectFactsFromToolResult(message: MessageLike): string[] { - const facts = new Map(); - if (message.toolCallId) facts.set("toolCallId", message.toolCallId); - collectStructuredFacts(message.details, facts); - const text = extractTextForEstimate(message).trim(); - collectStructuredFacts(parseJsonObject(text), facts); - collectTextFacts(text, facts); - return [...facts.entries()].map(([key, value]) => `${key}=${value}`); -} - -function parseJsonObject(text: string): unknown { - if (!text.startsWith("{") && !text.startsWith("[")) return null; - try { - return JSON.parse(text) as unknown; - } catch { - return null; - } -} - -function collectStructuredFacts(value: unknown, facts: Map, path: string[] = []): void { - if (facts.size >= MAX_TOOL_RESULT_FACTS) return; - if (value === null || value === undefined) return; - if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { - const key = path.at(-1); - if (key && shouldPreserveFactKey(key)) { - facts.set(key, truncate(String(value), MAX_FACT_VALUE_CHARS)); - } - return; - } - if (Array.isArray(value)) { - for (const item of value.slice(0, 8)) { - collectStructuredFacts(item, facts, path); - } - return; - } - if (typeof value !== "object") return; - for (const [key, nested] of Object.entries(value as Record)) { - collectStructuredFacts(nested, facts, [...path, key]); - } -} - -function collectTextFacts(text: string, facts: Map): void { - const pattern = /\b(taskId|approvalId|messageId|status|state|decision|error)\s*[:=]\s*("[^"]+"|'[^']+'|[^,;\s}]+)/g; - for (const match of text.matchAll(pattern)) { - const key = match[1]; - const rawValue = match[2]; - if (!key || !rawValue || facts.has(key)) continue; - facts.set(key, truncate(rawValue.replace(/^["']|["']$/g, ""), MAX_FACT_VALUE_CHARS)); - if (facts.size >= MAX_TOOL_RESULT_FACTS) break; - } -} - -function shouldPreserveFactKey(key: string): boolean { - const lower = key.toLowerCase(); - return ( - lower === "id" || - lower.endsWith("id") || - lower.endsWith("_id") || - lower === "status" || - lower === "state" || - lower === "error" || - lower === "decision" || - lower === "ok" - ); -} - -function firstSentence(text: string): string { - const collapsed = text.replace(/\s+/g, " ").trim(); - const sentenceEnd = collapsed.search(/[.?!](\s|$)/); - if (sentenceEnd > 0) return collapsed.slice(0, sentenceEnd + 1); - return collapsed; -} - -function truncate(text: string, maxLen: number): string { - if (text.length <= maxLen) return text; - return text.slice(0, maxLen - 1).trimEnd() + "…"; -} diff --git a/src/main/agent-runtime/cost-writer.ts b/src/main/agent-runtime/cost-writer.ts deleted file mode 100644 index 45c6f1eb..00000000 --- a/src/main/agent-runtime/cost-writer.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { calculateCost, type Usage } from "@mariozechner/pi-ai"; -import type { AppDatabase } from "@main/database"; -import { getConnectorDefinition } from "@main/connectors"; -import { resolveModel, resolveModelCostFallback } from "@main/model-resolver"; - -export interface CostWriterDeps { - db: AppDatabase; -} - -interface ObserveInput { - runId: string; - companyId: string; - agentId: string; - taskId: string | null; - connectorId: string; - modelId: string; - usage: Usage; -} - -// Local OpenAI-compatible servers run on the user's own machine, so the -// LLM call has no third-party billing line. Record a zero cost entry -// without invoking pi-ai's calculator (which would require the model's -// baseUrl from the credential — unnecessary work for a flat-zero cost). -const ZERO_COST_PROVIDERS: ReadonlySet = new Set(["ollama", "lm-studio"]); - -export class CostWriter { - constructor(private readonly deps: CostWriterDeps) {} - - observeAssistantMessage(input: ObserveInput): void { - const definition = getConnectorDefinition(input.connectorId); - if (!definition.provider) { - throw new Error(`[cost-writer] connector ${input.connectorId} has no provider mapping`); - } - if (ZERO_COST_PROVIDERS.has(definition.provider)) { - this.deps.db.core.runs.recordCostEntry({ - runId: input.runId, - companyId: input.companyId, - agentId: input.agentId, - taskId: input.taskId, - connectorId: input.connectorId, - amountUsd: 0, - unattributed: false, - }); - return; - } - const model = resolveModel(definition.provider, input.modelId); - if (!model) { - throw new Error(`[cost-writer] model ${input.modelId} not found for provider ${definition.provider}`); - } - const patchedModel = resolveModelCostFallback(model, definition.provider); - const cost = calculateCost(patchedModel, input.usage); - if (!Number.isFinite(cost.total)) { - throw new Error( - `[cost-writer] cost calculation returned non-finite total for ${input.connectorId}/${input.modelId}`, - ); - } - - this.deps.db.core.runs.recordCostEntry({ - runId: input.runId, - companyId: input.companyId, - agentId: input.agentId, - taskId: input.taskId, - connectorId: input.connectorId, - amountUsd: cost.total, - unattributed: false, - }); - } -} diff --git a/src/main/agent-runtime/hook-handlers.ts b/src/main/agent-runtime/hook-handlers.ts deleted file mode 100644 index 0d78f453..00000000 --- a/src/main/agent-runtime/hook-handlers.ts +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Main-side implementation of pi's tool-execution approval hook. - * Invoked by `RuntimeBridge.handleRpc` when the worker proxies - * `beforeToolCall`. - * - * The handler is deliberately isolated to the operational-approval - * gate: it blocks destructive tools while an approval that gates - * EXECUTION is pending. - * - * Policy lives here; `RuntimeBridge` stays a pure IPC router. - */ - -import type { AppDatabase } from "@main/database"; -import type { - BeforeToolCallRpcPayload, - BeforeToolCallRpcResult, -} from "./hook-rpc"; - -/** - * Lifecycle phase of an active pi run as seen by main. - * - * - `preparing`: `prepareRun` RPC has landed; main knows the run is real, - * but the worker has not yet constructed the Agent instance. The - * in-process `activeAgents` map is empty, so any `steer` attempt would - * be silently dropped. - * - `agent_active`: the worker has both constructed the Agent and - * subscribed to its event stream. Steer-run messages are safe to - * dispatch — `agent.steer()` will enqueue onto the live steering queue - * and pi will drain it at the next turn boundary. - * - `closing`: the Agent finished (or aborted) and the worker has - * unsubscribed and removed the instance from `activeAgents`. The - * `run-finished` child message may still be in flight; treat steer - * messages as rejected so inbox delivery falls back to the next run. - */ -export type ActiveRunLifecycleState = "preparing" | "agent_active" | "closing"; - -export interface ActiveRunContext { - runId: string; - agentId: string; - companyId: string; - taskId: string | null; - connectorId: string; - modelId: string; - taskSessionId: string; - workspaceId: string | null; - workspacePath: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - workspaceBaseline: import("./artifact-projector").WorkspaceBaseline | null; - state: ActiveRunLifecycleState; -} - -export interface HookHandlerDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -/** - * Tools that can mutate the workspace or execute host-level effects. - * Every other tool (read/grep/glob) is always permitted — gating them - * would only slow observation. - */ -const DESTRUCTIVE_TOOLS: ReadonlySet = new Set(["bash", "write", "edit"]); - -export function isDestructiveTool(toolName: string): boolean { - return DESTRUCTIVE_TOOLS.has(toolName); -} - -/** - * Approval gate for destructive tools. Runs at every - * `beforeToolCall`, so approvals created mid-run take effect on the - * next tool call with no cross-process cache to invalidate. - * - * Heartbeat-level wait-state pausing is the responsibility of the - * scheduler (`checkpoint-engine.shouldPauseHeartbeat`); mirroring it - * here would freeze every outbound message and every coordination - * reply while an unrelated thread was still waiting on the user — - * the exact failure mode that made Co-Founder agents silent. - */ -export function handleBeforeToolCall( - deps: HookHandlerDeps, - ctx: ActiveRunContext, - payload: BeforeToolCallRpcPayload, -): BeforeToolCallRpcResult { - if (!isDestructiveTool(payload.toolName)) { - return { block: false, reason: null }; - } - return checkOperationalApprovalBlock(deps, ctx, payload.toolName); -} - -function checkOperationalApprovalBlock( - deps: HookHandlerDeps, - ctx: ActiveRunContext, - toolName: string, -): BeforeToolCallRpcResult { - try { - const blocking = deps.db.core.approvals.getBlockingApproval(ctx.companyId, ctx.agentId, ctx.taskId); - if (!blocking) return { block: false, reason: null }; - return { - block: true, - reason: `Approval ${blocking.id} (${blocking.type}, state=${blocking.state}) is outstanding: ${blocking.payloadSummary}. Wait for the decision before retrying ${toolName}.`, - }; - } catch (error) { - // Fail closed: an unreadable approval table is a safety incident, - // not a reason to run destructive code. - deps.logger.error( - `[hook-handlers] approval lookup failed for agent ${ctx.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return { - block: true, - reason: `Approval lookup failed — ${toolName} is held until the approval subsystem recovers.`, - }; - } -} diff --git a/src/main/agent-runtime/hook-rpc.ts b/src/main/agent-runtime/hook-rpc.ts deleted file mode 100644 index 8aa0bd63..00000000 --- a/src/main/agent-runtime/hook-rpc.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Hook RPC contracts — the parent↔worker half of pi-agent-core's - * `beforeToolCall` hook. - * - * The Agent instance lives in the utility process. Approval policy - * lives in main. The hook is therefore proxied: the worker invokes an - * RPC that main answers from the same `RuntimeBridge` that already owns - * agent-event and `persistMessage` handling. Context compaction runs in - * the worker process and reports telemetry through a worker message. - * - * Payloads intentionally exclude pi's `AgentContext` (systemPrompt, - * messages, tools) because main policy only needs the tool call. This - * keeps the hook IPC well under the structured-clone budget even for - * large transcripts. - */ -// ─── beforeToolCall ─────────────────────────────────────────────────────── - -export interface BeforeToolCallRpcPayload { - toolName: string; - toolCallId: string; - args: unknown; -} - -export interface BeforeToolCallRpcResult { - block: boolean; - reason: string | null; -} diff --git a/src/main/agent-runtime/inbound-correlation-registry.ts b/src/main/agent-runtime/inbound-correlation-registry.ts deleted file mode 100644 index 923eee16..00000000 --- a/src/main/agent-runtime/inbound-correlation-registry.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { AgentMessageRecord } from "@shared/types"; - -export interface InboundCorrelationEntry { - fromAgentId: string; - senderKind: AgentMessageRecord["senderKind"]; - messageId: string; - /** - * Stable pi-message timestamp that the projected user turn carries. - * Reverse-indexed so `message_end` can resolve back to `messageId`. - */ - piTimestamp: number; -} - -interface InboundCorrelationRegistry { - byMessageId: Map; - byPiTimestamp: Map; - lastAllocatedTimestamp: number; -} - -export class InboundCorrelationRegistryStore { - private readonly registries = new Map(); - - register(runId: string, record: AgentMessageRecord, baselineTimestamp: number): number { - const registry = this.getOrCreate(runId); - const allocated = Math.max(baselineTimestamp, registry.lastAllocatedTimestamp + 1); - registry.lastAllocatedTimestamp = allocated; - const entry: InboundCorrelationEntry = { - fromAgentId: record.fromAgentId, - senderKind: record.senderKind, - messageId: record.id, - piTimestamp: allocated, - }; - registry.byMessageId.set(record.id, entry); - registry.byPiTimestamp.set(allocated, record.id); - return allocated; - } - - lookup(runId: string, timestamp: number | undefined): InboundCorrelationEntry | null { - if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) return null; - const registry = this.registries.get(runId); - if (!registry) return null; - const messageId = registry.byPiTimestamp.get(timestamp); - if (!messageId) return null; - return registry.byMessageId.get(messageId) ?? null; - } - - deleteRun(runId: string): void { - this.registries.delete(runId); - } - - private getOrCreate(runId: string): InboundCorrelationRegistry { - const existing = this.registries.get(runId); - if (existing) return existing; - const registry: InboundCorrelationRegistry = { - byMessageId: new Map(), - byPiTimestamp: new Map(), - lastAllocatedTimestamp: 0, - }; - this.registries.set(runId, registry); - return registry; - } -} diff --git a/src/main/agent-runtime/inbox-projection.ts b/src/main/agent-runtime/inbox-projection.ts deleted file mode 100644 index 6b1f9e4a..00000000 --- a/src/main/agent-runtime/inbox-projection.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Inbox projection — converts a stored AgentMessageRecord into a pi - * AgentMessage (user role) so inter-agent communication enters the - * recipient's transcript as natural conversation rather than a prompt - * block re-rendered every turn. - * - * The projection is the single source of truth for how an inbound message - * looks inside a recipient's context: `[Message from {sender}{· channel}]` - * header, optional subject line, then the body. Content is normalized - * (control characters stripped, oversized bodies truncated) via the same - * helpers used by the legacy prompt-builder boundary. - */ - -import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import type { AgentMessageRecord } from "@shared/types"; - -const MAX_MESSAGE_BODY_LENGTH = 4000; -const MAX_SUBJECT_LENGTH = 200; - -export interface AgentDirectory { - getAgentName(agentId: string): string; -} - -/** - * Strip control characters (except newlines/tabs) and collapse excessive - * whitespace runs. Mirrors `messaging/normalize.ts#cleanText` to keep the - * transcript resilient against garbage from upstream senders. - */ -function cleanText(text: string): string { - // eslint-disable-next-line no-control-regex - return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "") - .replace(/[ \t]{4,}/g, " ") - .trim(); -} - -function truncate(text: string, maxLen: number): string { - if (text.length <= maxLen) return text; - return text.slice(0, maxLen - 1) + "…"; -} - -function formatChannelLabel(record: AgentMessageRecord): string | null { - if (record.channel === "direct") return null; - if (record.channelTargetId) return `${record.channel}:${record.channelTargetId}`; - return record.channel; -} - -function resolveSenderLabel( - record: AgentMessageRecord, - directory: AgentDirectory, -): string { - switch (record.senderKind) { - case "human": - // The board-reader virtual account is the only non-agent human sender - // surfaced in practice; render it as "Board" so agents know where - // strategic directives originate. - if (record.fromAgentId === "__board__") return "Board"; - return "User"; - case "system": - return "System"; - case "agent": - default: - return directory.getAgentName(record.fromAgentId); - } -} - -/** - * Projects a stored `AgentMessageRecord` into a pi `AgentMessage` - * (role: "user") suitable for appending to the recipient's session - * transcript. - * - * `timestampOverride`, when supplied, replaces the wall-clock timestamp - * derived from `record.createdAt`. Callers use this to allocate a - * monotonically unique value per run — two inbound messages landing in - * the same millisecond would otherwise share the same key, and the - * `RuntimeBridge` correlation index would lose one author's identity - * on the `message_end` callback. The actual value still lives in pi's - * `timestamp` number so ordering semantics remain identical. - */ -export function projectInboxMessageToPi( - record: AgentMessageRecord, - directory: AgentDirectory, - options?: { timestampOverride?: number }, -): AgentMessage { - const senderLabel = resolveSenderLabel(record, directory); - const channelLabel = formatChannelLabel(record); - const replyContext = record.channel === "direct" - ? `reply-to: channel=direct, toAgentId=${record.fromAgentId}` - : `reply-to: channel=${record.channel}, channelTargetId=${record.channelTargetId ?? ""}`; - const header = channelLabel - ? `[Message from ${senderLabel} · ${channelLabel} | ${replyContext}]` - : `[Message from ${senderLabel} | ${replyContext}]`; - - const subject = record.subject ? truncate(cleanText(record.subject), MAX_SUBJECT_LENGTH) : ""; - const body = truncate(cleanText(record.body), MAX_MESSAGE_BODY_LENGTH); - - const parts: string[] = [header]; - if (subject.length > 0) parts.push(subject); - if (body.length > 0) parts.push(body); - const text = parts.join("\n\n"); - - let timestamp = options?.timestampOverride; - if (typeof timestamp !== "number" || !Number.isFinite(timestamp)) { - const parsed = Date.parse(record.createdAt); - timestamp = Number.isFinite(parsed) ? parsed : Date.now(); - } - return { - role: "user", - content: [{ type: "text", text }], - timestamp, - } as AgentMessage; -} diff --git a/src/main/agent-runtime/index.ts b/src/main/agent-runtime/index.ts deleted file mode 100644 index bfa688fb..00000000 --- a/src/main/agent-runtime/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { SqliteSessionStore } from "./sqlite-session-store"; -export { CostWriter } from "./cost-writer"; -export { RuntimeBridge } from "./runtime-bridge"; -export { RuntimeMessageInjector } from "./runtime-message-injector"; diff --git a/src/main/agent-runtime/internal-tools/file-approval-handler.ts b/src/main/agent-runtime/internal-tools/file-approval-handler.ts deleted file mode 100644 index 71aaad1c..00000000 --- a/src/main/agent-runtime/internal-tools/file-approval-handler.ts +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Main-side handler for the `file_approval` internal tool (C4 part 2/5). - * - * Mirrors the control flow of `POST /api/companies/:id/approvals` in - * `api-server/routes-approvals.ts`: validate → enforce the - * `approve_ceo_strategy` ordering gate → request approval → auto- - * approve or notify. Both the tool path and the HTTP path funnel - * through the same `db.core.approvals.requestApproval` + `shouldAutoApprove` - * plumbing, so the board sees identical rows regardless of entry point. - * - * No fallbacks: malformed input throws UserInputError, DB failures - * throw UpstreamError. The worker tool wrapper surfaces the classified - * message as a pi tool-error so the model can correct its call. - */ - -import type { AppDatabase } from "@main/database"; -import { approvalInputSchema, mergeApprovalAttachments } from "@shared/contracts"; -import { resolveApprovalDecision } from "@main/approval-policy"; -import { shouldAutoApprove } from "@main/execution-policy"; -import { UserInputError, UpstreamError, classifyUnknownError } from "@main/errors"; -import type { InvokeInternalToolRpcResult } from "@main/worker/runtime/internal-tools/internal-tool-rpc"; - -export interface FileApprovalHandlerDeps { - db: AppDatabase; - onApprovalCreated: (approvalId: string, companyId: string, taskId: string | null, approvalType: string, summary: string) => void; - onApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - onDomainChanged: () => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export interface FileApprovalHandlerContext { - companyId: string; - agentId: string; -} - -export function handleFileApprovalToolCall( - deps: FileApprovalHandlerDeps, - ctx: FileApprovalHandlerContext, - rawArgs: unknown, -): InvokeInternalToolRpcResult { - const { db } = deps; - const { companyId, agentId: requesterId } = ctx; - - const argObject = typeof rawArgs === "object" && rawArgs !== null - ? (rawArgs as Record) - : {}; - - const parsed = approvalInputSchema.safeParse({ - companyId, - ...argObject, - requestedByAgentId: requesterId, - }); - if (!parsed.success) { - throw new UserInputError({ - code: "file_approval.input.invalid", - message: `Invalid file_approval payload: ${parsed.error.issues - .map((i) => `${i.path.join(".")}: ${i.message}`) - .join("; ")}`, - context: { companyId, requesterId }, - }); - } - const input = parsed.data; - - // Mirror the HTTP route's `approve_ceo_strategy` ordering gate: the - // strategy approval cannot exist before any hire_agent approvals do, - // and cannot be re-filed once it exists. The tool path would - // otherwise re-open the exact loop the HTTP gate was written to - // close. - if (input.type === "approve_ceo_strategy") { - const companyHireApprovals = db.core.approvals.listCompanyApprovalsByType(companyId, "hire_agent"); - if (companyHireApprovals.length === 0) { - throw new UserInputError({ - code: "file_approval.strategy.before_hires", - message: - "approve_ceo_strategy requires at least one hire_agent approval to exist first. File the intended hires, then the strategy.", - }); - } - const existingStrategy = db.core.approvals - .listCompanyApprovalsByType(companyId, "approve_ceo_strategy") - .find((a) => a.state === "pending" || a.state === "approved"); - if (existingStrategy) { - throw new UserInputError({ - code: "file_approval.strategy.already_filed", - message: `approve_ceo_strategy already exists for this company (id ${existingStrategy.id}); do not submit another.`, - }); - } - } - - // Fold schema-level documentIds / workProductIds into payloadJson so the - // desktop inspector has a single source of truth. payloadJson remains the - // escape hatch for type-specific structured fields. Malformed payloadJson - // (non-JSON or non-object) is a producer bug — surface it to the agent as - // UserInputError so the tool call can be corrected, not silently stashed. - let mergedPayloadJson: string | null; - try { - mergedPayloadJson = mergeApprovalAttachments( - input.payloadJson, - input.documentIds, - input.workProductIds, - ); - } catch (error) { - throw new UserInputError({ - code: "file_approval.payload_json.invalid", - message: error instanceof Error ? error.message : "payloadJson must be a JSON object or null.", - }); - } - - let approvalId: string; - try { - approvalId = db.core.approvals.requestApproval({ - companyId, - type: input.type, - relatedTaskId: input.relatedTaskId ?? null, - requestedByAgentId: requesterId, - relatedAgentId: input.relatedAgentId ?? null, - payloadSummary: input.payloadSummary, - impactSummary: input.impactSummary, - payloadJson: mergedPayloadJson, - }); - } catch (error) { - throw classifyUnknownError(error, { - kind: "upstream", - code: "file_approval.create.failed", - message: error instanceof Error ? error.message : "Approval could not be created.", - context: { companyId, requesterId, type: input.type }, - }); - } - - try { - db.core.activity.addActivity({ - companyId, - actor: requesterId, - action: "approval.created", - entityType: "approval", - entityId: approvalId, - detail: input.payloadSummary, - }); - } catch (error) { - throw new UpstreamError({ - code: "file_approval.activity.failed", - message: "Failed to record activity for approval.", - cause: error, - }); - } - - deps.onApprovalCreated( - approvalId, - companyId, - input.relatedTaskId ?? null, - input.type, - input.payloadSummary ?? "", - ); - - let autoApproved = false; - if (shouldAutoApprove(db, companyId, input.type)) { - resolveApprovalDecision({ - db, - handleApprovalResolved: deps.onApprovalResolved, - companyId, - approvalId, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: "Auto-approved by company policy", - }); - autoApproved = true; - deps.logger.info( - `[file-approval-handler] Auto-approved approval ${approvalId}: ${input.payloadSummary}`, - ); - } - - deps.onDomainChanged(); - - const summary = autoApproved - ? `Filed ${input.type} approval ${approvalId}. Auto-approved by company policy.` - : `Filed ${input.type} approval ${approvalId}. Pending board decision.`; - - return { - content: [{ type: "text", text: summary }], - details: { - approvalId, - autoApproved, - type: input.type, - }, - isError: false, - }; -} diff --git a/src/main/agent-runtime/internal-tools/hire-agent-handler.ts b/src/main/agent-runtime/internal-tools/hire-agent-handler.ts deleted file mode 100644 index 300d5f89..00000000 --- a/src/main/agent-runtime/internal-tools/hire-agent-handler.ts +++ /dev/null @@ -1,305 +0,0 @@ -/** - * Main-side handler for the `hire_agent` internal tool (C4 part 1/5). - * - * Contract: this handler accepts the exact same field shape the HTTP - * `POST /api/companies/:id/agents` route accepts (see - * `api-server/routes-agents.ts`) and funnels through the same - * `db.createHireRequest` primitive + auto-approval policy so both paths - * produce identical approval rows. The HTTP path is kept live for - * legacy clients (see C4 part 5/5 deprecation marker); this is the - * tool-first path the CEO prompt now advertises. - * - * Error policy: - * - Input validation fails → throw `UserInputError`. The worker's tool - * wrapper converts `{ ok: false, error }` into a pi tool-error - * result, so the CEO sees the validation message on its next turn - * and can correct the call. - * - DB write / approval layer fails → throw `UpstreamError`. Same - * surface behaviour, different classification for telemetry. - * - * No fallbacks, no silent catches: a malformed hire is a bug worth - * surfacing to the model, not worth papering over. - */ - -import type { AppDatabase } from "@main/database"; -import { - canManageOrganization, - canRequestHire, - getHireNameValidationError, - getHireRoutingValidationError, - resolveHireReportsTo, -} from "@main/agent-permissions"; -import { resolveApprovalDecision } from "@main/approval-policy"; -import { shouldAutoApprove } from "@main/execution-policy"; -import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy"; -import { hireRequestSchema } from "@shared/contracts"; -import { UserInputError, UpstreamError, classifyUnknownError } from "@main/errors"; -import type { InvokeInternalToolRpcResult } from "@main/worker/runtime/internal-tools/internal-tool-rpc"; - -export interface HireAgentHandlerDeps { - db: AppDatabase; - onApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - onDomainChanged: () => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export interface HireAgentHandlerContext { - companyId: string; - agentId: string; -} - -/** - * Handle a `hire_agent` tool invocation from the worker RPC. - * - * Mirrors the control flow of the HTTP handler (validate → resolve - * reportsTo → name/routing checks → connector readiness → dedup → - * create → auto-approve) and returns the `{ agentId, approvalId, - * autoApproved }` shape wrapped as a pi tool-result. - */ -export function handleHireAgentToolCall( - deps: HireAgentHandlerDeps, - ctx: HireAgentHandlerContext, - rawArgs: unknown, -): InvokeInternalToolRpcResult { - const { db } = deps; - const { companyId, agentId: requesterId } = ctx; - - if (!canRequestHire(db, companyId, requesterId)) { - throw new UserInputError({ - code: "hire_agent.permission.denied", - message: "Current agent is not allowed to request hires.", - context: { companyId, requesterId }, - }); - } - - const argObject = typeof rawArgs === "object" && rawArgs !== null - ? (rawArgs as Record) - : {}; - const reportsToProvided = Object.prototype.hasOwnProperty.call(argObject, "reportsTo"); - - const parsed = hireRequestSchema.safeParse({ - companyId, - requestedByAgentId: requesterId, - ...argObject, - }); - if (!parsed.success) { - throw new UserInputError({ - code: "hire_agent.input.invalid", - message: `Invalid hire_agent payload: ${parsed.error.issues - .map((i) => `${i.path.join(".")}: ${i.message}`) - .join("; ")}`, - context: { companyId, requesterId }, - }); - } - const input = parsed.data; - - const resolvedReportsTo = resolveHireReportsTo( - db, - companyId, - requesterId, - reportsToProvided ? input.reportsTo : undefined, - input.department ?? null, - ); - - const nameError = getHireNameValidationError({ - name: input.name, - role: input.role, - title: input.title, - }); - if (nameError) { - throw new UserInputError({ - code: "hire_agent.name.invalid", - message: nameError, - context: { name: input.name, role: input.role }, - }); - } - - const routingError = getHireRoutingValidationError( - db, - companyId, - requesterId, - resolvedReportsTo, - input.department ?? null, - ); - if (routingError) { - throw new UserInputError({ - code: "hire_agent.routing.invalid", - message: routingError, - context: { resolvedReportsTo, department: input.department ?? null }, - }); - } - - if ( - resolvedReportsTo && - resolvedReportsTo !== requesterId && - !canManageOrganization(db, companyId, requesterId) && - !db.core.agents.getChainOfCommand(resolvedReportsTo).some((agent) => agent.id === requesterId) - ) { - throw new UserInputError({ - code: "hire_agent.routing.not_in_chain", - message: - "Requested hire must report to you or a manager in your reporting chain.", - context: { resolvedReportsTo }, - }); - } - - const connectorRecord = (() => { - try { - return db.core.connectors.getConnector(input.connectorId); - } catch (error) { - throw new UserInputError({ - code: "hire_agent.connector.missing", - message: `Connector ${input.connectorId} does not exist.`, - cause: error, - }); - } - })(); - const connectorIssue = getConnectorExecutionReadinessIssue(connectorRecord); - if (connectorIssue) { - throw new UserInputError({ - code: "hire_agent.connector.not_ready", - message: connectorIssue, - context: { connectorId: input.connectorId }, - }); - } - - const existingAgents = db.core.agents.listExistingAgentsForHireCheck(companyId); - const duplicateByName = existingAgents.find( - (a) => a.name.toLowerCase() === input.name.toLowerCase(), - ); - if (duplicateByName) { - throw new UserInputError({ - code: "hire_agent.duplicate.existing", - message: `Agent "${input.name}" already exists in this company (id: ${duplicateByName.id}, role: ${duplicateByName.role}). Use the existing agent instead of creating a duplicate.`, - }); - } - - const pendingHires = db.core.approvals.listPendingHireApprovalPayloads(companyId); - 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()) { - throw new UserInputError({ - code: "hire_agent.duplicate.pending", - message: `A hire request for "${input.name}" is already pending approval.`, - }); - } - } catch (error) { - if (error instanceof UserInputError) throw error; - deps.logger.warn( - `[hire-agent-handler] invalid pending-hire payloadJson for company ${companyId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - const managerLabel = resolvedReportsTo - ? (() => { - try { - return db.core.entity.getAgent(resolvedReportsTo).name; - } catch { - return resolvedReportsTo; - } - })() - : "the company board"; - - let result: { agentId: string; approvalId: string }; - try { - result = db.createHireRequest({ - companyId, - requestedByAgentId: input.requestedByAgentId ?? requesterId, - name: input.name, - role: input.role, - title: input.title, - department: input.department ?? null, - reportsTo: resolvedReportsTo, - connectorId: input.connectorId, - workspaceId: input.workspaceId ?? null, - model: input.model ?? null, - metadataJson: input.metadataJson ?? "{}", - capabilities: input.capabilities, - budgetMonthlyUsd: input.budgetMonthlyUsd, - payloadSummary: `Hire ${input.name} as ${input.role}`, - impactSummary: input.capabilities || `${input.name} will report to ${managerLabel}.`, - payloadJson: JSON.stringify({ - name: input.name, - role: input.role, - title: input.title, - requestedByAgentId: input.requestedByAgentId ?? requesterId, - requestedConfigurationSnapshot: { - connectorId: input.connectorId, - workspaceId: input.workspaceId ?? null, - model: input.model ?? null, - metadataJson: input.metadataJson ?? "{}", - capabilities: input.capabilities, - budgetMonthlyUsd: input.budgetMonthlyUsd, - reportsTo: resolvedReportsTo, - department: input.department ?? null, - title: input.title, - }, - }), - }); - } catch (error) { - throw classifyUnknownError(error, { - kind: "upstream", - code: "hire_agent.create.failed", - message: error instanceof Error ? error.message : "Hire could not be created.", - context: { companyId, requesterId }, - }); - } - - try { - db.core.activity.addActivity({ - companyId, - actor: requesterId, - action: "agent.hire_requested", - entityType: "agent", - entityId: result.agentId, - detail: input.name, - }); - } catch (error) { - throw new UpstreamError({ - code: "hire_agent.activity.failed", - message: "Failed to record activity for hire request.", - cause: error, - }); - } - - let autoApproved = false; - if (shouldAutoApprove(db, companyId, "hire_agent")) { - resolveApprovalDecision({ - db, - handleApprovalResolved: deps.onApprovalResolved, - companyId, - approvalId: result.approvalId, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: `Auto-approved hire: ${input.name}`, - }); - autoApproved = true; - deps.logger.info( - `[hire-agent-handler] Auto-approved hire of ${input.name} via agent tool.`, - ); - } - - deps.onDomainChanged(); - - const summary = autoApproved - ? `Hired ${input.name} (${input.role}). Approval ${result.approvalId} was auto-approved by company policy; the new agent id is ${result.agentId}.` - : `Filed hire_agent approval ${result.approvalId} for ${input.name} (${input.role}). Pending agent id is ${result.agentId}; awaiting board decision.`; - - return { - content: [{ type: "text", text: summary }], - details: { - agentId: result.agentId, - approvalId: result.approvalId, - autoApproved, - name: input.name, - role: input.role, - }, - isError: false, - }; -} diff --git a/src/main/agent-runtime/internal-tools/router.ts b/src/main/agent-runtime/internal-tools/router.ts deleted file mode 100644 index 3738fe5c..00000000 --- a/src/main/agent-runtime/internal-tools/router.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Dispatch router for main-side internal-tool handlers (C4 part 3/5). - * - * The worker RPC method `invokeInternalTool` lands here; this module - * picks the right handler by `toolName` and delegates. Adding a new - * internal tool means: (a) new worker-side tool definition under - * `src/main/worker/runtime/internal-tools/`, (b) new handler under - * `src/main/agent-runtime/internal-tools/`, (c) one new `case` in the - * switch below. No third file to update, no registry lookup — the - * compile-time `never`-exhaustiveness on the default case catches a - * missing branch at build time. - * - * The router never catches: every handler throws a classified - * `AppError` on failure and the caller (`RuntimeBridge`) translates the - * throw into the `{ ok: false, error }` RPC envelope. Silent swallow - * would collapse tool-error plus tool-success onto the same success - * wire shape, which is the exact failure mode the tool-error - * convention exists to prevent. - */ - -import { HIRE_AGENT_TOOL_NAME } from "@main/worker/runtime/internal-tools/hire-agent-tool"; -import { FILE_APPROVAL_TOOL_NAME } from "@main/worker/runtime/internal-tools/file-approval-tool"; -import type { - InvokeInternalToolRpcPayload, - InvokeInternalToolRpcResult, -} from "@main/worker/runtime/internal-tools/internal-tool-rpc"; -import { - handleHireAgentToolCall, - type HireAgentHandlerDeps, -} from "./hire-agent-handler"; -import { - handleFileApprovalToolCall, - type FileApprovalHandlerDeps, -} from "./file-approval-handler"; -import { UserInputError } from "@main/errors"; - -export interface InternalToolRouterDeps { - hireAgent: HireAgentHandlerDeps; - fileApproval: FileApprovalHandlerDeps; -} - -export interface InternalToolRouterContext { - companyId: string; - agentId: string; -} - -export function routeInternalToolCall( - deps: InternalToolRouterDeps, - ctx: InternalToolRouterContext, - payload: InvokeInternalToolRpcPayload, -): InvokeInternalToolRpcResult { - switch (payload.toolName) { - case HIRE_AGENT_TOOL_NAME: - return handleHireAgentToolCall(deps.hireAgent, ctx, payload.args); - case FILE_APPROVAL_TOOL_NAME: - return handleFileApprovalToolCall(deps.fileApproval, ctx, payload.args); - default: - throw new UserInputError({ - code: "internal_tool.unknown", - message: `Unknown internal tool: ${payload.toolName}`, - context: { toolName: payload.toolName }, - }); - } -} diff --git a/src/main/agent-runtime/runtime-artifact-reconciler.ts b/src/main/agent-runtime/runtime-artifact-reconciler.ts deleted file mode 100644 index 26872e53..00000000 --- a/src/main/agent-runtime/runtime-artifact-reconciler.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { AppDatabase } from "@main/database"; -import type { ActiveRunContext } from "./hook-handlers"; -import { reconcileWorkspaceArtifacts } from "./artifact-projector"; -import { - appendArtifactProjectionEvent, - appendArtifactProjectionFailureEvent, -} from "./artifact-projection-events"; - -export type RunResourceReleaseResult = - | { ok: true } - | { ok: false; errorMessage: string }; - -export interface RuntimeArtifactReconcilerDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export function reconcileArtifactsForActiveRun( - deps: RuntimeArtifactReconcilerDeps, - ctx: ActiveRunContext, -): RunResourceReleaseResult { - try { - const outcomes = deps.db.withTransaction(() => { - const projectionOutcomes = reconcileWorkspaceArtifacts(deps.db, { - runId: ctx.runId, - agentId: ctx.agentId, - companyId: ctx.companyId, - taskId: ctx.taskId, - workspaceId: ctx.workspaceId, - workspacePath: ctx.workspacePath, - workspaceMode: ctx.workspaceMode, - logger: deps.logger, - workspaceBaseline: ctx.workspaceBaseline, - }); - appendArtifactProjectionEvent(deps.db, { - companyId: ctx.companyId, - runId: ctx.runId, - agentId: ctx.agentId, - phase: "completion_reconcile", - workspaceId: ctx.workspaceId, - workspaceMode: ctx.workspaceMode, - outcomes: projectionOutcomes, - }); - return projectionOutcomes; - }); - const inserted = outcomes.filter((o) => o.kind === "inserted").length; - const retired = outcomes.filter((o) => o.kind === "retired").length; - if (inserted > 0 || retired > 0) { - deps.logger.info( - `[runtime-bridge] reconciliation for run ${ctx.runId}: ${inserted} registered, ${retired} retired`, - ); - } - return { ok: true }; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - try { - appendArtifactProjectionFailureEvent(deps.db, { - companyId: ctx.companyId, - runId: ctx.runId, - agentId: ctx.agentId, - phase: "completion_reconcile", - workspaceId: ctx.workspaceId, - workspaceMode: ctx.workspaceMode, - errorMessage, - }); - } catch (ackError) { - deps.logger.error( - `[runtime-bridge] artifact reconciliation failure ack failed for run ${ctx.runId}: ${ackError instanceof Error ? ackError.message : String(ackError)}`, - ); - } - deps.logger.error( - `[runtime-bridge] artifact reconciliation failed for run ${ctx.runId}: ${errorMessage}`, - ); - return { ok: false, errorMessage }; - } -} diff --git a/src/main/agent-runtime/runtime-bridge.ts b/src/main/agent-runtime/runtime-bridge.ts deleted file mode 100644 index b134fa28..00000000 --- a/src/main/agent-runtime/runtime-bridge.ts +++ /dev/null @@ -1,506 +0,0 @@ -import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import type { AppDatabase } from "@main/database"; -import type { AgentMessageRecord, DesktopEvent } from "@shared/types"; -import { SqliteSessionStore } from "./sqlite-session-store"; -import { CostWriter } from "./cost-writer"; -import type { CredentialResolver } from "@main/credentials"; -import { getConnectorDefinition } from "@main/connectors"; -import { projectInboxMessageToPi } from "./inbox-projection"; -import { projectAgentEventToLogChunk } from "./agent-event-projection"; -import { hasAttributableAssistantUsage } from "../run-usage-status"; -import { captureBaselineIfRequired } from "./artifact-projector"; -import { - reconcileArtifactsForActiveRun, - type RunResourceReleaseResult, -} from "./runtime-artifact-reconciler"; -import { - handleBeforeToolCall, - type ActiveRunContext, - type ActiveRunLifecycleState, -} from "./hook-handlers"; -import type { BeforeToolCallRpcPayload } from "./hook-rpc"; -import { routeInternalToolCall } from "./internal-tools/router"; -import type { InvokeInternalToolRpcPayload } from "@main/worker/runtime/internal-tools/internal-tool-rpc"; -import { InboundCorrelationRegistryStore } from "./inbound-correlation-registry"; -import { RuntimeThreadProjector } from "./runtime-thread-projector"; - -/** - * Side-effect callbacks the internal-tool handlers invoke after a - * successful DB write. These come from the same wire-api-server fabric - * the HTTP routes funnel through, so thread integration / automation / - * renderer domain-change notifications stay identical across both - * entry points. Supplied lazily via `setInternalToolCallbacks` because - * the graph builds `RuntimeBridge` before the orchestration/thread- - * integration layer exists. - */ -export interface InternalToolCallbacks { - onApprovalCreated: ( - approvalId: string, - companyId: string, - taskId: string | null, - approvalType: string, - summary: string, - ) => void; - onApprovalResolved: ( - approvalId: string, - companyId: string, - decision: string, - ) => void; - onDomainChanged: () => void; -} - -export interface RuntimeBridgeDeps { - db: AppDatabase; - emitEvent: (event: DesktopEvent) => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - credentialResolver: CredentialResolver; -} - -// Derived from the zod schema in `worker/entry/types.ts` so there is -// exactly one source of truth for the RPC method name list. The C4→C5 -// hotfix (9d9f003) showed what happens when this union and the zod -// enum drift — worker emits a new method, handler accepts it, and the -// runtime gate silently rejects the envelope. `z.infer` plus a -// compile-time `satisfies` check below makes that category of drift -// a TypeScript error rather than a production ZodError. -import type { WorkerRpcMethod } from "@main/worker/entry/types"; - -type RpcMethod = WorkerRpcMethod; - -/** - * Single owner of pi runtime side-effects in main. - * - * - Forwards `agent-event` from the worker to the renderer (push channel). - * - Persists each `message_end` message via `SqliteSessionStore`. - * - Calls `CostWriter` for assistant messages with usage. - * - Proxies pi's `beforeToolCall` hook into the approval-gate policy handler. - * - Reconciles filesystem artifacts during run resource release. - * - * Policy itself lives in `hook-handlers.ts`; this class is a pure IPC - * router plus an `ActiveRunContext` cache. - */ -export class RuntimeBridge { - private readonly costWriter: CostWriter; - private readonly threadProjector: RuntimeThreadProjector; - private readonly activeRuns = new Map(); - private readonly sessionStores = new Map(); - private internalToolCallbacks: InternalToolCallbacks | null = null; - private readonly inboundCorrelations = new InboundCorrelationRegistryStore(); - - constructor(private readonly deps: RuntimeBridgeDeps) { - this.costWriter = new CostWriter({ db: deps.db }); - this.threadProjector = new RuntimeThreadProjector({ - db: deps.db, - logger: deps.logger, - resolveAgentName: (agentId) => this.resolveAgentName(agentId), - lookupInboundCorrelation: (runId, timestamp) => - this.inboundCorrelations.lookup(runId, timestamp), - }); - } - - /** - * Late-bind the side-effect callbacks used by the internal-tool - * router. The graph must call this exactly once before any tool - * invocation fires; missing callbacks at RPC time throw rather than - * silently skipping the notification, so a wiring regression surfaces - * on the first tool call instead of as a stale-UI ghost. - */ - setInternalToolCallbacks(callbacks: InternalToolCallbacks): void { - if (this.internalToolCallbacks) { - throw new Error("RuntimeBridge.setInternalToolCallbacks called twice."); - } - this.internalToolCallbacks = callbacks; - } - - private registerActiveRun(context: ActiveRunContext): void { - this.activeRuns.set(context.runId, context); - this.getOrCreateStore(context.taskSessionId); - } - - private evictActiveRun(runId: string): ActiveRunContext | null { - const ctx = this.activeRuns.get(runId) ?? null; - this.activeRuns.delete(runId); - this.inboundCorrelations.deleteRun(runId); - if (ctx) this.sessionStores.delete(ctx.taskSessionId); - return ctx; - } - - private assertRunContextCurrent( - ctx: ActiveRunContext, - operation: string, - ): { ok: true } | { ok: false; error: string } { - const runState = this.deps.db.core.runs.getRunAuthState(ctx.runId); - if (!runState) { - this.evictActiveRun(ctx.runId); - const error = `${operation}: stale run ${ctx.runId} no longer exists.`; - this.deps.logger.warn(`[runtime-bridge] ${error}`); - return { ok: false, error }; - } - if (runState.companyId !== ctx.companyId || runState.agentId !== ctx.agentId) { - this.evictActiveRun(ctx.runId); - const error = `${operation}: stale run ${ctx.runId} context does not match the persisted run.`; - this.deps.logger.warn(`[runtime-bridge] ${error}`); - return { ok: false, error }; - } - return { ok: true }; - } - - /** - * Evicts the per-run `activeRuns` context, the per-session store cache, - * and the inbound-correlation log. Callers must invoke after a - * `run-finished` worker message so the maps stay bounded by concurrent- - * run count rather than process lifetime. - * - * Before eviction, sweeps the workspace to register filesystem - * artifacts produced during the run. This completion boundary keeps - * the DocumentCenter consistent with disk through one durable - * reconciliation acknowledgement. - */ - releaseRunResources(runId: string): RunResourceReleaseResult { - const ctx = this.activeRuns.get(runId); - let result: RunResourceReleaseResult = { ok: true }; - try { - if (ctx) { - const current = this.assertRunContextCurrent(ctx, "releaseRunResources"); - if (!current.ok) return { ok: true }; - result = this.reconcileArtifactsForRun(ctx); - } - return result; - } finally { - this.evictActiveRun(runId); - } - } - - private reconcileArtifactsForRun(ctx: ActiveRunContext): RunResourceReleaseResult { - return reconcileArtifactsForActiveRun(this.deps, ctx); - } - - /** - * Build the pi projection for an inbound message and register the - * correlation under `record.id`. Returns the projected user turn so - * callers (the prepareRun inbox loop, the runtime message injector) - * append / steer the same object that the bridge has indexed. - * - * A monotonically increasing `piTimestamp` is stamped onto the - * returned message so two inbound rows that share the same - * wall-clock millisecond still resolve to distinct correlation - * entries when `message_end` fires. - */ - projectInboundMessage(runId: string, record: AgentMessageRecord): AgentMessage { - const base = Date.parse(record.createdAt); - const baseline = Number.isFinite(base) ? base : Date.now(); - const allocated = this.inboundCorrelations.register(runId, record, baseline); - return projectInboxMessageToPi(record, { - getAgentName: (id) => this.resolveAgentName(id), - }, { timestampOverride: allocated }); - } - - /** Returns the active run context for a given agent, if any. Used by - * main-side services (inbox dispatcher) to decide whether a new inbox - * row should route to `agent.steer()` instead of waiting for the next - * `prepareRun` cycle. When `requireSteerReady` is set, only runs whose - * worker-side Agent is actually subscribed (`agent_active`) are - * returned — this avoids steering into `preparing` or `closing` runs - * where the steer would be silently dropped. */ - findActiveRunForAgent( - agentId: string, - options?: { requireSteerReady?: boolean }, - ): ActiveRunContext | null { - for (const ctx of this.activeRuns.values()) { - if (ctx.agentId !== agentId) continue; - if (options?.requireSteerReady && ctx.state !== "agent_active") continue; - return ctx; - } - return null; - } - - /** - * Transition an active run between lifecycle phases as the worker - * publishes `run-agent-state`. Unknown run ids are ignored: the worker - * may publish state for a run that main has already evicted when a - * `run-finished` races ahead of the trailing state message. - */ - setRunAgentState(runId: string, state: ActiveRunLifecycleState): void { - const ctx = this.activeRuns.get(runId); - if (!ctx) return; - ctx.state = state; - } - - private getOrCreateStore(taskSessionId: string): SqliteSessionStore { - const existing = this.sessionStores.get(taskSessionId); - if (existing) return existing; - const store = new SqliteSessionStore(this.deps.db, taskSessionId); - this.sessionStores.set(taskSessionId, store); - return store; - } - - /** - * Resolve a display name for an agent id used in inbox header lines. - * Falls back to the id when the lookup fails so the transcript remains - * unambiguous instead of silently rendering "undefined". - */ - private resolveAgentName(agentId: string): string { - try { - const name = this.deps.db.core.agents.findAgentName(agentId); - if (name && name.length > 0) return name; - } catch (error) { - this.deps.logger.warn( - `[runtime-bridge] agent name lookup failed for ${agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - return agentId; - } - - /** Receives an `agent-event` envelope from the worker; emits to renderer. */ - handleAgentEvent(envelope: { - runId: string; - agentId: string; - companyId: string; - taskId: string | null; - emittedAt: string; - event: { type: string } & Record; - }): void { - this.deps.emitEvent({ - type: "agent-event", - runId: envelope.runId, - agentId: envelope.agentId, - companyId: envelope.companyId, - taskId: envelope.taskId, - emittedAt: envelope.emittedAt, - event: envelope.event, - }); - - const logChunk = projectAgentEventToLogChunk(envelope.event); - if (logChunk) { - this.deps.emitEvent({ - type: "run-log", - runId: envelope.runId, - stream: logChunk.stream, - chunk: logChunk.chunk, - }); - } - - if (envelope.event.type === "message_end") { - const ctx = this.activeRuns.get(envelope.runId); - if (ctx) { - const current = this.assertRunContextCurrent(ctx, "agent-event"); - if (!current.ok) return; - } - const messageRaw = envelope.event.message as - | { - role?: string; - stopReason?: string; - usage?: { input?: unknown; output?: unknown }; - content?: unknown; - toolCallId?: string; - timestamp?: number; - } - | undefined; - if (ctx && hasAttributableAssistantUsage(messageRaw)) { - try { - this.costWriter.observeAssistantMessage({ - runId: ctx.runId, - companyId: ctx.companyId, - agentId: ctx.agentId, - taskId: ctx.taskId, - connectorId: ctx.connectorId, - modelId: ctx.modelId, - usage: messageRaw.usage as never, - }); - } catch (error) { - this.deps.logger.error( - `[runtime-bridge] cost recording failed for run ${ctx.runId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - this.threadProjector.recordThreadEvent(envelope, messageRaw); - } - } - - /** Handles RPC requests issued by the worker (`rpc-request` envelope). */ - async handleRpc(request: { - rpcId: string; - method: RpcMethod; - runId: string; - payload: unknown; - }): Promise<{ ok: true; result: unknown } | { ok: false; error: string }> { - try { - switch (request.method) { - case "persistMessage": { - const payload = request.payload as { taskSessionId: string; message: AgentMessage }; - this.getOrCreateStore(payload.taskSessionId).appendMessage(payload.message); - return { ok: true, result: undefined }; - } - case "prepareRun": - return await this.handlePrepareRunRpc(request.runId, request.payload); - case "beforeToolCall": - return this.handleBeforeToolCallRpc(request.runId, request.payload as BeforeToolCallRpcPayload); - case "invokeInternalTool": - return this.handleInvokeInternalToolRpc(request.runId, request.payload as InvokeInternalToolRpcPayload); - default: { - // Exhaustiveness guard. If `WorkerRpcMethod` widens in - // `worker/entry/types.ts` without a corresponding case here, - // the assignment to `never` is a TypeScript error — which is - // exactly what we want so the C4→C5 drift category cannot - // silently recur at runtime. - const _exhaustive: never = request.method; - return { ok: false, error: `unknown RPC method: ${String(_exhaustive)}` }; - } - } - } catch (error) { - return { ok: false, error: error instanceof Error ? error.message : String(error) }; - } - } - - private handleInvokeInternalToolRpc( - runId: string, - payload: InvokeInternalToolRpcPayload, - ): { ok: true; result: unknown } | { ok: false; error: string } { - const ctx = this.activeRuns.get(runId); - if (!ctx) { - return { ok: false, error: `invokeInternalTool: no active run ${runId}` }; - } - const current = this.assertRunContextCurrent(ctx, "invokeInternalTool"); - if (!current.ok) return { ok: false, error: current.error }; - const callbacks = this.internalToolCallbacks; - if (!callbacks) { - return { - ok: false, - error: "invokeInternalTool: internal-tool callbacks not wired — service graph init regression.", - }; - } - const result = routeInternalToolCall( - { - hireAgent: { - db: this.deps.db, - onApprovalResolved: callbacks.onApprovalResolved, - onDomainChanged: callbacks.onDomainChanged, - logger: this.deps.logger, - }, - fileApproval: { - db: this.deps.db, - onApprovalCreated: callbacks.onApprovalCreated, - onApprovalResolved: callbacks.onApprovalResolved, - onDomainChanged: callbacks.onDomainChanged, - logger: this.deps.logger, - }, - }, - { companyId: ctx.companyId, agentId: ctx.agentId }, - payload, - ); - return { ok: true, result }; - } - - private async handlePrepareRunRpc( - runId: string, - payloadRaw: unknown, - ): Promise<{ ok: true; result: unknown } | { ok: false; error: string }> { - const payload = payloadRaw as { - connectorId: string; - taskSessionId: string; - agentId: string; - companyId: string; - taskId: string | null; - modelId: string; - workspaceId: string | null; - workspacePath: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - }; - const runState = this.deps.db.core.runs.getRunAuthState(runId); - if (!runState) { - return { ok: false, error: `prepareRun: stale run ${runId} no longer exists.` }; - } - if (runState.companyId !== payload.companyId || runState.agentId !== payload.agentId) { - return { ok: false, error: `prepareRun: run ${runId} context does not match the persisted run.` }; - } - const baseline = captureBaselineIfRequired(payload.workspacePath, this.deps.logger); - this.registerActiveRun({ - runId, - agentId: payload.agentId, - companyId: payload.companyId, - taskId: payload.taskId, - connectorId: payload.connectorId, - modelId: payload.modelId, - taskSessionId: payload.taskSessionId, - workspaceId: payload.workspaceId, - workspacePath: payload.workspacePath, - workspaceMode: payload.workspaceMode, - workspaceBaseline: baseline, - state: "preparing", - }); - const definition = getConnectorDefinition(payload.connectorId); - const resolved = await this.deps.credentialResolver.resolve(payload.connectorId); - - // Project any pending inbox messages into the session transcript - // before loading priorMessages — the recipient must observe them - // as plain user turns in its context. - // - // Replay safety lives entirely on the `agent_message_projections` - // ledger. "We put the message into the agent's transcript" and - // "the agent has acknowledged the message" are two different - // facts, tracked in two different tables: projections are append- - // only on dispatch, while reads are inserted into - // `agent_message_reads` only when the agent POSTs - // /messages/{id}/read. Conflating the two (as an earlier build - // that wrote to `agent_messages.read_at` at projection time did) - // made every projected message immediately invisible to - // `?unreadOnly=true`, so agents posted status comments instead of - // replies. The explicit read endpoint is the sole signal. - const store = this.getOrCreateStore(payload.taskSessionId); - const inboxRecords = this.deps.db.core.messages.listAgentInboxUnread(payload.companyId, payload.agentId); - if (inboxRecords.length > 0) { - this.deps.db.withTransaction(() => { - for (const record of inboxRecords) { - const claimed = this.deps.db.projection.inbox.claimProjection(record.id, payload.taskSessionId); - if (!claimed) continue; - // `projectInboundMessage` allocates a monotonic pi-timestamp - // and indexes the correlation under `record.id`. Two rows - // that share the same wall-clock millisecond still resolve - // to distinct authors at `message_end`. - const projected = this.projectInboundMessage(runId, record); - store.appendMessage(projected); - this.threadProjector.recordInboundMessageAsThreadEvent( - { - runId, - agentId: payload.agentId, - companyId: payload.companyId, - taskId: payload.taskId, - }, - record, - ); - } - }); - } - - const priorMessages = store.loadMessages(); - return { - ok: true, - result: { - provider: definition.provider, - apiKey: resolved.apiKey, - extraEnv: resolved.extraEnv ?? {}, - baseUrl: resolved.baseUrl ?? null, - priorMessages, - }, - }; - } - - private handleBeforeToolCallRpc( - runId: string, - payload: BeforeToolCallRpcPayload, - ): { ok: true; result: unknown } | { ok: false; error: string } { - const ctx = this.activeRuns.get(runId); - if (!ctx) { - return { ok: false, error: `beforeToolCall: no active run ${runId}` }; - } - const current = this.assertRunContextCurrent(ctx, "beforeToolCall"); - if (!current.ok) return { ok: false, error: current.error }; - const result = handleBeforeToolCall(this.deps, ctx, payload); - return { ok: true, result }; - } - -} diff --git a/src/main/agent-runtime/runtime-message-injector.ts b/src/main/agent-runtime/runtime-message-injector.ts deleted file mode 100644 index 1dc56c1b..00000000 --- a/src/main/agent-runtime/runtime-message-injector.ts +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Runtime message injector — the inward half of the Slack-like messaging - * system. When an agent has an active pi run, incoming direct, channel, - * or mention messages must reach the agent during the loop rather than - * on the next heartbeat. Pre-injector, the only delivery path was the - * batched `prepareRun` projection, so any message that arrived while the - * recipient was running sat dark until the next wake. - * - * Delivery is a two-step handshake: - * - * main → worker steer-run { correlationId, runId, message } - * worker → main steer-ack { correlationId, accepted } - * - * The worker's `runner.steer()` is the single authority for whether the - * message reached the live Agent. Main holds the inbox `delivered_at` - * write until the ACK lands: a positive ACK commits the write; a rejected - * or timed-out ACK leaves the row unread and re-triggers the recipient's - * wake, so the next `prepareRun` picks the message up via the regular - * inbox projection. Either way the message is observed exactly once. - * - * The injector short-circuits when the active run is not in - * `agent_active` — `preparing` and `closing` windows cannot accept a - * steer — and the caller falls back to the wake + inbox flow directly. - */ - -import { randomUUID } from "node:crypto"; -import type { AppDatabase } from "@main/database"; -import type { AgentMessageRecord } from "@shared/types"; -import type { ParentMessage } from "@main/worker/runtime/helpers"; -import type { RuntimeBridge } from "./runtime-bridge"; - -export interface RuntimeMessageInjectorDeps { - db: AppDatabase; - runtimeBridge: RuntimeBridge; - postToWorker: (message: ParentMessage) => void; - /** - * Lazy wake hook. The injector is instantiated before orchestration so - * the wake function has to be resolved per-call; returning `null` means - * orchestration is not yet online, in which case the caller will have - * handled the wake path already. - */ - getWakeAgent: () => ((agentId: string, companyId: string, trigger: string) => string | null) | null; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - }; - steerAckTimeoutMs?: number; -} - -interface PendingSteer { - recipientAgentId: string; - companyId: string; - runId: string; - message: AgentMessageRecord; - timer: ReturnType; -} - -const DEFAULT_STEER_ACK_TIMEOUT_MS = 5_000; - -export class RuntimeMessageInjector { - private readonly pending = new Map(); - private readonly ackTimeoutMs: number; - - constructor(private readonly deps: RuntimeMessageInjectorDeps) { - this.ackTimeoutMs = deps.steerAckTimeoutMs ?? DEFAULT_STEER_ACK_TIMEOUT_MS; - } - - /** - * Attempts to deliver a persisted inbox message into the recipient's - * live pi run. Returns true when the steer was dispatched to the worker - * with a pending ACK — callers must skip the synchronous wake fallback - * for this recipient because the injector now owns the message's fate: - * it will either mark the row delivered on a positive ACK or trigger a - * wake on a negative/timed-out ACK. - * - * Returns false when no steer was dispatched (no active run, cross- - * company mismatch, or the run is not yet `agent_active`). Callers then - * fall through to the legacy inbox + wake flow immediately. - */ - tryInject(recipientAgentId: string, companyId: string, message: AgentMessageRecord): boolean { - const ctx = this.deps.runtimeBridge.findActiveRunForAgent(recipientAgentId, { - requireSteerReady: true, - }); - if (!ctx) return false; - if (ctx.companyId !== companyId) { - this.deps.logger.warn( - `[injector] refusing cross-company steer: agent ${recipientAgentId} active in ${ctx.companyId}, message from ${companyId}`, - ); - return false; - } - - // Delegate projection + correlation registration to the bridge so - // the worker steers the exact same pi-message object that the - // bridge has indexed under `record.id`. `projectInboundMessage` - // allocates a monotonic `piTimestamp` which is what `message_end` - // surfaces back on the wire — two inbound rows that share the - // same wall-clock millisecond are no longer indistinguishable. - const projected = this.deps.runtimeBridge.projectInboundMessage(ctx.runId, message); - const correlationId = randomUUID(); - - try { - this.deps.postToWorker({ - type: "steer-run", - runId: ctx.runId, - correlationId, - message: projected, - }); - } catch (error) { - this.deps.logger.warn( - `[injector] postToWorker steer-run failed for run ${ctx.runId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return false; - } - - const timer = setTimeout(() => { - this.resolvePending(correlationId, false, "timeout"); - }, this.ackTimeoutMs); - if (typeof timer.unref === "function") timer.unref(); - - this.pending.set(correlationId, { - recipientAgentId, - companyId, - runId: ctx.runId, - message, - timer, - }); - return true; - } - - /** - * Routed from `worker-message-handler` on every `steer-ack`. Confirms - * the message reached the live Agent (the bridge already registered - * the inbound correlation when it built the projection). On rejection - * the recipient is woken so the next `prepareRun` picks the message - * up through the regular inbox projection. - * - * The read receipt is intentionally NOT written here: "the worker - * queued this message onto the agent" is not "the agent replied". - * The agent inserts into `agent_message_reads` itself by POSTing - * /messages/{id}/read once it has actually processed the row. - */ - handleSteerAck(correlationId: string, accepted: boolean): void { - this.resolvePending(correlationId, accepted, "worker_ack"); - } - - private resolvePending( - correlationId: string, - accepted: boolean, - source: "worker_ack" | "timeout", - ): void { - const entry = this.pending.get(correlationId); - if (!entry) return; - clearTimeout(entry.timer); - this.pending.delete(correlationId); - - if (accepted) return; - - this.deps.logger.warn( - `[injector] steer rejected (${source}) for message ${entry.message.id} to agent ${entry.recipientAgentId}; falling back to wake + inbox projection`, - ); - - const wake = this.deps.getWakeAgent(); - if (!wake) return; - try { - wake(entry.recipientAgentId, entry.companyId, "message"); - } catch (error) { - this.deps.logger.warn( - `[injector] wake fallback failed for agent ${entry.recipientAgentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - -} diff --git a/src/main/agent-runtime/runtime-thread-projector.ts b/src/main/agent-runtime/runtime-thread-projector.ts deleted file mode 100644 index ee58cee3..00000000 --- a/src/main/agent-runtime/runtime-thread-projector.ts +++ /dev/null @@ -1,172 +0,0 @@ -import type { AppDatabase } from "@main/database"; -import type { AgentMessageRecord } from "@shared/types"; -import { - ensureAgentCommunicationThread, - ensureTaskThread, -} from "@main/thread-integration/thread-helpers"; -import { extractMessageText } from "./agent-event-projection"; -import type { InboundCorrelationEntry } from "./inbound-correlation-registry"; - -type RuntimeThreadEnvelope = { - runId: string; - agentId: string; - companyId: string; - taskId: string | null; -}; - -type RuntimeThreadMessage = { - role?: string; - content?: unknown; - toolCallId?: string; - timestamp?: number; -}; - -interface RuntimeThreadProjectorDeps { - db: AppDatabase; - logger: { - warn: (...args: unknown[]) => void; - }; - resolveAgentName: (agentId: string) => string; - lookupInboundCorrelation: ( - runId: string, - timestamp: number | undefined, - ) => InboundCorrelationEntry | null; -} - -export class RuntimeThreadProjector { - constructor(private readonly deps: RuntimeThreadProjectorDeps) {} - - /** - * Project the pi `message_end` event into a `conversation_events` row - * so renderer thread views stay live. - */ - recordThreadEvent( - envelope: RuntimeThreadEnvelope, - message: RuntimeThreadMessage | undefined, - ): void { - if (!message?.role) return; - if (message.role !== "assistant" && message.role !== "user") return; - - try { - const body = extractMessageText(message); - const actor = this.resolveThreadEventActor(envelope, message); - if (!actor) return; - if (body.length === 0) return; - const thread = this.resolveThreadForRun(envelope); - if (!thread) return; - this.deps.db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: actor.actorId, - actorType: actor.actorType, - eventType: "message", - body: body.length > 4000 ? `${body.slice(0, 3997)}...` : body, - metadataJson: JSON.stringify({ - runId: envelope.runId, - role: message.role, - sourceMessageId: actor.sourceMessageId ?? undefined, - }), - }); - } catch (error) { - this.deps.logger.warn( - `[runtime-bridge] failed to project agent-event for run ${envelope.runId}: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - } - - /** - * Persist an inbound peer message projected as a prior turn during - * `prepareRun`; priorMessages do not emit `message_end`. - */ - recordInboundMessageAsThreadEvent( - envelope: RuntimeThreadEnvelope, - record: AgentMessageRecord, - ): void { - const thread = this.resolveThreadForRun(envelope); - if (!thread) return; - try { - const body = record.body.length > 4000 ? `${record.body.slice(0, 3997)}...` : record.body; - const actorType: "agent" | "user" | "system" = - record.senderKind === "human" - ? "user" - : record.senderKind === "system" - ? "system" - : "agent"; - this.deps.db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: record.fromAgentId, - actorType, - eventType: "message", - body, - metadataJson: JSON.stringify({ - runId: envelope.runId, - role: "user", - sourceMessageId: record.id, - projection: "prepare_run", - }), - }); - } catch (error) { - this.deps.logger.warn( - `[runtime-bridge] inbound thread-event write failed for message ${record.id}: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } - } - - private resolveThreadForRun(envelope: RuntimeThreadEnvelope) { - if (envelope.taskId) { - try { - const task = this.deps.db.core.entity.getTask(envelope.taskId); - return ensureTaskThread(this.deps.db, envelope.taskId, envelope.companyId, task.title); - } catch (error) { - this.deps.logger.warn( - `[runtime-bridge] getTask failed for ${envelope.taskId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return null; - } - } - try { - const agentLabel = this.deps.resolveAgentName(envelope.agentId); - return ensureAgentCommunicationThread( - this.deps.db, - envelope.agentId, - envelope.companyId, - agentLabel, - ); - } catch (error) { - this.deps.logger.warn( - `[runtime-bridge] ensureAgentCommunicationThread failed for ${envelope.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return null; - } - } - - private resolveThreadEventActor( - envelope: { runId: string; agentId: string }, - message: { role?: string; timestamp?: number }, - ): { actorId: string; actorType: "agent" | "user" | "system"; sourceMessageId: string | null } | null { - if (message.role === "user") { - const correlation = this.deps.lookupInboundCorrelation(envelope.runId, message.timestamp); - if (correlation) { - const actorType: "agent" | "user" | "system" = - correlation.senderKind === "human" - ? "user" - : correlation.senderKind === "system" - ? "system" - : "agent"; - return { - actorId: correlation.fromAgentId, - actorType, - sourceMessageId: correlation.messageId, - }; - } - return null; - } - if (message.role === "assistant") { - return { actorId: envelope.agentId, actorType: "agent", sourceMessageId: null }; - } - return null; - } -} diff --git a/src/main/agent-runtime/sqlite-session-store.ts b/src/main/agent-runtime/sqlite-session-store.ts deleted file mode 100644 index 4caac801..00000000 --- a/src/main/agent-runtime/sqlite-session-store.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import type { AppDatabase } from "@main/database"; -import { compactMessagesIfNeeded } from "./context-compactor"; -import { - decodeAgentMessageFromSessionEntry, - encodeAgentMessageForSession, - getAgentMessageRole, - validateNewAgentMessageForSession, -} from "./agent-message-schema"; - -/** - * SQLite-backed pi `AgentMessage[]` store. - * - * One store instance per task_session. `appendMessage` runs exactly - * once per pi `message_end` event; `loadMessages` reads the live - * transcript back at `prepareRun`. When the persisted transcript - * crosses the compaction threshold, `loadMessages` writes a durable - * summary row and supersedes the older rows inside one DB transaction, - * leaving the recent tail as the active transcript. - */ -export class SqliteSessionStore { - constructor( - private readonly db: AppDatabase, - public readonly taskSessionId: string, - ) {} - - loadMessages(): AgentMessage[] { - const rows = this.db.projection.sessionEntries.listActive(this.taskSessionId); - const messages: AgentMessage[] = []; - for (const row of rows) { - if (row.kind === "message") { - messages.push(decodeAgentMessageFromSessionEntry(row)); - } - } - const outcome = compactMessagesIfNeeded(messages); - if (!outcome.changed || !outcome.messages || !outcome.telemetry) { - return messages; - } - const summary = outcome.messages[0]; - if (!summary) { - return messages; - } - const olderRows = rows.slice(0, outcome.telemetry.compactedOlderMessageCount); - this.db.projection.sessionEntries.compactWithSummary({ - taskSessionId: this.taskSessionId, - supersedeEntryIds: olderRows.map((row) => row.id), - summaryRole: getAgentMessageRole(summary), - summaryPayloadJson: encodeAgentMessageForSession(summary), - }); - return outcome.messages; - } - - appendMessage(message: AgentMessage): void { - const normalized = validateNewAgentMessageForSession(message); - this.db.projection.sessionEntries.append({ - taskSessionId: this.taskSessionId, - kind: "message", - role: getAgentMessageRole(normalized), - payloadJson: encodeAgentMessageForSession(normalized), - }); - } -} diff --git a/src/main/api-server.ts b/src/main/api-server.ts deleted file mode 100644 index 9d0e172d..00000000 --- a/src/main/api-server.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Re-export from the split module for backward compatibility. -// All route logic now lives in src/main/api-server/ -export { AgentApiServer, createApiServer } from "./api-server/index"; -export type { ApiServerEventCallbacks } from "./api-server/index"; diff --git a/src/main/api-server/deprecation-counter.ts b/src/main/api-server/deprecation-counter.ts deleted file mode 100644 index c9389992..00000000 --- a/src/main/api-server/deprecation-counter.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * In-process counter for deprecated HTTP routes (C4-followup #3). - * - * The counters let us assert "legacy HTTP hire traffic has hit zero" - * before physically deleting the deprecated handlers. Keys are the - * route label the handler passes in (e.g. `POST /api/companies/:companyId/agents`). - * - * Scope is intentionally narrow: module-level Map, synchronous mutation, - * no IO, no fallback. An empty label is a programmer error — we throw - * so it surfaces in tests instead of silently recording under "". - * - * The counter is not exposed over HTTP yet (scope creep). Internal - * code reads via `readDeprecationCounters()`. - */ - -const deprecationCallCounters = new Map(); - -export function incrementDeprecationCall(routeLabel: string): void { - if (typeof routeLabel !== "string" || routeLabel.length === 0) { - throw new Error("incrementDeprecationCall requires a non-empty routeLabel"); - } - const previous = deprecationCallCounters.get(routeLabel) ?? 0; - deprecationCallCounters.set(routeLabel, previous + 1); -} - -export function readDeprecationCounters(): Record { - const snapshot: Record = {}; - for (const [label, count] of deprecationCallCounters) { - snapshot[label] = count; - } - return snapshot; -} - -export function resetDeprecationCounters(): void { - deprecationCallCounters.clear(); -} diff --git a/src/main/api-server/index.ts b/src/main/api-server/index.ts deleted file mode 100644 index 348683bc..00000000 --- a/src/main/api-server/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AgentApiServer, type ApiServerEventCallbacks } from "./server-core"; -import { registerAgentRoutes } from "./routes-agents"; -import { registerAgentControlRoutes } from "./routes-agent-control"; -import { registerAgentStandupRoute } from "./routes-agents-standup"; -import { registerTaskRoutes } from "./routes-tasks"; -import { registerWorkGraphRoutes } from "./routes-work-graph"; -import { registerMessageRoutes } from "./routes-messages"; -import { registerApprovalRoutes } from "./routes-approvals"; -import { registerFileRoutes } from "./routes-files"; -import { registerMiscRoutes } from "./routes-misc"; -import { registerMeetingRoutes } from "./routes-meetings"; -import { registerRunRoutes } from "./routes-runs"; -import type { AppDatabase } from "../database"; - -export type { ApiServerEventCallbacks }; -export { AgentApiServer }; - -/** - * Factory that creates and returns a fully-wired AgentApiServer with all - * domain route modules registered. - */ -export function createApiServer( - db: AppDatabase, - callbacks: ApiServerEventCallbacks, - allowedOrigins?: Iterable, -): AgentApiServer { - const server = new AgentApiServer(db, callbacks, allowedOrigins); - registerAgentRoutes(server); - registerAgentControlRoutes(server); - registerAgentStandupRoute(server); - registerTaskRoutes(server); - registerWorkGraphRoutes(server); - registerMessageRoutes(server); - registerApprovalRoutes(server); - registerFileRoutes(server); - registerMiscRoutes(server); - registerMeetingRoutes(server); - registerRunRoutes(server); - return server; -} diff --git a/src/main/api-server/routes-agent-control.ts b/src/main/api-server/routes-agent-control.ts deleted file mode 100644 index dee49f97..00000000 --- a/src/main/api-server/routes-agent-control.ts +++ /dev/null @@ -1,169 +0,0 @@ -import log from "electron-log/main.js"; -import { z } from "zod"; -import { canControlAgent } from "../agent-permissions"; -import { requireParam, type AgentApiServer } from "./server-core"; - -export function registerAgentControlRoutes(server: AgentApiServer) { - const db = server.db; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - - server.addRoute("POST", "/api/agents/:agentId/wake", (_req, res, params, token, body) => { - const targetAgentId = requireParam(params, "agentId"); - const targetAgent = (() => { - try { - return db.core.entity.getAgent(targetAgentId); - } catch (err) { - log.warn(`[api/agent-control] getAgent failed for ${targetAgentId}:`, err instanceof Error ? err.message : String(err)); - return null; - } - })(); - if (!targetAgent || targetAgent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found" }); - return; - } - if (!canControlAgent(db, token.companyId, token.agentId, targetAgentId)) { - server.json(res, 403, { error: "Current agent is not allowed to wake this agent" }); - return; - } - const wakeSchema = z.object({ - reason: z.string().min(1).max(200).default("peer_request"), - }); - const parsed = wakeSchema.safeParse(body); - const reason = parsed.success ? parsed.data.reason : "peer_request"; - const alreadyActive = db.core.runs.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId }); - const runId = onWakeAgent(targetAgentId, token.companyId, reason); - if (runId) { - server.json(res, 200, { ok: true, runId, message: `Wake started for agent ${targetAgentId}` }); - return; - } - if (alreadyActive) { - server.json(res, 202, { - ok: true, - queued: true, - message: `Agent ${targetAgentId} is already running. Wake will be retried after the active run completes.`, - }); - return; - } - server.json(res, 409, { ok: false, error: "Agent could not be woken right now" }); - }); - - server.addRoute("PATCH", "/api/agents/:agentId/heartbeat", (_req, res, params, token) => { - const targetAgentId = requireParam(params, "agentId"); - let targetAgent; - try { - targetAgent = db.core.entity.getAgent(targetAgentId); - } catch (err) { - log.warn(`[api/agent-control] getAgent failed for heartbeat ${targetAgentId}:`, err instanceof Error ? err.message : String(err)); - targetAgent = null; - } - if (!targetAgent || targetAgent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found or not in the same company" }); - return; - } - if (!canControlAgent(db, token.companyId, token.agentId, targetAgentId)) { - server.json(res, 403, { error: "Current agent is not allowed to trigger heartbeat for this agent" }); - return; - } - const alreadyActive = db.core.runs.hasActiveRun({ companyId: token.companyId, agentId: targetAgentId }); - const runId = onWakeAgent(targetAgentId, token.companyId, "peer_request"); - if (runId) { - server.json(res, 200, { ok: true, runId, message: `Heartbeat triggered for agent ${targetAgentId}` }); - return; - } - if (alreadyActive) { - server.json(res, 202, { - ok: true, - queued: true, - message: `Agent ${targetAgentId} is already running. Heartbeat will retry after the current run.`, - }); - return; - } - server.json(res, 409, { ok: false, error: "Heartbeat could not be started for this agent" }); - }); - - server.addRoute("GET", "/api/agents/:agentId/skills", (_req, res, params, token) => { - const agentId = requireParam(params, "agentId"); - let agent; - try { - agent = db.core.entity.getAgent(agentId); - } catch (error) { - log.warn(`[api/agent-skills:GET] getAgent(${agentId}) failed: ${error instanceof Error ? error.message : String(error)}`); - agent = null; - } - if (!agent || agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found in your company" }); - return; - } - const skillIds = db.core.skills.listAgentSkillAssignments(token.companyId, agentId); - const skills = skillIds - .map((sid) => db.core.skills.getCompanySkill(token.companyId, sid)) - .filter((s): s is NonNullable => s != null); - server.json(res, 200, skills.map((s) => ({ - id: s.id, - name: s.name, - slug: s.slug, - description: s.description, - sourceType: s.sourceType, - trustLevel: s.trustLevel, - }))); - }); - - server.addRoute("POST", "/api/agents/:agentId/skills", (_req, res, params, token, body) => { - const agentId = requireParam(params, "agentId"); - const parsed = z.object({ skillId: z.string().uuid() }).safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid body: skillId (uuid) required" }); - return; - } - let agent; - try { - agent = db.core.entity.getAgent(agentId); - } catch (error) { - log.warn(`[api/agent-skills:POST] getAgent(${agentId}) failed: ${error instanceof Error ? error.message : String(error)}`); - agent = null; - } - if (!agent || agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found in your company" }); - return; - } - const skill = db.core.skills.getCompanySkill(token.companyId, parsed.data.skillId); - if (!skill) { - server.json(res, 404, { error: "Skill not found in your company" }); - return; - } - if (!db.core.skills.assignSkillToAgent(token.companyId, agentId, parsed.data.skillId)) { - server.json(res, 404, { error: "Skill assignment targets not found in your company" }); - return; - } - onDomainChanged(); - server.json(res, 200, { ok: true, message: `Skill "${skill.name}" assigned to agent ${agent.name}` }); - }); - - server.addRoute("DELETE", "/api/agents/:agentId/skills/:skillId", (_req, res, params, token) => { - const agentId = requireParam(params, "agentId"); - const skillId = requireParam(params, "skillId"); - let agent; - try { - agent = db.core.entity.getAgent(agentId); - } catch (error) { - log.warn(`[api/agent-skills:DELETE] getAgent(${agentId}) failed: ${error instanceof Error ? error.message : String(error)}`); - agent = null; - } - if (!agent || agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found in your company" }); - return; - } - const skill = db.core.skills.getCompanySkill(token.companyId, skillId); - if (!skill) { - server.json(res, 404, { error: "Skill not found in your company" }); - return; - } - if (!db.core.skills.removeSkillFromAgent(token.companyId, agentId, skillId)) { - server.json(res, 404, { error: "Skill assignment not found in your company" }); - return; - } - onDomainChanged(); - server.json(res, 200, { ok: true, message: `Skill removed from agent ${agent.name}` }); - }); -} diff --git a/src/main/api-server/routes-agents-standup.ts b/src/main/api-server/routes-agents-standup.ts deleted file mode 100644 index 43f8155c..00000000 --- a/src/main/api-server/routes-agents-standup.ts +++ /dev/null @@ -1,181 +0,0 @@ -import type { AgentApiServer } from "./server-core"; - -export function registerAgentStandupRoute(server: AgentApiServer): void { - const db = server.db; - server.addRoute("GET", "/api/agents/me/standup", (_req, res, _params, token) => { - const agent = db.core.entity.getAgent(token.agentId); - if (!agent || agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found" }); - return; - } - - const directReports = db.core.agents.listDirectReportsForStandup(token.companyId, token.agentId); - - const myTasks = db.core.tasks.listAssigneeTasksForStandup(token.companyId, token.agentId); - - const reportTasks = db.core.tasks.listTasksForAssignees( - token.companyId, - directReports.map((r) => r.id), - ); - - const reportStatusRows = directReports.length > 0 - ? db.core.agents.listReportStatusesForStandup(token.companyId, token.agentId) - : []; - - const tasksAwaitingMyReview = reportTasks.filter((t) => t.status === "in_review"); - const blockedReportTasks = reportTasks.filter((t) => t.status === "blocked"); - const myBlockedTasks = myTasks.filter((t) => t.status === "blocked"); - const myInProgressTasks = myTasks.filter((t) => t.status === "in_progress"); - const myTodoTasks = myTasks.filter((t) => t.status === "todo"); - - const allRelevantTaskIds = new Set([ - ...myTasks.map((t) => t.id), - ...reportTasks.map((t) => t.id), - ]); - const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(); - const recentComments = db.core.activity.listRecentTaskComments([...allRelevantTaskIds], twoHoursAgo, 20); - - const myPendingApprovals = db.core.approvals.listAgentPendingApprovals(token.companyId, token.agentId); - const myResolvedApprovals = db.core.approvals.listAgentResolvedApprovals(token.companyId, token.agentId, 5); - - // Unread inbox lives in the standup briefing as the agent's - // canonical view of pending communication. Pre-fix the agent had - // to make a second API call to /messages?unreadOnly=true that the - // model frequently skipped, so messages from peers and managers - // sat dark while the agent posted heartbeat status comments. - const unreadInbox = db.core.messages.listAgentInboxUnread(token.companyId, token.agentId); - const senderIds = new Set(unreadInbox.map((m) => m.fromAgentId)); - const senderNames = senderIds.size > 0 - ? new Map(db.core.agents.listAgentNamesByIds(token.companyId, Array.from(senderIds)).map((row) => [row.id, row.name])) - : new Map(); - - // Recent outputs the AGENT itself produced — closes the - // trust-but-verify loop. Without this view the model could - // narrate "I wrote the spec doc" in its assistant text without - // ever calling the persistence API, and we'd never catch it. - // Filter scope: documents the agent authored, work_products on - // any task the agent has worked on (assigned tasks). Taskless - // run outputs are intentionally out of scope here — the smaller - // surface keeps the briefing readable. - const RECENT_OUTPUT_LIMIT = 20; - const myTaskIds = new Set(myTasks.map((t) => t.id)); - const recentDocuments = db.core.documents.listDocuments(token.companyId) - .filter((doc) => doc.authorAgentId === token.agentId) - .slice(0, RECENT_OUTPUT_LIMIT); - const recentWorkProducts = db.core.documents.listWorkProductsForCompany(token.companyId) - .filter((wp) => wp.taskId !== null && myTaskIds.has(wp.taskId)) - .slice(0, RECENT_OUTPUT_LIMIT); - - const reportNameMap = new Map(directReports.map((a) => [a.id, a.name])); - const taskTitleMap = new Map([ - ...myTasks.map<[string, string]>((t) => [t.id, t.title]), - ...reportTasks.map<[string, string]>((t) => [t.id, t.title]), - ]); - const socialAccounts = db.core.social.listSocialAccounts(token.companyId); - - server.json(res, 200, { - agent: { id: agent.id, name: agent.name, role: agent.role, status: agent.status }, - summary: { - unreadMessages: unreadInbox.length, - tasksAwaitingReview: tasksAwaitingMyReview.length, - blockedReportTasks: blockedReportTasks.length, - myBlockedTasks: myBlockedTasks.length, - myInProgress: myInProgressTasks.length, - myTodo: myTodoTasks.length, - pendingApprovals: myPendingApprovals.length, - directReports: directReports.length, - }, - unreadMessages: unreadInbox.map((m) => ({ - id: m.id, - from: senderNames.get(m.fromAgentId) ?? m.fromAgentId, - fromAgentId: m.fromAgentId, - toAgentId: m.toAgentId, - channel: m.channel, - channelTargetId: m.channelTargetId, - subject: m.subject, - bodyPreview: m.body.slice(0, 240), - priority: m.priority, - parentMessageId: m.parentMessageId, - createdAt: m.createdAt, - })), - recentDocuments: recentDocuments.map((d) => ({ - id: d.id, - type: d.type, - title: d.title, - status: d.status, - version: d.version, - updatedAt: d.updatedAt, - })), - recentWorkProducts: recentWorkProducts.map((wp) => ({ - id: wp.id, - type: wp.type, - provider: wp.provider, - title: wp.title, - externalId: wp.externalId, - url: wp.url, - status: wp.status, - taskId: wp.taskId, - taskTitle: wp.taskId ? (taskTitleMap.get(wp.taskId) ?? "") : "", - updatedAt: wp.updatedAt, - })), - tasksAwaitingReview: tasksAwaitingMyReview.map((t) => ({ - id: t.id, - title: t.title, - assignee: reportNameMap.get(t.assigneeAgentId) ?? "Unknown", - priority: t.priority, - })), - blockedTasks: [ - ...blockedReportTasks.map((t) => ({ - id: t.id, - title: t.title, - assignee: reportNameMap.get(t.assigneeAgentId) ?? "Unknown", - priority: t.priority, - })), - ...myBlockedTasks.map((t) => ({ - id: t.id, - title: t.title, - assignee: agent.name, - priority: t.priority, - })), - ], - recentComments: recentComments.map((c) => ({ - taskId: c.taskId, - taskTitle: taskTitleMap.get(c.taskId) ?? "", - author: c.authorName, - body: c.body.slice(0, 200), - createdAt: c.createdAt, - })), - pendingApprovals: myPendingApprovals.map((a) => ({ - id: a.id, - type: a.type, - summary: a.payloadSummary, - state: a.state, - })), - resolvedApprovals: myResolvedApprovals.map((a) => ({ - id: a.id, - type: a.type, - summary: a.payloadSummary, - state: a.state, - decisionNote: a.decisionNote, - })), - reportStatuses: reportStatusRows.map((r) => ({ - id: r.id, - name: r.name, - role: r.role, - status: r.status, - tasksInProgress: r.tasksInProgress, - tasksInReview: r.tasksInReview, - tasksBlocked: r.tasksBlocked, - tasksDone: r.tasksDone, - })), - socialAccounts: socialAccounts.map((a) => ({ - id: a.id, - platform: a.platform, - accountName: a.accountName, - displayName: a.displayName, - status: a.status, - requireApproval: a.requireApproval, - })), - }); - }); -} diff --git a/src/main/api-server/routes-agents.ts b/src/main/api-server/routes-agents.ts deleted file mode 100644 index 79d6ecef..00000000 --- a/src/main/api-server/routes-agents.ts +++ /dev/null @@ -1,314 +0,0 @@ -import log from "electron-log/main.js"; -import { hireRequestSchema } from "@shared/contracts"; -import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy"; -import { - canManageOrganization, - canRequestHire, - getHireNameValidationError, - getHireRoutingValidationError, - resolveHireReportsTo, -} from "../agent-permissions"; -import { resolveApprovalDecision } from "../approval-policy"; -import { shouldAutoApprove } from "../execution-policy"; -import { incrementDeprecationCall } from "./deprecation-counter"; -import { requireParam, type AgentApiServer } from "./server-core"; - -// C4-followup #3: RFC 8594 deprecation headers for the legacy HTTP hire -// route. Sunset is the 30-day removal gate — if the counter stays zero -// through this date, delete the handler. -const LEGACY_HIRE_ROUTE_LABEL = "POST /api/companies/:companyId/agents"; -const LEGACY_HIRE_SUNSET = new Date("2026-05-20T00:00:00Z").toUTCString(); - -export function registerAgentRoutes(server: AgentApiServer) { - const db = server.db; - const callbacks = server.callbacks; - const onDomainChanged = server.onDomainChanged; - server.addRoute("GET", "/api/agents/me", (_req, res, _params, token) => { - const agent = db.core.entity.getAgent(token.agentId); - const chainOfCommand = db.core.agents.getChainOfCommand(token.agentId); - const directReports = db.core.agents.getDirectReports(token.agentId, token.companyId); - server.json(res, 200, { agent, chainOfCommand, directReports }); - }); - - // GET /api/agents/me/standup lives in routes-agents-standup.ts, which - // uses targeted standup-shaped DB queries. The inline duplicate that - // used to sit here was dead code — the router keeps the first match - // and the standup module is registered separately in api-server/index.ts. - - server.addRoute("GET", "/api/agents/me/metrics", (_req, res, _params, token) => { - const companyMetrics = db.core.company.getCompanyMetrics(token.companyId, 30); - const agentMetric = companyMetrics.agentMetrics.find(m => m.agentId === token.agentId); - if (!agentMetric) { - server.json(res, 404, { error: "Metrics not found" }); - return; - } - server.json(res, 200, agentMetric); - }); - - server.addRoute("GET", "/api/agents/:agentId/metrics", (_req, res, params, token) => { - const agentId = requireParam(params, "agentId"); - const agent = db.core.entity.getAgent(agentId); - if (!agent || agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found" }); - return; - } - const companyMetrics = db.core.company.getCompanyMetrics(token.companyId, 30); - const agentMetric = companyMetrics.agentMetrics.find((metric) => metric.agentId === agentId); - if (!agentMetric) { - server.json(res, 404, { error: "Metrics not found" }); - return; - } - server.json(res, 200, agentMetric); - }); - - server.addRoute("GET", "/api/agents/:agentId", (_req, res, params, token) => { - let agent; - try { - agent = db.core.entity.getAgent(requireParam(params, "agentId")); - } catch (err) { - log.warn(`[api/agents] getAgent failed:`, err instanceof Error ? err.message : String(err)); - server.json(res, 404, { error: "Agent not found" }); - return; - } - if (agent.companyId !== token.companyId) { - server.json(res, 404, { error: "Agent not found" }); - return; - } - const directReports = db.core.agents.getDirectReports(agent.id, token.companyId); - const reportsTo = agent.reportsTo; - const manager = reportsTo - ? (() => { - try { - return db.core.entity.getAgent(reportsTo); - } catch (error) { - log.warn(`[api/agents] manager lookup failed for ${reportsTo}: ${error instanceof Error ? error.message : String(error)}`); - return null; - } - })() - : null; - server.json(res, 200, { - ...agent, - manager: manager ? { id: manager.id, name: manager.name, role: manager.role } : null, - directReports: directReports.map(r => ({ id: r.id, name: r.name, role: r.role, status: r.status })), - }); - }); - - server.addRoute("GET", "/api/companies/:companyId/agents", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const agents = db.core.agents.listAgentsForApi(params.companyId); - server.json(res, 200, agents); - }); - - /** - * @deprecated since C4 (2026-04-20). Agents should file hires via the - * first-class `hire_agent` pi tool (see - * `src/main/worker/runtime/internal-tools/hire-agent-tool.ts`). This - * HTTP route stays live for legacy clients (UI form post, automation - * tests, unmigrated scripts) during the deprecation window and will - * be removed once tool-path eval confirms no regressions. Every - * successful request emits a `log.warn` tagged with `[deprecated]` - * so residual callers are easy to audit. - */ - server.addRoute("POST", "/api/companies/:companyId/agents", (_req, res, params, token, body) => { - // RFC 8594 deprecation signaling — emit on every response from this - // handler regardless of downstream validation outcome. - res.setHeader("Deprecation", "true"); - res.setHeader("Sunset", LEGACY_HIRE_SUNSET); - res.setHeader("Link", '; rel="deprecation"'); - incrementDeprecationCall(LEGACY_HIRE_ROUTE_LABEL); - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - if (!canRequestHire(db, companyId, token.agentId)) { - server.json(res, 403, { error: "Current agent is not allowed to request hires" }); - return; - } - log.warn( - `[deprecated][C4] POST /api/companies/${companyId}/agents — prefer the hire_agent internal tool (caller agent=${token.agentId}).`, - ); - const reportsToProvided = - typeof body === "object" && - body !== null && - Object.prototype.hasOwnProperty.call(body, "reportsTo"); - const parsed = hireRequestSchema.safeParse({ - companyId, - requestedByAgentId: token.agentId, - ...(typeof body === "object" && body ? body : {}), - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid hire payload" }); - return; - } - const input = parsed.data; - const resolvedReportsTo = resolveHireReportsTo( - db, - companyId, - token.agentId, - reportsToProvided ? input.reportsTo : undefined, - input.department ?? null, - ); - const nameError = getHireNameValidationError({ - name: input.name, - role: input.role, - title: input.title, - }); - if (nameError) { - server.json(res, 422, { error: nameError }); - return; - } - const routingError = getHireRoutingValidationError( - db, - companyId, - token.agentId, - resolvedReportsTo, - input.department ?? null, - ); - if (routingError) { - server.json(res, 422, { error: routingError }); - return; - } - if (server.companyRefError(res, companyId, [ - { id: input.requestedByAgentId, table: "agents", label: "requesting agent" }, - { id: resolvedReportsTo, table: "agents", label: "manager" }, - { id: input.workspaceId, table: "workspaces", label: "workspace" }, - ])) { - return; - } - if ( - resolvedReportsTo && - resolvedReportsTo !== token.agentId && - !canManageOrganization(db, companyId, token.agentId) && - !db.core.agents.getChainOfCommand(resolvedReportsTo).some((agent) => agent.id === token.agentId) - ) { - server.json(res, 403, { error: "Requested hire must report to you or a manager in your reporting chain." }); - return; - } - const connectorRecord = (() => { - try { - return db.core.connectors.getConnector(input.connectorId); - } catch (err) { - log.warn(`[api/agents] getConnector failed for ${input.connectorId}:`, err instanceof Error ? err.message : String(err)); - return null; - } - })(); - if (!connectorRecord) { - server.json(res, 422, { error: "The selected connector does not exist." }); - return; - } - const connectorIssue = getConnectorExecutionReadinessIssue(connectorRecord); - if (connectorIssue) { - server.json(res, 422, { error: connectorIssue }); - return; - } - - // Prevent duplicate agents: reject if a non-terminated agent with the same name already exists - const existingAgents = db.core.agents.listExistingAgentsForHireCheck(companyId); - const duplicateByName = existingAgents.find( - (a) => a.name.toLowerCase() === input.name.toLowerCase(), - ); - if (duplicateByName) { - server.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 = db.core.approvals.listPendingHireApprovalPayloads(companyId); - 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()) { - server.json(res, 409, { error: `A hire request for "${input.name}" is already pending approval.` }); - return; - } - } catch (error) { - log.warn( - `[api/agents] invalid pending-hire payloadJson for company ${companyId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - const managerLabel = resolvedReportsTo - ? (() => { - try { - return db.core.entity.getAgent(resolvedReportsTo).name; - } catch (err) { - log.warn(`[api/agents] getAgent failed for manager ${resolvedReportsTo}:`, err instanceof Error ? err.message : String(err)); - return resolvedReportsTo; - } - })() - : "the company board"; - - let result: { agentId: string; approvalId: string }; - try { - result = db.createHireRequest({ - companyId, - requestedByAgentId: input.requestedByAgentId ?? token.agentId, - name: input.name, - role: input.role, - title: input.title, - department: input.department ?? null, - reportsTo: resolvedReportsTo, - connectorId: input.connectorId, - workspaceId: input.workspaceId ?? null, - model: input.model ?? null, - metadataJson: input.metadataJson ?? "{}", - capabilities: input.capabilities, - budgetMonthlyUsd: input.budgetMonthlyUsd, - payloadSummary: `Hire ${input.name} as ${input.role}`, - impactSummary: input.capabilities || `${input.name} will report to ${managerLabel}.`, - payloadJson: JSON.stringify({ - name: input.name, - role: input.role, - title: input.title, - requestedByAgentId: input.requestedByAgentId ?? token.agentId, - requestedConfigurationSnapshot: { - connectorId: input.connectorId, - workspaceId: input.workspaceId ?? null, - model: input.model ?? null, - metadataJson: input.metadataJson ?? "{}", - capabilities: input.capabilities, - budgetMonthlyUsd: input.budgetMonthlyUsd, - reportsTo: resolvedReportsTo, - department: input.department ?? null, - title: input.title, - }, - }), - }); - } catch (error) { - server.json(res, 422, { error: error instanceof Error ? error.message : "Hire could not be created" }); - return; - } - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "agent.hire_requested", - entityType: "agent", - entityId: result.agentId, - detail: input.name, - }); - - let autoApproved = false; - if (shouldAutoApprove(db, companyId, "hire_agent")) { - resolveApprovalDecision({ - db, - handleApprovalResolved: callbacks.onApprovalResolved, - companyId, - approvalId: result.approvalId, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: `Auto-approved hire: ${input.name}`, - }); - autoApproved = true; - log.info(`[auto-approve] Auto-approved hire of ${input.name} via agent API`); - } - - onDomainChanged(); - server.json(res, 201, { ...result, autoApproved }); - }); - -} diff --git a/src/main/api-server/routes-approvals.ts b/src/main/api-server/routes-approvals.ts deleted file mode 100644 index e884f3fa..00000000 --- a/src/main/api-server/routes-approvals.ts +++ /dev/null @@ -1,286 +0,0 @@ -import { z } from "zod"; -import log from "electron-log/main.js"; -import { approvalInputSchema, mergeApprovalAttachments } from "@shared/contracts"; -import { resolveApprovalDecision } from "../approval-policy"; -import { shouldAutoApprove } from "../execution-policy"; -import { incrementDeprecationCall } from "./deprecation-counter"; -import { requireParam, type AgentApiServer } from "./server-core"; - -// C4-followup #3: RFC 8594 deprecation headers for the legacy -// approve_ceo_strategy HTTP path. Only this approval type is -// deprecated — other types still use this route as first-class. -const LEGACY_APPROVE_CEO_STRATEGY_LABEL = - "POST /api/companies/:companyId/approvals type=approve_ceo_strategy"; -const LEGACY_APPROVE_CEO_STRATEGY_SUNSET = new Date("2026-05-20T00:00:00Z").toUTCString(); - -const approvalListQuerySchema = z.object({ - requestedByAgentId: z.string().uuid().optional(), - relatedTaskId: z.string().uuid().optional(), - status: z.string().optional(), -}); - -export function registerApprovalRoutes(server: AgentApiServer) { - const db = server.db; - const callbacks = server.callbacks; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - - /** - * @deprecated since C4 (2026-04-20) for the `approve_ceo_strategy` - * flow. CEOs should file that approval via the `file_approval` pi - * tool (see `src/main/worker/runtime/internal-tools/file-approval- - * tool.ts`). Other approval types still use this HTTP route. Once - * every approval type has a tool surface, this route is removed - * outright; until then, the deprecated warn is scoped to - * `approve_ceo_strategy` so signal stays clean. - */ - server.addRoute("POST", "/api/companies/:companyId/approvals", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const parsed = approvalInputSchema.safeParse({ - companyId, - ...(typeof body === "object" && body ? body : {}), - requestedByAgentId: token.agentId, - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid approval payload" }); - return; - } - const input = parsed.data; - if (input.type === "approve_ceo_strategy") { - res.setHeader("Deprecation", "true"); - res.setHeader("Sunset", LEGACY_APPROVE_CEO_STRATEGY_SUNSET); - res.setHeader("Link", '; rel="deprecation"'); - incrementDeprecationCall(LEGACY_APPROVE_CEO_STRATEGY_LABEL); - log.warn( - `[deprecated][C4] POST /api/companies/${companyId}/approvals type=approve_ceo_strategy — prefer the file_approval internal tool (caller agent=${token.agentId}).`, - ); - } - if (server.companyRefError(res, companyId, [ - { id: input.relatedTaskId, table: "tasks", label: "related task" }, - { id: token.agentId, table: "agents", label: "requesting agent" }, - { id: input.relatedAgentId, table: "agents", label: "related agent" }, - ])) { - return; - } - - // Team-building strategy approvals must follow their intended hires. - // Accepting an approve_ceo_strategy before any hire_agent requests - // exist was observed to re-enter the empty team-building loop (see - // comment in ceo-modes/team-building.en.md and §5.2 of 问题.md). - // Reject the request at the API boundary so the model cannot - // circumvent the ordering by resubmitting. - if (input.type === "approve_ceo_strategy") { - const companyHireApprovals = db.core.approvals.listCompanyApprovalsByType(companyId, "hire_agent"); - if (companyHireApprovals.length === 0) { - server.json(res, 409, { - error: "approve_ceo_strategy requires at least one hire_agent approval to exist first. Submit the intended hires, then file the strategy.", - code: "STRATEGY_BEFORE_HIRES", - }); - return; - } - const existingStrategy = db.core.approvals.listCompanyApprovalsByType(companyId, "approve_ceo_strategy") - .find((a) => a.state === "pending" || a.state === "approved"); - if (existingStrategy) { - server.json(res, 409, { - error: "approve_ceo_strategy already exists for this company; do not submit another.", - code: "STRATEGY_ALREADY_FILED", - existingApprovalId: existingStrategy.id, - }); - return; - } - } - - // Fold the schema-level documentIds / workProductIds into payloadJson so - // the ApprovalInspector and extractApprovalDocumentReferences can read a - // single source of truth. Legacy callers that stuffed documentIds inside - // payloadJson keep working unchanged. Malformed payloadJson (non-JSON - // or non-object) surfaces as 400 at the API boundary — no silent - // rawPayload stashing, because that hid producer bugs from the operator. - let mergedPayloadJson: string | null; - try { - mergedPayloadJson = mergeApprovalAttachments( - input.payloadJson, - input.documentIds, - input.workProductIds, - ); - } catch (error) { - server.json(res, 400, { - error: error instanceof Error ? error.message : "Invalid approval payloadJson", - code: "INVALID_PAYLOAD_JSON", - }); - return; - } - - let id: string; - try { - id = db.core.approvals.requestApproval({ - companyId, - type: input.type, - relatedTaskId: input.relatedTaskId ?? null, - requestedByAgentId: token.agentId, - relatedAgentId: input.relatedAgentId ?? null, - payloadSummary: input.payloadSummary, - impactSummary: input.impactSummary, - payloadJson: mergedPayloadJson, - }); - } catch (error) { - server.json(res, 422, { error: error instanceof Error ? error.message : "Approval could not be created" }); - return; - } - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "approval.created", - entityType: "approval", - entityId: id, - detail: input.payloadSummary, - }); - - // Notify thread integration about the new approval - callbacks.onApprovalCreated(id, companyId, input.relatedTaskId ?? null, input.type, input.payloadSummary ?? ""); - - if (shouldAutoApprove(db, companyId, input.type)) { - resolveApprovalDecision({ - db, - handleApprovalResolved: callbacks.onApprovalResolved, - companyId, - approvalId: id, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: "Auto-approved by company policy", - }); - log.info(`[auto-approve] Auto-approved approval ${id}: ${input.payloadSummary}`); - } else { - callbacks.notify({ - title: "Approval Required", - body: input.payloadSummary ?? `${input.type} approval pending`, - urgency: "critical", - navigation: { section: "approvals", entityId: id }, - batchKey: "pending_approval", - }); - } - - onDomainChanged(); - server.json(res, 201, { id }); - }); - - server.addRoute("GET", "/api/companies/:companyId/approvals", (req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - const parsedQuery = approvalListQuerySchema.safeParse({ - requestedByAgentId: url.searchParams.get("requestedByAgentId") ?? undefined, - relatedTaskId: url.searchParams.get("relatedTaskId") ?? undefined, - status: url.searchParams.get("status") ?? undefined, - }); - if (!parsedQuery.success) { - server.json(res, 400, { error: "Invalid approval query" }); - return; - } - const statuses = parsedQuery.data.status?.split(",").filter(Boolean) ?? null; - const approvals = db.core.approvals.listApprovalsForApi(companyId, { - requestedByAgentId: parsedQuery.data.requestedByAgentId, - relatedTaskId: parsedQuery.data.relatedTaskId, - statuses, - }); - server.json(res, 200, approvals); - }); - - server.addRoute("GET", "/api/approvals/:approvalId", (_req, res, params, token) => { - const approval = db.core.approvals.findApprovalById(requireParam(params, "approvalId")); - if (!approval || approval.companyId !== token.companyId) { - server.json(res, 404, { error: "Approval not found" }); - return; - } - server.json(res, 200, approval); - }); - - server.addRoute("PATCH", "/api/approvals/:approvalId", (_req, res) => { - server.json(res, 403, { error: "Approvals must be decided from the desktop board, not from an agent run token" }); - }); - - server.addRoute("GET", "/api/approvals/:approvalId/comments", (_req, res, params, token) => { - const approvalId = requireParam(params, "approvalId"); - const approval = db.core.approvals.findApprovalById(approvalId); - if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; } - if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; } - const comments = db.core.approvals.listApprovalComments(approvalId, approval.companyId); - server.json(res, 200, comments); - }); - - server.addRoute("POST", "/api/approvals/:approvalId/comments", (_req, res, params, token, body) => { - const approval = db.core.approvals.findApprovalById(requireParam(params, "approvalId")); - if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; } - if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; } - const data = body as Record; - const commentBody = typeof data.body === "string" ? data.body.trim() : ""; - if (!commentBody) { server.json(res, 400, { error: "Comment body is required" }); return; } - const commentId = db.core.approvals.addApprovalComment({ - companyId: approval.companyId, - approvalId: approval.id, - authorAgentId: token.agentId ?? null, - body: commentBody, - }); - // Wake mentioned agents in comment - const mentionedIds = db.core.agents.findMentionedAgentIds(approval.companyId, commentBody); - for (const mentionedId of mentionedIds) { - if (mentionedId !== token.agentId) { - onWakeAgent(mentionedId, approval.companyId, "approval_comment_mentioned"); - } - } - onDomainChanged(); - server.json(res, 201, { id: commentId }); - }); - - server.addRoute("POST", "/api/approvals/:approvalId/resubmit", (_req, res, params, token) => { - const approval = db.core.approvals.findApprovalById(requireParam(params, "approvalId")); - if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; } - if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; } - if (approval.state !== "revision_requested") { - server.json(res, 422, { error: "Only revision_requested approvals can be resubmitted" }); - return; - } - if (token.agentId !== approval.requestedByAgentId) { - server.json(res, 403, { error: "Only the requesting agent can resubmit this approval" }); - return; - } - db.core.approvals.resubmitApproval(approval.id, approval.companyId); - onDomainChanged(); - server.json(res, 200, { resubmitted: true }); - }); - - server.addRoute("GET", "/api/approvals/:approvalId/tasks", (_req, res, params, token) => { - const approvalId = requireParam(params, "approvalId"); - const approval = db.core.approvals.findApprovalById(approvalId); - if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; } - if (approval.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; } - const taskIds = db.core.approvals.listTasksForApproval(approvalId); - server.json(res, 200, taskIds); - }); - - server.addRoute("POST", "/api/approvals/:approvalId/tasks", (_req, res, params, token, body) => { - const approvalId = requireParam(params, "approvalId"); - const approval = db.core.approvals.findApprovalById(approvalId); - if (!approval) { server.json(res, 404, { error: "Approval not found" }); return; } - if (approval.companyId !== token.companyId) { server.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) { server.json(res, 400, { error: "taskIds array is required" }); return; } - for (const taskId of taskIds) { - if (!db.core.settings.belongsToCompany("tasks", taskId, token.companyId)) { - server.json(res, 400, { error: `Task ${taskId} does not belong to this company` }); return; - } - } - db.core.approvals.linkManyTasksToApproval(approvalId, taskIds, token.companyId, token.agentId ?? null); - onDomainChanged(); - server.json(res, 200, { linked: taskIds.length }); - }); -} diff --git a/src/main/api-server/routes-files.ts b/src/main/api-server/routes-files.ts deleted file mode 100644 index 760e173e..00000000 --- a/src/main/api-server/routes-files.ts +++ /dev/null @@ -1,402 +0,0 @@ -import log from "electron-log/main.js"; -import { z } from "zod"; -import { - canonicalOptionalJsonString, - jsonStringArraySchema, - workProductProviderEnum, - workProductReviewStateEnum, - workProductStatusEnum, - workProductTypeEnum, -} from "@shared/contracts"; -import { requireParam, type AgentApiServer } from "./server-core"; -import { normalizeExternalHttpUrl } from "../external-url-policy"; -import { WorkProductScopeError } from "../database/documents-work-products"; - -const workProductUrlSchema = z.string().trim().superRefine((value, ctx) => { - try { - normalizeExternalHttpUrl(value); - } catch (error) { - ctx.addIssue({ - code: "custom", - message: error instanceof Error ? error.message : String(error), - }); - } -}).transform((value) => normalizeExternalHttpUrl(value)); - -const createDocumentSchema = z.object({ - type: z.string().optional(), - title: z.string().optional(), - content: z.string().optional(), - status: z.string().optional(), - reviewerAgentId: z.string().optional(), - projectId: z.string().optional(), - goalId: z.string().optional(), - tagsJson: canonicalOptionalJsonString(jsonStringArraySchema).optional(), -}); - -const updateDocumentSchema = z.object({ - type: z.string().optional(), - title: z.string().optional(), - content: z.string().optional(), - status: z.string().optional(), - reviewerAgentId: z.union([z.string(), z.null()]).optional(), - tagsJson: canonicalOptionalJsonString(jsonStringArraySchema).optional(), - changeSummary: z.string().optional(), - baseRevisionId: z.string().optional(), -}); - -const createWorkProductSchema = z.object({ - type: workProductTypeEnum, - provider: workProductProviderEnum, - title: z.string(), - projectId: z.string().optional(), - externalId: z.string().optional(), - url: workProductUrlSchema.optional(), - status: workProductStatusEnum.optional(), - reviewState: workProductReviewStateEnum.optional(), - isPrimary: z.boolean().optional(), - summary: z.string().optional(), - metadata: z.unknown().optional(), -}); - -const updateWorkProductSchema = z.object({ - type: workProductTypeEnum.optional(), - provider: workProductProviderEnum.optional(), - externalId: z.string().optional(), - title: z.string().optional(), - url: workProductUrlSchema.optional(), - status: workProductStatusEnum.optional(), - reviewState: workProductReviewStateEnum.optional(), - isPrimary: z.boolean().optional(), - summary: z.string().optional(), - metadataJson: z.string().optional(), -}).strict(); - -const linkDocumentSchema = z.object({ - documentId: z.string(), -}); - -function writeWorkProductCreateError( - server: AgentApiServer, - res: Parameters[0], - error: unknown, -): boolean { - if (error instanceof WorkProductScopeError) { - server.json(res, 422, { error: error.message }); - return true; - } - const message = error instanceof Error ? error.message : String(error); - if (/UNIQUE constraint failed/i.test(message)) { - const conflict = message.includes("work_products.company_id, work_products.task_id, work_products.type") - ? "Work product primary selection conflicts with an existing active primary" - : "Work product identity conflicts with an existing artifact"; - server.json(res, 409, { error: conflict }); - return true; - } - if (/constraint failed/i.test(message)) { - server.json(res, 422, { error: "Work product violates a database constraint" }); - return true; - } - return false; -} - -export function registerFileRoutes(server: AgentApiServer) { - const db = server.db; - const callbacks = server.callbacks; - const onDomainChanged = server.onDomainChanged; - - server.addRoute("POST", "/api/companies/:companyId/documents", (_req, res, params, token, body) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const parsed = createDocumentSchema.safeParse(body); - if (!parsed.success) { server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); return; } - const data = parsed.data; - const reviewerAgentId = data.reviewerAgentId ?? null; - const projectId = data.projectId ?? null; - const goalId = data.goalId ?? null; - if (reviewerAgentId && !db.core.settings.belongsToCompany("agents", reviewerAgentId, token.companyId)) { - server.json(res, 400, { error: "Reviewer agent does not belong to the current company" }); - return; - } - if (projectId && !db.core.settings.belongsToCompany("projects", projectId, token.companyId)) { - server.json(res, 400, { error: "Project does not belong to the current company" }); - return; - } - if (goalId && !db.core.settings.belongsToCompany("goals", goalId, token.companyId)) { - server.json(res, 400, { error: "Goal does not belong to the current company" }); - return; - } - const docType = data.type ?? "knowledge_article"; - const docTitle = data.title ?? "Untitled"; - // Single source of truth for document-creation side effects lives in - // `document-lifecycle.ts`. Persistence, thread/checkpoint/automation - // fan-out, reviewer wake, and the deliverable-review gate all fire - // from inside the pipeline so this HTTP route and the desktop IPC - // handler stay byte-for-byte consistent. - const outcome = callbacks.createDocument({ - id: null, - companyId: token.companyId, - type: docType, - title: docTitle, - content: data.content ?? "", - authorAgentId: token.agentId, - reviewerAgentId, - projectId, - goalId, - parentDocId: null, - version: 1, - status: data.status ?? "draft", - tagsJson: data.tagsJson ?? "[]", - sourceRunId: token.runId ?? null, - }); - server.json(res, 201, { id: outcome.id }); - }); - - server.addRoute("GET", "/api/companies/:companyId/documents", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const docs = db.core.documents.listDocuments(token.companyId); - server.json(res, 200, docs); - }); - - server.addRoute("GET", "/api/companies/:companyId/documents/:documentId", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const documentId = params.documentId; - if (!documentId) { - server.json(res, 400, { error: "Missing documentId" }); - return; - } - const doc = db.core.documents.getDocumentForUpdate(documentId, token.companyId); - if (!doc) { - server.json(res, 404, { error: "Document not found in this company" }); - return; - } - server.json(res, 200, doc); - }); - - server.addRoute("PATCH", "/api/companies/:companyId/documents/:documentId", (_req, res, params, token, body) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const documentId = params.documentId; - if (!documentId) { - server.json(res, 400, { error: "Missing documentId" }); - return; - } - const doc = db.core.documents.getDocumentForUpdate(documentId, token.companyId); - if (!doc) { - server.json(res, 404, { error: "Document not found in this company" }); - return; - } - const parsed = updateDocumentSchema.safeParse(body); - if (!parsed.success) { server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); return; } - const data = parsed.data; - const VALID_STATUSES = new Set(["draft", "in_review", "approved", "archived", "superseded"]); - const reviewerAgentId = data.reviewerAgentId !== undefined - ? (data.reviewerAgentId ?? null) - : doc.reviewerAgentId; - if (data.reviewerAgentId !== undefined && reviewerAgentId && !db.core.settings.belongsToCompany("agents", reviewerAgentId, token.companyId)) { - server.json(res, 400, { error: "Reviewer agent does not belong to the current company" }); - return; - } - - // Conflict detection: if baseRevisionId provided, verify it matches current - if (data.baseRevisionId !== undefined) { - const currentRevId = db.core.documents.getDocumentLatestRevisionId(documentId, token.companyId); - if (currentRevId && data.baseRevisionId !== currentRevId) { - server.json(res, 409, { error: "Document was updated by someone else", currentRevisionId: currentRevId }); - return; - } - } - - if (data.status !== undefined) { - if (!VALID_STATUSES.has(data.status)) { - server.json(res, 400, { error: `Invalid status "${data.status}". Must be one of: ${[...VALID_STATUSES].join(", ")}` }); - return; - } - } - - // Content update → create revision for audit trail - let updatedVersion = doc.version; - if (data.content !== undefined) { - const revision = db.core.documents.createDocumentRevision({ - documentId, - companyId: token.companyId, - body: data.content, - changeSummary: data.changeSummary ?? null, - createdByAgentId: token.agentId ?? null, - }); - updatedVersion = revision.revisionNumber; - } - - // Field updates (title, reviewer, tags, etc.) - if (data.status !== undefined) { - db.core.documents.updateDocumentStatus(documentId, token.companyId, data.status); - } - db.core.documents.saveDocument({ - id: documentId, - companyId: token.companyId, - type: data.type ?? doc.type, - title: data.title ?? doc.title, - content: data.content ?? doc.content, - authorAgentId: doc.authorAgentId, - reviewerAgentId, - projectId: doc.projectId, - goalId: doc.goalId, - version: updatedVersion, - status: data.status ?? doc.status, - tagsJson: data.tagsJson ?? doc.tagsJson, - sourceRunId: data.content !== undefined ? (token.runId ?? null) : null, - }); - - onDomainChanged(); - server.json(res, 200, { updated: true, latestRevisionId: db.core.documents.getDocumentLatestRevisionId(documentId, token.companyId) }); - }); - - server.addRoute("GET", "/api/companies/:companyId/documents/:documentId/revisions", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { server.json(res, 403, { error: "Company mismatch" }); return; } - const documentId = params.documentId; - if (!documentId) { server.json(res, 400, { error: "Missing documentId" }); return; } - const revisions = db.core.documents.listDocumentRevisions(documentId, token.companyId); - server.json(res, 200, revisions); - }); - - // ── Work Products ── - - server.addRoute("GET", "/api/issues/:issueId/work-products", (_req, res, params, token) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { server.json(res, 404, { error: "Task not found" }); return; } - const products = db.core.documents.listWorkProductsForTask(task.id, task.companyId); - server.json(res, 200, products); - } catch (error) { - log.warn(`[api/work-products] list failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 404, { error: "Task not found" }); - } - }); - - server.addRoute("POST", "/api/issues/:issueId/work-products", (_req, res, params, token, body) => { - let task: ReturnType; - try { - task = db.core.entity.getTask(requireParam(params, "issueId")); - } catch (error) { - log.warn(`[api/work-products] task lookup failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 404, { error: "Task not found" }); - return; - } - if (task.companyId !== token.companyId) { server.json(res, 404, { error: "Task not found" }); return; } - const parsed = createWorkProductSchema.safeParse(body); - if (!parsed.success) { server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); return; } - const data = parsed.data; - try { - const id = db.core.documents.createWorkProduct({ - companyId: task.companyId, - taskId: task.id, - projectId: data.projectId, - workspaceId: task.workspaceId ?? null, - type: data.type, - provider: data.provider, - externalId: data.externalId ?? null, - title: data.title, - url: data.url ?? null, - status: data.status ?? "active", - reviewState: data.reviewState ?? "none", - isPrimary: data.isPrimary === true, - summary: data.summary ?? null, - metadataJson: data.metadata ? JSON.stringify(data.metadata) : null, - createdByRunId: token.runId ?? null, - }); - onDomainChanged(); - server.json(res, 201, { id }); - } catch (error) { - if (writeWorkProductCreateError(server, res, error)) return; - log.warn(`[api/work-products] create failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 500, { error: "Work product could not be created" }); - } - }); - - server.addRoute("PATCH", "/api/work-products/:workProductId", (_req, res, params, token, body) => { - const wpId = params.workProductId; - if (!wpId) { server.json(res, 400, { error: "Missing workProductId" }); return; } - const parsed = updateWorkProductSchema.safeParse(body); - if (!parsed.success) { server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); return; } - try { - const changes = db.core.documents.updateWorkProduct(wpId, token.companyId, parsed.data); - if (changes === 0) { server.json(res, 404, { error: "Work product not found" }); return; } - onDomainChanged(); - server.json(res, 200, { updated: true }); - } catch (error) { - if (writeWorkProductCreateError(server, res, error)) return; - log.warn(`[api/work-products] update failed for work product ${wpId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 500, { error: "Work product could not be updated" }); - } - }); - - server.addRoute("DELETE", "/api/work-products/:workProductId", (_req, res, params, token) => { - const wpId = params.workProductId; - if (!wpId) { server.json(res, 400, { error: "Missing workProductId" }); return; } - const changes = db.core.documents.deleteWorkProduct(wpId, token.companyId); - if (changes === 0) { server.json(res, 404, { error: "Work product not found" }); return; } - onDomainChanged(); - server.json(res, 200, { deleted: true }); - }); - - // ── Task-Document Links ── - - server.addRoute("GET", "/api/issues/:issueId/documents", (_req, res, params, token) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { server.json(res, 404, { error: "Task not found" }); return; } - const links = db.core.documents.listDocumentsForTask(task.id, task.companyId); - server.json(res, 200, links); - } catch (error) { - log.warn(`[api/task-documents] list failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 404, { error: "Task not found" }); - } - }); - - server.addRoute("PUT", "/api/issues/:issueId/documents/:key", (_req, res, params, token, body) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { server.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) { - server.json(res, 400, { error: "Invalid document key. Must be lowercase alphanumeric with _ or -, 1-64 chars." }); return; - } - const parsed = linkDocumentSchema.safeParse(body); - if (!parsed.success) { server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); return; } - const documentId = parsed.data.documentId; - if (!db.core.settings.belongsToCompany("documents", documentId, token.companyId)) { - server.json(res, 400, { error: "Document does not belong to this company" }); return; - } - const linkId = db.core.documents.linkDocumentToTask(task.id, documentId, task.companyId, key); - onDomainChanged(); - server.json(res, 200, { id: linkId, key }); - } catch (error) { - log.warn(`[api/task-documents] link failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 404, { error: "Task not found" }); - } - }); - - server.addRoute("DELETE", "/api/issues/:issueId/documents/:key", (_req, res, params, token) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { server.json(res, 404, { error: "Task not found" }); return; } - const key = String(params.key ?? "").trim().toLowerCase(); - db.core.documents.unlinkDocumentFromTask(task.id, key, task.companyId); - onDomainChanged(); - server.json(res, 200, { unlinked: true }); - } catch (error) { - log.warn(`[api/task-documents] unlink failed for issue ${params.issueId}: ${error instanceof Error ? error.message : String(error)}`); - server.json(res, 404, { error: "Task not found" }); - } - }); -} diff --git a/src/main/api-server/routes-meetings.ts b/src/main/api-server/routes-meetings.ts deleted file mode 100644 index d9b9657f..00000000 --- a/src/main/api-server/routes-meetings.ts +++ /dev/null @@ -1,158 +0,0 @@ -import log from "electron-log/main.js"; -import { canonicalJsonString, canonicalOptionalJsonString, jsonArraySchema, jsonStringArraySchema, meetingActionItemArraySchema } from "@shared/contracts"; -import { z } from "zod"; -import { validateTaskCreation } from "../task-quality-gates"; -import { requireParam, type AgentApiServer } from "./server-core"; - -export function registerMeetingRoutes(server: AgentApiServer) { - const db = server.db; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - - server.addRoute("POST", "/api/companies/:companyId/meetings", (_req, res, params, token, body) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const meetingCreateSchema = z.object({ - type: z.string().default("department_sync"), - title: z.string().default("Meeting"), - participantAgentIds: canonicalJsonString(jsonStringArraySchema, []), - scheduledAt: z.string().default(new Date().toISOString()), - durationMinutes: z.number().default(30), - agendaJson: canonicalJsonString(jsonArraySchema, []), - }); - - const parsed = meetingCreateSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid meeting payload", details: parsed.error.issues }); - return; - } - - const input = parsed.data; - try { - const parsedParticipants = JSON.parse(input.participantAgentIds) as string[]; - for (const agentId of parsedParticipants) { - if (typeof agentId !== "string" || !db.core.settings.belongsToCompany("agents", agentId, token.companyId)) { - server.json(res, 400, { error: "Meeting participants must belong to the current company" }); - return; - } - } - } catch (err) { - log.warn(`[api/meetings] participantAgentIds JSON parse failed:`, err instanceof Error ? err.message : String(err)); - server.json(res, 400, { error: "participantAgentIds must be a JSON array of agent ids" }); - return; - } - const id = db.core.knowledge.saveMeeting({ - companyId: token.companyId, - type: input.type, - title: input.title, - organizerAgentId: token.agentId, - participantAgentIds: input.participantAgentIds, - scheduledAt: input.scheduledAt, - durationMinutes: input.durationMinutes, - agendaJson: input.agendaJson, - status: "scheduled", - }); - onDomainChanged(); - server.json(res, 201, { id }); - }); - - server.addRoute("GET", "/api/companies/:companyId/meetings", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const meetings = db.core.knowledge.listMeetings(token.companyId); - server.json(res, 200, meetings); - }); - - server.addRoute("PATCH", "/api/meetings/:meetingId", (_req, res, params, token, body) => { - const meetingId = requireParam(params, "meetingId"); - const existing = db.core.knowledge.getMeeting(meetingId, token.companyId); - if (!existing) { - server.json(res, 404, { error: "Meeting not found" }); - return; - } - - const meetingUpdateSchema = z.object({ - type: z.string().optional(), - title: z.string().optional(), - notesJson: canonicalOptionalJsonString(jsonArraySchema).optional(), - decisionsJson: canonicalOptionalJsonString(jsonArraySchema).optional(), - actionItemsJson: canonicalOptionalJsonString(meetingActionItemArraySchema).optional(), - status: z.string().optional(), - scheduledAt: z.string().optional(), - }); - - const parsed = meetingUpdateSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid meeting update payload", details: parsed.error.issues }); - return; - } - - const data = parsed.data; - let actionItems: Array<{ title?: string; assigneeAgentId?: string; description?: string }> = []; - if (data.actionItemsJson) { - try { - actionItems = JSON.parse(data.actionItemsJson) as Array<{ title?: string; assigneeAgentId?: string; description?: string }>; - } catch (err) { - log.warn(`[api/meetings] actionItemsJson parse failed:`, err instanceof Error ? err.message : String(err)); - server.json(res, 400, { error: "actionItemsJson must be valid JSON" }); - return; - } - for (const item of actionItems) { - if (item.assigneeAgentId && !db.core.settings.belongsToCompany("agents", item.assigneeAgentId, token.companyId)) { - server.json(res, 400, { error: "Meeting action item assignees must belong to the current company" }); - return; - } - } - } - db.core.knowledge.saveMeeting({ - id: meetingId, - companyId: token.companyId, - type: data.type ?? existing.type, - title: data.title ?? existing.title, - organizerAgentId: existing.organizerAgentId, - participantAgentIds: existing.participantAgentIds, - durationMinutes: existing.durationMinutes, - agendaJson: existing.agendaJson, - notesJson: data.notesJson ?? existing.notesJson ?? "[]", - decisionsJson: data.decisionsJson ?? existing.decisionsJson ?? "[]", - actionItemsJson: data.actionItemsJson ?? existing.actionItemsJson ?? "[]", - status: data.status ?? existing.status, - scheduledAt: data.scheduledAt ?? existing.scheduledAt, - }); - onDomainChanged(); - // When action items are added, create tasks for them automatically - if (actionItems.length > 0) { - for (const item of actionItems) { - if (item.title && typeof item.title === "string") { - const meetingTaskValidation = validateTaskCreation( - { title: item.title, description: item.description ?? `Action item from meeting: ${data.title ?? existing.title}` }, - ); - if (!meetingTaskValidation.valid) { - log.warn( - `[meetings] Skipped invalid action item from meeting ${existing.id}: ${meetingTaskValidation.errors.join("; ")}`, - ); - continue; - } - db.core.tasks.saveTask({ - companyId: token.companyId, - title: item.title, - description: item.description ?? `Action item from meeting: ${data.title ?? existing.title}`, - assigneeAgentId: item.assigneeAgentId ?? null, - status: item.assigneeAgentId ? "todo" : "backlog", - priority: "medium", - requiresFilesystem: false, - }); - if (item.assigneeAgentId) { - onWakeAgent(item.assigneeAgentId, token.companyId, "assignment"); - } - } - } - } - server.json(res, 200, { updated: true }); - }); -} diff --git a/src/main/api-server/routes-messages.ts b/src/main/api-server/routes-messages.ts deleted file mode 100644 index c0b9239f..00000000 --- a/src/main/api-server/routes-messages.ts +++ /dev/null @@ -1,179 +0,0 @@ -import log from "electron-log/main.js"; -import { agentMessageInputSchema } from "@shared/contracts"; -import { dispatchAgentMessage } from "../messaging/dispatch"; -import { requireParam, type AgentApiServer } from "./server-core"; - -export function registerMessageRoutes(server: AgentApiServer) { - const db = server.db; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - const emitEvent = server.emitEvent; - - server.addRoute("POST", "/api/issues/:issueId/comments", (_req, res, params, token, body) => { - const input = body as { body?: string } | null; - if (!input?.body || typeof input.body !== "string") { - server.json(res, 400, { error: "body is required" }); - return; - } - if (input.body.length > 4000) { - server.json(res, 400, { error: "Comment body must not exceed 4000 characters" }); - return; - } - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { - server.json(res, 404, { error: "Task not found" }); - return; - } - const agent = db.core.entity.getAgent(token.agentId); - const comment = db.core.activity.addComment({ - companyId: task.companyId, - taskId: task.id, - authorAgentId: token.agentId, - authorName: agent.name, - body: input.body, - }); - onDomainChanged(); - - // Fire comment automation rules - server.callbacks.onCommentPosted(task.id, task.companyId, token.agentId); - - const wokenForComment = new Set(); - if (task.assigneeAgentId && task.assigneeAgentId !== token.agentId) { - onWakeAgent(task.assigneeAgentId, task.companyId, "comment"); - wokenForComment.add(task.assigneeAgentId); - } - - const chain = db.core.agents.getChainOfCommand(token.agentId); - if (chain.length > 0 && chain[0].id !== token.agentId && !wokenForComment.has(chain[0].id)) { - onWakeAgent(chain[0].id, task.companyId, "comment"); - wokenForComment.add(chain[0].id); - } - - // @mention detection: wake any mentioned agents not already woken - const mentionedIds = db.core.agents.findMentionedAgentIds(task.companyId, input.body); - for (const mentionedId of mentionedIds) { - if (mentionedId !== token.agentId && !wokenForComment.has(mentionedId)) { - onWakeAgent(mentionedId, task.companyId, "comment_mentioned"); - wokenForComment.add(mentionedId); - } - } - - server.json(res, 201, comment); - } catch (err) { - log.warn(`[api/messages] addComment failed:`, err instanceof Error ? err.message : String(err)); - server.json(res, 404, { error: "Task not found" }); - } - }); - - server.addRoute("GET", "/api/issues/:issueId/comments", (_req, res, params, token) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { - server.json(res, 404, { error: "Task not found" }); - return; - } - } catch (err) { - log.warn(`[api/messages] getTask failed for comments list:`, err instanceof Error ? err.message : String(err)); - server.json(res, 404, { error: "Task not found" }); - return; - } - const comments = db.core.activity.listComments(requireParam(params, "issueId")); - server.json(res, 200, comments); - }); - - server.addRoute("POST", "/api/companies/:companyId/messages", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const parsed = agentMessageInputSchema.safeParse({ - ...(body as Record), - companyId, - fromAgentId: token.agentId, - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); - return; - } - - const dispatchResult = dispatchAgentMessage( - { - db, - emitEvent, - notify: server.callbacks.notify, - publishDomainChanged: onDomainChanged, - wakeAgentIfPossible: (agentId, cid, trigger) => { - if (!agentId) return null; - return onWakeAgent(agentId, cid, trigger); - }, - injectRuntimeMessage: server.callbacks.injectRuntimeMessage, - onHumanMessage: server.callbacks.onHumanMessage, - }, - parsed.data, - "message", - ); - if (!dispatchResult.ok) { - server.json(res, 400, { error: dispatchResult.error.message, code: dispatchResult.error.code }); - return; - } - - server.json(res, 201, { id: dispatchResult.data.id }); - }); - - server.addRoute("GET", "/api/companies/:companyId/messages", (req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - const channelParam = url.searchParams.get("channel"); - const channelTargetId = url.searchParams.get("channelTargetId"); - const unreadOnly = url.searchParams.get("unreadOnly") === "true"; - const limitStr = url.searchParams.get("limit"); - const limit = limitStr ? Math.min(Math.max(parseInt(limitStr, 10) || 50, 1), 200) : 50; - const allowedChannels = new Set(["direct", "department", "company", "project", "incident"]); - if (channelParam && !allowedChannels.has(channelParam)) { - server.json(res, 400, { error: `Invalid channel filter: ${channelParam}` }); - return; - } - - const messages = db.core.messages.listAgentMessages(companyId, { - agentId: token.agentId, - channel: channelParam ?? undefined, - channelTargetId: channelTargetId && channelTargetId.length > 0 ? channelTargetId : undefined, - unreadOnly, - limit, - }); - server.json(res, 200, messages); - }); - - server.addRoute("POST", "/api/companies/:companyId/messages/:messageId/read", (_req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const message = db.core.messages.getAgentMessage(requireParam(params, "messageId"), companyId); - if (!message) { - server.json(res, 404, { error: "Message not found" }); - return; - } - const visibleToAgent = db.core.messages.listAgentMessages(companyId, { - agentId: token.agentId, - messageId: message.id, - limit: 1, - }).some((entry) => entry.id === message.id); - if (!visibleToAgent) { - server.json(res, 403, { error: "This message is not visible to the current agent" }); - return; - } - db.core.messages.markMessageReadForReader(requireParam(params, "messageId"), companyId, token.agentId); - onDomainChanged(); - server.json(res, 200, { ok: true }); - }); -} diff --git a/src/main/api-server/routes-misc.ts b/src/main/api-server/routes-misc.ts deleted file mode 100644 index 9f92fbec..00000000 --- a/src/main/api-server/routes-misc.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { z } from "zod"; -import { canonicalJsonString, jsonStringArraySchema } from "@shared/contracts"; -import { requireParam, type AgentApiServer } from "./server-core"; -import { SocialAccountScopeError } from "../database/social"; - -const socialDraftSchema = z.object({ - socialAccountId: z.string().uuid(), - platform: z.string(), - content: z.string().min(1).max(10000), - mediaUrls: z.array(z.string()).default([]), - scheduledAt: z.string().datetime().optional(), -}); - -function writeSocialScopeError( - server: AgentApiServer, - res: Parameters[0], - error: unknown, -): boolean { - if (error instanceof SocialAccountScopeError) { - server.json(res, 422, { error: error.message, reference: error.reference }); - return true; - } - return false; -} - -export function registerMiscRoutes(server: AgentApiServer) { - const db = server.db; - const onDomainChanged = server.onDomainChanged; - - server.addRoute("POST", "/api/companies/:companyId/browser/action", async (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const actionSchema = z.object({ - socialAccountId: z.string().uuid(), - actionType: z.enum(["post", "reply", "like", "follow", "browse_feed", "screenshot", "navigate", "search"]), - payload: z.record(z.string(), z.unknown()).default({}), - }); - - const parsed = actionSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid browser action payload", details: parsed.error.issues }); - return; - } - - const input = parsed.data; - - const account = db.core.social.getSocialAccount(input.socialAccountId, companyId); - if (!account) { - server.json(res, 404, { error: "Social account not found" }); - return; - } - - const postActions = ["post", "reply", "dm"]; - if (account.requireApproval && postActions.includes(input.actionType)) { - const approvalId = db.core.approvals.requestApproval({ - companyId, - type: "dangerous_command", - relatedTaskId: null, - requestedByAgentId: token.agentId, - payloadSummary: `${input.actionType} on ${account.platform}/@${account.accountName}: ${String(input.payload.content || "").slice(0, 100)}`, - impactSummary: `Will ${input.actionType} on ${account.displayName || account.accountName}'s ${account.platform} account. Content will be publicly visible.`, - }); - - let actionId: string; - try { - actionId = db.core.social.saveBrowserAction({ - companyId, - socialAccountId: input.socialAccountId, - agentId: token.agentId, - actionType: input.actionType, - payloadJson: JSON.stringify(input.payload), - status: "approval_required", - approvalId, - }); - } catch (error) { - if (writeSocialScopeError(server, res, error)) return; - throw error; - } - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "browser.action_pending_approval", - entityType: "browser_action", - entityId: actionId, - detail: `${input.actionType} on ${account.platform} requires approval`, - }); - - onDomainChanged(); - server.json(res, 202, { id: actionId, status: "approval_required", approvalId, message: "Action requires Board approval before execution" }); - return; - } - - let actionId: string; - try { - actionId = db.core.social.saveBrowserAction({ - companyId, - socialAccountId: input.socialAccountId, - agentId: token.agentId, - actionType: input.actionType, - payloadJson: JSON.stringify(input.payload), - status: "queued", - }); - } catch (error) { - if (writeSocialScopeError(server, res, error)) return; - throw error; - } - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "browser.action_queued", - entityType: "browser_action", - entityId: actionId, - detail: `${input.actionType} on ${account.platform}/@${account.accountName}`, - }); - - onDomainChanged(); - - const onBrowserAction = server.onBrowserAction; - if (onBrowserAction) { - try { - onBrowserAction(actionId, companyId); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - db.core.social.updateBrowserAction(actionId, { - status: "failed", - resultSummary: "Browser action dispatch failed before execution completed.", - errorMessage: message, - finishedAt: new Date().toISOString(), - }); - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "browser.action_dispatch_failed", - entityType: "browser_action", - entityId: actionId, - detail: message, - }); - onDomainChanged(); - server.json(res, 500, { id: actionId, status: "failed", error: "Browser action dispatch failed" }); - return; - } - } - - server.json(res, 201, { id: actionId, status: "queued", message: "Browser action queued for execution" }); - }); - - server.addRoute("GET", "/api/companies/:companyId/social-accounts", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const accounts = db.core.social.listSocialAccounts(requireParam(params, "companyId")); - const sanitized = accounts.map(a => ({ - id: a.id, - platform: a.platform, - accountName: a.accountName, - displayName: a.displayName, - profileUrl: a.profileUrl, - status: a.status, - requireApproval: a.requireApproval, - })); - server.json(res, 200, sanitized); - }); - - server.addRoute("POST", "/api/companies/:companyId/social/draft", async (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const parsed = socialDraftSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid draft", details: parsed.error.issues }); - return; - } - - const account = db.core.social.getSocialAccount(parsed.data.socialAccountId, companyId); - if (!account) { - server.json(res, 404, { error: "Social account not found" }); - return; - } - - const contentPreview = parsed.data.content.slice(0, 120) + (parsed.data.content.length > 120 ? "..." : ""); - - const approvalId = db.core.approvals.requestApproval({ - companyId, - requestedByAgentId: token.agentId, - type: "social_post", - payloadSummary: contentPreview, - impactSummary: `Post to ${account.platform} via @${account.accountName}`, - payloadJson: JSON.stringify({ - socialAccountId: parsed.data.socialAccountId, - platform: account.platform, - content: parsed.data.content, - mediaUrls: parsed.data.mediaUrls, - scheduledAt: parsed.data.scheduledAt ?? null, - }), - }); - - onDomainChanged(); - server.json(res, 201, { approvalId, status: "pending_approval" }); - }); - - server.addRoute("GET", "/api/companies/:companyId/browser/actions", (req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - const socialAccountId = url.searchParams.get("socialAccountId") ?? undefined; - const status = url.searchParams.get("status") ?? undefined; - const limit = Number(url.searchParams.get("limit") || 50); - - const actions = db.core.social.listBrowserActions(requireParam(params, "companyId"), { socialAccountId, status, limit }); - server.json(res, 200, actions); - }); - - server.addRoute("POST", "/api/companies/:companyId/knowledge", (_req, res, params, token, body) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - - const knowledgeCreateSchema = z.object({ - category: z.string().default("lesson_learned"), - topic: z.string().default(""), - content: z.string().default(""), - importance: z.string().default("medium"), - tagsJson: canonicalJsonString(jsonStringArraySchema, []), - referencedEntityType: z.string().nullable().optional(), - referencedEntityId: z.string().nullable().optional(), - }); - - const parsed = knowledgeCreateSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid knowledge entry payload", details: parsed.error.issues }); - return; - } - - const input = parsed.data; - const id = db.core.knowledge.saveKnowledgeEntry({ - companyId: token.companyId, - category: input.category, - topic: input.topic, - content: input.content, - authorAgentId: token.agentId, - importance: input.importance, - tagsJson: input.tagsJson, - referencedEntityType: input.referencedEntityType ?? null, - referencedEntityId: input.referencedEntityId ?? null, - sourceRunId: token.runId ?? null, - }); - onDomainChanged(); - server.json(res, 201, { id }); - }); - - server.addRoute("GET", "/api/companies/:companyId/knowledge", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const entries = db.core.knowledge.listKnowledgeEntries(token.companyId); - server.json(res, 200, entries); - }); - - // ── Skill REST API endpoints ────────────────────────────────────── - - server.addRoute("GET", "/api/companies/:companyId/skills", (_req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const skills = db.core.skills.listCompanySkills(companyId); - server.json(res, 200, skills.map((s) => ({ - id: s.id, - name: s.name, - slug: s.slug, - description: s.description, - sourceType: s.sourceType, - trustLevel: s.trustLevel, - createdAt: s.createdAt, - }))); - }); - - server.addRoute("GET", "/api/skills/:skillId", (_req, res, params, token) => { - const skill = db.core.skills.getCompanySkill(token.companyId, requireParam(params, "skillId")); - if (!skill) { - server.json(res, 404, { error: "Skill not found" }); - return; - } - server.json(res, 200, skill); - }); -} diff --git a/src/main/api-server/routes-runs.ts b/src/main/api-server/routes-runs.ts deleted file mode 100644 index 12149b34..00000000 --- a/src/main/api-server/routes-runs.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { TokenPayload } from "../agent-auth"; -import { requireParam, type AgentApiServer } from "./server-core"; - -const DEFAULT_EVENT_LIMIT = 500; -const MAX_EVENT_LIMIT = 5_000; -const SSE_BATCH_LIMIT = 500; -const EVENT_POLL_INTERVAL_MS = 1_000; -const SSE_HEARTBEAT_MS = 15_000; - -function parsePositiveInt(value: string | null, fallback: number) { - const parsed = Number.parseInt(value ?? "", 10); - if (!Number.isFinite(parsed) || parsed < 0) { - return fallback; - } - return parsed; -} - -function resolveAuthorizedRun(server: AgentApiServer, token: TokenPayload, runId: string) { - const runState = server.db.core.runs.getRunAuthState(runId); - if (!runState || runState.companyId !== token.companyId || runState.agentId !== token.agentId) { - return null; - } - return runState; -} - -function writeSse(res: Parameters[0], event: string, data: unknown) { - res.write(`event: ${event}\n`); - res.write(`data: ${JSON.stringify(data)}\n\n`); -} - -export function registerRunRoutes(server: AgentApiServer) { - server.addRoute("GET", "/api/runs/:runId/events", (req, res, params, token) => { - const runId = requireParam(params, "runId"); - const runState = resolveAuthorizedRun(server, token, runId); - if (!runState) { - server.json(res, 404, { error: "Run not found for the current agent token" }); - return; - } - - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - const offset = parsePositiveInt(url.searchParams.get("offset"), 0); - const limit = Math.min(parsePositiveInt(url.searchParams.get("limit"), DEFAULT_EVENT_LIMIT), MAX_EVENT_LIMIT); - const events = server.db.core.runs.listRunEvents(runId, token.companyId, { offset, limit }); - server.json(res, 200, { events, nextOffset: offset + events.length }); - }); - - server.addRoute("GET", "/api/runs/:runId/events/stream", (req, res, params, token) => { - const runId = requireParam(params, "runId"); - const runState = resolveAuthorizedRun(server, token, runId); - if (!runState) { - server.json(res, 404, { error: "Run not found for the current agent token" }); - return; - } - - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - let cursor = parsePositiveInt(url.searchParams.get("after"), 0); - - res.writeHead(200, { - "Content-Type": "text/event-stream; charset=utf-8", - "Cache-Control": "no-cache, no-transform", - Connection: "keep-alive", - "X-Accel-Buffering": "no", - }); - res.flushHeaders(); - writeSse(res, "connected", { runId, after: cursor }); - - const flushPendingEvents = () => { - while (true) { - const events = server.db.core.runs.listRunEventsAfter(runId, token.companyId, cursor, SSE_BATCH_LIMIT); - if (events.length === 0) return; - for (const event of events) { - writeSse(res, "run-event", event); - cursor = event.seq; - } - if (events.length < SSE_BATCH_LIMIT) return; - } - }; - - flushPendingEvents(); - const pollTimer = setInterval(flushPendingEvents, EVENT_POLL_INTERVAL_MS); - const heartbeatTimer = setInterval(() => { - res.write(":keepalive\n\n"); - }, SSE_HEARTBEAT_MS); - - const cleanup = () => { - clearInterval(pollTimer); - clearInterval(heartbeatTimer); - }; - - req.on("close", cleanup); - req.on("error", cleanup); - res.on("close", cleanup); - res.on("error", cleanup); - }); -} diff --git a/src/main/api-server/routes-tasks.ts b/src/main/api-server/routes-tasks.ts deleted file mode 100644 index a00af3ca..00000000 --- a/src/main/api-server/routes-tasks.ts +++ /dev/null @@ -1,384 +0,0 @@ -import log from "electron-log/main.js"; -import { z } from "zod"; -import { taskInputSchema } from "@shared/contracts"; -import { IMPORTANT_DOC_TYPES } from "@shared/document-categories"; -import { canAssignTask, canUpdateTask } from "../agent-permissions"; -import { inferTaskType } from "../connector-matching"; -import { validateTaskCreation } from "../task-quality-gates"; -import { resolveTaskWorkspaceBinding } from "../task-workspace-binding"; -import { requireParam, type AgentApiServer } from "./server-core"; - -const taskUpdateSchema = z.object({ - status: z.enum(["backlog", "todo", "in_progress", "in_review", "done", "blocked", "cancelled"]).optional(), - comment: z.string().min(1).max(4000).optional(), - title: z.string().min(2).max(160).optional(), - description: z.string().max(4000).optional(), - assigneeAgentId: z.string().uuid().nullable().optional(), - priority: z.enum(["critical", "high", "medium", "low"]).optional(), - requiresFilesystem: z.boolean().optional(), -}); - -const checkoutSchema = z.object({ - agentId: z.string().uuid().optional(), -}); - -export function registerTaskRoutes(server: AgentApiServer) { - const db = server.db; - const callbacks = server.callbacks; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - - server.addRoute("GET", "/api/companies/:companyId/issues", (req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const url = new URL(req.url ?? "/", `http://127.0.0.1:${server.port}`); - const assigneeAgentId = url.searchParams.get("assigneeAgentId"); - const statusFilter = url.searchParams.get("status"); - const statuses = statusFilter ? statusFilter.split(",") : ["todo", "in_progress", "blocked"]; - - if (assigneeAgentId) { - const tasks = db.core.tasks.listAgentTasks(assigneeAgentId, companyId, statuses); - server.json(res, 200, tasks); - } else { - const tasks = db.core.tasks.listTasksByStatuses(companyId, statuses); - server.json(res, 200, tasks); - } - }); - - server.addRoute("GET", "/api/issues/:issueId", (_req, res, params, token) => { - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { - server.json(res, 404, { error: "Task not found" }); - return; - } - server.json(res, 200, task); - } catch (err) { - log.warn(`[api/tasks] getTask failed:`, err instanceof Error ? err.message : String(err)); - server.json(res, 404, { error: "Task not found" }); - } - }); - - server.addRoute("POST", "/api/issues/:issueId/checkout", (_req, res, params, token, body) => { - const parsedBody = checkoutSchema.safeParse(body); - if (!parsedBody.success) { - server.json(res, 400, { error: "Invalid checkout payload" }); - return; - } - const agentId = parsedBody.data.agentId ?? token.agentId; - if (agentId !== token.agentId) { - server.json(res, 403, { error: "Agents can only checkout work for themselves" }); - return; - } - let task; - try { - task = db.core.entity.getTask(requireParam(params, "issueId")); - } catch (err) { - log.warn(`[api/tasks] getTask failed for checkout:`, err instanceof Error ? err.message : String(err)); - server.json(res, 404, { error: "Task not found" }); - return; - } - if (task.companyId !== token.companyId) { - server.json(res, 404, { error: "Task not found" }); - return; - } - if (task.assigneeAgentId && !canUpdateTask(db, token.companyId, token.agentId, task)) { - server.json(res, 403, { error: "Current agent is not allowed to checkout this task" }); - return; - } - const previousStatus = task.status; - const success = db.core.tasks.checkoutTask(task.id, token.runId); - if (!success) { - server.json(res, 409, { error: "Task cannot be checked out — already assigned or not in valid status" }); - return; - } - onDomainChanged(); - // Checkout changes status from todo/backlog to in_progress — use actual previous status - callbacks.onTaskStatusChanged(task.id, task.companyId, previousStatus, "in_progress"); - server.json(res, 200, { ok: true }); - }); - - server.addRoute("PATCH", "/api/issues/:issueId", (_req, res, params, token, body) => { - const parsedUpdate = taskUpdateSchema.safeParse(body); - if (!parsedUpdate.success) { - server.json(res, 400, { error: "Invalid task update payload" }); - return; - } - const update = parsedUpdate.data; - - try { - const task = db.core.entity.getTask(requireParam(params, "issueId")); - if (task.companyId !== token.companyId) { - server.json(res, 404, { error: "Task not found" }); - return; - } - if (!canUpdateTask(db, token.companyId, token.agentId, task)) { - server.json(res, 403, { error: "Current agent is not allowed to update this task" }); - return; - } - - const newAssignee = update.assigneeAgentId !== undefined ? update.assigneeAgentId : task.assigneeAgentId; - if (!canAssignTask(db, token.companyId, token.agentId, newAssignee ?? null)) { - server.json(res, 403, { error: "Current agent is not allowed to assign this task to the selected agent" }); - return; - } - - // 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)) { - server.json(res, 400, { error: `Invalid task status: ${update.status}` }); - return; - } - - const actorAgent = db.core.entity.getAgent(token.agentId); - let reviewRequest: { reviewerAgentName: string; documents: Array<{ id: string; title: string } & Record> } | null = null; - if (effectiveStatus === "done" && task.requiresUserReview) { - const docs = db.core.documents.listImportantDocsForReview({ - companyId: task.companyId, - types: IMPORTANT_DOC_TYPES, - authorAgentId: task.assigneeAgentId ?? null, - taskId: task.id, - limit: 10, - }); - reviewRequest = { reviewerAgentName: actorAgent.name, documents: docs }; - } - - const nextRequiresFilesystem = update.requiresFilesystem ?? task.requiresFilesystem; - const workspaceBinding = resolveTaskWorkspaceBinding(db, { - companyId: task.companyId, - requiresFilesystem: nextRequiresFilesystem, - explicitWorkspaceId: task.workspaceId, - projectId: task.projectId, - assigneeAgentId: newAssignee, - creatorAgentId: token.agentId, - currentRunId: token.runId ?? null, - }); - if (!workspaceBinding.ok) { - server.json(res, 422, { error: workspaceBinding.error }); - return; - } - - const updateResult = db.core.tasks.updateTaskWithReviewSideEffects({ - taskId: task.id, - companyId: task.companyId, - actorAgentId: token.agentId, - actorName: actorAgent.name, - task: { - title: update.title ?? task.title, - description: update.description ?? task.description, - status: effectiveStatus, - priority: update.priority ?? task.priority, - projectId: task.projectId, - goalId: task.goalId, - parentId: task.parentId, - assigneeAgentId: newAssignee, - workspaceId: workspaceBinding.workspaceId, - requiresFilesystem: nextRequiresFilesystem, - }, - comment: update.comment, - reviewRequest, - activity: { - action: `task.${update.status ? "status_changed" : "updated"}`, - detail: update.comment ?? `Status -> ${update.status ?? task.status}`, - }, - }); - - onDomainChanged(); - - // Fire automation rules for status changes - const previousStatus = updateResult.previousStatus; - const newStatus = updateResult.newStatus; - if (update.status && updateResult.statusChanged) { - callbacks.onTaskStatusChanged(task.id, task.companyId, previousStatus, newStatus); - } - - if (update.status && ["done", "in_review"].includes(newStatus)) { - if (updateResult.parentId) { - try { - const parentTask = db.core.entity.getTask(updateResult.parentId); - if (parentTask.assigneeAgentId && parentTask.assigneeAgentId !== token.agentId) { - onWakeAgent(parentTask.assigneeAgentId, task.companyId, "subtask_completed"); - } - } catch (error) { - log.warn( - `[api/tasks] parent task lookup failed for ${updateResult.parentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } else { - // Top-level task submission goes to the assignee's manager. - // This is not a subtask — use a distinct wake reason so the - // reviewer prompt does not misframe the work as "a subtask - // you delegated". - const chain = db.core.agents.getChainOfCommand(token.agentId); - if (chain.length > 0) { - onWakeAgent(chain[0].id, task.companyId, "task_review_requested"); - } - } - } - - if (update.status && newStatus === "blocked") { - const chain = db.core.agents.getChainOfCommand(token.agentId); - if (chain.length > 0) { - onWakeAgent(chain[0].id, task.companyId, "report_blocked"); - } - } - - if (update.status && ["in_progress", "todo"].includes(newStatus) && - updateResult.newAssigneeAgentId && updateResult.newAssigneeAgentId !== token.agentId) { - onWakeAgent(updateResult.newAssigneeAgentId, task.companyId, "assignment"); - } - - if (update.comment) { - // Fire comment automation rules - callbacks.onCommentPosted(task.id, task.companyId, token.agentId); - - const wokenForComment = new Set(); - if (task.assigneeAgentId && task.assigneeAgentId !== token.agentId) { - onWakeAgent(task.assigneeAgentId, task.companyId, "comment"); - wokenForComment.add(task.assigneeAgentId); - } - const chain = db.core.agents.getChainOfCommand(token.agentId); - if (chain.length > 0 && chain[0].id !== token.agentId && !wokenForComment.has(chain[0].id)) { - onWakeAgent(chain[0].id, task.companyId, "comment"); - } - } - - // Wake new assignee when task is reassigned - if (updateResult.newAssigneeAgentId && updateResult.newAssigneeAgentId !== updateResult.previousAssigneeAgentId && updateResult.newAssigneeAgentId !== token.agentId) { - onWakeAgent(updateResult.newAssigneeAgentId, task.companyId, "assignment"); - } - - server.json(res, 200, { ok: true }); - } catch (error) { - if (error instanceof Error && error.message.includes("require an assignee")) { - server.json(res, 422, { error: error.message }); - return; - } - if (error instanceof Error && error.message.includes("not found")) { - server.json(res, 404, { error: error.message }); - return; - } - // Top-level assignee self-review guard: translate to a 422 so the - // agent sees an actionable business-logic rejection rather than a - // generic server failure. - if (error instanceof Error && error.message.includes("cannot enter in_review")) { - server.json(res, 422, { - error: error.message, - code: "NO_REVIEWER_ON_TOP_LEVEL_TASK", - hint: "Either reassign the task to a report, mark it done directly if the work is complete, or set requires_user_review=1 if the Board should review.", - }); - return; - } - server.json(res, 500, { error: error instanceof Error ? error.message : "Task update failed" }); - } - }); - - server.addRoute("POST", "/api/companies/:companyId/issues", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const parsed = taskInputSchema.safeParse({ - companyId, - ...(typeof body === "object" && body ? body : {}), - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid task payload" }); - return; - } - const input = parsed.data; - if (server.companyRefError(res, companyId, [ - { id: input.assigneeAgentId, table: "agents", label: "assignee" }, - { id: input.parentId, table: "tasks", label: "parent task" }, - { id: input.projectId, table: "projects", label: "project" }, - { id: input.goalId, table: "goals", label: "goal" }, - { id: input.workspaceId, table: "workspaces", label: "workspace" }, - ])) { - return; - } - if (!canAssignTask(db, companyId, token.agentId, input.assigneeAgentId ?? null)) { - server.json(res, 403, { error: "Current agent is not allowed to assign this task to the selected agent" }); - return; - } - const taskValidation = validateTaskCreation({ title: input.title, description: input.description ?? "" }); - if (!taskValidation.valid) { - server.json(res, 422, { error: taskValidation.errors.join("; ") }); - return; - } - - let id: string; - try { - const workspaceBinding = resolveTaskWorkspaceBinding(db, { - companyId, - requiresFilesystem: input.requiresFilesystem, - explicitWorkspaceId: input.workspaceId ?? null, - projectId: input.projectId ?? null, - assigneeAgentId: input.assigneeAgentId ?? null, - creatorAgentId: token.agentId, - currentRunId: token.runId ?? null, - }); - if (!workspaceBinding.ok) { - server.json(res, 422, { error: workspaceBinding.error }); - return; - } - id = db.core.tasks.saveTask({ - companyId, - title: input.title, - description: input.description ?? "", - assigneeAgentId: input.assigneeAgentId ?? null, - parentId: input.parentId ?? null, - projectId: input.projectId ?? null, - goalId: input.goalId ?? null, - priority: input.priority, - status: input.status, - workspaceId: workspaceBinding.workspaceId, - requiresFilesystem: input.requiresFilesystem, - }); - } catch (error) { - server.json(res, 422, { error: error instanceof Error ? error.message : "Task could not be saved" }); - return; - } - - // Auto-infer task_type from assignee's department - if (input.assigneeAgentId) { - const assignee = db.core.entity.getAgent(input.assigneeAgentId); - const inferredType = inferTaskType(assignee.department); - db.core.tasks.setTaskType(id, inferredType); - } - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "task.created", - entityType: "task", - entityId: id, - detail: input.title, - }); - - onDomainChanged(); - - // Fire the full task creation event chain (automation rules, auto-assign, etc.) - callbacks.onTaskCreated(id, companyId); - - // Also wake the assignee directly if specified - if (input.assigneeAgentId && input.assigneeAgentId !== token.agentId) { - onWakeAgent(input.assigneeAgentId, companyId, "assignment"); - } - - // If no assignee specified, auto-assign - if (!input.assigneeAgentId) { - const assignedId = callbacks.onAutoAssignTask(id, companyId); - if (assignedId && assignedId !== token.agentId) { - onWakeAgent(assignedId, companyId, "assignment"); - } - } - - server.json(res, 201, { id }); - }); - -} diff --git a/src/main/api-server/routes-work-graph.ts b/src/main/api-server/routes-work-graph.ts deleted file mode 100644 index 7de1849a..00000000 --- a/src/main/api-server/routes-work-graph.ts +++ /dev/null @@ -1,282 +0,0 @@ -import log from "electron-log/main.js"; -import { z } from "zod"; -import { goalInputSchema, projectInputSchema } from "@shared/contracts"; -import { canManageGoal, canManageProject } from "../agent-permissions"; -import { requireParam, type AgentApiServer } from "./server-core"; - -export function registerWorkGraphRoutes(server: AgentApiServer) { - const db = server.db; - const onDomainChanged = server.onDomainChanged; - const onWakeAgent = server.onWakeAgent; - - server.addRoute("POST", "/api/companies/:companyId/projects", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const parsed = projectInputSchema.safeParse({ - companyId, - ...(typeof body === "object" && body ? body : {}), - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid project payload" }); - return; - } - const input = parsed.data; - if (server.companyRefError(res, companyId, [ - { id: input.goalId, table: "goals", label: "goal" }, - { id: input.leadAgentId, table: "agents", label: "lead agent" }, - ])) { - return; - } - if (!canManageProject(db, companyId, token.agentId, input.leadAgentId ?? null)) { - server.json(res, 403, { error: "Current agent is not allowed to create or assign this project" }); - return; - } - - const id = db.core.entity.saveProject({ - companyId, - name: input.name, - description: input.description ?? "", - goalId: input.goalId ?? null, - leadAgentId: input.leadAgentId ?? null, - status: (input.status as "planned") ?? "planned", - targetDate: input.targetDate ?? null, - }); - - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "project.created", - entityType: "project", - entityId: id, - detail: input.name, - }); - - onDomainChanged(); - if (input.leadAgentId && input.leadAgentId !== token.agentId) { - onWakeAgent(input.leadAgentId, companyId, "assignment"); - } - server.json(res, 201, { id }); - }); - - server.addRoute("PATCH", "/api/projects/:projectId", (_req, res, params, token, body) => { - const projectId = requireParam(params, "projectId"); - - const updateSchema = z.object({ - name: z.string().min(2).max(120).optional(), - description: z.string().max(2000).optional(), - status: z.enum(["planned", "active", "completed", "cancelled"]).optional(), - leadAgentId: z.string().uuid().optional(), - goalId: z.string().uuid().nullable().optional(), - targetDate: z.string().nullable().optional(), - }); - - const parsed = updateSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); - return; - } - - const existing = db.core.entity.getProjectForUpdate(projectId, token.companyId); - if (!existing) { - server.json(res, 404, { error: "Project not found" }); - return; - } - const nextLeadAgentId = parsed.data.leadAgentId ?? existing.leadAgentId ?? null; - if (!canManageProject(db, token.companyId, token.agentId, nextLeadAgentId)) { - server.json(res, 403, { error: "Current agent is not allowed to update this project" }); - return; - } - - try { - db.core.entity.saveProject({ - id: projectId, - companyId: token.companyId, - name: parsed.data.name ?? existing.name, - description: parsed.data.description ?? existing.description, - status: parsed.data.status ?? existing.status, - leadAgentId: nextLeadAgentId, - goalId: parsed.data.goalId !== undefined ? parsed.data.goalId : (existing.goalId ?? null), - targetDate: parsed.data.targetDate !== undefined ? parsed.data.targetDate : (existing.targetDate ?? null), - }); - onDomainChanged(); - server.json(res, 200, { ok: true }); - } catch (err) { - log.warn(`[api/work-graph] Failed to update project:`, err instanceof Error ? err.message : String(err)); - server.json(res, 500, { error: "Failed to update project" }); - } - }); - - server.addRoute("POST", "/api/companies/:companyId/goals", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const parsed = goalInputSchema.safeParse({ - companyId, - ...(typeof body === "object" && body ? body : {}), - }); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid goal payload" }); - return; - } - const input = parsed.data; - if (server.companyRefError(res, companyId, [ - { id: input.parentId, table: "goals", label: "parent goal" }, - { id: input.ownerAgentId, table: "agents", label: "owner agent" }, - ])) { - return; - } - if (!canManageGoal(db, companyId, token.agentId, input.ownerAgentId ?? null)) { - server.json(res, 403, { error: "Current agent is not allowed to create this goal" }); - return; - } - - const id = db.core.entity.saveGoal(input); - db.core.activity.addActivity({ - companyId, - actor: token.agentId, - action: "goal.created", - entityType: "goal", - entityId: id, - detail: input.title, - }); - onDomainChanged(); - if (input.ownerAgentId && input.ownerAgentId !== token.agentId && input.status === "active") { - onWakeAgent(input.ownerAgentId, companyId, "goal_activated"); - } - server.json(res, 201, { id }); - }); - - server.addRoute("PATCH", "/api/goals/:goalId", (_req, res, params, token, body) => { - const goalId = requireParam(params, "goalId"); - - const updateSchema = z.object({ - title: z.string().min(2).max(120).optional(), - description: z.string().max(2000).optional(), - status: z.enum(["planned", "active", "achieved", "cancelled"]).optional(), - ownerAgentId: z.string().uuid().optional(), - }); - - const parsed = updateSchema.safeParse(body); - if (!parsed.success) { - server.json(res, 400, { error: "Invalid input", details: parsed.error.flatten() }); - return; - } - - const existing = db.core.entity.getGoalForUpdate(goalId, token.companyId); - if (!existing) { - server.json(res, 404, { error: "Goal not found" }); - return; - } - const nextOwnerAgentId = parsed.data.ownerAgentId ?? existing.ownerAgentId ?? null; - if (!canManageGoal(db, token.companyId, token.agentId, nextOwnerAgentId)) { - server.json(res, 403, { error: "Current agent is not allowed to update this goal" }); - return; - } - - try { - db.core.entity.saveGoal({ - id: goalId, - companyId: token.companyId, - title: parsed.data.title ?? existing.title, - description: parsed.data.description ?? existing.description, - status: parsed.data.status ?? existing.status, - ownerAgentId: nextOwnerAgentId, - }); - onDomainChanged(); - server.json(res, 200, { ok: true }); - } catch (err) { - log.warn(`[api/work-graph] Failed to update goal:`, err instanceof Error ? err.message : String(err)); - server.json(res, 500, { error: "Failed to update goal" }); - } - }); - - server.addRoute("GET", "/api/companies/:companyId/goals", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const goals = db.core.entity.listGoals(params.companyId); - server.json(res, 200, goals); - }); - - server.addRoute("GET", "/api/companies/:companyId/projects", (_req, res, params, token) => { - if (params.companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const projects = db.core.entity.listProjects(params.companyId); - server.json(res, 200, projects); - }); - - server.addRoute("GET", "/api/companies/:companyId/sprints", (_req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const sprints = db.core.knowledge.listSprints(companyId); - server.json(res, 200, sprints); - }); - - server.addRoute("POST", "/api/companies/:companyId/sprints", (_req, res, params, token, body) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const data = body as Record; - try { - const id = db.core.knowledge.saveSprint({ - companyId, - name: String(data.name ?? "Sprint"), - goal: String(data.goal ?? ""), - startDate: String(data.startDate ?? new Date().toISOString()), - endDate: String(data.endDate ?? new Date(Date.now() + 14 * 86400000).toISOString()), - status: String(data.status ?? "planning") as "planning" | "active" | "review" | "completed" | "cancelled", - retrospectiveNotes: String(data.retrospectiveNotes ?? ""), - velocityPoints: Number(data.velocityPoints ?? 0), - completedPoints: Number(data.completedPoints ?? 0), - }); - onDomainChanged(); - server.json(res, 201, { id }); - } catch (err) { - log.warn(`[api/work-graph] Invalid sprint data:`, err instanceof Error ? err.message : String(err)); - server.json(res, 400, { error: "Invalid sprint data" }); - } - }); - - server.addRoute("GET", "/api/companies/:companyId/dashboard", (_req, res, params, token) => { - const companyId = requireParam(params, "companyId"); - if (companyId !== token.companyId) { - server.json(res, 403, { error: "Company mismatch" }); - return; - } - const { agents, tasks, recentActivity } = db.core.company.getDashboardSnapshot(companyId); - - const tasksByStatus: Record = {}; - for (const t of tasks) { - tasksByStatus[t.status] = (tasksByStatus[t.status] ?? 0) + 1; - } - - server.json(res, 200, { - totalAgents: agents.length, - activeAgents: agents.filter((a) => a.status === "active" || a.status === "running").length, - totalTasks: tasks.length, - tasksByStatus, - recentActivity: recentActivity.map((a) => ({ - id: a.id, - actor: a.actor, - action: a.action, - entityType: a.entityType, - entityId: a.entityId, - detail: a.detail, - createdAt: a.createdAt, - })), - }); - }); -} diff --git a/src/main/api-server/server-core.ts b/src/main/api-server/server-core.ts deleted file mode 100644 index fe4584ab..00000000 --- a/src/main/api-server/server-core.ts +++ /dev/null @@ -1,412 +0,0 @@ -import { createServer, type IncomingMessage, type ServerResponse } from "node:http"; -import log from "electron-log/main.js"; -import { validateAgentToken, type TokenPayload } from "../agent-auth"; -import type { AppDatabase } from "../database"; -import type { AgentMessageRecord, DesktopEvent, SectionId } from "@shared/types"; -import type { DocumentLifecycleInput, DocumentLifecycleOutcome } from "../document-lifecycle"; - -export function decodeBodyToUtf8(raw: Buffer): string { - if (raw.length === 0) return ""; - return new TextDecoder("utf-8", { fatal: true }).decode(raw); -} - -function parseContentType(value: string | string[] | undefined): { mediaType: string; charsets: string[] } | null { - const raw = Array.isArray(value) ? value[0] : value; - if (!raw) return null; - const [mediaTypeRaw, ...params] = raw.split(";"); - const mediaType = mediaTypeRaw?.trim().toLowerCase(); - if (!mediaType) return null; - const charsets: string[] = []; - for (const param of params) { - const [keyRaw, valueRaw] = param.split("="); - if (keyRaw?.trim().toLowerCase() === "charset") { - charsets.push(valueRaw?.trim().replace(/^"|"$/g, "").toLowerCase() ?? ""); - } - } - return { mediaType, charsets }; -} - -function getJsonContentTypeError(req: IncomingMessage): string | null { - const parsed = parseContentType(req.headers["content-type"]); - if (!parsed) return null; - if (parsed.mediaType !== "application/json") return "Content-Type must be application/json."; - if (parsed.charsets.length > 1) return "JSON request bodies must declare one charset."; - if (parsed.charsets.some((charset) => charset !== "utf-8" && charset !== "utf8")) { - return "JSON request bodies must declare charset=utf-8."; - } - return null; -} - -function firstHeaderValue(value: string | string[] | undefined): string | null { - if (Array.isArray(value)) return value[0] ?? null; - return value ?? null; -} - -function extractCompanyIdFromUrl(rawUrl: string | undefined): string | null { - try { - const url = new URL(rawUrl ?? "/", "http://127.0.0.1"); - const match = /^\/api\/companies\/([^/]+)/.exec(url.pathname); - return match ? decodeURIComponent(match[1]) : null; - } catch { - return null; - } -} - -/** - * Extract a required route parameter or throw a 400-level error. - * The HTTP router guarantees all named params are present when a route - * matches, but TypeScript cannot prove this statically. - */ -export function requireParam(params: Record, name: string): string { - const value = params[name]; - if (value === undefined) throw Object.assign(new Error(`Missing route parameter: ${name}`), { statusCode: 400 }); - return value; -} - -export type RequestHandler = ( - req: IncomingMessage, - res: ServerResponse, - params: Record, - token: TokenPayload, - body: unknown, -) => void | Promise; - -export interface Route { - method: string; - pattern: RegExp; - paramNames: string[]; - handler: RequestHandler; -} - -export interface ApiServerEventCallbacks { - onDomainChanged: () => void; - onWakeAgent: (agentId: string, companyId: string, trigger: string) => string | null; - onTaskCreated: (taskId: string, companyId: string) => void; - onTaskStatusChanged: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; - onCommentPosted: (taskId: string, companyId: string, authorAgentId: string | null) => void; - onApprovalCreated: (approvalId: string, companyId: string, taskId: string | null, approvalType: string, summary: string) => void; - onApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - /** - * Persist a document through the shared `document-lifecycle` pipeline. - * Collapses the two previous entry points (this HTTP route and the - * desktop IPC handler) onto a single fan-out so thread, checkpoint, - * automation, and deliverable-review side effects land consistently - * regardless of which surface authored the write. - */ - createDocument: (input: DocumentLifecycleInput) => DocumentLifecycleOutcome; - onAutoAssignTask: (taskId: string, companyId: string) => string | null; - onHumanMessage: (companyId: string, toAgentId?: string | null, threadId?: string | null, waitStateId?: string | null) => void; - /** - * Tries to hand a freshly persisted message to the recipient's live - * pi run via the runtime steer channel. Returns true when the worker - * accepted the steer; dispatch should then skip the regular wake - * pipeline for this recipient. - */ - injectRuntimeMessage: (recipientAgentId: string, companyId: string, message: AgentMessageRecord) => boolean; - emitEvent: (event: DesktopEvent) => void; - notify: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string }; batchKey?: string }) => void; -} - -const REQUIRED_API_SERVER_CALLBACKS: readonly (keyof ApiServerEventCallbacks)[] = [ - "onDomainChanged", - "onWakeAgent", - "onTaskCreated", - "onTaskStatusChanged", - "onCommentPosted", - "onApprovalCreated", - "onApprovalResolved", - "createDocument", - "onAutoAssignTask", - "onHumanMessage", - "injectRuntimeMessage", - "emitEvent", - "notify", -]; - -function assertCompleteApiServerCallbacks( - callbacks: Partial | null | undefined, -): asserts callbacks is ApiServerEventCallbacks { - if (!callbacks) { - throw new Error("Missing AgentApiServer callbacks."); - } - for (const name of REQUIRED_API_SERVER_CALLBACKS) { - if (typeof callbacks[name] !== "function") { - throw new Error(`Missing AgentApiServer callback: ${name}`); - } - } -} - -/** - * Token-bucket rate limiter scoped per (companyId, agentId). - * - * An agent that exceeds the burst capacity (`maxTokens`) is rejected with 429 - * until enough wall-clock time has passed for the bucket to refill at - * `refillRatePerSec` tokens/second. The bucket is in-memory and resets on - * process restart — agents misbehaving across restarts are detected at the - * next bucket; this is a defence against runaway loops, not a quota system. - */ -class AgentRateLimiter { - private buckets = new Map(); - private readonly maxTokens: number; - private readonly refillRatePerSec: number; - - constructor(opts: { maxTokens: number; refillRatePerSec: number }) { - this.maxTokens = opts.maxTokens; - this.refillRatePerSec = opts.refillRatePerSec; - } - - /** Returns retry-after seconds when blocked, or `null` to allow. */ - consume(key: string): number | null { - const now = Date.now(); - const existing = this.buckets.get(key); - const bucket = existing ?? { tokens: this.maxTokens, lastRefillMs: now }; - if (existing) { - const elapsedSec = (now - existing.lastRefillMs) / 1000; - bucket.tokens = Math.min(this.maxTokens, existing.tokens + elapsedSec * this.refillRatePerSec); - bucket.lastRefillMs = now; - } - if (bucket.tokens < 1) { - this.buckets.set(key, bucket); - const tokensShort = 1 - bucket.tokens; - return Math.max(1, Math.ceil(tokensShort / this.refillRatePerSec)); - } - bucket.tokens -= 1; - this.buckets.set(key, bucket); - return null; - } -} - -export class AgentApiServer { - private _routes: Route[] = []; - private _server: ReturnType | null = null; - private _port = 0; - private _db: AppDatabase; - private _onDomainChangedCb: () => void; - private _onWakeAgentCb: (agentId: string, companyId: string, trigger: string) => string | null; - private _emitEventCb: (event: DesktopEvent) => void; - private _callbacks: ApiServerEventCallbacks; - private _allowedOrigins: Set; - private _onBrowserActionCb: ((actionId: string, companyId: string) => void) | null = null; - /** 60 req/min sustained, 30 req burst per (companyId, agentId). */ - private _rateLimiter = new AgentRateLimiter({ maxTokens: 30, refillRatePerSec: 1 }); - - constructor( - db: AppDatabase, - callbacks: ApiServerEventCallbacks, - allowedOrigins: Iterable = ["app://-"], - ) { - assertCompleteApiServerCallbacks(callbacks); - this._db = db; - this._onDomainChangedCb = callbacks.onDomainChanged; - this._onWakeAgentCb = callbacks.onWakeAgent; - this._emitEventCb = callbacks.emitEvent; - this._allowedOrigins = new Set(Array.from(allowedOrigins).filter(Boolean)); - this._callbacks = { ...callbacks }; - } - - setBrowserActionHandler(handler: (actionId: string, companyId: string) => void) { - this._onBrowserActionCb = handler; - } - - async start(): Promise { - return new Promise((resolve, reject) => { - this._server = createServer((req, res) => void this.handleRequest(req, res)); - this._server.listen(0, "127.0.0.1", () => { - const srv = this._server; - const addr = srv ? srv.address() : null; - this._port = typeof addr === "object" && addr ? addr.port : 0; - log.info(`[api] Agent API server listening on http://127.0.0.1:${this._port}`); - resolve(this._port); - }); - this._server.on("error", reject); - }); - } - - stop() { - this._server?.close(); - this._server = null; - } - - addRoute(method: string, path: string, handler: RequestHandler) { - const paramNames: string[] = []; - const patternStr = path.replace(/:(\w+)/g, (_match, name: string) => { - paramNames.push(name); - return "([^/]+)"; - }); - this._routes.push({ method, pattern: new RegExp(`^${patternStr}$`), paramNames, handler }); - } - - private authenticateRequest( - req: IncomingMessage, - ): - | { ok: true; token: TokenPayload } - | { ok: false; status: number; error: string } { - const authHeader = req.headers.authorization; - if (typeof authHeader !== "string" || !authHeader.startsWith("Bearer ")) { - return { ok: false, status: 401, error: "Missing or invalid Authorization header" }; - } - const runHeader = req.headers["x-agent-company-run-id"]; - const claimedRunId = firstHeaderValue(runHeader); - const token = validateAgentToken(authHeader.slice(7), { - runId: claimedRunId, - companyId: extractCompanyIdFromUrl(req.url), - requestId: firstHeaderValue(req.headers["x-request-id"]), - }); - if (!token) { - return { ok: false, status: 401, error: "Invalid or expired token" }; - } - if (typeof claimedRunId !== "string" || claimedRunId.trim() !== token.runId) { - return { ok: false, status: 401, error: "Missing or mismatched X-Agent-Company-Run-Id header" }; - } - const runState = this._db.core.runs.getRunAuthState(token.runId); - if (!runState || runState.companyId !== token.companyId || runState.agentId !== token.agentId) { - return { ok: false, status: 403, error: "Token references an unknown or mismatched run" }; - } - if (!["queued", "running"].includes(runState.status)) { - return { ok: false, status: 401, error: "Run token is no longer active" }; - } - return { ok: true, token }; - } - - private async handleRequest(req: IncomingMessage, res: ServerResponse) { - const origin = req.headers.origin; - const authHeader = req.headers.authorization; - const hasBearer = typeof authHeader === "string" && authHeader.startsWith("Bearer "); - const isPreflight = req.method === "OPTIONS"; - - // Origin policy: - // - Bearer-token requests (agent CLIs, non-browser) are allowed without an Origin header. - // If an Origin IS present, it must be in the allowlist. - // - All other requests (browser-originating, including CORS preflight) MUST carry an - // Origin header and it MUST be in the allowlist. - if (origin) { - if (!this._allowedOrigins.has(origin)) { - this.json(res, 403, { error: "Origin not allowed" }); - return; - } - res.setHeader("Access-Control-Allow-Origin", origin); - res.setHeader("Vary", "Origin"); - } else if (!hasBearer || isPreflight) { - this.json(res, 403, { error: "Origin header required" }); - return; - } - res.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Agent-Company-Run-Id"); - - if (isPreflight) { - res.writeHead(204); - res.end(); - return; - } - - const url = new URL(req.url ?? "/", `http://127.0.0.1:${this._port}`); - const pathname = url.pathname; - const method = (req.method ?? "GET").toUpperCase(); - - const auth = this.authenticateRequest(req); - if (!auth.ok) { - this.json(res, auth.status, { error: auth.error }); - return; - } - const token = auth.token; - - const retryAfter = this._rateLimiter.consume(`${token.companyId}:${token.agentId}`); - if (retryAfter !== null) { - res.setHeader("Retry-After", String(retryAfter)); - this.json(res, 429, { error: "Rate limit exceeded", retryAfterSeconds: retryAfter }); - return; - } - - for (const route of this._routes) { - if (route.method !== method) continue; - const match = pathname.match(route.pattern); - if (!match) continue; - - const params: Record = {}; - route.paramNames.forEach((name: string, i: number) => { - params[name] = match[i + 1] ?? ""; - }); - - let body: unknown = null; - if (["POST", "PATCH", "PUT"].includes(method)) { - const contentTypeError = getJsonContentTypeError(req); - if (contentTypeError) { - this.json(res, 415, { error: contentTypeError }); - return; - } - try { - body = await this.readBody(req); - } catch (bodyErr) { - if (bodyErr instanceof Error && bodyErr.message === "Request body too large") { - this.json(res, 413, { error: "Request body too large (max 1 MB)" }); - } else { - this.json(res, 400, { error: "Invalid JSON body" }); - } - return; - } - } - - try { - await route.handler(req, res, params, token, body); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - log.error(`[api] ${method} ${pathname}: ${message}`); - this.json(res, 500, { error: "Internal server error" }); - } - return; - } - - this.json(res, 404, { error: "Not found" }); - } - - private readBody(req: IncomingMessage): Promise { - const MAX_BODY_BYTES = 1_048_576; // 1 MB - return new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - let bytes = 0; - req.on("data", (chunk: Buffer) => { - bytes += chunk.length; - if (bytes > MAX_BODY_BYTES) { - req.destroy(); - reject(new Error("Request body too large")); - return; - } - chunks.push(chunk); - }); - req.on("end", () => { - try { - const raw = Buffer.concat(chunks); - const data = decodeBodyToUtf8(raw); - resolve(data ? JSON.parse(data) : null); - } - catch { reject(new Error("Invalid JSON")); } - }); - req.on("error", reject); - }); - } - - json(res: ServerResponse, status: number, data: unknown) { - res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" }); - res.end(JSON.stringify(data)); - } - - companyRefError( - res: ServerResponse, - companyId: string, - refs: Array<{ id: string | null | undefined; table: "agents" | "goals" | "projects" | "tasks" | "workspaces" | "approvals"; label: string }>, - ) { - const invalid = refs.find((ref) => ref.id && !this._db.core.settings.belongsToCompany(ref.table, ref.id, companyId)); - if (!invalid) return false; - this.json(res, 422, { error: `${invalid.label} does not belong to the current company` }); - return true; - } - - // Accessors for route registrars - get db(): AppDatabase { return this._db; } - get callbacks(): ApiServerEventCallbacks { return this._callbacks; } - get onDomainChanged(): () => void { return this._onDomainChangedCb; } - get onWakeAgent(): (agentId: string, companyId: string, trigger: string) => string | null { return this._onWakeAgentCb; } - get emitEvent(): (event: DesktopEvent) => void { return this._emitEventCb; } - get onBrowserAction(): ((actionId: string, companyId: string) => void) | null { return this._onBrowserActionCb; } - get port(): number { return this._port; } -} diff --git a/src/main/app-lifecycle-service.ts b/src/main/app-lifecycle-service.ts deleted file mode 100644 index 08b9f0a2..00000000 --- a/src/main/app-lifecycle-service.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { app } from "electron"; - -interface AppLifecycleDependencies { - getMainWindow: () => Electron.BrowserWindow | null; - ensureWindow: () => Promise; - shouldQuit: () => boolean; - /** - * Invoked on the Electron `before-quit` event. The lifecycle service will - * call `event.preventDefault()` on the first invocation so the owner of - * this hook can perform an awaited drain and then invoke `app.exit()` - * explicitly when the drain resolves. Subsequent `before-quit` events are - * ignored because the drain is already in flight. - */ - onBeforeQuit: () => void; -} - -export function createAppLifecycleService({ - getMainWindow, - ensureWindow, - shouldQuit, - onBeforeQuit, -}: AppLifecycleDependencies) { - function register(hasSingleInstanceLock: boolean) { - app.on("activate", async () => { - const mainWindow = getMainWindow(); - if (mainWindow && !mainWindow.isDestroyed()) { - if (!mainWindow.isVisible()) { - mainWindow.show(); - } - mainWindow.focus(); - return; - } - await ensureWindow(); - }); - - app.on("second-instance", () => { - if (!hasSingleInstanceLock) { - return; - } - const mainWindow = getMainWindow(); - if (!mainWindow) { - return; - } - if (!mainWindow.isVisible()) { - mainWindow.show(); - } - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - mainWindow.focus(); - }); - - app.on("window-all-closed", () => { - // macOS keeps the app alive when all windows close (standard platform behavior), - // except after the user picked Quit (before-quit already fired -> shouldQuit()). - if (process.platform === "darwin" && !shouldQuit()) { - return; - } - app.quit(); - }); - - let drainStarted = false; - app.on("before-quit", (event) => { - if (drainStarted) return; - drainStarted = true; - // Block Electron's default quit until the owner's drain resolves. The - // owner must call app.exit() itself when drain is complete. - event.preventDefault(); - onBeforeQuit(); - }); - } - - return { - register, - }; -} diff --git a/AgentCompany-New/src/main/app/coalesce.ts b/src/main/app/coalesce.ts similarity index 100% rename from AgentCompany-New/src/main/app/coalesce.ts rename to src/main/app/coalesce.ts diff --git a/AgentCompany-New/src/main/app/create-window.ts b/src/main/app/create-window.ts similarity index 100% rename from AgentCompany-New/src/main/app/create-window.ts rename to src/main/app/create-window.ts diff --git a/AgentCompany-New/src/main/app/external-url.ts b/src/main/app/external-url.ts similarity index 100% rename from AgentCompany-New/src/main/app/external-url.ts rename to src/main/app/external-url.ts diff --git a/AgentCompany-New/src/main/app/ipc-handlers.ts b/src/main/app/ipc-handlers.ts similarity index 100% rename from AgentCompany-New/src/main/app/ipc-handlers.ts rename to src/main/app/ipc-handlers.ts diff --git a/AgentCompany-New/src/main/app/provider-background-worker.ts b/src/main/app/provider-background-worker.ts similarity index 100% rename from AgentCompany-New/src/main/app/provider-background-worker.ts rename to src/main/app/provider-background-worker.ts diff --git a/AgentCompany-New/src/main/app/startup-recovery.ts b/src/main/app/startup-recovery.ts similarity index 100% rename from AgentCompany-New/src/main/app/startup-recovery.ts rename to src/main/app/startup-recovery.ts diff --git a/AgentCompany-New/src/main/app/task-queue-worker.ts b/src/main/app/task-queue-worker.ts similarity index 100% rename from AgentCompany-New/src/main/app/task-queue-worker.ts rename to src/main/app/task-queue-worker.ts diff --git a/AgentCompany-New/src/main/app/window-security.ts b/src/main/app/window-security.ts similarity index 100% rename from AgentCompany-New/src/main/app/window-security.ts rename to src/main/app/window-security.ts diff --git a/src/main/approval-policy-definitions.ts b/src/main/approval-policy-definitions.ts deleted file mode 100644 index d264c89b..00000000 --- a/src/main/approval-policy-definitions.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { approvalTypeEnum, type ApprovalType, type ExecutionMode } from "@shared/types"; - -export type ApprovalPolicyScope = "requester_or_task" | "related_agent"; -export type ApprovalPolicyRequiredMode = "any" | ExecutionMode; - -export interface ApprovalPolicyDefinition { - approvalType: ApprovalType; - scopeType: ApprovalPolicyScope; - blocksExecution: boolean; - requiredMode: ApprovalPolicyRequiredMode; - autoApprovable: boolean; -} - -const DEFAULT_POLICY: Omit = { - scopeType: "requester_or_task", - blocksExecution: false, - requiredMode: "any", - autoApprovable: false, -}; - -const POLICY_OVERRIDES: Record>> = { - hire_agent: { - scopeType: "related_agent", - blocksExecution: true, - autoApprovable: true, - }, - approve_ceo_strategy: { - blocksExecution: true, - requiredMode: "ai_cofounder", - autoApprovable: true, - }, - dangerous_command: { - blocksExecution: true, - }, - secret_access: { - blocksExecution: true, - }, - budget_request: {}, - promotion: {}, - termination: {}, - vendor_approval: {}, - document_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - production_deploy: { - blocksExecution: true, - }, - incident_escalation: {}, - social_post: { - blocksExecution: true, - }, - deliverable_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - budget_override: { - blocksExecution: true, - }, - plan_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - scope_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - draft_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - strategy_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, - exception_review: { - blocksExecution: true, - requiredMode: "ai_cofounder", - }, -}; - -export const APPROVAL_POLICY_SEED: readonly ApprovalPolicyDefinition[] = approvalTypeEnum.options.map((approvalType) => ({ - approvalType, - ...DEFAULT_POLICY, - ...POLICY_OVERRIDES[approvalType], -})); - -export const COFOUNDER_MANDATORY_APPROVAL_TYPES: readonly ApprovalType[] = APPROVAL_POLICY_SEED - .filter((policy) => policy.blocksExecution && policy.requiredMode === "ai_cofounder") - .map((policy) => policy.approvalType); - -export const OPERATIONAL_APPROVAL_TYPES: readonly ApprovalType[] = APPROVAL_POLICY_SEED - .filter((policy) => - policy.blocksExecution && - policy.requiredMode === "any" && - policy.scopeType === "requester_or_task") - .map((policy) => policy.approvalType); diff --git a/src/main/approval-policy.ts b/src/main/approval-policy.ts deleted file mode 100644 index 06b0edd5..00000000 --- a/src/main/approval-policy.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { AppDatabase } from "./database"; - -export function resolveApprovalDecision({ - db, - handleApprovalResolved, - companyId, - approvalId, - state, - decisionNote, - detail, - actor = "board", -}: { - db: AppDatabase; - handleApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - companyId: string; - approvalId: string; - state: "approved" | "rejected" | "revision_requested"; - decisionNote?: string; - detail?: string | null; - actor?: string; -}) { - const note = decisionNote ?? ""; - db.core.approvals.decideApproval({ - companyId, - approvalId, - state, - decisionNote: note, - }); - db.core.activity.addActivity({ - companyId, - actor, - action: `approval.${state}`, - entityType: "approval", - entityId: approvalId, - detail: detail ?? note, - }); - handleApprovalResolved(approvalId, companyId, state); -} diff --git a/src/main/automation-service.ts b/src/main/automation-service.ts deleted file mode 100644 index 80cdd9bd..00000000 --- a/src/main/automation-service.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { createAutomationService } from "./automation/index"; -export type { AutomationEventContext } from "./automation/index"; diff --git a/src/main/automation/automation-action-handlers.ts b/src/main/automation/automation-action-handlers.ts deleted file mode 100644 index df7dece6..00000000 --- a/src/main/automation/automation-action-handlers.ts +++ /dev/null @@ -1,401 +0,0 @@ -import type { AutomationAction } from "@shared/types"; -import { dispatchAgentMessage } from "../messaging/dispatch"; -import { validateTaskCreation } from "../task-quality-gates"; -import { resolveTaskWorkspaceBinding } from "../task-workspace-binding"; -import { - createAutomationActionHandler, - type AutomationActionHandler, - type TypedAutomationActionExecution, -} from "./automation-action-runtime"; - -const HEARTBEAT_WAKE_TRIGGER_MAP: Record = { - run_completed: "subtask_completed", - run_failed: "report_failed", - hire_approved: "assignment", - agent_idle: "timer", -}; - -const ESCALATION_STATUS_TRIGGER_MAP: Record = { - in_review: "subtask_completed", - blocked: "report_blocked", -}; - -const ESCALATION_RULE_TRIGGER_MAP: Record = { - run_completed: "subtask_completed", - run_failed: "report_failed", -}; - -const TASK_PRIORITY_SCORE: Record = { critical: 4, high: 3, medium: 2, low: 1 }; - -export const AUTOMATION_ACTION_HANDLERS = { - assign_task: createAutomationActionHandler("assign_task", handleAssignTask), - create_task: createAutomationActionHandler("create_task", handleCreateTask), - notify_agent: createAutomationActionHandler("notify_agent", handleAgentNotification), - send_message: createAutomationActionHandler("send_message", handleAgentNotification), - trigger_heartbeat: createAutomationActionHandler("trigger_heartbeat", handleTriggerHeartbeat), - create_approval: createAutomationActionHandler("create_approval", handleCreateApproval), - update_task_status: createAutomationActionHandler("update_task_status", handleUpdateTaskStatus), - escalate_to_manager: createAutomationActionHandler("escalate_to_manager", handleEscalateToManager), - cross_department_notify: createAutomationActionHandler("cross_department_notify", handleCrossDepartmentNotify), - schedule_meeting: createAutomationActionHandler("schedule_meeting", handleScheduleMeeting), - create_document: createAutomationActionHandler("create_document", handleCreateDocument), - auto_approve: createAutomationActionHandler("auto_approve", handleAutoApprove), - reassign_task: createAutomationActionHandler("reassign_task", handleReassignTask), - run_task: createAutomationActionHandler("run_task", handleRunTask), -} satisfies Record; - -function deriveHeartbeatWakeTrigger(triggerType: string, previousStatus: string | null): string { - if (triggerType === "task_status_changed" && previousStatus === "in_review") return "comment"; - return HEARTBEAT_WAKE_TRIGGER_MAP[triggerType] ?? "manual"; -} - -function deriveEscalationWakeTrigger(newStatus: string | null, ruleTrigger: string | null): string { - if (newStatus && ESCALATION_STATUS_TRIGGER_MAP[newStatus]) return ESCALATION_STATUS_TRIGGER_MAP[newStatus]; - if (ruleTrigger && ESCALATION_RULE_TRIGGER_MAP[ruleTrigger]) return ESCALATION_RULE_TRIGGER_MAP[ruleTrigger]; - return "report_blocked"; -} - -function handleAssignTask({ deps, ctx }: TypedAutomationActionExecution<"assign_task">): void { - const { db, logger, wakeAgentIfPossible } = deps; - - if (ctx.taskId) { - const assignedId = db.core.tasks.autoAssignTask(ctx.taskId, ctx.companyId); - if (assignedId) { - wakeAgentIfPossible(assignedId, ctx.companyId, "assignment"); - } - return; - } - - if (!ctx.agentId) return; - - const snapshot = db.projection.snapshot.listSnapshot(); - const unassigned = snapshot.tasks - .filter((task) => task.companyId === ctx.companyId && !task.assigneeAgentId && ["backlog", "todo"].includes(task.status)) - .sort((a, b) => (TASK_PRIORITY_SCORE[b.priority] ?? 0) - (TASK_PRIORITY_SCORE[a.priority] ?? 0)); - if (unassigned.length === 0) return; - - const task = unassigned[0]!; - db.core.tasks.saveTask({ - id: task.id, - companyId: task.companyId, - projectId: task.projectId, - goalId: task.goalId, - parentId: task.parentId, - title: task.title, - description: task.description, - assigneeAgentId: ctx.agentId, - workspaceId: task.workspaceId, - requiresFilesystem: task.requiresFilesystem, - priority: task.priority, - status: "todo", - }); - wakeAgentIfPossible(ctx.agentId, ctx.companyId, "assignment"); - logger.info(`[automation] Auto-assigned task "${task.title}" to idle agent ${ctx.agentId}`); -} - -function handleCreateTask({ deps, callbacks, ctx, config }: TypedAutomationActionExecution<"create_task">): void { - const { db, logger } = deps; - const { handleTaskCreated } = callbacks; - const title = config.title ?? "[Auto] Task from automation rule"; - const description = config.description ?? ""; - const priority = config.priority ?? "medium"; - const assigneeAgentId = config.assigneeAgentId ?? null; - const taskValidation = validateTaskCreation({ title, description }); - - if (!taskValidation.valid) { - logger.warn(`[automation] Skipping create_task - validation failed: ${taskValidation.errors.join("; ")}`); - return; - } - - const workspaceBinding = resolveTaskWorkspaceBinding(db, { - companyId: ctx.companyId, - requiresFilesystem: config.requiresFilesystem, - explicitWorkspaceId: config.workspaceId ?? null, - projectId: ctx.projectId ?? config.projectId ?? null, - assigneeAgentId, - creatorAgentId: ctx.agentId ?? null, - }); - if (!workspaceBinding.ok) { - logger.warn(`[automation] Skipping create_task - ${workspaceBinding.error}`); - return; - } - - const taskId = db.core.tasks.saveTask({ - companyId: ctx.companyId, - projectId: ctx.projectId ?? config.projectId ?? null, - title, - description, - assigneeAgentId, - workspaceId: workspaceBinding.workspaceId, - priority, - status: assigneeAgentId ? "todo" : "backlog", - requiresFilesystem: config.requiresFilesystem, - }); - handleTaskCreated(taskId, ctx.companyId); - logger.info(`[automation] Created task: ${title} (${taskId})`); -} - -function handleAgentNotification({ - deps, - rule, - ctx, - config, -}: TypedAutomationActionExecution): void { - const { db, logger, emitEvent, publishDomainChanged, wakeAgentIfPossible } = deps; - const toAgentId = config.toAgentId ?? ctx.agentId ?? null; - const fromAgentId = config.fromAgentId ?? ctx.agentId ?? toAgentId; - if (!fromAgentId) return; - - const defaultChannel = toAgentId ? "direct" : "company"; - const requestedChannel = config.channel ?? defaultChannel; - const channel = (["direct", "department", "company", "project", "incident"] as const).includes(requestedChannel) - ? requestedChannel - : defaultChannel; - let channelTargetId: string | null = config.channelTargetId ?? config.department ?? ctx.department ?? null; - - if (channel === "department" && !channelTargetId) { - try { - const sender = db.core.entity.getAgent(fromAgentId); - channelTargetId = sender.department ?? null; - } catch (err) { - logger.warn(`[automation] getAgent failed for sender ${fromAgentId}; dropping department target:`, err instanceof Error ? err.message : String(err)); - channelTargetId = null; - } - } - - const channelNeedsTarget = channel === "department" || channel === "project"; - if (channelNeedsTarget && !channelTargetId) { - logger.info( - `[automation] Skipping rule "${rule.name}" - no ${channel} channel target available for sender ${fromAgentId}`, - ); - return; - } - if (channel === "direct" && toAgentId === fromAgentId) { - logger.info( - `[automation] Skipping rule "${rule.name}" - direct messages require two distinct participants`, - ); - return; - } - - const dispatchResult = dispatchAgentMessage( - { db, emitEvent, publishDomainChanged, wakeAgentIfPossible }, - { - companyId: ctx.companyId, - fromAgentId, - toAgentId: channel === "direct" ? toAgentId : null, - channel, - channelTargetId, - subject: config.subject ?? "Automation notification", - body: config.body ?? `Automation rule triggered for task ${ctx.taskId ?? "n/a"}`, - priority: config.priority ?? "normal", - }, - "message", - ); - if (!dispatchResult.ok) { - logger.warn( - `[automation] Failed to dispatch message for rule ${rule.name} (${rule.id}): ${dispatchResult.error.code} ${dispatchResult.error.message}`, - ); - } -} - -function handleTriggerHeartbeat({ deps, rule, ctx, config }: TypedAutomationActionExecution<"trigger_heartbeat">): void { - const { db, wakeAgentIfPossible } = deps; - let targetAgentId = config.agentId ?? null; - - if (!targetAgentId && ctx.agentId) { - const triggerType = rule.trigger ?? ""; - if (triggerType === "run_completed" || triggerType === "run_failed") { - const manager = db.core.agents.getManagerForAgent(ctx.agentId); - targetAgentId = manager?.id ?? ctx.agentId; - } else { - targetAgentId = ctx.agentId; - } - } - - if (targetAgentId) { - wakeAgentIfPossible(targetAgentId, ctx.companyId, deriveHeartbeatWakeTrigger(rule.trigger ?? "", ctx.previousStatus ?? null)); - } -} - -function handleCreateApproval({ deps, ctx, config }: TypedAutomationActionExecution<"create_approval">): void { - deps.db.core.approvals.requestApproval({ - companyId: ctx.companyId, - relatedTaskId: ctx.taskId ?? null, - requestedByAgentId: ctx.agentId ?? null, - type: config.approvalType ?? "document_review", - payloadSummary: config.summary ?? "Auto-generated approval request", - impactSummary: config.impact ?? "Triggered by automation rule", - }); -} - -function handleUpdateTaskStatus({ - deps, - callbacks, - rule, - ctx, - config, -}: TypedAutomationActionExecution<"update_task_status">): void { - if (!ctx.taskId) return; - - const { db, publishDomainChanged } = deps; - const { handleTaskStatusChange } = callbacks; - const newStatus = config.status ?? "todo"; - const previousTask = db.core.entity.getTask(ctx.taskId); - db.core.tasks.advanceTaskStatus(ctx.taskId, newStatus, "Status changed by automation rule"); - publishDomainChanged(); - - if (previousTask.status !== newStatus && rule.trigger !== "task_status_changed") { - handleTaskStatusChange(ctx.taskId, ctx.companyId, previousTask.status, newStatus); - } -} - -function handleEscalateToManager({ - deps, - rule, - ctx, - config, -}: TypedAutomationActionExecution<"escalate_to_manager">): void { - const { db, logger, emitEvent, publishDomainChanged, wakeAgentIfPossible } = deps; - const targetAgentId = ctx.agentId; - if (!targetAgentId) return; - - let agentName = "an agent"; - try { - agentName = db.core.entity.getAgent(targetAgentId).name; - } catch (err) { - logger.warn(`[automation] getAgent failed for escalation target ${targetAgentId}; using generic label:`, err instanceof Error ? err.message : String(err)); - } - - let taskTitle = ctx.taskId ?? "unknown"; - try { - if (ctx.taskId) taskTitle = db.core.entity.getTask(ctx.taskId).title; - } catch (err) { - logger.warn(`[automation] getTask failed for escalation task ${ctx.taskId}; using id as title:`, err instanceof Error ? err.message : String(err)); - } - - const manager = db.core.agents.getManagerForAgent(targetAgentId); - const escalationBody = config.body ?? `Task "${taskTitle}" needs your attention. ${agentName} has flagged this as requiring manager intervention.`; - const wakeTrigger = deriveEscalationWakeTrigger(ctx.newStatus ?? null, rule.trigger ?? null); - - if (manager) { - const escalationResult = dispatchAgentMessage( - { db, emitEvent, publishDomainChanged, wakeAgentIfPossible }, - { - companyId: ctx.companyId, - fromAgentId: targetAgentId, - toAgentId: manager.id, - channel: "direct", - subject: `Escalation from ${agentName}: ${taskTitle}`, - body: escalationBody, - priority: "urgent", - }, - wakeTrigger, - ); - if (!escalationResult.ok) { - logger.warn( - `[automation] Failed to escalate "${taskTitle}" to manager: ${escalationResult.error.code} ${escalationResult.error.message}`, - ); - } - return; - } - - logger.info(`[automation] Skipping escalation for top-level agent "${agentName}" - no manager to escalate to.`); -} - -function handleCrossDepartmentNotify({ - deps, - rule, - ctx, - config, -}: TypedAutomationActionExecution<"cross_department_notify">): void { - const { db, logger, emitEvent, publishDomainChanged, wakeAgentIfPossible } = deps; - const targetDepartment = rule.targetDepartment ?? config.department; - if (!targetDepartment) return; - - const departmentAgents = db.core.agents.getIdleAgentsForDepartment(ctx.companyId, targetDepartment); - const senderAgentId = ctx.agentId ?? departmentAgents[0]?.id; - if (!senderAgentId) return; - - const dispatchResult = dispatchAgentMessage( - { db, emitEvent, publishDomainChanged, wakeAgentIfPossible }, - { - companyId: ctx.companyId, - fromAgentId: senderAgentId, - toAgentId: null, - channel: "department", - channelTargetId: targetDepartment, - subject: config.subject ?? "Cross-department notification", - body: config.body ?? "Automation triggered a cross-department alert.", - priority: "normal", - }, - "message", - ); - if (!dispatchResult.ok) { - logger.warn( - `[automation] Failed cross-department notification for ${targetDepartment}: ${dispatchResult.error.code} ${dispatchResult.error.message}`, - ); - } -} - -function handleScheduleMeeting({ deps, ctx, config }: TypedAutomationActionExecution<"schedule_meeting">): void { - const meetingType = config.meetingType ?? "department_sync"; - const title = config.title ?? "Auto-scheduled meeting"; - const offsetMinutes = config.scheduleOffsetMinutes ?? 60; - const scheduledAt = config.scheduledAt ?? new Date(Date.now() + offsetMinutes * 60_000).toISOString(); - - deps.db.core.knowledge.saveMeeting({ - companyId: ctx.companyId, - type: meetingType, - title, - organizerAgentId: ctx.agentId ?? null, - participantAgentIds: config.participantAgentIds ?? "[]", - scheduledAt, - durationMinutes: config.durationMinutes ?? 30, - }); -} - -function handleCreateDocument({ deps, ctx, config }: TypedAutomationActionExecution<"create_document">): void { - deps.db.core.documents.saveDocument({ - companyId: ctx.companyId, - type: config.documentType ?? "status_report", - title: config.title ?? "Auto-generated document", - content: config.content ?? "", - authorAgentId: ctx.agentId ?? null, - projectId: ctx.projectId ?? null, - }); -} - -function handleAutoApprove({ deps, callbacks, ctx }: TypedAutomationActionExecution<"auto_approve">): void { - const snapshot = deps.db.projection.snapshot.listSnapshot(); - const pendingApprovals = snapshot.approvals.filter( - (approval) => approval.companyId === ctx.companyId && approval.state === "pending", - ); - - for (const approval of pendingApprovals.slice(0, 5)) { - deps.db.core.approvals.decideApproval({ - companyId: ctx.companyId, - approvalId: approval.id, - state: "approved", - decisionNote: "Auto-approved by automation rule.", - }); - callbacks.handleApprovalResolved(approval.id, ctx.companyId, "approved"); - } -} - -function handleReassignTask({ deps, ctx }: TypedAutomationActionExecution<"reassign_task">): void { - if (!ctx.taskId) return; - - const newAssignee = deps.db.core.tasks.autoAssignTask(ctx.taskId, ctx.companyId); - if (newAssignee) { - deps.wakeAgentIfPossible(newAssignee, ctx.companyId, "assignment"); - } -} - -function handleRunTask({ deps, ctx, config }: TypedAutomationActionExecution<"run_task">): void { - const targetTaskId = config.taskId ?? ctx.taskId; - if (!targetTaskId) return; - - const task = deps.db.core.entity.getTask(targetTaskId); - if (!task.assigneeAgentId) return; - deps.wakeAgentIfPossible(task.assigneeAgentId, ctx.companyId, "assignment"); -} diff --git a/src/main/automation/automation-action-runtime.ts b/src/main/automation/automation-action-runtime.ts deleted file mode 100644 index d3f02788..00000000 --- a/src/main/automation/automation-action-runtime.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { AutomationAction, DesktopEvent } from "@shared/types"; -import type { AutomationEventContext } from "./types"; -import type { AutomationActionConfigMap } from "./automation-action-schemas"; - -export interface ActionDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; -} - -export interface ActionCallbacks { - handleTaskCreated: (taskId: string, companyId: string) => void; - handleApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; -} - -export interface AutomationRuleInput { - id?: string; - name?: string; - action: string; - actionConfigJson: string; - targetDepartment: string | null; - trigger?: string; -} - -export interface AutomationRuleExecution extends Omit { - action: AutomationAction; -} - -export type AutomationActionExecution = { - deps: ActionDeps; - callbacks: ActionCallbacks; - rule: AutomationRuleExecution; - ctx: AutomationEventContext; - config: AutomationActionConfigMap[AutomationAction]; -}; - -export type TypedAutomationActionExecution = Omit & { - config: AutomationActionConfigMap[K]; -}; - -export type TypedAutomationActionHandler = (input: TypedAutomationActionExecution) => void; -export type AutomationActionHandler = (input: AutomationActionExecution) => void; - -export function createAutomationActionHandler( - action: K, - handler: TypedAutomationActionHandler, -): AutomationActionHandler { - return (input) => { - if (input.rule.action !== action) { - throw new Error(`Automation handler ${action} received ${input.rule.action}.`); - } - handler(input as TypedAutomationActionExecution); - }; -} diff --git a/src/main/automation/automation-action-schemas.ts b/src/main/automation/automation-action-schemas.ts deleted file mode 100644 index 724ff8dc..00000000 --- a/src/main/automation/automation-action-schemas.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Per-action config schemas for automation rules. - * - * Previously `automation-actions.ts` coerced `config.x as string` at every - * branch without runtime validation, which hid config-authoring mistakes - * behind silent default values (e.g. a numeric `priority` landed as the - * literal string "medium"). Each schema describes the contract of the JSON - * stored in `automation_rules.action_config_json`; validation failures are - * surfaced to the caller so the rule is skipped and logged. - */ - -import { z } from "zod"; -import { approvalTypeEnum, type AutomationAction } from "@shared/types"; - -const messageChannelSchema = z.enum(["direct", "department", "company", "project", "incident"]); -const messagePrioritySchema = z.enum(["urgent", "normal", "low"]); -const taskPrioritySchema = z.enum(["critical", "high", "medium", "low"]); - -export const assignTaskConfigSchema = z.object({}).passthrough(); - -export const createTaskConfigSchema = z.object({ - title: z.string().optional(), - description: z.string().optional(), - priority: taskPrioritySchema.optional(), - assigneeAgentId: z.string().nullable().optional(), - projectId: z.string().optional(), - workspaceId: z.string().nullable().optional(), - requiresFilesystem: z.boolean().default(false), -}); - -export const notifyAgentConfigSchema = z.object({ - toAgentId: z.string().optional(), - fromAgentId: z.string().optional(), - channel: messageChannelSchema.optional(), - channelTargetId: z.string().nullable().optional(), - department: z.string().optional(), - subject: z.string().optional(), - body: z.string().optional(), - priority: messagePrioritySchema.optional(), -}); - -export const triggerHeartbeatConfigSchema = z.object({ - agentId: z.string().optional(), -}); - -export const createApprovalConfigSchema = z.object({ - approvalType: approvalTypeEnum.optional(), - summary: z.string().optional(), - impact: z.string().optional(), -}); - -export const updateTaskStatusConfigSchema = z.object({ - status: z.string().optional(), -}); - -export const escalateToManagerConfigSchema = z.object({ - body: z.string().optional(), -}); - -export const crossDepartmentNotifyConfigSchema = z.object({ - department: z.string().optional(), - subject: z.string().optional(), - body: z.string().optional(), -}); - -export const scheduleMeetingConfigSchema = z.object({ - meetingType: z.string().optional(), - title: z.string().optional(), - participantAgentIds: z.string().optional(), - durationMinutes: z.number().int().positive().optional(), - // Absolute ISO-8601 scheduling is preferred; otherwise callers can specify - // an offset in minutes from now (replaces the previous hard-coded 60min). - scheduledAt: z.string().optional(), - scheduleOffsetMinutes: z.number().int().positive().optional(), -}); - -export const createDocumentConfigSchema = z.object({ - documentType: z.string().optional(), - title: z.string().optional(), - content: z.string().optional(), -}); - -export const autoApproveConfigSchema = z.object({}).passthrough(); - -export const reassignTaskConfigSchema = z.object({}).passthrough(); - -export const runTaskConfigSchema = z.object({ - taskId: z.string().optional(), -}); - -export const ACTION_SCHEMAS = { - assign_task: assignTaskConfigSchema, - create_task: createTaskConfigSchema, - notify_agent: notifyAgentConfigSchema, - send_message: notifyAgentConfigSchema, - trigger_heartbeat: triggerHeartbeatConfigSchema, - create_approval: createApprovalConfigSchema, - update_task_status: updateTaskStatusConfigSchema, - escalate_to_manager: escalateToManagerConfigSchema, - cross_department_notify: crossDepartmentNotifyConfigSchema, - schedule_meeting: scheduleMeetingConfigSchema, - create_document: createDocumentConfigSchema, - auto_approve: autoApproveConfigSchema, - reassign_task: reassignTaskConfigSchema, - run_task: runTaskConfigSchema, -} as const satisfies Record; - -export const AUTOMATION_ACTIONS = Object.freeze(Object.keys(ACTION_SCHEMAS)) as readonly AutomationAction[]; -export const WORKFLOW_ACTIONS: ReadonlySet = new Set(AUTOMATION_ACTIONS); - -export function isAutomationAction(action: string): action is AutomationAction { - return WORKFLOW_ACTIONS.has(action as AutomationAction); -} - -export type AutomationActionConfigMap = { - [K in keyof typeof ACTION_SCHEMAS]: z.infer; -}; - -/** - * Parse action config JSON against its per-action schema. - * Returns the validated config or throws with the action name so the caller - * can log/skip the rule instead of silently advancing with defaults. - */ -export function parseActionConfig( - action: K, - json: string, -): AutomationActionConfigMap[K] { - const raw = JSON.parse(json) as unknown; - const schema = ACTION_SCHEMAS[action] as z.ZodSchema; - return schema.parse(raw); -} diff --git a/src/main/automation/automation-actions.ts b/src/main/automation/automation-actions.ts deleted file mode 100644 index e1cbd265..00000000 --- a/src/main/automation/automation-actions.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { AutomationAction } from "@shared/types"; -import { AUTOMATION_ACTION_HANDLERS } from "./automation-action-handlers"; -import { isAutomationAction, parseActionConfig } from "./automation-action-schemas"; -import type { - ActionCallbacks, - ActionDeps, - AutomationRuleExecution, - AutomationRuleInput, -} from "./automation-action-runtime"; -import type { AutomationEventContext } from "./types"; - -export { AUTOMATION_ACTION_HANDLERS } from "./automation-action-handlers"; -export type { ActionCallbacks, ActionDeps } from "./automation-action-runtime"; - -export function executeAutomationAction( - deps: ActionDeps, - callbacks: ActionCallbacks, - rule: AutomationRuleInput, - ctx: AutomationEventContext, -): void { - const action = parseAutomationAction(rule.action); - const executionRule: AutomationRuleExecution = { ...rule, action }; - const config = parseActionConfig(action, rule.actionConfigJson); - AUTOMATION_ACTION_HANDLERS[action]({ deps, callbacks, rule: executionRule, ctx, config }); -} - -function parseAutomationAction(action: string): AutomationAction { - if (isAutomationAction(action)) return action; - throw new Error(`Unknown automation action: ${action}`); -} diff --git a/src/main/automation/automation-approval-handler.ts b/src/main/automation/automation-approval-handler.ts deleted file mode 100644 index b779ec69..00000000 --- a/src/main/automation/automation-approval-handler.ts +++ /dev/null @@ -1,375 +0,0 @@ -import { z } from "zod"; -import type { AppDatabase } from "../database"; -import type { NotificationOptions } from "../notification-service"; -import { extractApprovalDocumentIds } from "@shared/approval-documents"; -import { notifyHireApproved } from "../hire-hook"; -import { autoAssignSkillsForHire } from "../skills/auto-assign-on-hire"; -import type { AutomationEventContext } from "./types"; -import { normalizeWorkflowSteps } from "./automation-workflow"; - -const workflowApprovalPayloadSchema = z.object({ - workflowId: z.string().optional(), - stepId: z.string().optional(), - stepName: z.string().optional(), -}).passthrough(); - -function localizeNotification(locale: string | null | undefined, en: string, zh: string): string { - return locale === "zh" ? zh : en; -} - -function recordReviewFeedbackKnowledge( - db: AppDatabase, - approval: { - companyId: string; - relatedTaskId: string | null; - requestedByAgentId: string | null; - decisionNote: string | null; - }, - decision: string, -): void { - if (!approval.relatedTaskId) return; - if (decision === "approved") return; - - const task = db.core.entity.getTask(approval.relatedTaskId); - const feedback = approval.decisionNote?.trim() || "Board requested revisions before approval."; - const topic = `Review feedback: ${task.title}`; - const content = [ - `Decision: ${decision}`, - `Feedback: ${feedback}`, - "Use this review guidance to improve future deliverables for similar work.", - ].join("\n"); - - db.core.knowledge.saveKnowledgeEntry({ - companyId: approval.companyId, - category: "lesson_learned", - topic, - content, - authorAgentId: approval.requestedByAgentId ?? null, - importance: "high", - tagsJson: JSON.stringify(["review_feedback", decision]), - referencedEntityType: "task", - referencedEntityId: task.id, - }); -} - -export interface ApprovalHandlerDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - queueBrowserActionExecution: (actionId: string, companyId: string) => void; - isQuitting: () => boolean; -} - -export interface ApprovalHandlerCallbacks { - dispatchAutomation: (trigger: string, ctx: AutomationEventContext) => void; - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; - runWorkflowPipeline: (workflowId: string, companyId: string) => Promise; - trackTimer: (timer: ReturnType) => void; -} - -export function handleApprovalResolved( - deps: ApprovalHandlerDeps, - callbacks: ApprovalHandlerCallbacks, - approvalId: string, - companyId: string, - decision: string, -): void { - if (deps.isQuitting()) return; - const { db, logger, publishDomainChanged, notify, wakeAgentIfPossible, queueBrowserActionExecution } = deps; - const { dispatchAutomation, handleTaskStatusChange, runWorkflowPipeline, trackTimer } = callbacks; - const explicitlyWokenAgentIds = new Set(); - - function wakeAgent(agentId: string | null | undefined, trigger: string): void { - if (!agentId) return; - wakeAgentIfPossible(agentId, companyId, trigger); - explicitlyWokenAgentIds.add(agentId); - } - - const snapshot = db.projection.snapshot.listSnapshot(); - const approval = snapshot.approvals.find((entry) => entry.id === approvalId); - if (!approval) return; - - dispatchAutomation("approval_resolved", { - companyId, - agentId: approval.requestedByAgentId ?? undefined, - taskId: approval.relatedTaskId ?? undefined, - }); - - if (approval.type === "hire_agent" && decision === "approved" && approval.relatedAgentId) { - const agent = db.core.entity.getAgent(approval.relatedAgentId); - - if (agent.status === "idle") { - // Deterministic default skill kit. The CEO's operating prompt - // used to carry this responsibility ("ensure every direct report - // has skills"), turning O(reports) API calls into a per-wake - // tax. At hire approval time we know the agent's department and - // the company's seeded catalogue — assign the default bundle so - // the new hire's first run already has the right SKILL.md - // manifest. - const { assignedSkillIds } = autoAssignSkillsForHire(db, { - agentId: agent.id, - companyId, - department: agent.department, - }); - if (assignedSkillIds.length > 0) { - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "agent.skills_defaulted", - entityType: "agent", - entityId: agent.id, - detail: `${assignedSkillIds.length} default skill(s) assigned on hire.`, - }); - } - - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "agent.hired", - entityType: "agent", - entityId: agent.id, - detail: `${agent.name} hire approved and activated.`, - }); - - dispatchAutomation("hire_approved", { - companyId, - agentId: agent.id, - }); - wakeAgent(agent.id, "assignment"); - - const ceo = db.core.agents.getCeoForCompany(companyId); - if (ceo && ceo.id !== agent.id) { - wakeAgent(ceo.id, "assignment"); - } - - publishDomainChanged(); - const hireLocale = db.projection.snapshot.listSnapshot().locale; - notify({ - title: localizeNotification(hireLocale, "Agent Hired", "新员工入职"), - body: localizeNotification(hireLocale, `${agent.name} joined as ${agent.role}`, `${agent.name} 已加入,职位:${agent.role}`), - urgency: "informational", - navigation: { section: "agents", entityId: agent.id }, - batchKey: "agent_hired", - }); - - // Notify adapter that hire was approved (Paperclip hire-hook parity) - void notifyHireApproved(db, { - companyId, - agentId: agent.id, - source: "approval", - sourceId: approvalId, - approvedAt: new Date().toISOString(), - }).catch(() => {}); - } - } - - if (approval.type === "deliverable_review") { - const documentIds = extractApprovalDocumentIds(approval.payloadJson); - const docStatus = decision === "approved" - ? "approved" - : decision === "rejected" || decision === "revision_requested" - ? "draft" - : "in_review"; - for (const docId of documentIds) { - db.core.documents.updateDocumentStatus(docId, companyId, docStatus); - } - - if (approval.relatedTaskId) { - const task = db.core.entity.getTask(approval.relatedTaskId); - if (task.assigneeAgentId) { - const agent = db.core.entity.getAgent(task.assigneeAgentId); - if (!agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(task.assigneeAgentId, true, agent.heartbeatIntervalSec || 120); - logger.info(`[deliverable-review] Resumed heartbeat for ${agent.name} after user ${decision}.`); - } - } - if (decision === "approved") { - db.core.tasks.advanceTaskStatus(task.id, "done", "Board approved deliverable."); - handleTaskStatusChange(task.id, companyId, task.status, "done"); - db.core.activity.addActivity({ companyId, actor: "board", action: "deliverable.approved", entityType: "task", entityId: task.id, detail: approval.decisionNote || "Deliverable approved by board." }); - } else if (decision === "rejected" || decision === "revision_requested") { - const previousStatus = task.status; - const statusMessage = decision === "rejected" - ? `Board rejected deliverable: ${approval.decisionNote || "No reason given."}` - : `Board requested revisions: ${approval.decisionNote || "No reason given."}`; - recordReviewFeedbackKnowledge(db, approval, decision); - db.core.tasks.advanceTaskStatus(task.id, "todo", statusMessage); - handleTaskStatusChange(task.id, companyId, previousStatus, "todo"); - wakeAgent(task.assigneeAgentId, "revision_needed"); - } - } else if (approval.requestedByAgentId) { - const agent = db.core.entity.getAgent(approval.requestedByAgentId); - if (!agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(approval.requestedByAgentId, true, agent.heartbeatIntervalSec || 120); - logger.info(`[deliverable-review] Resumed heartbeat for ${agent.name} after user ${decision}.`); - } - if (decision !== "approved") { - wakeAgent(approval.requestedByAgentId, "revision_needed"); - } - } - - publishDomainChanged(); - } - - if (approval.type === "draft_review" || approval.type === "strategy_review") { - const documentIds = extractApprovalDocumentIds(approval.payloadJson); - const docStatus = decision === "approved" ? "approved" : "draft"; - for (const docId of documentIds) { - db.core.documents.updateDocumentStatus(docId, companyId, docStatus); - } - publishDomainChanged(); - } - - // Handle budget override approvals - if (approval.type === "budget_override" && decision === "approved") { - try { - const payload = JSON.parse(approval.payloadJson ?? "{}") as { - policyId?: string; - scopeType?: string; - scopeId?: string; - newAmount?: number; - }; - if (payload.policyId) { - // Resolve the budget incident that triggered this approval - db.core.budget.resolveBudgetIncident(payload.policyId, companyId); - db.core.activity.addActivity({ - companyId, - actor: "board", - action: "budget.override_approved", - entityType: "approval", - entityId: approvalId, - detail: `Budget override approved for ${payload.scopeType} scope`, - }); - } - } catch (err) { - logger.error(`[automation] Failed to process budget_override approval: ${err instanceof Error ? err.message : String(err)}`); - } - } - - const browserAction = db.core.social.getBrowserActionByApprovalId(approvalId, companyId); - if (browserAction) { - if (decision === "approved") { - db.core.social.updateBrowserAction(browserAction.id, { - status: "queued", - resultSummary: "Approval granted. Dispatching browser action.", - errorMessage: null, - }); - publishDomainChanged(); - queueBrowserActionExecution(browserAction.id, companyId); - } else if (decision === "rejected") { - db.core.social.updateBrowserAction(browserAction.id, { - status: "cancelled", - resultSummary: "Browser action was rejected during approval.", - errorMessage: "Approval rejected by board.", - finishedAt: new Date().toISOString(), - }); - publishDomainChanged(); - } else if (decision === "revision_requested") { - db.core.social.updateBrowserAction(browserAction.id, { - status: "approval_required", - resultSummary: "Board requested revisions before execution.", - errorMessage: "Approval requires revisions before the browser action can run.", - }); - publishDomainChanged(); - } - } - - if (approval.type === "social_post" && decision === "approved" && approval.payloadJson) { - try { - const draft = JSON.parse(approval.payloadJson) as { - socialAccountId: string; - platform: string; - content: string; - mediaUrls: string[]; - scheduledAt: string | null; - }; - - const dispatchSocialAction = () => { - const actionId = db.core.social.saveBrowserAction({ - companyId: approval.companyId, - socialAccountId: draft.socialAccountId, - agentId: approval.requestedByAgentId ?? "", - actionType: "post", - payloadJson: JSON.stringify({ content: draft.content, mediaUrls: draft.mediaUrls, scheduledAt: draft.scheduledAt }), - status: "queued", - approvalId: approval.id, - }); - publishDomainChanged(); - queueBrowserActionExecution(actionId, approval.companyId); - }; - - if (draft.scheduledAt) { - const delay = new Date(draft.scheduledAt).getTime() - Date.now(); - if (delay > 0) { - const timer = setTimeout(() => { - if (deps.isQuitting()) return; - dispatchSocialAction(); - }, delay); - trackTimer(timer); - } else { - dispatchSocialAction(); - } - } else { - dispatchSocialAction(); - } - } catch (err) { - logger.error("[automation] Failed to dispatch approved social post:", err); - } - } - - // Workflow-step approvals are emitted by runWorkflowPipeline with - // type "dangerous_command" + workflowId/stepId in payloadJson. Gate the - // parse explicitly on that type instead of attempting a speculative - // JSON.parse for every approval. - if (approval.type === "dangerous_command" && approval.payloadJson) { - const payload = workflowApprovalPayloadSchema.safeParse(JSON.parse(approval.payloadJson)); - if (payload.success && payload.data.workflowId && payload.data.stepId) { - const { workflowId, stepId } = payload.data; - const workflow = db.automation.rules.getWorkflowRecord(workflowId, companyId); - if (workflow) { - const steps = normalizeWorkflowSteps(JSON.parse(workflow.stepsJson || "[]")); - const stepIndex = steps.findIndex((step) => step.id === stepId); - if (stepIndex >= 0) { - if (decision === "approved") { - steps[stepIndex]!.status = "pending"; - db.automation.rules.updateWorkflowExecution({ - id: workflow.id, - companyId, - status: "paused", - currentStepIndex: stepIndex, - stepsJson: JSON.stringify(steps), - lastRunAt: workflow.lastRunAt, - }); - publishDomainChanged(); - void runWorkflowPipeline(workflow.id, companyId).catch((error) => { - logger.error(`[workflow] Failed to resume workflow ${workflow.id} after approval ${approvalId}: ${error instanceof Error ? error.message : String(error)}`); - }); - } else { - steps[stepIndex]!.status = decision === "revision_requested" ? "pending" : "failed"; - db.automation.rules.updateWorkflowExecution({ - id: workflow.id, - companyId, - status: decision === "revision_requested" ? "paused" : "failed", - currentStepIndex: stepIndex, - stepsJson: JSON.stringify(steps), - lastRunAt: workflow.lastRunAt, - }); - publishDomainChanged(); - } - } - } - } - } - - if (approval.requestedByAgentId) { - if (!explicitlyWokenAgentIds.has(approval.requestedByAgentId)) { - wakeAgentIfPossible(approval.requestedByAgentId, companyId, "approval_resolved"); - } - } -} diff --git a/src/main/automation/automation-conditions.ts b/src/main/automation/automation-conditions.ts deleted file mode 100644 index 632a0115..00000000 --- a/src/main/automation/automation-conditions.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { AutomationEventContext } from "./types"; - -type ConditionLogger = { - warn: (...args: unknown[]) => void; -}; - -export function matchesEventConfig( - db: AppDatabase, - configJson: string, - sourceDepartment: string | null, - ctx: AutomationEventContext, - logger?: ConditionLogger, -): boolean { - if (sourceDepartment && ctx.department && sourceDepartment !== ctx.department) { - return false; - } - // Surface malformed condition JSON to the caller (automation service) so the - // operator sees it in logs instead of silently filtering out the rule. - const conditions = JSON.parse(configJson) as Record; - if (Object.keys(conditions).length === 0) return true; - if (conditions.status && ctx.newStatus && conditions.status !== ctx.newStatus) return false; - if (conditions.previousStatus && ctx.previousStatus && conditions.previousStatus !== ctx.previousStatus) return false; - if (conditions.priority) { - try { - const task = ctx.taskId ? db.core.entity.getTask(ctx.taskId) : null; - if (task && task.priority !== conditions.priority) return false; - // If task was deleted, skip this condition instead of rejecting the rule. - } catch (err) { - logger?.warn(`[automation-conditions] getTask failed for ${ctx.taskId}; treating priority condition as not applicable:`, err instanceof Error ? err.message : String(err)); - } - } - if (typeof conditions.budgetThresholdPct === "number" && ctx.agentId) { - try { - const agent = db.core.entity.getAgent(ctx.agentId); - if (agent.budgetMonthlyUsd > 0) { - const utilization = agent.spentMonthlyUsd / agent.budgetMonthlyUsd; - if (utilization < (conditions.budgetThresholdPct as number) / 100) return false; - } - // If budget is 0 (unlimited), skip budget condition instead of rejecting. - } catch (err) { - logger?.warn(`[automation-conditions] getAgent failed for ${ctx.agentId}; treating budget condition as not applicable:`, err instanceof Error ? err.message : String(err)); - } - } - if (conditions.taskId && ctx.taskId && conditions.taskId !== ctx.taskId) return false; - if (conditions.projectId && ctx.projectId && conditions.projectId !== ctx.projectId) return false; - if (conditions.agentId && ctx.agentId && conditions.agentId !== ctx.agentId) return false; - return true; -} - -export function matchesConditions( - db: AppDatabase, - rule: { conditionsJson: string; sourceDepartment: string | null }, - ctx: AutomationEventContext, - logger?: ConditionLogger, -): boolean { - return matchesEventConfig(db, rule.conditionsJson, rule.sourceDepartment, ctx, logger); -} diff --git a/src/main/automation/automation-handlers.ts b/src/main/automation/automation-handlers.ts deleted file mode 100644 index b8f0b7ca..00000000 --- a/src/main/automation/automation-handlers.ts +++ /dev/null @@ -1,165 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { NotificationOptions } from "../notification-service"; -import type { AutomationEventContext } from "./types"; -import { logAppError } from "../errors/index.js"; - -export interface HandlerDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - queueBrowserActionExecution: (actionId: string, companyId: string) => void; - isQuitting: () => boolean; -} - -export interface HandlerCallbacks { - dispatchAutomation: (trigger: string, ctx: AutomationEventContext) => void; - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; - runWorkflowPipeline: (workflowId: string, companyId: string) => Promise; -} - -export function handleTaskStatusChange( - deps: HandlerDeps, - callbacks: Pick, - taskId: string, - companyId: string, - previousStatus: string, - newStatus: string, -): void { - if (deps.isQuitting()) return; - if (previousStatus === newStatus) { - // Caller should gate this; log the no-op so the offender can be traced. - deps.logger.warn( - `[automation] handleTaskStatusChange called with no-op status (${previousStatus}) for task ${taskId} — caller should gate this.`, - ); - return; - } - const { db, wakeAgentIfPossible } = deps; - const { dispatchAutomation } = callbacks; - - let task: ReturnType | null = null; - try { - task = db.core.entity.getTask(taskId); - } catch (error) { - logAppError(deps.logger, error, { - kind: "recoverable", - code: "automation.task_status_change.task_not_found", - message: `handleTaskStatusChange: task ${taskId} disappeared before handler could read it`, - context: { taskId, companyId }, - }, "warn"); - return; - } - if (!task) return; - - db.core.activity.addActivity({ - companyId, - actor: task.assigneeAgentId ?? "board", - action: "task.status_changed", - entityType: "task", - entityId: taskId, - detail: `${previousStatus} → ${newStatus}`, - }); - - const context: AutomationEventContext = { - companyId, - taskId, - agentId: task.assigneeAgentId ?? undefined, - previousStatus, - newStatus, - }; - try { - if (task.assigneeAgentId) { - const agent = db.core.entity.getAgent(task.assigneeAgentId); - context.department = agent.department ?? undefined; - } - } catch (error) { - logAppError(deps.logger, error, { - kind: "recoverable", - code: "automation.task_status_change.assignee_deleted", - message: `Agent ${task.assigneeAgentId} deleted after task update; continuing without department context`, - context: { taskId, agentId: task.assigneeAgentId, companyId }, - }, "warn"); - } - - dispatchAutomation("task_status_changed", context); - - if (newStatus === "blocked") { - dispatchAutomation("task_blocked", context); - if (task.assigneeAgentId) { - const manager = db.core.agents.getManagerForAgent(task.assigneeAgentId); - if (manager) { - wakeAgentIfPossible(manager.id, companyId, "report_blocked"); - } - } - } - - if (newStatus === "done" && task.parentId) { - try { - const siblings = db.core.tasks.listChildTasks(task.parentId, companyId); - const allDone = siblings.every((entry) => entry.id === taskId ? true : entry.status === "done"); - if (allDone) { - const parent = db.core.entity.getTask(task.parentId); - if (parent.assigneeAgentId) { - wakeAgentIfPossible(parent.assigneeAgentId, companyId, "subtask_completed"); - } else { - const assignedId = db.core.tasks.autoAssignTask(parent.id, companyId); - if (assignedId) { - wakeAgentIfPossible(assignedId, companyId, "subtask_completed"); - } - } - } - } catch (err) { - logAppError(deps.logger, err, { - kind: "recoverable", - code: "automation.task_status_change.parent_lookup_failed", - message: `Parent task ${task.parentId} lookup failed during completion cascade`, - context: { taskId, parentTaskId: task.parentId, companyId }, - }, "warn"); - } - } -} - -export function handleTaskCreated( - deps: HandlerDeps, - callbacks: Pick, - taskId: string, - companyId: string, -): void { - if (deps.isQuitting()) return; - const { db, wakeAgentIfPossible } = deps; - const { dispatchAutomation } = callbacks; - - let task: ReturnType | null = null; - try { - task = db.core.entity.getTask(taskId); - } catch (error) { - logAppError(deps.logger, error, { - kind: "recoverable", - code: "automation.task_created.task_not_found", - message: `handleTaskCreated: task ${taskId} disappeared before handler could read it`, - context: { taskId, companyId }, - }, "warn"); - return; - } - if (!task) return; - - dispatchAutomation("task_created", { - companyId, - taskId, - agentId: task.assigneeAgentId ?? undefined, - }); - - if (!task.assigneeAgentId) { - const assignedId = db.core.tasks.autoAssignTask(taskId, companyId); - if (assignedId) { - wakeAgentIfPossible(assignedId, companyId, "assignment"); - } - } else { - wakeAgentIfPossible(task.assigneeAgentId, companyId, "assignment"); - } -} diff --git a/src/main/automation/automation-run-completion.ts b/src/main/automation/automation-run-completion.ts deleted file mode 100644 index f1ba9934..00000000 --- a/src/main/automation/automation-run-completion.ts +++ /dev/null @@ -1,475 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { RunRecord, SectionId } from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; -import type { AutomationEventContext, RunFinishedEvent } from "./types"; -import { IMPORTANT_DOCUMENT_TYPES } from "./types"; - -function localizeNotification(locale: string | null | undefined, en: string, zh: string): string { - return locale === "zh" ? zh : en; -} - -export interface RunCompletionDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; -} - -export interface RunCompletionCallbacks { - dispatchAutomation: (trigger: string, ctx: AutomationEventContext) => void; - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; -} - -// ─── Pure helpers exported for testing ───────────────────────────────────── - -export type DeliverableTaskType = "code" | "research" | "content" | "management" | "general"; - -/** Returns true for task types that require a tangible artifact before auto-advancing. */ -export function needsDeliverableCheck(taskType: DeliverableTaskType | string): boolean { - return taskType === "research" || taskType === "content"; -} - -export interface DeliverableSignals { - hasKnowledgeEntry: boolean; - hasDocument: boolean; - hasWorkProduct: boolean; - hasSubstantialComment: boolean; -} - -export interface DeliverableCheckInput extends DeliverableSignals { - taskType: DeliverableTaskType | string; -} - -/** - * Valid artifact surfaces for each task type. A task advances to review - * only when at least one signal from the set is present. The `work_product` - * surface covers filesystem deliverables the agent writes via bash / write - * / edit; before this table included it, a research task that produced a - * markdown file instead of a knowledge entry would stay in `in_progress` - * forever even though the deliverable was sitting on disk. - */ -const VALID_DELIVERABLE_SIGNALS: Record> = { - research: new Set(["hasKnowledgeEntry", "hasDocument", "hasWorkProduct", "hasSubstantialComment"]), - content: new Set(["hasDocument", "hasWorkProduct"]), - code: new Set(["hasWorkProduct", "hasDocument"]), - management: new Set(["hasKnowledgeEntry", "hasDocument", "hasWorkProduct", "hasSubstantialComment"]), - general: new Set(["hasKnowledgeEntry", "hasDocument", "hasWorkProduct", "hasSubstantialComment"]), -}; - -function validSignalsForTaskType(taskType: string): ReadonlySet { - return VALID_DELIVERABLE_SIGNALS[taskType as DeliverableTaskType] - ?? VALID_DELIVERABLE_SIGNALS.general; -} - -export function hasValidDeliverableFor(taskType: string, signals: DeliverableSignals): boolean { - const valid = validSignalsForTaskType(taskType); - for (const key of valid) { - if (signals[key]) return true; - } - return false; -} - -/** Returns the next task status and comment after a successful run. */ -export function determinePostRunStatus(input: DeliverableCheckInput): { - nextStatus: "in_review" | "in_progress"; - comment: string; -} { - if (!needsDeliverableCheck(input.taskType)) { - return { - nextStatus: "in_review", - comment: "Run completed successfully. Awaiting review.", - }; - } - if (hasValidDeliverableFor(input.taskType, input)) { - return { - nextStatus: "in_review", - comment: "Run completed with deliverable. Awaiting review.", - }; - } - return { - nextStatus: "in_progress", - comment: `${input.taskType} task run completed but no deliverable artifact was detected. Flagging for manager review.`, - }; -} - -export interface BudgetThresholdInput { - name: string; - budgetMonthlyUsd: number; - spentMonthlyUsd: number; -} - -/** - * Fires budget threshold notifications when utilization >= 80%. - * The notify callback receives a NotificationOptions-style object so callers - * can forward it directly to the notification service. - */ -export function checkBudgetThreshold( - agent: BudgetThresholdInput, - notify: (opts: { title: string; body: string; urgency: "critical" | "informational"; navigation: { section: SectionId }; batchKey?: string }) => void, - localizeNotification: (en: string, zh: string) => string, -): void { - if (agent.budgetMonthlyUsd <= 0) return; - const utilization = agent.spentMonthlyUsd / agent.budgetMonthlyUsd; - if (utilization < 0.8) return; - - const pct = Math.round(utilization * 100); - notify({ - title: localizeNotification("Budget Warning", "预算警告"), - body: localizeNotification( - `${agent.name} has used ${pct}% of monthly budget`, - `${agent.name} 已使用月度预算的 ${pct}%`, - ), - urgency: "informational", - navigation: { section: "costs" }, - batchKey: "budget_alerts", - }); - - if (utilization >= 1.0) { - notify({ - title: localizeNotification("Budget Exhausted", "预算耗尽"), - body: localizeNotification( - `${agent.name} has reached 100% of monthly budget and is paused`, - `${agent.name} 已达到月度预算上限并已暂停`, - ), - urgency: "critical", - navigation: { section: "costs" }, - }); - } -} - -// ─── Internal DB-backed deliverable check ─────────────────────────────────── - -function checkRunProducedDeliverable( - db: AppDatabase, - runId: string, - companyId: string, - taskId: string, - taskType: string, -): boolean { - const signals = db.core.knowledge.collectRunDeliverableSignals(runId, companyId, taskId); - return hasValidDeliverableFor(taskType, signals); -} - -/** Returns important documents created during this run (matching IMPORTANT_DOCUMENT_TYPES). */ -function findImportantDocsForRun(db: AppDatabase, runId: string, companyId: string): Array<{ id: string; type: string; title: string }> { - const placeholders = [...IMPORTANT_DOCUMENT_TYPES].map(() => "?").join(", "); - // Prefer causal binding, fall back to time-window for legacy data - const causal = db.queryAll<{ id: string; type: string; title: string }>( - `select id, type, title from documents where company_id = ? and type in (${placeholders}) and source_run_id = ?`, - companyId, ...IMPORTANT_DOCUMENT_TYPES, runId, - ); - if (causal.length > 0) return causal; - return db.queryAll<{ id: string; type: string; title: string }>( - `select id, type, title from documents where company_id = ? and type in (${placeholders}) and source_run_id is null and created_at >= (select started_at from runs where id = ?)`, - companyId, ...IMPORTANT_DOCUMENT_TYPES, runId, - ); -} - -/** Creates a deliverable_review approval and fires OS notification. */ -function createDeliverableReviewApproval( - deps: RunCompletionDeps, - companyId: string, - taskId: string, - agentId: string, - docs: Array<{ id: string; type: string; title: string }>, - reviewerNote?: string, -): string { - const { db, logger, publishDomainChanged, notify } = deps; - const docTitles = docs.map((d) => d.title).join(", "); - const approvalId = db.core.approvals.requestApproval({ - companyId, - relatedTaskId: taskId, - requestedByAgentId: agentId, - type: "deliverable_review", - payloadSummary: `Review deliverable: ${docTitles}`.slice(0, 280), - impactSummary: reviewerNote ?? "Agent completed work with important deliverables. Awaiting your final review.", - payloadJson: JSON.stringify({ documentIds: docs.map((d) => d.id), documents: docs }), - }); - db.core.tasks.setTaskRequiresUserReview(taskId, false); - const agent = db.core.entity.getAgent(agentId); - if (agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(agentId, false, agent.heartbeatIntervalSec || 120); - logger.info(`[deliverable-review] Paused heartbeat for ${agent.name} — awaiting user review.`); - } - notify({ - title: "Deliverable Ready for Review", - body: `${docTitles}`.slice(0, 200), - urgency: "informational", - navigation: { section: "approvals", entityId: approvalId }, - batchKey: "deliverable_review", - }); - publishDomainChanged(); - return approvalId; -} - -/** - * Decide the terminal status a successful run should leave the task in. - * - * `in_review` only makes sense when there is a reachable reviewer: - * - a non-top-level assignee always has a manager who reviews; - * - in `ai_cofounder` mode the human is the implicit reviewer; - * - in `ai_ceo` mode the operator opted out of human review, but - * they can re-opt-in per company via `reviewDeliverables`. - * - * Top-level agents in `ai_ceo` mode without `reviewDeliverables` have - * no reviewer — neither a manager to walk up to nor a human gate. - * Routing them through `in_review` strands the task forever (the - * heartbeat candidate filter only picks `todo / in_progress / blocked` - * so the CEO never sees its own stuck rows) and the codebase's old - * workaround was to force-flag `requires_user_review` so the - * `guardInReviewHasReviewer` would let the transition through. That - * was paper over the symptom; the right answer is to skip review - * entirely and advance straight to `done`. - */ -function decideTerminalStatus( - db: RunCompletionDeps["db"], - agent: ReturnType, - companyId: string, -): "in_review" | "done" { - if (agent.reportsTo !== null) return "in_review"; - const mode = db.core.company.getCompanyExecutionMode(companyId); - if (mode !== "ai_ceo") return "in_review"; - const settings = db.core.company.getCompanyApprovalSettings(companyId); - return settings?.reviewDeliverables ? "in_review" : "done"; -} - -/** Auto-resolves the task as a successful autonomous completion. */ -function advanceToDone( - deps: RunCompletionDeps, - callbacks: RunCompletionCallbacks, - run: RunRecord, - taskId: string, - statusMessage: string, -): void { - const { db, publishDomainChanged } = deps; - db.core.tasks.advanceTaskStatus(taskId, "done", statusMessage); - callbacks.handleTaskStatusChange(taskId, run.companyId, "in_progress", "done"); - publishDomainChanged(); -} - -/** Advances a task to in_review and optionally flags deliverables for user review. */ -function advanceToInReview( - deps: RunCompletionDeps, - callbacks: RunCompletionCallbacks, - run: RunRecord, - taskId: string, - statusMessage: string, -): void { - const { db, logger, publishDomainChanged } = deps; - // The tasks-status guard refuses an `in_review` transition for a - // top-level assignee (reports_to IS NULL) unless the task is - // flagged for user review. The caller (`processRunCompletion`) only - // routes top-level runs through this helper when human review is - // expected (`ai_cofounder` mode or `reviewDeliverables = true`), so - // pre-flagging here is the right semantics — the human IS the - // reviewer in those configurations. - const agent = db.core.entity.getAgent(run.agentId); - if (agent.reportsTo === null) { - db.core.tasks.setTaskRequiresUserReview(taskId, true); - } - db.core.tasks.advanceTaskStatus(taskId, "in_review", statusMessage); - callbacks.handleTaskStatusChange(taskId, run.companyId, "in_progress", "in_review"); - const company = db.projection.snapshot.listSnapshot().companies.find((c) => c.id === run.companyId); - if (company?.reviewDeliverables) { - const importantDocs = findImportantDocsForRun(db, run.id, run.companyId); - if (importantDocs.length > 0) { - db.core.tasks.setTaskRequiresUserReview(taskId, true); - if (agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(agent.id, false, agent.heartbeatIntervalSec || 120); - logger.info(`[deliverable-review] Paused heartbeat for ${agent.name} — deliverable flagged for review.`); - } - const chain = db.core.agents.getChainOfCommand(agent.id); - if (chain.length === 0) { - createDeliverableReviewApproval(deps, run.companyId, taskId, run.agentId, importantDocs); - } - } - } - publishDomainChanged(); -} - -/** - * Pick the right terminal-status helper for this run. `processRunCompletion` - * uses it after every successful "produced something or didn't need to" - * branch; `decideTerminalStatus` is the single source of truth that says - * `done` (no reviewer needed) vs `in_review` (reviewer expected). - */ -function advanceSuccessfulRun( - deps: RunCompletionDeps, - callbacks: RunCompletionCallbacks, - run: RunRecord, - taskId: string, - statusMessage: string, -): "in_review" | "done" { - const agent = deps.db.core.entity.getAgent(run.agentId); - const target = decideTerminalStatus(deps.db, agent, run.companyId); - if (target === "done") { - advanceToDone(deps, callbacks, run, taskId, statusMessage); - } else { - advanceToInReview(deps, callbacks, run, taskId, statusMessage); - } - return target; -} - -export function processRunCompletion( - deps: RunCompletionDeps, - callbacks: RunCompletionCallbacks, - run: RunRecord, - event: RunFinishedEvent, - isQuitting: () => boolean, -): void { - if (isQuitting()) return; - const { db, logger: _logger, publishDomainChanged, notify, wakeAgentIfPossible } = deps; - const { dispatchAutomation, handleTaskStatusChange } = callbacks; - - if (!run.taskId) return; - let task: ReturnType | null = null; - try { - task = db.core.entity.getTask(run.taskId); - } catch (error) { - deps.logger.warn(`[automation] processRunCompletion: task ${run.taskId} not found for run ${run.id}:`, error); - return; - } - if (!task) return; - - const isSuccess = event.status === "succeeded"; - const isFailed = event.status === "failed" || event.status === "timed_out"; - - let effectiveStatus = task.status; - - if (isSuccess && effectiveStatus === "in_progress") { - // Delegate the task-type → deliverable-required decision to the pure - // helper so production and tests share a single source of truth. - const taskType = task.taskType ?? "general"; - - if (needsDeliverableCheck(taskType)) { - const hasDeliverable = checkRunProducedDeliverable(db, run.id, run.companyId, task.id, taskType); - if (!hasDeliverable) { - // Don't auto-advance to in_review: the run succeeded but did not - // produce the required deliverable, so it's not ready for - // manager sign-off. - // - // Park the task as `blocked` rather than leaving it at - // `in_progress`. finishRun has already cleared the run's - // task_leases, so a task still tagged - // `in_progress` has no lock, no run, and no path back to - // `todo` — heartbeat picks it up, checkoutTask rejects it - // (status ∉ todo/backlog), and the assignee is stuck in a - // permanent `checkout_race_lost` loop. Blocking instead puts - // the task in the manager's blocker queue with the diagnostic - // comment attached; the manager patches it back to `todo` (or - // `cancelled`) after deciding how to proceed. - db.core.tasks.advanceTaskStatus( - task.id, - "blocked", - `${taskType} task run completed but no deliverable artifact was detected. Flagging for manager review.`, - ); - handleTaskStatusChange(task.id, run.companyId, "in_progress", "blocked"); - // Wake manager for review - try { - const agent = db.core.entity.getAgent(run.agentId); - const chain = db.core.agents.getChainOfCommand(agent.id); - if (chain.length > 0) { - wakeAgentIfPossible(chain[0].id, run.companyId, "review_needed"); - } - } catch (error) { - deps.logger.warn( - `[automation] deliverable-review manager wake failed for agent ${run.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - publishDomainChanged(); - effectiveStatus = "blocked"; - // Skip the normal in_review advance - } else { - effectiveStatus = advanceSuccessfulRun( - deps, - callbacks, - run, - task.id, - "Run completed with deliverable.", - ); - } - } else { - // Code/management/general tasks: route through the same selector - // so ai_ceo top-level completions land in `done` instead of - // stalling in the `in_review` dead-letter. - effectiveStatus = advanceSuccessfulRun( - deps, - callbacks, - run, - task.id, - "Run completed successfully.", - ); - } - } - - const automationContext: AutomationEventContext = { - companyId: run.companyId, - taskId: run.taskId ?? undefined, - agentId: run.agentId, - runId: run.id, - }; - try { - const agent = db.core.entity.getAgent(run.agentId); - automationContext.department = agent.department ?? undefined; - } catch (err) { - deps.logger.warn(`[automation] getAgent failed for ${run.agentId} during run completion; dropping department from context:`, err instanceof Error ? err.message : String(err)); - } - - if (isSuccess) { - dispatchAutomation("run_completed", automationContext); - if (task.parentId) { - try { - const siblings = db.core.tasks.listChildTasks(task.parentId, run.companyId); - const allSiblingsDoneOrReview = siblings.every((entry) => entry.status === "done" || entry.status === "in_review"); - if (allSiblingsDoneOrReview) { - const parent = db.core.entity.getTask(task.parentId); - if (parent.assigneeAgentId) { - wakeAgentIfPossible(parent.assigneeAgentId, run.companyId, "subtask_completed"); - } else { - const assignedId = db.core.tasks.autoAssignTask(parent.id, run.companyId); - if (assignedId) { - wakeAgentIfPossible(assignedId, run.companyId, "subtask_completed"); - } - } - } - } catch (err) { - deps.logger.warn(`[automation] Parent task ${task.parentId} cascade failed during run completion:`, err instanceof Error ? err.message : String(err)); - } - } - } - - if (isFailed) { - dispatchAutomation("run_failed", automationContext); - } - - // Budget threshold check runs after every succeeded run; finishRun - // has already summed cost_entries and updated spentMonthlyUsd, so we - // just read the post-run spend and fire if it crosses 80%. - if (isSuccess) { - try { - const agent = db.core.entity.getAgent(run.agentId); - if (agent.budgetMonthlyUsd > 0) { - const utilization = agent.spentMonthlyUsd / agent.budgetMonthlyUsd; - if (utilization >= 0.8) { - dispatchAutomation("budget_threshold", { - ...automationContext, - agentId: agent.id, - }); - } - } - const budgetLocale = db.projection.snapshot.listSnapshot().locale; - checkBudgetThreshold( - agent, - notify, - (en, zh) => localizeNotification(budgetLocale, en, zh), - ); - } catch (err) { - deps.logger.warn(`[automation] Budget follow-up failed for agent ${run.agentId}:`, err instanceof Error ? err.message : String(err)); - } - } -} diff --git a/src/main/automation/automation-workflow.ts b/src/main/automation/automation-workflow.ts deleted file mode 100644 index c43f09bf..00000000 --- a/src/main/automation/automation-workflow.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { z } from "zod"; -import type { AppDatabase } from "../database"; -import type { AgentRecord } from "@shared/types"; -import type { WorkflowStepState, AutomationEventContext } from "./types"; -import type { ActionDeps, ActionCallbacks } from "./automation-actions"; -import { executeAutomationAction } from "./automation-actions"; -import { isAutomationAction } from "./automation-action-schemas"; - -// Raw workflow step shape accepted from the DB `stepsJson` column. All fields -// are optional/loose because legacy rows used free-form typeof checks; zod -// applies the normalized defaults once via `.parse(...)`. -const workflowStepInputSchema = z.object({ - id: z.string().optional(), - name: z.string().optional(), - action: z.string().optional(), - configJson: z.string().optional(), - assigneeDepartment: z.string().nullable().optional(), - assigneeAgentId: z.string().nullable().optional(), - requiresApproval: z.boolean().optional(), - timeoutSec: z.number().optional(), - status: z.enum(["pending", "running", "completed", "failed", "skipped"]).optional(), -}).passthrough(); - -const workflowStepsInputSchema = z.array(workflowStepInputSchema); - -export interface WorkflowDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; -} - -export function normalizeWorkflowSteps(raw: unknown): WorkflowStepState[] { - const parsed = workflowStepsInputSchema.parse(raw); - return parsed.map((step, index) => { - const rawAction = step.action ?? "send_message"; - if (!isAutomationAction(rawAction)) { - throw new Error(`Workflow step ${index + 1} has unsupported action "${rawAction}".`); - } - return { - id: step.id && step.id.length > 0 ? step.id : `step-${index + 1}`, - name: step.name && step.name.length > 0 ? step.name : `Step ${index + 1}`, - action: rawAction, - configJson: step.configJson ?? "{}", - assigneeDepartment: step.assigneeDepartment ?? null, - assigneeAgentId: step.assigneeAgentId ?? null, - requiresApproval: step.requiresApproval === true, - timeoutSec: step.timeoutSec ?? 0, - status: step.status ?? "pending", - }; - }); -} - -export function resolveWorkflowStepActor( - db: AppDatabase, - step: WorkflowStepState, - companyId: string, -): AgentRecord | null { - if (step.assigneeAgentId) { - const agent = db.core.entity.getAgent(step.assigneeAgentId); - if (agent.companyId !== companyId) { - throw new Error(`Workflow step assignee ${step.assigneeAgentId} does not belong to company ${companyId}.`); - } - return agent; - } - - if (step.assigneeDepartment) { - const idleAgents = db.core.agents.getIdleAgentsForDepartment(companyId, step.assigneeDepartment); - if (idleAgents.length > 0) { - return db.core.entity.getAgent(idleAgents[0]!.id); - } - } - - const snapshot = db.projection.snapshot.listSnapshot(); - return snapshot.agents.find((agent) => agent.companyId === companyId && !agent.reportsTo && agent.status !== "terminated") ?? null; -} - -export function buildWorkflowActionContext( - companyId: string, - step: WorkflowStepState, - actor: AgentRecord | null, -): { config: Record; ctx: AutomationEventContext } { - let config: Record = {}; - try { - config = JSON.parse(step.configJson) as Record; - } catch { - throw new Error(`Workflow step "${step.name}" has invalid config JSON.`); - } - - return { - config, - ctx: { - companyId, - agentId: actor?.id, - department: actor?.department ?? step.assigneeDepartment ?? undefined, - taskId: typeof config.taskId === "string" ? config.taskId : undefined, - runId: typeof config.runId === "string" ? config.runId : undefined, - projectId: typeof config.projectId === "string" ? config.projectId : undefined, - newStatus: typeof config.status === "string" ? config.status : undefined, - } satisfies AutomationEventContext, - }; -} - -export async function runWorkflowPipeline( - workflowId: string, - companyId: string, - deps: WorkflowDeps, - actionDeps: ActionDeps, - actionCallbacks: ActionCallbacks, -): Promise { - const { db, publishDomainChanged } = deps; - - const workflow = db.automation.rules.getWorkflowRecord(workflowId, companyId); - if (!workflow) { - throw new Error("Workflow not found."); - } - const parsedSteps = normalizeWorkflowSteps(JSON.parse(workflow.stepsJson || "[]")); - if (parsedSteps.some((step) => step.status === "running")) { - throw new Error("Workflow is already running."); - } - if (parsedSteps.length === 0) { - throw new Error("Workflow has no steps."); - } - - const resumeFrom = workflow.status === "paused" ? workflow.currentStepIndex : 0; - const steps: WorkflowStepState[] = parsedSteps.map((step, index) => { - if (workflow.status !== "paused") { - return { ...step, status: index < resumeFrom ? "completed" : "pending" }; - } - return step; - }); - - db.automation.rules.updateWorkflowExecution({ - id: workflowId, - companyId, - status: "active", - currentStepIndex: resumeFrom, - stepsJson: JSON.stringify(steps), - incrementRunCount: workflow.status !== "paused", - lastRunAt: new Date().toISOString(), - }); - publishDomainChanged(); - - for (let index = resumeFrom; index < steps.length; index += 1) { - const step = steps[index]!; - step.status = "running"; - db.automation.rules.updateWorkflowExecution({ - id: workflowId, - companyId, - status: "active", - currentStepIndex: index, - stepsJson: JSON.stringify(steps), - lastRunAt: new Date().toISOString(), - }); - publishDomainChanged(); - - const actor = resolveWorkflowStepActor(db, step, companyId); - const { config, ctx } = buildWorkflowActionContext(companyId, step, actor); - - if (step.requiresApproval) { - const approvalId = db.core.approvals.requestApproval({ - companyId, - requestedByAgentId: actor?.id ?? null, - relatedTaskId: ctx.taskId ?? null, - type: "dangerous_command", - payloadSummary: `Workflow approval required: ${workflow.name} / ${step.name}`, - impactSummary: `Workflow step "${step.name}" requires board approval before ${step.action}.`, - payloadJson: JSON.stringify({ workflowId, stepId: step.id, stepName: step.name }), - }); - step.status = "pending"; - db.automation.rules.updateWorkflowExecution({ - id: workflowId, - companyId, - status: "paused", - currentStepIndex: index, - stepsJson: JSON.stringify(steps), - lastRunAt: new Date().toISOString(), - }); - db.core.activity.addActivity({ - companyId, - actor: actor?.id ?? "system", - action: "workflow.paused_for_approval", - entityType: "workflow", - entityId: workflowId, - detail: `Paused on step "${step.name}" with approval ${approvalId}.`, - }); - publishDomainChanged(); - return; - } - - try { - executeAutomationAction( - actionDeps, - actionCallbacks, - { - action: step.action, - actionConfigJson: JSON.stringify(config), - targetDepartment: step.assigneeDepartment, - trigger: "workflow_step", - }, - ctx, - ); - step.status = "completed"; - db.core.activity.addActivity({ - companyId, - actor: actor?.id ?? "system", - action: "workflow.step_completed", - entityType: "workflow", - entityId: workflowId, - detail: step.name, - }); - const isLastStep = index === steps.length - 1; - const completionStatus = isLastStep ? "completed" : "active"; - db.automation.rules.updateWorkflowExecution({ - id: workflowId, - companyId, - status: completionStatus, - currentStepIndex: index + 1, - stepsJson: JSON.stringify(steps), - lastRunAt: new Date().toISOString(), - }); - publishDomainChanged(); - } catch (error) { - step.status = "failed"; - db.automation.rules.updateWorkflowExecution({ - id: workflowId, - companyId, - status: "failed", - currentStepIndex: index, - stepsJson: JSON.stringify(steps), - lastRunAt: new Date().toISOString(), - }); - db.core.activity.addActivity({ - companyId, - actor: actor?.id ?? "system", - action: "workflow.step_failed", - entityType: "workflow", - entityId: workflowId, - detail: `${step.name}: ${error instanceof Error ? error.message : String(error)}`, - }); - publishDomainChanged(); - throw error; - } - } -} diff --git a/src/main/automation/index.ts b/src/main/automation/index.ts deleted file mode 100644 index 9001c564..00000000 --- a/src/main/automation/index.ts +++ /dev/null @@ -1,224 +0,0 @@ -import type { AutomationTrigger, AutomationAction, RunRecord } from "@shared/types"; -import type { AutomationDependencies, AutomationEventContext, RunFinishedEvent } from "./types"; -import { matchesConditions, matchesEventConfig } from "./automation-conditions"; -import { executeAutomationAction } from "./automation-actions"; -import type { ActionDeps, ActionCallbacks } from "./automation-actions"; -import { runWorkflowPipeline } from "./automation-workflow"; -import type { WorkflowDeps } from "./automation-workflow"; -import { processRunCompletion } from "./automation-run-completion"; -import type { RunCompletionDeps, RunCompletionCallbacks } from "./automation-run-completion"; -import { handleApprovalResolved } from "./automation-approval-handler"; -import type { ApprovalHandlerDeps, ApprovalHandlerCallbacks } from "./automation-approval-handler"; -import { handleTaskStatusChange, handleTaskCreated } from "./automation-handlers"; -import type { HandlerDeps } from "./automation-handlers"; - -export type { AutomationEventContext } from "./types"; - -export function createAutomationService({ - db, - logger, - emitEvent, - publishDomainChanged, - notify, - wakeAgentIfPossible, - queueBrowserActionExecution, - isQuitting, -}: AutomationDependencies) { - const activeAutomationExecutions = new Set(); - const activeWorkflowTriggerExecutions = new Set(); - const pendingScheduledTimers = new Set>(); - - const actionDeps: ActionDeps = { - db, - logger, - emitEvent, - publishDomainChanged, - wakeAgentIfPossible, - }; - - const workflowDeps: WorkflowDeps = { - db, - logger, - publishDomainChanged, - }; - - const handlerDeps: HandlerDeps = { - db, - logger, - publishDomainChanged, - notify, - wakeAgentIfPossible, - queueBrowserActionExecution, - isQuitting, - }; - - const approvalDeps: ApprovalHandlerDeps = { - db, - logger, - publishDomainChanged, - notify, - wakeAgentIfPossible, - queueBrowserActionExecution, - isQuitting, - }; - - const runCompletionDeps: RunCompletionDeps = { - db, - logger, - publishDomainChanged, - notify, - wakeAgentIfPossible, - }; - - // Forward-declared so callbacks can reference each other - function _runWorkflowPipeline(workflowId: string, companyId: string): Promise { - return runWorkflowPipeline(workflowId, companyId, workflowDeps, actionDeps, actionCallbacks); - } - - function _handleTaskCreated(taskId: string, companyId: string): void { - handleTaskCreated(handlerDeps, { dispatchAutomation }, taskId, companyId); - } - - function _handleApprovalResolved(approvalId: string, companyId: string, decision: string): void { - handleApprovalResolved(approvalDeps, approvalCallbacks, approvalId, companyId, decision); - } - - function _handleTaskStatusChange(taskId: string, companyId: string, previousStatus: string, newStatus: string): void { - handleTaskStatusChange(handlerDeps, { dispatchAutomation }, taskId, companyId, previousStatus, newStatus); - } - - const actionCallbacks: ActionCallbacks = { - handleTaskCreated: _handleTaskCreated, - handleApprovalResolved: _handleApprovalResolved, - handleTaskStatusChange: _handleTaskStatusChange, - }; - - const approvalCallbacks: ApprovalHandlerCallbacks = { - dispatchAutomation, - handleTaskStatusChange: _handleTaskStatusChange, - runWorkflowPipeline: _runWorkflowPipeline, - trackTimer: (timer) => { pendingScheduledTimers.add(timer); }, - }; - - const runCompletionCallbacks: RunCompletionCallbacks = { - dispatchAutomation, - handleTaskStatusChange: _handleTaskStatusChange, - }; - - function evaluateAutomationRules(trigger: string, ctx: AutomationEventContext) { - try { - const rules = db.automation.rules.listActiveAutomationRules(ctx.companyId, trigger); - for (const rule of rules) { - if (!matchesConditions(db, rule, ctx, logger)) continue; - const executionKey = JSON.stringify({ - ruleId: rule.id, - trigger, - companyId: ctx.companyId, - taskId: ctx.taskId ?? null, - agentId: ctx.agentId ?? null, - runId: ctx.runId ?? null, - previousStatus: ctx.previousStatus ?? null, - newStatus: ctx.newStatus ?? null, - }); - if (activeAutomationExecutions.has(executionKey)) { - logger.warn(`[automation] Skipping re-entrant execution for rule "${rule.name}" (${executionKey})`); - continue; - } - activeAutomationExecutions.add(executionKey); - try { - executeAutomationAction(actionDeps, actionCallbacks, rule, ctx); - db.automation.rules.recordAutomationExecution( - rule.id, - ctx.companyId, - rule.name, - trigger, - rule.action, - `Fired for ${trigger} in context: taskId=${ctx.taskId ?? "n/a"}, agentId=${ctx.agentId ?? "n/a"}`, - ); - emitEvent({ - type: "automation-fired", - ruleId: rule.id, - ruleName: rule.name, - trigger: trigger as AutomationTrigger, - action: rule.action as AutomationAction, - }); - logger.info(`[automation] Fired rule "${rule.name}" (${trigger} → ${rule.action})`); - } catch (error) { - logger.error(`[automation] Failed to execute action for rule "${rule.name}": ${error instanceof Error ? error.message : String(error)}`); - db.automation.rules.recordAutomationExecution( - rule.id, - ctx.companyId, - rule.name, - trigger, - rule.action, - `FAILED: ${error instanceof Error ? error.message : String(error)}`, - ); - } finally { - activeAutomationExecutions.delete(executionKey); - } - } - } catch (error) { - logger.error(`[automation] Error evaluating rules for trigger "${trigger}": ${error instanceof Error ? error.message : String(error)}`); - } - } - - function evaluateWorkflowTriggers(trigger: string, ctx: AutomationEventContext) { - try { - const workflows = db.automation.rules.listTriggerableWorkflows(ctx.companyId, trigger); - for (const workflow of workflows) { - if (!matchesEventConfig(db, workflow.triggerConfigJson, null, ctx, logger)) continue; - const executionKey = JSON.stringify({ - workflowId: workflow.id, - trigger, - companyId: ctx.companyId, - taskId: ctx.taskId ?? null, - agentId: ctx.agentId ?? null, - runId: ctx.runId ?? null, - previousStatus: ctx.previousStatus ?? null, - newStatus: ctx.newStatus ?? null, - }); - if (activeWorkflowTriggerExecutions.has(executionKey)) { - logger.warn(`[workflow] Skipping re-entrant trigger for workflow "${workflow.name}" (${executionKey})`); - continue; - } - activeWorkflowTriggerExecutions.add(executionKey); - void _runWorkflowPipeline(workflow.id, ctx.companyId) - .then(() => { - logger.info(`[workflow] Triggered workflow "${workflow.name}" via ${trigger}`); - }) - .catch((error) => { - logger.error(`[workflow] Trigger failed for "${workflow.name}": ${error instanceof Error ? error.message : String(error)}`); - }) - .finally(() => { - activeWorkflowTriggerExecutions.delete(executionKey); - }); - } - } catch (error) { - logger.error(`[workflow] Error evaluating workflow triggers for "${trigger}": ${error instanceof Error ? error.message : String(error)}`); - } - } - - function dispatchAutomation(trigger: string, ctx: AutomationEventContext) { - if (isQuitting()) return; - evaluateAutomationRules(trigger, ctx); - evaluateWorkflowTriggers(trigger, ctx); - } - - function destroy() { - for (const timer of pendingScheduledTimers) { - clearTimeout(timer); - } - pendingScheduledTimers.clear(); - } - - return { - runWorkflowPipeline: _runWorkflowPipeline, - dispatchAutomation, - processRunCompletion: (run: RunRecord, event: RunFinishedEvent) => - processRunCompletion(runCompletionDeps, runCompletionCallbacks, run, event, isQuitting), - handleApprovalResolved: _handleApprovalResolved, - handleTaskStatusChange: _handleTaskStatusChange, - handleTaskCreated: _handleTaskCreated, - destroy, - }; -} diff --git a/src/main/automation/types.ts b/src/main/automation/types.ts deleted file mode 100644 index 0133da22..00000000 --- a/src/main/automation/types.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { - AutomationAction, - DesktopEvent, - RunStatus, -} from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; - -/** Document types considered important enough to gate behind user review when reviewDeliverables is enabled. */ -export const IMPORTANT_DOCUMENT_TYPES = new Set([ - "prd", "technical_spec", "design_doc", "project_brief", "proposal", - "budget_proposal", "architecture_decision", "contract", "sop", -]); - -export interface WorkflowStepState { - id: string; - name: string; - action: AutomationAction; - configJson: string; - assigneeDepartment: string | null; - assigneeAgentId: string | null; - requiresApproval: boolean; - timeoutSec: number; - status: "pending" | "running" | "completed" | "failed" | "skipped"; -} - -export interface AutomationEventContext { - companyId: string; - taskId?: string; - agentId?: string; - runId?: string; - projectId?: string; - department?: string; - previousStatus?: string; - newStatus?: string; - costUsd?: number; -} - -export interface AutomationDependencies { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - queueBrowserActionExecution: (actionId: string, companyId: string) => void; - isQuitting: () => boolean; -} - -export interface RunFinishedEvent { - status: RunStatus; - summary: string | null; - errorMessage: string | null; -} diff --git a/src/main/bootstrap-application.ts b/src/main/bootstrap-application.ts deleted file mode 100644 index 68c2b8b2..00000000 --- a/src/main/bootstrap-application.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { app } from "electron"; -import type { AgentApiServer } from "./api-server"; -import type { AppDatabase } from "./database"; -import type { BrowserManager } from "./browser-manager"; -import { prepareHostEnvironment } from "./host-environment-service"; -import type { createServiceGraph } from "./service-graph"; -import type { createIpcSupport } from "./ipc-support"; -import type { createThreadIntegration } from "./thread-integration"; -import type { createCheckpointEngine } from "./checkpoint-engine"; -import { - DocumentLifecycleProcessor, - makeLifecycleProcessorOptions, -} from "./document-lifecycle-processor"; -import { registerLifecycleHandlers } from "./document-lifecycle-handlers"; -import { prepareLogger } from "./bootstrap/prepare-logger"; -import { prepareDatabase } from "./bootstrap/prepare-database"; -import { prepareServices } from "./bootstrap/prepare-services"; -import { wireApiServer, type CreateApiServerFn } from "./bootstrap/wire-api-server"; -import { recoverScheduledPosts } from "./bootstrap/recover-scheduled-posts"; -import { backfillWorkspaceArtifacts } from "./bootstrap/backfill-workspace-artifacts"; -import { runStartupHealthChecks } from "./bootstrap/run-startup-health-checks"; -import { emitCrashRecoveryNotification, recoverShutdownInterruptedTasks } from "./bootstrap/recover-interrupted-tasks"; - -interface BootstrapApplicationDependencies { - hasSingleInstanceLock: boolean; - isDev: boolean; - devServerOrigin: string | null; - profileDir: string; - appDatabaseFactory: (profileDir: string) => AppDatabase; - initSigningKey: (profileDir: string) => void; - windowStatePath: string; - preloadPath: string; - rendererDist: string; - iconPath: string; - devServerUrl?: string; - workerPath: string; - createApiServer: CreateApiServerFn; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - seedDefaultAutomationRules: (companyId: string) => void; - isQuittingRef: { current: boolean }; - onRuntimeReady?: (state: { - db: AppDatabase; - apiServer: AgentApiServer; - serviceGraph: ReturnType; - ipcSupport: ReturnType; - threadIntegration: ReturnType; - checkpointEngine: ReturnType; - lifecycleProcessor: DocumentLifecycleProcessor; - }) => void; -} - -export async function bootstrapApplication(deps: BootstrapApplicationDependencies) { - await app.whenReady(); - const log = prepareLogger(); - - await prepareHostEnvironment({ logger: log }); - - const db = prepareDatabase({ - profileDir: deps.profileDir, - appDatabaseFactory: deps.appDatabaseFactory, - initSigningKey: deps.initSigningKey, - }); - - const apiServerRef = { current: null as AgentApiServer | null }; - const browserManagerRef = { current: null as BrowserManager | null }; - - const services = prepareServices({ - db, - apiServerRef, - browserManagerRef, - isQuittingRef: deps.isQuittingRef, - preloadPath: deps.preloadPath, - rendererDist: deps.rendererDist, - iconPath: deps.iconPath, - isDev: deps.isDev, - devServerUrl: deps.devServerUrl, - devServerOrigin: deps.devServerOrigin, - windowStatePath: deps.windowStatePath, - workerPath: deps.workerPath, - logger: log, - createRunToken: deps.createRunToken, - seedDefaultAutomationRules: deps.seedDefaultAutomationRules, - }); - const { serviceGraph, ipcSupport, threadIntegration, notificationService, checkpointEngine, notify, emitEvent, publishDomainChanged } = services; - - const wakeAgentIfPossible = (agentId: string | null | undefined, companyId: string, trigger: string) => { - const orchestration = serviceGraph.getOrchestrationService(); - if (!orchestration) throw new Error("Orchestration service is not initialized."); - return orchestration.wakeAgentIfPossible(agentId, companyId, trigger); - }; - - const lifecycleProcessor = new DocumentLifecycleProcessor( - makeLifecycleProcessorOptions({ db, logger: log }), - ); - registerLifecycleHandlers(lifecycleProcessor, { - dispatchAutomation: (trigger, ctx) => { - const automation = serviceGraph.getAutomationService(); - if (!automation) throw new Error("Automation service is not initialized."); - automation.dispatchAutomation(trigger, ctx); - }, - wakeAgentIfPossible, - }); - - const apiServer = wireApiServer({ - db, - serviceGraph, - threadIntegration, - checkpointEngine, - lifecycleProcessor, - emitEvent, - notify, - publishDomainChanged, - isDev: deps.isDev, - devServerUrl: deps.devServerUrl, - createApiServer: deps.createApiServer, - }); - - apiServerRef.current = apiServer; - await apiServer.start(); - deps.onRuntimeReady?.({ - db, - apiServer, - serviceGraph, - ipcSupport, - threadIntegration, - checkpointEngine, - lifecycleProcessor, - }); - - lifecycleProcessor.start(); - app.on("before-quit", () => lifecycleProcessor.stop()); - - if (apiServer && serviceGraph.getBrowserActionService()) { - apiServer.setBrowserActionHandler((actionId, companyId) => { - const browserActions = serviceGraph.getBrowserActionService(); - if (!browserActions) { - const message = "Browser action service is not initialized."; - log.error(`[browser] ${message} action=${actionId}`); - db.core.social.updateBrowserAction(actionId, { - status: "failed", - resultSummary: "Browser action dispatch failed before execution completed.", - errorMessage: message, - finishedAt: new Date().toISOString(), - }); - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "browser.action_dispatch_failed", - entityType: "browser_action", - entityId: actionId, - detail: message, - }); - publishDomainChanged(); - return; - } - browserActions.queueBrowserActionExecution(actionId, companyId); - }); - } - - const scheduledPostTimers = recoverScheduledPosts({ - db, - logger: log, - isQuittingRef: deps.isQuittingRef, - getBrowserActionService: () => serviceGraph.getBrowserActionService(), - }); - - // One-time backfill: surface deliverables that cognitive runs wrote - // to disk while the projector was suppressed by the pre-observationPath - // bug (regression of T1 workspace fix, repaired in 2c12c1a). Gated by - // a settings flag so subsequent boots skip the workspace walk; the - // post-fix projector handles new file activity inside each run. - backfillWorkspaceArtifacts({ db, logger: log }); - - // Register cleanup for bootstrap-owned resources during quit. - // Runs BEFORE service-graph's onBeforeQuit (which is registered later). - app.on("before-quit", () => { - for (const timer of scheduledPostTimers) clearTimeout(timer); - scheduledPostTimers.clear(); - notificationService.destroy(); - }); - - // Show the window immediately so the user sees the app launch without delay. - await serviceGraph.getDesktopShellService()?.ensureWindow(); - serviceGraph.getAppLifecycleService()?.register(deps.hasSingleInstanceLock); - - // Run connector health checks AFTER the window is visible to unblock startup. - await runStartupHealthChecks(db, serviceGraph.getConnectorHealthService(), log); - - serviceGraph.getOrchestrationService()?.startAllSchedulers(); - - emitCrashRecoveryNotification({ - db, - logger: log, - emitEvent, - notify, - publishDomainChanged, - wakeAgentIfPossible, - }); - - serviceGraph.getOrchestrationService()?.resumeQueuedRuns(); - - recoverShutdownInterruptedTasks({ - db, - logger: log, - emitEvent, - notify, - publishDomainChanged, - wakeAgentIfPossible, - }); - - return { db, apiServer, serviceGraph, ipcSupport, threadIntegration }; -} diff --git a/src/main/bootstrap/backfill-workspace-artifacts.ts b/src/main/bootstrap/backfill-workspace-artifacts.ts deleted file mode 100644 index b52252b3..00000000 --- a/src/main/bootstrap/backfill-workspace-artifacts.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { existsSync, readdirSync, statSync } from "node:fs"; -import { relative, resolve } from "node:path"; -import type { AppDatabase } from "../database"; - -/** - * One-shot rescan that surfaces files written by cognitive runs whose - * artifact projector was suppressed by the pre-`observationPath` bug - * (regression of T1, fixed in commit 2c12c1a). - * - * The post-fix projector observes per-run via mtime baselines. Files - * that already existed on disk before the projector was repaired never - * advance their mtime past the new run's baseline, so they remain - * invisible to subsequent runs — they are real deliverables that the - * DocumentCenter still does not list. This module walks every company - * primary workspace once at startup, applies the same registrability - * filter as `artifact-projector.ts`, and upserts a `work_products` row - * for each file that is missing one. - * - * Idempotent through `findWorkProductByExternalId` — a file that was - * already projected by some earlier run will short-circuit on lookup - * and be skipped. Bounded by `MAX_BACKFILL_FILES_PER_WORKSPACE` so a - * pathological workspace tree cannot lock the bootstrap path. - * - * Gated by a one-time settings flag (`artifact_rescan_v1_done`) so a - * second startup does not re-walk every workspace tree on disk; the - * projector handles all subsequent file activity. - */ - -const SETTINGS_FLAG_KEY = "artifact_rescan_v1_done"; -const MAX_BACKFILL_FILES_PER_WORKSPACE = 5_000; -const SKIP_DIR_NAMES: ReadonlySet = new Set([ - ".git", - "node_modules", - ".next", - "dist", - "build", - "out", - ".cache", - ".pnpm-store", -]); -const IGNORED_PATH_SEGMENTS: readonly string[] = [ - "/.git/", - "/node_modules/", - "/.next/", - "/dist/", - "/build/", - "/out/", - "/.cache/", - "/.pnpm-store/", - "/.DS_Store", -]; -const IGNORED_EXACT_NAMES: ReadonlySet = new Set([ - ".DS_Store", - "package-lock.json", - "pnpm-lock.yaml", - "yarn.lock", - ".gitignore", -]); -const IGNORED_EXTENSIONS: ReadonlySet = new Set([ - ".lock", - ".log", - ".map", - ".min.js", - ".min.css", -]); - -interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; -} - -export interface BackfillWorkspaceArtifactsDeps { - db: AppDatabase; - logger: Logger; -} - -export interface BackfillWorkspaceArtifactsResult { - /** True when the rescan ran (first launch after the fix). */ - ran: boolean; - /** Files inspected across every company workspace. */ - filesScanned: number; - /** Files inserted as work_products (previously missing rows). */ - filesInserted: number; - /** Files skipped because a row already existed (idempotency). */ - filesAlreadyTracked: number; - /** Files skipped by the registrability filter. */ - filesIgnored: number; -} - -export function backfillWorkspaceArtifacts( - deps: BackfillWorkspaceArtifactsDeps, -): BackfillWorkspaceArtifactsResult { - const empty: BackfillWorkspaceArtifactsResult = { - ran: false, - filesScanned: 0, - filesInserted: 0, - filesAlreadyTracked: 0, - filesIgnored: 0, - }; - const flag = deps.db.core.settings.getSetting(SETTINGS_FLAG_KEY); - if (flag === "true") return empty; - - let filesScanned = 0; - let filesInserted = 0; - let filesAlreadyTracked = 0; - let filesIgnored = 0; - - const snapshot = deps.db.projection.snapshot.listSnapshot(); - for (const company of snapshot.companies) { - const observation = deps.db.core.workspaces.getCompanyObservationWorkspace(company.id); - if (!observation) continue; - const workspaceRoot = observation.localPath; - if (!workspaceRoot || !existsSync(workspaceRoot)) continue; - let stat; - try { - stat = statSync(workspaceRoot); - } catch { - continue; - } - if (!stat.isDirectory()) continue; - - const stack: string[] = [workspaceRoot]; - let countForThisWorkspace = 0; - while (stack.length > 0) { - if (countForThisWorkspace >= MAX_BACKFILL_FILES_PER_WORKSPACE) { - deps.logger.warn( - `[backfill-workspace-artifacts] hit per-workspace cap (${MAX_BACKFILL_FILES_PER_WORKSPACE}) for company=${company.id} workspace=${observation.id}; remaining files will be picked up by future runs as they are touched`, - ); - break; - } - const dir = stack.pop(); - if (!dir) break; - let entries: { name: string; isDirectory: () => boolean; isSymbolicLink: () => boolean }[]; - try { - entries = readdirSync(dir, { withFileTypes: true }); - } catch { - continue; - } - for (const entry of entries) { - if (entry.isSymbolicLink()) continue; - const abs = resolve(dir, entry.name); - if (entry.isDirectory()) { - if (SKIP_DIR_NAMES.has(entry.name)) continue; - stack.push(abs); - continue; - } - try { - const fileStat = statSync(abs); - if (!fileStat.isFile()) continue; - } catch { - continue; - } - filesScanned += 1; - countForThisWorkspace += 1; - - const rel = relative(workspaceRoot, abs); - if (rel.length === 0) { - filesIgnored += 1; - continue; - } - const probe = `/${rel}/`; - if (IGNORED_PATH_SEGMENTS.some((seg) => probe.includes(seg))) { - filesIgnored += 1; - continue; - } - const lastSlash = rel.lastIndexOf("/"); - const basename = lastSlash >= 0 ? rel.slice(lastSlash + 1) : rel; - if (IGNORED_EXACT_NAMES.has(basename)) { - filesIgnored += 1; - continue; - } - const dot = basename.lastIndexOf("."); - if (dot > 0) { - const ext = basename.slice(dot).toLowerCase(); - if (IGNORED_EXTENSIONS.has(ext)) { - filesIgnored += 1; - continue; - } - const prevDot = basename.lastIndexOf(".", dot - 1); - if (prevDot > 0) { - const compound = basename.slice(prevDot).toLowerCase(); - if (IGNORED_EXTENSIONS.has(compound)) { - filesIgnored += 1; - continue; - } - } - } - - const existing = deps.db.core.documents.findWorkProductByExternalId( - company.id, - "filesystem", - rel, - observation.id, - ); - if (existing) { - filesAlreadyTracked += 1; - continue; - } - const title = lastSlash >= 0 ? rel.slice(lastSlash + 1) : rel; - deps.db.core.documents.createWorkProduct({ - companyId: company.id, - taskId: null, - workspaceId: observation.id, - type: "file", - provider: "filesystem", - externalId: rel, - title, - url: null, - }); - filesInserted += 1; - } - } - } - - deps.db.core.settings.setSetting(SETTINGS_FLAG_KEY, "true"); - deps.logger.info( - `[backfill-workspace-artifacts] scanned=${filesScanned} inserted=${filesInserted} already-tracked=${filesAlreadyTracked} ignored=${filesIgnored}`, - ); - return { - ran: true, - filesScanned, - filesInserted, - filesAlreadyTracked, - filesIgnored, - }; -} diff --git a/src/main/bootstrap/prepare-database.ts b/src/main/bootstrap/prepare-database.ts deleted file mode 100644 index 992da534..00000000 --- a/src/main/bootstrap/prepare-database.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { AppDatabase } from "../database"; - -export interface PrepareDatabaseDeps { - profileDir: string; - appDatabaseFactory: (profileDir: string) => AppDatabase; - initSigningKey: (profileDir: string) => void; -} - -export function prepareDatabase(deps: PrepareDatabaseDeps): AppDatabase { - const db = deps.appDatabaseFactory(deps.profileDir); - db.init(); - deps.initSigningKey(db.profileDir); - return db; -} diff --git a/src/main/bootstrap/prepare-logger.ts b/src/main/bootstrap/prepare-logger.ts deleted file mode 100644 index a781b3ed..00000000 --- a/src/main/bootstrap/prepare-logger.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { app } from "electron"; -import log from "electron-log/main.js"; - -export function prepareLogger() { - log.initialize(); - log.transports.console.format = "[{h}:{i}:{s}] [{level}] {text}"; - log.transports.file.format = "[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}"; - if (app.isPackaged) { - log.transports.console.level = "warn"; - log.transports.file.level = "info"; - } else { - log.transports.console.level = "info"; - log.transports.file.level = "debug"; - } - return log; -} diff --git a/src/main/bootstrap/prepare-services.ts b/src/main/bootstrap/prepare-services.ts deleted file mode 100644 index d208f752..00000000 --- a/src/main/bootstrap/prepare-services.ts +++ /dev/null @@ -1,142 +0,0 @@ -import type { AgentApiServer } from "../api-server"; -import type { AppDatabase } from "../database"; -import type { BrowserManager } from "../browser-manager"; -import { createServiceGraph } from "../service-graph"; -import { createIpcSupport } from "../ipc-support"; -import { createNotificationService } from "../notification-service"; -import { createThreadIntegration } from "../thread-integration"; -import { createCheckpointEngine } from "../checkpoint-engine"; -import { createRunHousekeeping } from "../run-housekeeping"; -import type { DesktopEvent } from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; - -export interface PrepareServicesDeps { - db: AppDatabase; - apiServerRef: { current: AgentApiServer | null }; - browserManagerRef: { current: BrowserManager | null }; - isQuittingRef: { current: boolean }; - preloadPath: string; - rendererDist: string; - iconPath: string; - isDev: boolean; - devServerUrl?: string; - devServerOrigin: string | null; - windowStatePath: string; - workerPath: string; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - seedDefaultAutomationRules: (companyId: string) => void; -} - -export interface ServiceGraphHandles { - serviceGraph: ReturnType; - ipcSupport: ReturnType; - threadIntegration: ReturnType; - notificationService: ReturnType; - checkpointEngine: ReturnType; - notify: (options: NotificationOptions) => void; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; -} - -export function prepareServices(deps: PrepareServicesDeps): ServiceGraphHandles { - let ipcSupport: ReturnType | null = null; - let serviceGraph: ReturnType | null = null; - - const notificationService = createNotificationService({ - getMainWindow: () => serviceGraph?.getDesktopShellService()?.getMainWindow() ?? null, - emitEvent: (event: DesktopEvent) => ipcSupport?.emitEvent(event), - logger: deps.logger, - }); - - const notify = (options: NotificationOptions) => { - if (!ipcSupport) { - throw new Error("IPC support is not initialized."); - } - ipcSupport.notify(options); - }; - const emitEvent = (event: DesktopEvent) => ipcSupport?.emitEvent(event); - const publishDomainChanged = () => ipcSupport?.publishDomainChanged(); - - const threadIntegration = createThreadIntegration({ - db: deps.db, - logger: deps.logger, - emitEvent, - publishDomainChanged, - notify: (options) => notify({ ...options, urgency: "informational" }), - }); - const checkpointEngine = createCheckpointEngine({ - db: deps.db, - logger: deps.logger, - threadIntegration, - publishDomainChanged, - notify, - }); - const runHousekeeping = createRunHousekeeping({ - db: deps.db, - logger: deps.logger, - threadIntegration, - }); - - serviceGraph = createServiceGraph({ - db: deps.db, - apiServerRef: deps.apiServerRef, - browserManagerRef: deps.browserManagerRef, - isQuittingRef: deps.isQuittingRef, - preloadPath: deps.preloadPath, - rendererDist: deps.rendererDist, - iconPath: deps.iconPath, - isDev: deps.isDev, - devServerUrl: deps.devServerUrl, - windowStatePath: deps.windowStatePath, - workerPath: deps.workerPath, - logger: deps.logger, - emitEvent, - publishDomainChanged, - notify, - createRunToken: deps.createRunToken, - seedDefaultAutomationRules: deps.seedDefaultAutomationRules, - onRunStarted: (runId, taskId, agentId, companyId) => - threadIntegration.onRunStarted(runId, taskId, agentId, companyId), - onRunCompleted: (runId, taskId, agentId, companyId, status, summary, errorMessage) => - runHousekeeping.onRunCompleted(runId, taskId, agentId, companyId, status, summary, errorMessage), - checkpointEngine, - // Lazy forwarder — ipcSupport is constructed below but only invoked - // inside serviceGraph.init(), which runs after that point. - registerHandle: (channel, handler) => { - if (!ipcSupport) { - throw new Error("IPC support is not initialized."); - } - ipcSupport.registerHandle(channel, handler); - }, - }); - ipcSupport = createIpcSupport({ - isDev: deps.isDev, - devServerOrigin: deps.devServerOrigin, - logger: deps.logger, - getMainWindow: () => serviceGraph?.getDesktopShellService()?.getMainWindow() ?? null, - getDb: () => ({ - hasCompany: (companyId: string) => deps.db.core.settings.hasCompany(companyId), - belongsToCompany: (table: string, id: string, companyId: string) => - deps.db.core.settings.belongsToCompany(table as Parameters[0], id, companyId), - }), - notificationService, - }); - serviceGraph.init(); - - return { - serviceGraph, - ipcSupport, - threadIntegration, - notificationService, - checkpointEngine, - notify, - emitEvent, - publishDomainChanged, - }; -} diff --git a/src/main/bootstrap/recover-interrupted-tasks.ts b/src/main/bootstrap/recover-interrupted-tasks.ts deleted file mode 100644 index ac1c11f4..00000000 --- a/src/main/bootstrap/recover-interrupted-tasks.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DesktopEvent } from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; - -interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; -} - -export interface RecoverInterruptedTasksDeps { - db: AppDatabase; - logger: Logger; - emitEvent: (event: DesktopEvent) => void; - notify: (options: NotificationOptions) => void; - publishDomainChanged: () => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; -} - -/** Emit the session-recovery notification for runs interrupted by crash. */ -export function emitCrashRecoveryNotification(deps: RecoverInterruptedTasksDeps): void { - const interruptedCount = deps.db.lastInterruptedCount; - if (interruptedCount <= 0) return; - deps.logger.warn(`[bootstrap] Detected ${interruptedCount} interrupted runs from previous session. Sending recovery notification.`); - const interruptedRuns = deps.db.core.runs.getInterruptedRunsForRecovery(); - if (interruptedRuns.length === 0) return; - deps.emitEvent({ type: "recovery-needed", interruptedRuns }); - deps.notify({ - title: "Session Recovered", - body: `${interruptedRuns.length} interrupted task(s) detected from previous session`, - urgency: "informational", - navigation: { section: "overview" }, - }); -} - -/** - * Resume tasks interrupted by a clean shutdown. worker-service marks running/ - * queued runs as `interrupted` on destroy but does not reset the tasks; without - * this recovery the assigned agents never re-wake to continue them. - */ -export function recoverShutdownInterruptedTasks(deps: RecoverInterruptedTasksDeps): void { - try { - const snapshot = deps.db.projection.snapshot.listSnapshot(); - const shutdownRuns = snapshot.runs.filter( - (r) => r.status === "interrupted" && - (r.summary === "Application shut down." || r.summary === "Worker process crashed."), - ); - if (shutdownRuns.length === 0) return; - const resumedAgents = new Set(); - for (const run of shutdownRuns) { - try { - if (run.taskId) { - const task = deps.db.core.entity.getTask(run.taskId); - if (task.status === "in_progress" || task.status === "blocked") { - deps.db.core.tasks.advanceTaskStatus(run.taskId, "todo", "Auto-resumed after app restart."); - deps.db.core.tasks.releaseTaskLock(run.taskId, run.id); - } - } - if (!resumedAgents.has(run.agentId)) { - resumedAgents.add(run.agentId); - deps.wakeAgentIfPossible(run.agentId, run.companyId, "app_restart_resume"); - } - } catch (error) { - deps.logger.warn(`[bootstrap] Skipped shutdown recovery for run ${run.id} (task/agent may have been deleted):`, error); - } - } - if (resumedAgents.size > 0) { - deps.logger.info(`[bootstrap] Resumed ${shutdownRuns.length} interrupted task(s) across ${resumedAgents.size} agent(s) after clean shutdown recovery.`); - deps.publishDomainChanged(); - } - } catch (err) { - deps.logger.warn(`[bootstrap] Shutdown recovery failed: ${err instanceof Error ? err.message : String(err)}`); - } -} diff --git a/src/main/bootstrap/recover-scheduled-posts.ts b/src/main/bootstrap/recover-scheduled-posts.ts deleted file mode 100644 index 1d901715..00000000 --- a/src/main/bootstrap/recover-scheduled-posts.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { AppDatabase } from "../database"; - -interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; -} - -export interface RecoverScheduledPostsDeps { - db: AppDatabase; - logger: Logger; - isQuittingRef: { current: boolean }; - getBrowserActionService: () => { queueBrowserActionExecution: (actionId: string, companyId: string) => void } | null; -} - -export function recoverScheduledPosts(deps: RecoverScheduledPostsDeps): Set> { - const timers = new Set>(); - try { - const snapshot = deps.db.projection.snapshot.listSnapshot(); - for (const company of snapshot.companies) { - const queuedActions = deps.db.core.social.listBrowserActions(company.id, { status: "queued" }); - for (const action of queuedActions) { - if (!action.payloadJson) continue; - try { - const payload = JSON.parse(action.payloadJson) as { scheduledAt?: string }; - if (!payload.scheduledAt) continue; - const delay = new Date(payload.scheduledAt).getTime() - Date.now(); - if (delay <= 0) continue; - const timer = setTimeout(() => { - timers.delete(timer); - if (deps.isQuittingRef.current) return; - const browserActions = deps.getBrowserActionService(); - if (browserActions) { - browserActions.queueBrowserActionExecution(action.id, company.id); - } - }, delay); - timers.add(timer); - deps.logger.info(`[bootstrap] Re-registered scheduled post timer: action ${action.id} in ${Math.round(delay / 1000)}s`); - } catch (error) { - deps.logger.warn( - `[bootstrap] malformed scheduled-post payload for action ${action.id}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - } - } catch (error) { - deps.logger.warn(`[bootstrap] Failed to re-register scheduled post timers: ${error instanceof Error ? error.message : String(error)}`); - } - return timers; -} diff --git a/src/main/bootstrap/run-startup-health-checks.ts b/src/main/bootstrap/run-startup-health-checks.ts deleted file mode 100644 index 6491ac75..00000000 --- a/src/main/bootstrap/run-startup-health-checks.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { createConnectorHealthService } from "../connector-health-service"; - -interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; -} - -type ConnectorHealthService = ReturnType; - -export async function runStartupHealthChecks( - db: AppDatabase, - connectorHealth: ConnectorHealthService | null | undefined, - logger: Logger, -): Promise { - if (!connectorHealth) return; - const connectors = db.projection.snapshot.listSnapshot().connectors; - const results = await Promise.allSettled( - connectors.map((connector) => connectorHealth.checkConnector(connector.id)), - ); - for (let i = 0; i < results.length; i++) { - const result = results[i]!; - if (result.status === "rejected") { - logger.warn(`[bootstrap] Connector health check failed for ${connectors[i]?.id}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`); - } - } - logger.info(`[bootstrap] Connector health checks completed (${results.filter((r) => r.status === "fulfilled").length}/${connectors.length} succeeded)`); -} diff --git a/src/main/bootstrap/wire-api-server.ts b/src/main/bootstrap/wire-api-server.ts deleted file mode 100644 index bdd64008..00000000 --- a/src/main/bootstrap/wire-api-server.ts +++ /dev/null @@ -1,143 +0,0 @@ -import log from "electron-log/main.js"; -import type { AgentApiServer, ApiServerEventCallbacks } from "../api-server"; -import type { AppDatabase } from "../database"; -import type { DesktopEvent } from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; -import type { createServiceGraph } from "../service-graph"; -import type { createThreadIntegration } from "../thread-integration"; -import type { createCheckpointEngine } from "../checkpoint-engine"; -import type { AutomationEventContext } from "../automation/types"; -import { createDocumentWithLifecycle } from "../document-lifecycle"; -import type { DocumentLifecycleProcessor } from "../document-lifecycle-processor"; - -type ServiceGraph = ReturnType; -type ThreadIntegration = ReturnType; -type CheckpointEngine = ReturnType; - -export interface CreateApiServerFn { - (db: AppDatabase, callbacks: ApiServerEventCallbacks, allowedOrigins: string[]): AgentApiServer; -} - -export interface WireApiServerDeps { - db: AppDatabase; - serviceGraph: ServiceGraph; - threadIntegration: ThreadIntegration; - checkpointEngine: CheckpointEngine; - lifecycleProcessor: DocumentLifecycleProcessor; - emitEvent: (event: DesktopEvent) => void; - notify: (options: NotificationOptions) => void; - publishDomainChanged: () => void; - isDev: boolean; - devServerUrl?: string; - createApiServer: CreateApiServerFn; -} - -export function wireApiServer(deps: WireApiServerDeps): AgentApiServer { - const wakeAgentIfPossible = (agentId: string | null | undefined, companyId: string, trigger: string) => { - const orchestration = deps.serviceGraph.getOrchestrationService(); - if (!orchestration) throw new Error("Orchestration service is not initialized."); - return orchestration.wakeAgentIfPossible(agentId, companyId, trigger); - }; - const dispatchAutomation = (trigger: string, ctx: AutomationEventContext) => { - const automation = deps.serviceGraph.getAutomationService(); - if (!automation) throw new Error("Automation service is not initialized."); - automation.dispatchAutomation(trigger, ctx); - }; - - const onTaskCreated = (taskId: string, companyId: string) => { - const automation = deps.serviceGraph.getAutomationService(); - if (!automation) throw new Error("Automation service is not initialized."); - automation.handleTaskCreated(taskId, companyId); - deps.threadIntegration.onTaskCreated(taskId, companyId); - }; - const onTaskStatusChanged = (taskId: string, companyId: string, prev: string, next: string) => { - const automation = deps.serviceGraph.getAutomationService(); - if (!automation) throw new Error("Automation service is not initialized."); - automation.handleTaskStatusChange(taskId, companyId, prev, next); - deps.threadIntegration.onTaskStatusChanged(taskId, companyId, prev, next); - if (prev === "todo" && next === "in_progress") { - try { - const task = deps.db.core.entity.getTask(taskId); - deps.checkpointEngine.onTaskStarted(taskId, companyId, task.assigneeAgentId); - } catch (error) { - log.warn( - `[wire-api-server] checkpointEngine.onTaskStarted failed for task ${taskId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - }; - const onApprovalResolved = (approvalId: string, companyId: string, decision: string) => { - const automation = deps.serviceGraph.getAutomationService(); - if (!automation) throw new Error("Automation service is not initialized."); - automation.handleApprovalResolved(approvalId, companyId, decision); - deps.threadIntegration.onApprovalResolved(approvalId, companyId, decision); - }; - const onApprovalCreated = ( - approvalId: string, - companyId: string, - taskId: string | null, - approvalType: string, - summary: string, - ) => { - deps.threadIntegration.onApprovalCreated(approvalId, companyId, taskId, approvalType, summary); - }; - - // Cross-wire the same callbacks into the pi runtime bridge so the - // internal-tool path (C4) triggers identical thread/automation - // notifications as the HTTP route. - const piRuntime = deps.serviceGraph.getPiRuntime(); - if (!piRuntime) { - throw new Error("Pi runtime is not initialized; cannot wire internal-tool callbacks."); - } - piRuntime.runtimeBridge.setInternalToolCallbacks({ - onApprovalCreated, - onApprovalResolved, - onDomainChanged: deps.publishDomainChanged, - }); - - const allowedOrigins = [deps.isDev && deps.devServerUrl ? new URL(deps.devServerUrl).origin : null, "app://-"] - .filter((origin): origin is string => Boolean(origin)); - - return deps.createApiServer(deps.db, { - onDomainChanged: deps.publishDomainChanged, - onWakeAgent: (agentId, companyId, trigger) => wakeAgentIfPossible(agentId, companyId, trigger), - onTaskCreated, - onTaskStatusChanged, - onCommentPosted: (taskId, companyId, authorAgentId) => { - dispatchAutomation("comment_posted", { companyId, taskId, agentId: authorAgentId ?? undefined }); - }, - onApprovalCreated, - onApprovalResolved, - createDocument: (input) => - createDocumentWithLifecycle( - { - db: deps.db, - threadIntegration: deps.threadIntegration, - checkpointEngine: deps.checkpointEngine, - lifecycleProcessor: deps.lifecycleProcessor, - publishDomainChanged: deps.publishDomainChanged, - logger: log, - }, - input, - ), - onAutoAssignTask: (taskId, companyId) => deps.db.core.tasks.autoAssignTask(taskId, companyId), - onHumanMessage: (companyId, toAgentId, threadId, waitStateId) => { - deps.threadIntegration.onHumanMessage(companyId, toAgentId, threadId, waitStateId); - deps.publishDomainChanged(); - }, - injectRuntimeMessage: (recipientAgentId, companyId, message) => { - const injector = deps.serviceGraph.getRuntimeMessageInjector(); - if (!injector) return false; - try { - return injector.tryInject(recipientAgentId, companyId, message); - } catch (error) { - log.warn( - `[wire-api-server] runtime message injection failed for agent ${recipientAgentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return false; - } - }, - emitEvent: deps.emitEvent, - notify: deps.notify, - }, allowedOrigins); -} diff --git a/src/main/boss-seed.ts b/src/main/boss-seed.ts deleted file mode 100644 index 71771385..00000000 --- a/src/main/boss-seed.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Empty in the public build. The Boss edition build (`boss-build/build-boss-edition.mjs`) -// rewrites this literal at package time to embed the Fireworks Fire Pass API -// key so the onboarding card boots in the "active" state without any user -// interaction. `database-base.init()` reads the constant and, when non-empty, -// seeds both the credentials table and the connector envBindingText in a single -// pass. -export const BOSS_FIREWORKS_API_KEY: string = ""; diff --git a/src/main/browser-action-service.ts b/src/main/browser-action-service.ts deleted file mode 100644 index 6342f597..00000000 --- a/src/main/browser-action-service.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { join } from "node:path"; -import log from "electron-log/main.js"; -import type { AppDatabase } from "./database"; -import { BrowserManager } from "./browser-manager"; -import { classifyUnknownError, logAppError } from "./errors/index.js"; - -interface BrowserActionDependencies { - db: AppDatabase; - browserManagerRef: { current: BrowserManager | null }; - publishDomainChanged: () => void; -} - -export function createBrowserActionService({ - db, - browserManagerRef, - publishDomainChanged, -}: BrowserActionDependencies) { - function requireBrowserManager() { - if (!browserManagerRef.current) { - throw new Error("Browser manager is not initialized."); - } - return browserManagerRef.current; - } - - function formatError(error: unknown): string { - return error instanceof Error ? error.message : String(error); - } - - function recordDispatchFailure(actionId: string, companyId: string, error: unknown) { - const message = formatError(error); - logAppError(log, error, { - kind: "upstream", - code: "browser_action.dispatch.failed", - message: `Browser action ${actionId} dispatch failed`, - cause: error, - context: { actionId, companyId }, - }); - - const action = db.core.social.getBrowserAction(actionId, companyId); - if (action && (action.status === "queued" || action.status === "running")) { - db.core.social.updateBrowserAction(actionId, { - status: "failed", - resultSummary: "Browser action dispatch failed before execution completed.", - errorMessage: message, - finishedAt: new Date().toISOString(), - }); - } - db.core.activity.addActivity({ - companyId, - actor: action?.agentId ?? "system", - action: "browser.action_dispatch_failed", - entityType: "browser_action", - entityId: actionId, - detail: message, - }); - log.info("[browser] action dispatch telemetry", { - actionId, - companyId, - final_outcome: "dispatch_failed", - error: message, - }); - publishDomainChanged(); - } - - function queueBrowserActionExecution(actionId: string, companyId: string): void { - void dispatchBrowserAction(actionId, companyId).catch((error) => { - try { - recordDispatchFailure(actionId, companyId, error); - } catch (recordError) { - logAppError(log, recordError, { - kind: "fatal", - code: "browser_action.dispatch_failure_record.failed", - message: `Failed to record browser action ${actionId} dispatch failure`, - cause: recordError, - context: { actionId, companyId, dispatchError: formatError(error) }, - }); - } - }); - } - - async function dispatchBrowserAction(actionId: string, companyId: string) { - const action = db.core.social.getBrowserAction(actionId, companyId); - if (!action) { - throw new Error(`Browser action not found: ${actionId}`); - } - if (action.status !== "queued") { - throw new Error(`Browser action ${actionId} is ${action.status} and cannot be dispatched.`); - } - if (action.approvalId) { - const approval = db.core.approvals.getApprovalRecord(action.approvalId); - if (!approval || approval.companyId !== companyId) { - throw new Error(`Browser action approval ${action.approvalId} does not belong to company ${companyId}.`); - } - if (approval.state !== "approved") { - db.core.social.updateBrowserAction(actionId, { - status: "approval_required", - resultSummary: "Browser action is still waiting for approval.", - errorMessage: "Approval must be granted before execution.", - }); - publishDomainChanged(); - return; - } - } - - const account = db.core.social.getSocialAccount(action.socialAccountId, companyId); - if (!account) { - db.core.social.updateBrowserAction(actionId, { - status: "failed", - errorMessage: "Social account no longer exists.", - finishedAt: new Date().toISOString(), - }); - publishDomainChanged(); - return; - } - - let payload: Record; - try { - payload = JSON.parse(action.payloadJson) as Record; - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "user_input", - code: "browser_action.payload.invalid_json", - message: `Browser action ${actionId} has invalid JSON payload`, - context: { actionId }, - }); - log.warn(`[${classified.code}]`, classified.message, classified.context); - db.core.social.updateBrowserAction(actionId, { - status: "failed", - errorMessage: "Browser action payload is not valid JSON.", - finishedAt: new Date().toISOString(), - }); - publishDomainChanged(); - return; - } - - db.core.social.updateBrowserAction(actionId, { - status: "running", - startedAt: new Date().toISOString(), - errorMessage: null, - }); - publishDomainChanged(); - - try { - const result = await requireBrowserManager().executeAction({ - id: actionId, - socialAccountId: account.id, - platform: account.platform, - actionType: action.actionType, - payload, - }); - - db.core.social.updateBrowserAction(actionId, { - status: result.cancelled ? "cancelled" : result.success ? "succeeded" : "failed", - resultSummary: result.summary, - screenshotPath: result.screenshotPath, - errorMessage: result.error, - finishedAt: new Date().toISOString(), - }); - } catch (error) { - db.core.social.updateBrowserAction(actionId, { - status: "failed", - errorMessage: error instanceof Error ? error.message : String(error), - finishedAt: new Date().toISOString(), - }); - } - - publishDomainChanged(); - } - - async function clearSocialAccountData(socialAccountId: string, screenshotPaths: string[] = []) { - if (!browserManagerRef.current) { - return; - } - await browserManagerRef.current.clearSocialAccountData(socialAccountId, screenshotPaths); - } - - function cancelAction(actionId: string) { - return browserManagerRef.current?.cancelAction(actionId) ?? false; - } - - async function launchLoginBrowser(socialAccountId: string, platform: string, loginUrl?: string) { - return requireBrowserManager().launchLoginBrowser(socialAccountId, platform, loginUrl); - } - - async function resetBrowserManager() { - await browserManagerRef.current?.shutdown(); - browserManagerRef.current = new BrowserManager(join(db.artifactsDir, "browser")); - } - - async function extractProfileFromSession(socialAccountId: string, platform: string) { - return requireBrowserManager().extractProfileFromSession(socialAccountId, platform); - } - - return { - dispatchBrowserAction, - queueBrowserActionExecution, - clearSocialAccountData, - cancelAction, - launchLoginBrowser, - extractProfileFromSession, - resetBrowserManager, - }; -} diff --git a/src/main/browser-manager.ts b/src/main/browser-manager.ts deleted file mode 100644 index 5514ff73..00000000 --- a/src/main/browser-manager.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { BrowserWindow, session } from "electron"; -import { existsSync, mkdirSync } from "node:fs"; -import { readdir, rm, stat } from "node:fs/promises"; -import { join, resolve, sep } from "node:path"; -import log from "electron-log/main.js"; -import type { BrowserAction, BrowserActionResult, QueuedAction } from "./browser/browser-types"; -import { getPlatformRules, attachWindowSecurity, assertAllowedUrl, waitForLoad, runAction } from "./browser/browser-action-executor"; -import { hasAuthenticatedCookie } from "./browser/browser-action-auth"; - -export type { BrowserAction, BrowserActionResult } from "./browser/browser-types"; - -/** - * Hard ceiling for a single browser action end-to-end (navigation, screenshot, - * login verification, scripted DOM interaction). A hung page would otherwise - * block every queued action for the same account forever; the renderer cannot - * be trusted to always call `cancelAction`. Five minutes matches the longest - * legitimate flow (first-time OAuth with 2FA). - */ -const ACTION_TIMEOUT_MS = 5 * 60 * 1000; -const SCREENSHOT_RETENTION_MS = 7 * 24 * 60 * 60 * 1000; - -export class BrowserManager { - private screenshotDir: string; - private queues = new Map(); - private processing = new Set(); - private loginWindows = new Map(); - private initializedSessions = new Set(); - private activeActionWindows = new Map(); - private cancelledActionIds = new Set(); - - constructor(profileDir: string) { - this.screenshotDir = join(profileDir, "browser-screenshots"); - if (!existsSync(this.screenshotDir)) mkdirSync(this.screenshotDir, { recursive: true }); - void this.pruneExpiredScreenshots(); - } - - private async pruneExpiredScreenshots() { - const cutoff = Date.now() - SCREENSHOT_RETENTION_MS; - try { - const entries = await readdir(this.screenshotDir, { withFileTypes: true }); - await Promise.all(entries - .filter((entry) => entry.isFile() && entry.name.endsWith(".png")) - .map(async (entry) => { - const screenshotPath = join(this.screenshotDir, entry.name); - const fileStat = await stat(screenshotPath); - if (fileStat.mtimeMs < cutoff) { - await rm(screenshotPath, { force: true }); - } - })); - } catch (error) { - log.warn(`[browser] Failed to prune expired screenshots: ${error instanceof Error ? error.message : String(error)}`); - } - } - - private getSession(socialAccountId: string): Electron.Session { - const partition = `persist:social-${socialAccountId}`; - const socialSession = session.fromPartition(partition); - if (!this.initializedSessions.has(partition)) { - socialSession.setPermissionCheckHandler(() => false); - socialSession.setPermissionRequestHandler((_webContents, _permission, callback) => callback(false)); - this.initializedSessions.add(partition); - } - return socialSession; - } - - async clearSocialAccountData(socialAccountId: string, screenshotPaths: string[] = []) { - const existing = this.loginWindows.get(socialAccountId); - if (existing && !existing.isDestroyed()) { - existing.close(); - } - this.loginWindows.delete(socialAccountId); - this.queues.delete(socialAccountId); - this.processing.delete(socialAccountId); - - const ses = this.getSession(socialAccountId); - try { - await ses.clearStorageData(); - await ses.clearCache(); - await ses.clearAuthCache(); - } catch (error) { - log.warn(`[browser] Failed to fully clear session for ${socialAccountId}: ${error instanceof Error ? error.message : String(error)}`); - } - - const resolvedRoot = resolve(this.screenshotDir); - await Promise.all( - screenshotPaths - .filter((entry): entry is string => typeof entry === "string" && entry.length > 0) - .filter((screenshotPath) => { - const resolvedPath = resolve(screenshotPath); - return resolvedPath === resolvedRoot || resolvedPath.startsWith(`${resolvedRoot}${sep}`); - }) - .map((screenshotPath) => rm(screenshotPath, { force: true }).catch(() => undefined)), - ); - } - - async launchLoginBrowser( - socialAccountId: string, - platform: string, - loginUrl?: string, - ): Promise { - const existing = this.loginWindows.get(socialAccountId); - if (existing && !existing.isDestroyed()) { - existing.focus(); - return { success: true, cancelled: false, summary: "Login window already open", screenshotPath: null, error: null }; - } - - const rules = getPlatformRules(platform); - const url = loginUrl || rules.loginUrl; - const ses = this.getSession(socialAccountId); - - assertAllowedUrl(platform, url, "login"); - - log.info(`[browser] Opening login window for ${platform} → ${url}`); - - const win = new BrowserWindow({ - width: 1280, - height: 860, - title: `Login to ${platform} — AgentCompany`, - webPreferences: { - session: ses, - nodeIntegration: false, - contextIsolation: true, - sandbox: true, - }, - }); - - this.loginWindows.set(socialAccountId, win); - attachWindowSecurity(win, platform); - - win.setMenuBarVisibility(false); - - try { - await win.loadURL(url); - } catch (err) { - log.error(`[browser] Failed to load ${url}: ${err}`); - } - - return new Promise((resolve) => { - win.on("closed", () => { - this.loginWindows.delete(socialAccountId); - void this.verifyLoginSession(socialAccountId, platform).then((verified) => { - log.info(`[browser] Login window closed for ${platform} — verified=${verified}`); - resolve({ - success: verified, - cancelled: false, - summary: verified - ? `Authenticated session detected for ${platform}` - : `No authenticated ${platform} session detected`, - screenshotPath: null, - error: verified ? null : `Authentication for ${platform} was not completed.`, - }); - }); - }); - }); - } - - async executeAction(action: BrowserAction): Promise { - return new Promise((resolve, reject) => { - const queue = this.queues.get(action.socialAccountId) ?? []; - queue.push({ action, resolve, reject }); - this.queues.set(action.socialAccountId, queue); - void this.processQueue(action.socialAccountId); - }); - } - - cancelAction(actionId: string): boolean { - this.cancelledActionIds.add(actionId); - const activeWindow = this.activeActionWindows.get(actionId); - if (activeWindow && !activeWindow.isDestroyed()) { - activeWindow.close(); - return true; - } - - for (const [socialAccountId, queue] of this.queues.entries()) { - const index = queue.findIndex((item) => item.action.id === actionId); - if (index < 0) { - continue; - } - const [item] = queue.splice(index, 1); - item?.resolve({ - success: false, - cancelled: true, - summary: "Action cancelled before execution.", - screenshotPath: null, - error: "Action cancelled.", - }); - if (queue.length === 0) { - this.queues.delete(socialAccountId); - } - return true; - } - - return false; - } - - private async processQueue(socialAccountId: string) { - if (this.processing.has(socialAccountId)) return; - const queue = this.queues.get(socialAccountId); - if (!queue || queue.length === 0) return; - - this.processing.add(socialAccountId); - try { - while (queue.length > 0) { - const item = queue.shift()!; - try { - const result = await this.runActionWithDeadline(item.action); - item.resolve(result); - } catch (error) { - item.reject(error instanceof Error ? error : new Error(String(error))); - } - } - } finally { - this.processing.delete(socialAccountId); - if ((this.queues.get(socialAccountId)?.length ?? 0) === 0) { - this.queues.delete(socialAccountId); - } - } - } - - private runActionWithDeadline(action: BrowserAction): Promise { - return new Promise((resolve, reject) => { - let settled = false; - const timer = setTimeout(() => { - if (settled) return; - settled = true; - this.cancelledActionIds.add(action.id); - const activeWindow = this.activeActionWindows.get(action.id); - if (activeWindow && !activeWindow.isDestroyed()) { - activeWindow.close(); - } - this.activeActionWindows.delete(action.id); - log.warn(`[browser] action ${action.id} exceeded ${ACTION_TIMEOUT_MS}ms timeout`); - resolve({ - success: false, - cancelled: true, - summary: "Action timed out and was cancelled.", - screenshotPath: null, - error: "Action timed out.", - }); - }, ACTION_TIMEOUT_MS); - - runAction( - action, - this.screenshotDir, - this.getSession(action.socialAccountId), - this.cancelledActionIds, - this.activeActionWindows, - ).then( - (result) => { - if (settled) return; - settled = true; - clearTimeout(timer); - resolve(result); - }, - (error) => { - if (settled) return; - settled = true; - clearTimeout(timer); - reject(error instanceof Error ? error : new Error(String(error))); - }, - ); - }); - } - - private async verifyLoginSession(socialAccountId: string, platform: string): Promise { - const ses = this.getSession(socialAccountId); - const rules = getPlatformRules(platform); - const cookieSets = await Promise.all( - rules.cookieOrigins.map(async (origin) => { - try { - return await ses.cookies.get({ url: origin }); - } catch (err) { - log.warn(`[browser-manager] cookies.get failed for origin ${origin}:`, err instanceof Error ? err.message : String(err)); - return []; - } - }), - ); - const hasCookies = hasAuthenticatedCookie(cookieSets, rules.authenticatedCookieNames); - if (!hasCookies) { - return false; - } - - const verificationWindow = new BrowserWindow({ - show: false, - webPreferences: { - session: ses, - nodeIntegration: false, - contextIsolation: true, - sandbox: true, - }, - }); - - try { - await verificationWindow.loadURL(rules.authCheckUrl); - await waitForLoad(verificationWindow, 10000); - const finalUrl = verificationWindow.webContents.getURL(); - const finalUrlLower = finalUrl.toLowerCase(); - const bouncedToLogin = rules.unauthenticatedUrlMarkers.some((marker) => finalUrlLower.includes(marker.toLowerCase())); - return !bouncedToLogin; - } catch (error) { - log.warn(`[browser] Login verification failed for ${platform}: ${error instanceof Error ? error.message : String(error)}`); - return false; - } finally { - if (!verificationWindow.isDestroyed()) { - verificationWindow.close(); - } - } - } - - async extractProfileFromSession(socialAccountId: string, platform: string): Promise<{ accountName: string; displayName: string }> { - const ses = this.getSession(socialAccountId); - const win = new BrowserWindow({ - show: false, - webPreferences: { session: ses, nodeIntegration: false, contextIsolation: true, sandbox: true }, - }); - - try { - const rules = getPlatformRules(platform); - await win.loadURL(rules.authCheckUrl); - await waitForLoad(win, 12000); - const result = await win.webContents.executeJavaScript(` - (() => { - const meta = document.querySelector('meta[property="al:ios:url"], meta[name="user-login"], meta[property="profile:username"]'); - if (meta) return { accountName: meta.getAttribute("content") || "", displayName: "" }; - const title = document.title || ""; - return { accountName: "", displayName: title.split(/[|–—\\-/]/).map(s => s.trim()).find(s => s.length > 0 && s.length < 40) || "" }; - })() - `); - return result && (result.accountName || result.displayName) ? result : { accountName: "", displayName: "" }; - } catch (err) { - log.warn(`[browser-manager] extractProfileFromSession evaluation failed:`, err instanceof Error ? err.message : String(err)); - return { accountName: "", displayName: "" }; - } finally { - if (!win.isDestroyed()) win.close(); - } - } - - async shutdown() { - // Wait for each pending window-close to finish so any callers that chain - // `await shutdown()` before recreating the manager don't observe torn - // state (half-closed login windows still holding a partition). - const closePromises: Promise[] = []; - for (const [, win] of this.loginWindows) { - if (!win.isDestroyed()) { - closePromises.push( - new Promise((resolve) => { - win.once("closed", () => resolve()); - win.close(); - }), - ); - } - } - await Promise.all(closePromises); - this.loginWindows.clear(); - this.activeActionWindows.clear(); - this.cancelledActionIds.clear(); - this.queues.clear(); - this.processing.clear(); - } -} diff --git a/src/main/browser/browser-action-auth.ts b/src/main/browser/browser-action-auth.ts deleted file mode 100644 index 81aca311..00000000 --- a/src/main/browser/browser-action-auth.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { Session } from "electron"; -import { browserNotLoggedIn } from "./browser-action-errors"; -import { getPlatformRules } from "./browser-url-helpers"; - -type CookieLike = { - name?: string; -}; - -export async function assertAuthenticatedSession( - session: Pick, - platform: string, - actionType: string, -): Promise { - const rules = getPlatformRules(platform); - const cookieSets = await Promise.all( - rules.cookieOrigins.map((origin) => session.cookies.get({ url: origin }).catch(() => [])), - ); - if (!hasAuthenticatedCookie(cookieSets, rules.authenticatedCookieNames)) { - throw browserNotLoggedIn(platform, actionType); - } -} - -export function hasAuthenticatedCookie( - cookieSets: readonly (readonly CookieLike[])[], - authenticatedCookieNames?: readonly string[], -): boolean { - if (!authenticatedCookieNames || authenticatedCookieNames.length === 0) { - return cookieSets.some((cookies) => cookies.length > 0); - } - const expectedNames = new Set(authenticatedCookieNames.map((name) => name.toLowerCase())); - return cookieSets.some((cookies) => - cookies.some((cookie) => cookie.name && expectedNames.has(cookie.name.toLowerCase())), - ); -} - -export async function assertAuthenticatedPage( - getUrl: () => string, - platform: string, - actionType: string, -): Promise { - const finalUrl = getUrl().toLowerCase(); - const rules = getPlatformRules(platform); - const bouncedToLogin = rules.unauthenticatedUrlMarkers.some((marker) => - finalUrl.includes(marker.toLowerCase()), - ); - if (bouncedToLogin) { - throw browserNotLoggedIn(platform, actionType); - } -} diff --git a/src/main/browser/browser-action-cdp.ts b/src/main/browser/browser-action-cdp.ts deleted file mode 100644 index 57721abf..00000000 --- a/src/main/browser/browser-action-cdp.ts +++ /dev/null @@ -1,251 +0,0 @@ -import type { WebContents } from "electron"; -import { browserNotLoggedIn, browserSelectorDrift, browserVerificationFailed } from "./browser-action-errors"; -import { isAppError } from "../errors/index.js"; - -type RuntimeEvaluateResult = { - result?: { value?: unknown }; - exceptionDetails?: { text?: string }; -}; - -type ElementProbe = { - selector: string; - x: number; - y: number; - text: string; -}; - -const POLL_INTERVAL_MS = 250; - -export class BrowserCdpClient { - private attachedByClient = false; - private retryCount = 0; - - constructor( - private readonly webContents: WebContents, - private readonly platform: string, - private readonly actionType: string, - ) {} - - async attach(): Promise { - if (this.webContents.debugger.isAttached()) return; - this.webContents.debugger.attach("1.3"); - this.attachedByClient = true; - } - - async dispose(): Promise { - if (this.attachedByClient && this.webContents.debugger.isAttached()) { - this.webContents.debugger.detach(); - } - } - - getRetryCount(): number { - return this.retryCount; - } - - async evaluate(expression: string): Promise { - await this.attach(); - const response = await this.webContents.debugger.sendCommand("Runtime.evaluate", { - expression, - awaitPromise: true, - returnByValue: true, - }) as RuntimeEvaluateResult; - if (response.exceptionDetails) { - throw browserVerificationFailed( - this.platform, - this.actionType, - response.exceptionDetails.text ?? "runtime evaluation failed", - ); - } - return response.result?.value as T; - } - - async clickFirst(candidates: readonly string[], selectorKey: string, timeoutMs = 10_000): Promise { - const element = await this.waitForElement(candidates, selectorKey, timeoutMs); - await this.webContents.debugger.sendCommand("Input.dispatchMouseEvent", { - type: "mouseMoved", - x: element.x, - y: element.y, - button: "none", - }); - await this.webContents.debugger.sendCommand("Input.dispatchMouseEvent", { - type: "mousePressed", - x: element.x, - y: element.y, - button: "left", - clickCount: 1, - }); - await this.webContents.debugger.sendCommand("Input.dispatchMouseEvent", { - type: "mouseReleased", - x: element.x, - y: element.y, - button: "left", - clickCount: 1, - }); - return element.selector; - } - - async clickOptional(candidates: readonly string[], selectorKey: string, timeoutMs = 1_500): Promise { - try { - return await this.clickFirst(candidates, selectorKey, timeoutMs); - } catch (error) { - if (!isAppError(error) || error.code !== "browser.selector_drift") throw error; - return null; - } - } - - async waitForFirst(candidates: readonly string[], selectorKey: string, timeoutMs = 10_000): Promise { - return (await this.waitForElement(candidates, selectorKey, timeoutMs)).selector; - } - - async waitForAuthenticatedSurface( - candidates: readonly string[], - authenticatedCookieNames?: readonly string[], - timeoutMs = 5_000, - ): Promise { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - const selector = await this.evaluate( - buildAuthenticatedSurfaceExpression(candidates, authenticatedCookieNames ?? []), - ); - if (selector) return selector; - this.retryCount += 1; - await delay(POLL_INTERVAL_MS); - } - throw browserNotLoggedIn(this.platform, this.actionType); - } - - async focusAndType(candidates: readonly string[], text: string, selectorKey: string): Promise { - const selector = await this.clickFirst(candidates, selectorKey); - await this.webContents.debugger.sendCommand("Input.insertText", { text }); - return selector; - } - - async waitForText( - candidates: readonly string[], - expectedText: string, - timeoutMs = 12_000, - ): Promise { - const fingerprint = expectedText.trim().slice(0, 40); - if (fingerprint.length === 0) { - throw browserVerificationFailed(this.platform, this.actionType, "empty text fingerprint"); - } - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - const matched = await this.evaluate(buildTextMatchExpression(candidates, fingerprint)); - if (matched) return; - this.retryCount += 1; - await delay(POLL_INTERVAL_MS); - } - throw browserVerificationFailed(this.platform, this.actionType, `text not found after submit: ${fingerprint}`); - } - - async waitForAnyText(candidates: readonly string[], timeoutMs = 10_000): Promise { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - const texts = await this.evaluate(buildVisibleTextsExpression(candidates)); - if (texts.length > 0) return texts; - this.retryCount += 1; - await delay(POLL_INTERVAL_MS); - } - throw browserSelectorDrift(this.platform, this.actionType, "content_items"); - } - - private async waitForElement( - candidates: readonly string[], - selectorKey: string, - timeoutMs: number, - ): Promise { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - const element = await this.evaluate(buildElementProbeExpression(candidates)); - if (element) return element; - this.retryCount += 1; - await delay(POLL_INTERVAL_MS); - } - throw browserSelectorDrift(this.platform, this.actionType, selectorKey); - } -} - -function buildElementProbeExpression(candidates: readonly string[]): string { - return `(() => { - const candidates = ${JSON.stringify(candidates)}; - for (const selector of candidates) { - const elements = Array.from(document.querySelectorAll(selector)); - for (const element of elements) { - const rect = element.getBoundingClientRect(); - const style = window.getComputedStyle(element); - const disabled = element.disabled === true || element.getAttribute("aria-disabled") === "true"; - if (rect.width <= 0 || rect.height <= 0 || style.visibility === "hidden" || style.display === "none" || disabled) continue; - element.scrollIntoView({ block: "center", inline: "center" }); - const nextRect = element.getBoundingClientRect(); - return { - selector, - x: nextRect.left + nextRect.width / 2, - y: nextRect.top + nextRect.height / 2, - text: (element.innerText || element.textContent || "").slice(0, 200) - }; - } - } - return null; - })()`; -} - -function buildTextMatchExpression(candidates: readonly string[], fingerprint: string): string { - return `(() => { - const candidates = ${JSON.stringify(candidates)}; - const fingerprint = ${JSON.stringify(fingerprint)}; - for (const selector of candidates) { - for (const element of Array.from(document.querySelectorAll(selector))) { - const text = element.innerText || element.textContent || ""; - if (text.includes(fingerprint)) return true; - } - } - return false; - })()`; -} - -function buildVisibleTextsExpression(candidates: readonly string[]): string { - return `(() => { - const out = []; - const candidates = ${JSON.stringify(candidates)}; - for (const selector of candidates) { - for (const element of Array.from(document.querySelectorAll(selector))) { - const rect = element.getBoundingClientRect(); - if (rect.width <= 0 || rect.height <= 0) continue; - const text = (element.innerText || element.textContent || "").trim(); - if (text.length > 0) out.push(text.slice(0, 300)); - if (out.length >= 20) return out; - } - } - return out; - })()`; -} - -function buildAuthenticatedSurfaceExpression( - candidates: readonly string[], - authenticatedCookieNames: readonly string[], -): string { - return `(() => { - const candidates = ${JSON.stringify(candidates)}; - for (const selector of candidates) { - for (const element of Array.from(document.querySelectorAll(selector))) { - const rect = element.getBoundingClientRect(); - const style = window.getComputedStyle(element); - if (rect.width <= 0 || rect.height <= 0 || style.visibility === "hidden" || style.display === "none") continue; - return selector; - } - } - const cookie = document.cookie || ""; - const authenticatedCookieNames = ${JSON.stringify(authenticatedCookieNames.map((name) => name.toLowerCase()))}; - if (authenticatedCookieNames.length === 0 && cookie.trim().length > 0) return "document.cookie"; - const cookieNames = new Set(cookie.split(";").map((part) => part.split("=")[0]?.trim().toLowerCase()).filter(Boolean)); - for (const name of authenticatedCookieNames) { - if (cookieNames.has(name)) return "document.cookie:" + name; - } - return null; - })()`; -} - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/src/main/browser/browser-action-errors.ts b/src/main/browser/browser-action-errors.ts deleted file mode 100644 index 224f0709..00000000 --- a/src/main/browser/browser-action-errors.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { RecoverableError, UpstreamError, UserInputError } from "../errors/index.js"; - -export function browserNotLoggedIn(platform: string, actionType: string): UserInputError { - return new UserInputError({ - code: "browser.not_logged_in", - message: `${platform} session is not authenticated for ${actionType}.`, - context: { platform, actionType }, - }); -} - -export function browserSelectorDrift( - platform: string, - actionType: string, - selectorKey: string, -): UpstreamError { - return new UpstreamError({ - code: "browser.selector_drift", - message: `${platform} selector set did not expose ${selectorKey} for ${actionType}.`, - context: { platform, actionType, selectorKey }, - }); -} - -export function browserVerificationFailed( - platform: string, - actionType: string, - expectation: string, -): RecoverableError { - return new RecoverableError({ - code: "browser.verification_failed", - message: `${platform} ${actionType} did not pass verification: ${expectation}.`, - context: { platform, actionType, expectation }, - }); -} diff --git a/src/main/browser/browser-action-executor.ts b/src/main/browser/browser-action-executor.ts deleted file mode 100644 index c7686e9b..00000000 --- a/src/main/browser/browser-action-executor.ts +++ /dev/null @@ -1,361 +0,0 @@ -import { BrowserWindow } from "electron"; -import { existsSync, writeFileSync } from "node:fs"; -import type { NativeImage } from "electron"; -import log from "electron-log/main.js"; -import type { BrowserAction, BrowserActionResult } from "./browser-types"; -import { - assertAllowedUrl, - attachWindowSecurity, - getComposeUrl, - getFeedUrl, - getPlatformRules, - getSearchUrl, -} from "./browser-url-helpers"; -import { BrowserCdpClient } from "./browser-action-cdp"; -import { assertAuthenticatedPage, assertAuthenticatedSession } from "./browser-action-auth"; -import { getPlatformSelectors } from "./platform-selectors"; -import type { PlatformSelectors } from "./platform-selectors"; -import { browserVerificationFailed } from "./browser-action-errors"; -import { shouldCaptureSuccessScreenshot } from "./browser-screenshot-policy"; -import { isAppError } from "../errors/index.js"; - -export { getPlatformRules, assertAllowedUrl, attachWindowSecurity } from "./browser-url-helpers"; - -type BrowserActionOutcome = - | "success" - | "logged_out" - | "selector_drift" - | "network" - | "rate_limited" - | "cancelled" - | "verification_failed"; - -interface BrowserActionTelemetry { - platform: string; - action_type: string; - selector_hit: string | null; - selector_hits: string[]; - retries: number; - duration_ms: number; - final_outcome: BrowserActionOutcome; -} - -export function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export function waitForLoad( - win: BrowserWindow, - timeoutMs = 15000, - context: { platform: string; actionType: string } = { platform: "browser", actionType: "load" }, -): Promise { - return new Promise((resolve, reject) => { - if (!win.webContents.isLoading()) { - resolve(); - return; - } - - const cleanup = () => { - clearTimeout(timer); - win.webContents.off("did-finish-load", onFinish); - win.webContents.off("did-fail-load", onFail); - win.off("closed", onClosed); - }; - const fail = (expectation: string) => { - cleanup(); - reject(browserVerificationFailed(context.platform, context.actionType, expectation)); - }; - const onFinish = () => { - cleanup(); - resolve(); - }; - const onFail = ( - _event: Electron.Event, - errorCode: number, - errorDescription: string, - _validatedUrl: string, - isMainFrame: boolean, - ) => { - if (isMainFrame) fail(`page load failed: ${errorDescription} (${errorCode})`); - }; - const onClosed = () => fail("window closed during page load"); - const timer = setTimeout(() => fail(`page load exceeded ${timeoutMs}ms`), timeoutMs); - - win.webContents.once("did-finish-load", onFinish); - win.webContents.on("did-fail-load", onFail); - win.once("closed", onClosed); - }); -} - -export async function runAction( - action: BrowserAction, - screenshotDir: string, - session: Electron.Session, - cancelledActionIds: Set, - activeActionWindows: Map, -): Promise { - const payload = action.payload; - const screenshotPath = `${screenshotDir}/${action.id}.png`; - const platform = action.platform; - const startedAt = Date.now(); - const selectorHits: string[] = []; - - log.info(`[browser] Executing ${action.actionType} for ${platform}/${action.socialAccountId}`); - - const win = new BrowserWindow({ - width: 1280, - height: 860, - title: `AgentCompany — ${action.actionType}`, - show: true, - webPreferences: { - session, - nodeIntegration: false, - contextIsolation: true, - sandbox: true, - }, - }); - activeActionWindows.set(action.id, win); - attachWindowSecurity(win, platform); - win.setMenuBarVisibility(false); - - const cdp = new BrowserCdpClient(win.webContents, platform, action.actionType); - const selectors = getPlatformSelectors(platform); - const assertNotCancelled = () => { - if (cancelledActionIds.has(action.id)) { - throw new Error("BROWSER_ACTION_CANCELLED"); - } - }; - const remember = (selector: string | null) => { - if (selector) selectorHits.push(selector); - }; - - try { - assertNotCancelled(); - await assertAuthenticatedSession(session, platform, action.actionType); - let summary = "Action completed"; - - switch (action.actionType) { - case "navigate": { - const url = String(payload.url || getFeedUrl(platform)); - await loadActionUrl(win, platform, action.actionType, url); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - const title = await cdp.evaluate("document.title"); - summary = `Navigated to ${title}`; - break; - } - - case "post": { - const content = requirePayloadText(payload.content, "content"); - await loadActionUrl(win, platform, action.actionType, getComposeUrl(platform)); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - remember(await cdp.clickOptional(selectors.composerOpen, "composer_open")); - remember(await cdp.focusAndType(selectors.editor, content, "editor")); - assertNotCancelled(); - remember(await cdp.clickFirst(selectors.submit, "submit")); - await cdp.waitForText(selectors.feedItems, content); - summary = `Posted to ${platform}: "${content.slice(0, 50)}..."`; - break; - } - - case "reply": { - const targetUrl = requirePayloadText(payload.targetUrl, "targetUrl"); - const replyContent = requirePayloadText(payload.content, "content"); - await loadActionUrl(win, platform, action.actionType, targetUrl); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - remember(await cdp.focusAndType(selectors.replyEditor, replyContent, "reply_editor")); - assertNotCancelled(); - remember(await cdp.clickFirst(selectors.replySubmit, "reply_submit")); - await cdp.waitForText(selectors.feedItems, replyContent); - summary = `Replied to ${targetUrl.slice(0, 50)}`; - break; - } - - case "like": { - const targetUrl = requirePayloadText(payload.targetUrl, "targetUrl"); - await loadActionUrl(win, platform, action.actionType, targetUrl); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - remember(await cdp.clickFirst(selectors.likeButton, "like_button")); - await cdp.waitForFirst(selectors.likedButton, "liked_state", 5_000); - summary = `Liked post at ${targetUrl.slice(0, 50)}`; - break; - } - - case "follow": { - const targetUrl = String(payload.targetUrl || payload.profileUrl || ""); - if (!targetUrl) throw browserVerificationFailed(platform, action.actionType, "missing targetUrl/profileUrl"); - await loadActionUrl(win, platform, action.actionType, targetUrl); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - remember(await cdp.clickFirst(selectors.followButton, "follow_button")); - await cdp.waitForFirst(selectors.followingButton, "following_state", 5_000); - summary = `Followed user at ${targetUrl.slice(0, 50)}`; - break; - } - - case "browse_feed": { - const feedUrl = String(payload.url || getFeedUrl(platform)); - const maxPosts = Number(payload.maxPosts || 10); - await loadActionUrl(win, platform, action.actionType, feedUrl); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - for (let i = 0; i < 3; i += 1) { - await cdp.evaluate("window.scrollBy(0, window.innerHeight)"); - } - const posts = await cdp.waitForAnyText(selectors.feedItems); - summary = `Browsed feed — found ${Math.min(posts.length, maxPosts)} posts`; - break; - } - - case "search": { - const query = requirePayloadText(payload.query, "query"); - await loadActionUrl(win, platform, action.actionType, getSearchUrl(platform, query)); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - const results = await cdp.waitForAnyText(selectors.searchItems); - summary = `Search "${query.slice(0, 30)}" — ${results.length} results`; - break; - } - - case "screenshot": { - const url = String(payload.url || getFeedUrl(platform)); - await loadActionUrl(win, platform, action.actionType, url); - remember(await confirmAuthenticatedPage(win, cdp, selectors, platform, action.actionType)); - const title = await cdp.evaluate("document.title"); - summary = `Screenshot captured: ${title}`; - break; - } - - default: - throw new Error(`Unsupported browser action type: ${action.actionType}`); - } - - assertNotCancelled(); - const successScreenshotPath = shouldCaptureSuccessScreenshot(action) - ? await captureScreenshot(win, screenshotPath, action.id, "success") - : null; - await closeWindow(win); - logActionTelemetry({ - platform, - action_type: action.actionType, - selector_hit: selectorHits.at(-1) ?? null, - selector_hits: selectorHits, - retries: cdp.getRetryCount(), - duration_ms: Date.now() - startedAt, - final_outcome: "success", - }); - return { - success: true, - cancelled: false, - summary, - screenshotPath: successScreenshotPath, - error: null, - }; - } catch (error) { - const wasCancelled = cancelledActionIds.has(action.id) - || (error instanceof Error && error.message === "BROWSER_ACTION_CANCELLED"); - const failureScreenshotPath = wasCancelled - ? null - : await captureScreenshot(win, screenshotPath, action.id, "failure"); - await closeWindow(win); - - const msg = wasCancelled ? "Action cancelled." : describeBrowserActionError(error); - const finalOutcome = classifyBrowserOutcome(error, wasCancelled); - if (!wasCancelled) { - log.error(`[browser] Action ${action.actionType} failed: ${msg}`); - } - logActionTelemetry({ - platform, - action_type: action.actionType, - selector_hit: selectorHits.at(-1) ?? null, - selector_hits: selectorHits, - retries: cdp.getRetryCount(), - duration_ms: Date.now() - startedAt, - final_outcome: finalOutcome, - }); - return { - success: false, - cancelled: wasCancelled, - summary: wasCancelled ? "Action cancelled" : "Action failed", - screenshotPath: failureScreenshotPath, - error: msg, - }; - } finally { - await cdp.dispose().catch(() => undefined); - activeActionWindows.delete(action.id); - cancelledActionIds.delete(action.id); - } -} - -async function confirmAuthenticatedPage( - win: BrowserWindow, - cdp: BrowserCdpClient, - selectors: PlatformSelectors, - platform: string, - actionType: string, -): Promise { - await assertAuthenticatedPage(() => win.webContents.getURL(), platform, actionType); - return cdp.waitForAuthenticatedSurface( - selectors.authenticated, - getPlatformRules(platform).authenticatedCookieNames, - ); -} - -async function loadActionUrl( - win: BrowserWindow, - platform: string, - actionType: string, - url: string, -): Promise { - assertAllowedUrl(platform, url, actionType); - await win.loadURL(url); - await waitForLoad(win, 15000, { platform, actionType }); -} - -function requirePayloadText(value: unknown, key: string): string { - const text = typeof value === "string" ? value.trim() : ""; - if (text.length === 0) { - throw new Error(`Browser action payload missing ${key}.`); - } - return text; -} - -async function captureScreenshot( - win: BrowserWindow, - screenshotPath: string, - actionId: string, - phase: "success" | "failure", -): Promise { - try { - const image: NativeImage = await win.webContents.capturePage(); - if (!image.isEmpty()) { - writeFileSync(screenshotPath, image.toPNG()); - return existsSync(screenshotPath) ? screenshotPath : null; - } - } catch (err) { - log.warn(`[browser] ${phase} screenshot failed for action ${actionId}: ${err instanceof Error ? err.message : String(err)}`); - } - return null; -} - -async function closeWindow(win: BrowserWindow): Promise { - if (win.isDestroyed()) return; - await delay(250); - if (!win.isDestroyed()) win.close(); -} - -function describeBrowserActionError(error: unknown): string { - if (isAppError(error)) return `[${error.code}] ${error.message}`; - return error instanceof Error ? error.message : String(error); -} - -function classifyBrowserOutcome(error: unknown, wasCancelled: boolean): BrowserActionOutcome { - if (wasCancelled) return "cancelled"; - if (isAppError(error)) { - if (error.code === "browser.not_logged_in") return "logged_out"; - if (error.code === "browser.selector_drift") return "selector_drift"; - if (error.code === "browser.verification_failed") return "verification_failed"; - } - if (error instanceof Error && /429|rate[_ -]?limit|too many requests/i.test(error.message)) return "rate_limited"; - return "network"; -} - -function logActionTelemetry(telemetry: BrowserActionTelemetry): void { - log.info("[browser] action telemetry", telemetry); -} diff --git a/src/main/browser/browser-screenshot-policy.ts b/src/main/browser/browser-screenshot-policy.ts deleted file mode 100644 index ffc34b5b..00000000 --- a/src/main/browser/browser-screenshot-policy.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { BrowserAction } from "./browser-types"; - -export function shouldCaptureSuccessScreenshot(action: BrowserAction): boolean { - return action.actionType === "screenshot" - || action.payload.captureSuccessScreenshot === true - || action.payload.retainSuccessScreenshot === true; -} diff --git a/src/main/browser/browser-types.ts b/src/main/browser/browser-types.ts deleted file mode 100644 index 233ab0a0..00000000 --- a/src/main/browser/browser-types.ts +++ /dev/null @@ -1,183 +0,0 @@ -export interface BrowserAction { - id: string; - socialAccountId: string; - platform: string; - actionType: string; - payload: Record; -} - -export interface BrowserActionResult { - success: boolean; - cancelled: boolean; - summary: string; - screenshotPath: string | null; - error: string | null; -} - -export interface QueuedAction { - action: BrowserAction; - resolve: (result: BrowserActionResult) => void; - reject: (error: Error) => void; -} - -export interface PlatformRule { - loginUrl: string; - authCheckUrl: string; - allowedHosts: string[]; - cookieOrigins: string[]; - authenticatedCookieNames?: string[]; - unauthenticatedUrlMarkers: string[]; -} - -export const PLATFORM_RULES: Record = { - twitter: { - loginUrl: "https://x.com/i/flow/login", - authCheckUrl: "https://x.com/home", - allowedHosts: ["x.com", "twitter.com"], - cookieOrigins: ["https://x.com", "https://twitter.com"], - authenticatedCookieNames: ["auth_token"], - unauthenticatedUrlMarkers: ["/i/flow/login", "/login"], - }, - linkedin: { - loginUrl: "https://www.linkedin.com/login", - authCheckUrl: "https://www.linkedin.com/feed/", - allowedHosts: ["linkedin.com"], - cookieOrigins: ["https://www.linkedin.com"], - authenticatedCookieNames: ["li_at"], - unauthenticatedUrlMarkers: ["/login", "/checkpoint"], - }, - instagram: { - loginUrl: "https://www.instagram.com/accounts/login/", - authCheckUrl: "https://www.instagram.com/", - allowedHosts: ["instagram.com"], - cookieOrigins: ["https://www.instagram.com"], - authenticatedCookieNames: ["sessionid", "ds_user_id"], - unauthenticatedUrlMarkers: ["/accounts/login"], - }, - facebook: { - loginUrl: "https://www.facebook.com/login", - authCheckUrl: "https://www.facebook.com/", - allowedHosts: ["facebook.com"], - cookieOrigins: ["https://www.facebook.com"], - authenticatedCookieNames: ["c_user", "xs"], - unauthenticatedUrlMarkers: ["/login"], - }, - reddit: { - loginUrl: "https://www.reddit.com/login", - authCheckUrl: "https://www.reddit.com/", - allowedHosts: ["reddit.com"], - cookieOrigins: ["https://www.reddit.com"], - authenticatedCookieNames: ["reddit_session", "token_v2"], - unauthenticatedUrlMarkers: ["/login"], - }, - youtube: { - loginUrl: "https://accounts.google.com/signin", - authCheckUrl: "https://www.youtube.com/", - allowedHosts: ["youtube.com", "google.com"], - cookieOrigins: ["https://www.youtube.com", "https://accounts.google.com"], - authenticatedCookieNames: ["SAPISID", "LOGIN_INFO"], - unauthenticatedUrlMarkers: ["/signin", "/ServiceLogin"], - }, - tiktok: { - loginUrl: "https://www.tiktok.com/login", - authCheckUrl: "https://www.tiktok.com/foryou", - allowedHosts: ["tiktok.com"], - cookieOrigins: ["https://www.tiktok.com"], - authenticatedCookieNames: ["sessionid", "sessionid_ss"], - unauthenticatedUrlMarkers: ["/login"], - }, - bluesky: { - loginUrl: "https://bsky.app", - authCheckUrl: "https://bsky.app/", - allowedHosts: ["bsky.app"], - cookieOrigins: ["https://bsky.app"], - unauthenticatedUrlMarkers: ["/login"], - }, - discord: { - loginUrl: "https://discord.com/login", - authCheckUrl: "https://discord.com/channels/@me", - allowedHosts: ["discord.com"], - cookieOrigins: ["https://discord.com"], - unauthenticatedUrlMarkers: ["/login"], - }, - threads: { - loginUrl: "https://www.threads.net/login", - authCheckUrl: "https://www.threads.net/", - allowedHosts: ["threads.net"], - cookieOrigins: ["https://www.threads.net"], - authenticatedCookieNames: ["sessionid", "ds_user_id"], - unauthenticatedUrlMarkers: ["/login"], - }, - pinterest: { - loginUrl: "https://www.pinterest.com/login/", - authCheckUrl: "https://www.pinterest.com/", - allowedHosts: ["pinterest.com"], - cookieOrigins: ["https://www.pinterest.com"], - authenticatedCookieNames: ["_pinterest_sess"], - unauthenticatedUrlMarkers: ["/login"], - }, - telegram: { - loginUrl: "https://web.telegram.org/", - authCheckUrl: "https://web.telegram.org/", - allowedHosts: ["telegram.org", "t.me"], - cookieOrigins: ["https://web.telegram.org"], - unauthenticatedUrlMarkers: ["/auth"], - }, - whatsapp: { - loginUrl: "https://web.whatsapp.com/", - authCheckUrl: "https://web.whatsapp.com/", - allowedHosts: ["whatsapp.com"], - cookieOrigins: ["https://web.whatsapp.com"], - unauthenticatedUrlMarkers: [], - }, - wechat: { - loginUrl: "https://mp.weixin.qq.com/", - authCheckUrl: "https://mp.weixin.qq.com/", - allowedHosts: ["mp.weixin.qq.com", "weixin.qq.com"], - cookieOrigins: ["https://mp.weixin.qq.com"], - unauthenticatedUrlMarkers: ["/cgi-bin/loginpage"], - }, - weibo: { - loginUrl: "https://weibo.com/login.php", - authCheckUrl: "https://weibo.com/", - allowedHosts: ["weibo.com", "weibo.cn"], - cookieOrigins: ["https://weibo.com"], - authenticatedCookieNames: ["SUB", "SUBP"], - unauthenticatedUrlMarkers: ["/login", "/signup"], - }, - xiaohongshu: { - loginUrl: "https://www.xiaohongshu.com/explore", - authCheckUrl: "https://www.xiaohongshu.com/", - allowedHosts: ["xiaohongshu.com"], - cookieOrigins: ["https://www.xiaohongshu.com"], - unauthenticatedUrlMarkers: ["/login"], - }, - douyin: { - loginUrl: "https://www.douyin.com/", - authCheckUrl: "https://www.douyin.com/", - allowedHosts: ["douyin.com"], - cookieOrigins: ["https://www.douyin.com"], - unauthenticatedUrlMarkers: [], - }, - bilibili: { - loginUrl: "https://passport.bilibili.com/login", - authCheckUrl: "https://www.bilibili.com/", - allowedHosts: ["bilibili.com"], - cookieOrigins: ["https://www.bilibili.com", "https://passport.bilibili.com"], - unauthenticatedUrlMarkers: ["/login"], - }, - zhihu: { - loginUrl: "https://www.zhihu.com/signin", - authCheckUrl: "https://www.zhihu.com/", - allowedHosts: ["zhihu.com"], - cookieOrigins: ["https://www.zhihu.com"], - unauthenticatedUrlMarkers: ["/signin", "/sign-in"], - }, - other: { - loginUrl: "https://google.com", - authCheckUrl: "https://google.com", - allowedHosts: ["google.com"], - cookieOrigins: ["https://google.com"], - unauthenticatedUrlMarkers: ["/login"], - }, -}; diff --git a/src/main/browser/browser-url-helpers.ts b/src/main/browser/browser-url-helpers.ts deleted file mode 100644 index 2a93a01e..00000000 --- a/src/main/browser/browser-url-helpers.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { BrowserWindow } from "electron"; -import log from "electron-log/main.js"; -import { PLATFORM_RULES } from "./browser-types"; - -export function getPlatformRules(platform: string) { - return PLATFORM_RULES[platform] ?? PLATFORM_RULES.other; -} - -export function assertAllowedUrl(platform: string, rawUrl: string, actionType: string) { - const allowedHosts = getPlatformRules(platform).allowedHosts; - let url: URL; - try { - url = new URL(rawUrl); - } catch { - throw new Error(`Invalid URL for ${actionType}: ${rawUrl}`); - } - if (url.protocol !== "https:") { - throw new Error(`Navigation blocked for ${actionType}. Only https URLs are allowed.`); - } - const host = url.hostname.toLowerCase(); - const isAllowed = allowedHosts.some((allowedHost) => host === allowedHost || host.endsWith(`.${allowedHost}`)); - if (!isAllowed) { - throw new Error(`Navigation blocked for ${actionType}. ${host} is outside the allowed ${platform} domains.`); - } -} - -export function isAllowedNavigation(platform: string, rawUrl: string): boolean { - try { - assertAllowedUrl(platform, rawUrl, "navigate"); - return true; - } catch { - return false; - } -} - -export function attachWindowSecurity(win: BrowserWindow, platform: string) { - win.webContents.setWindowOpenHandler(({ url }) => { - if (!isAllowedNavigation(platform, url)) { - return { action: "deny" }; - } - setImmediate(() => { - void win.loadURL(url).catch((error) => { - log.warn(`[browser] Failed to open allowed popup target for ${platform}: ${error instanceof Error ? error.message : String(error)}`); - }); - }); - return { action: "deny" }; - }); - win.webContents.on("will-navigate", (event, navigationUrl) => { - if (isAllowedNavigation(platform, navigationUrl)) { - return; - } - event.preventDefault(); - log.warn(`[browser] Blocked navigation outside allowlist for ${platform}: ${navigationUrl}`); - }); - win.webContents.on("will-redirect", (event, navigationUrl) => { - if (isAllowedNavigation(platform, navigationUrl)) { - return; - } - event.preventDefault(); - log.warn(`[browser] Blocked redirect outside allowlist for ${platform}: ${navigationUrl}`); - }); -} - -export function getComposeUrl(platform: string): string { - const urls: Record = { - twitter: "https://x.com/compose/tweet", - linkedin: "https://www.linkedin.com/feed/", - instagram: "https://www.instagram.com/", - facebook: "https://www.facebook.com/", - reddit: "https://www.reddit.com/submit", - bluesky: "https://bsky.app/", - youtube: "https://www.youtube.com/", - tiktok: "https://www.tiktok.com/", - discord: "https://discord.com/channels/@me", - threads: "https://www.threads.net/", - pinterest: "https://www.pinterest.com/pin-creation-tool/", - telegram: "https://web.telegram.org/", - whatsapp: "https://web.whatsapp.com/", - wechat: "https://mp.weixin.qq.com/", - weibo: "https://weibo.com/", - xiaohongshu: "https://www.xiaohongshu.com/explore", - douyin: "https://www.douyin.com/", - bilibili: "https://www.bilibili.com/", - zhihu: "https://www.zhihu.com/question/waiting", - }; - return urls[platform] || getPlatformRules(platform).loginUrl; -} - -export function getFeedUrl(platform: string): string { - const urls: Record = { - twitter: "https://x.com/home", - linkedin: "https://www.linkedin.com/feed/", - instagram: "https://www.instagram.com/", - facebook: "https://www.facebook.com/", - reddit: "https://www.reddit.com/", - bluesky: "https://bsky.app/", - youtube: "https://www.youtube.com/", - tiktok: "https://www.tiktok.com/", - discord: "https://discord.com/channels/@me", - threads: "https://www.threads.net/", - pinterest: "https://www.pinterest.com/", - telegram: "https://web.telegram.org/", - whatsapp: "https://web.whatsapp.com/", - wechat: "https://mp.weixin.qq.com/", - weibo: "https://weibo.com/", - xiaohongshu: "https://www.xiaohongshu.com/explore", - douyin: "https://www.douyin.com/", - bilibili: "https://www.bilibili.com/", - zhihu: "https://www.zhihu.com/", - }; - return urls[platform] || getPlatformRules(platform).loginUrl; -} - -export function getSearchUrl(platform: string, query: string): string { - const q = encodeURIComponent(query); - const urls: Record = { - twitter: `https://x.com/search?q=${q}`, - linkedin: `https://www.linkedin.com/search/results/all/?keywords=${q}`, - reddit: `https://www.reddit.com/search/?q=${q}`, - discord: `https://discord.com/channels/@me`, - pinterest: `https://www.pinterest.com/search/pins/?q=${q}`, - weibo: `https://s.weibo.com/weibo?q=${q}`, - xiaohongshu: `https://www.xiaohongshu.com/search_result?keyword=${q}`, - bilibili: `https://search.bilibili.com/all?keyword=${q}`, - zhihu: `https://www.zhihu.com/search?type=content&q=${q}`, - }; - return urls[platform] || `https://google.com/search?q=${q}`; -} diff --git a/src/main/browser/platform-selectors.ts b/src/main/browser/platform-selectors.ts deleted file mode 100644 index 4c5a4207..00000000 --- a/src/main/browser/platform-selectors.ts +++ /dev/null @@ -1,135 +0,0 @@ -export interface PlatformSelectors { - authenticated: readonly string[]; - composerOpen: readonly string[]; - editor: readonly string[]; - submit: readonly string[]; - replyEditor: readonly string[]; - replySubmit: readonly string[]; - likeButton: readonly string[]; - likedButton: readonly string[]; - followButton: readonly string[]; - followingButton: readonly string[]; - feedItems: readonly string[]; - searchItems: readonly string[]; -} - -const GENERIC_SELECTORS: PlatformSelectors = { - authenticated: [ - "[data-testid='AppTabBar_Profile_Link']", - "a[href*='/in/']", - "img[alt*='profile' i]", - "[aria-label*='profile' i]", - ], - composerOpen: [ - "button[aria-label*='post' i]", - "button[aria-label*='compose' i]", - "button.share-box-feed-entry__trigger", - ], - editor: [ - "[role='textbox'][contenteditable='true']", - "textarea", - ".ql-editor[contenteditable='true']", - ], - submit: [ - "button[type='submit']", - "button[aria-label*='post' i]", - "button[aria-label*='send' i]", - ], - replyEditor: [ - "[role='textbox'][contenteditable='true']", - "textarea", - ], - replySubmit: [ - "button[type='submit']", - "button[aria-label*='reply' i]", - "button[aria-label*='send' i]", - ], - likeButton: [ - "button[aria-label*='like' i]", - "[role='button'][aria-label*='like' i]", - ], - likedButton: [ - "button[aria-pressed='true'][aria-label*='like' i]", - "[data-testid='unlike']", - ], - followButton: [ - "button[aria-label*='follow' i]", - "[role='button'][aria-label*='follow' i]", - ], - followingButton: [ - "button[aria-label*='following' i]", - "button[aria-label*='requested' i]", - ], - feedItems: ["article", "[role='article']", ".feed-shared-update-v2"], - searchItems: ["article", "[role='article']", ".search-result", ".feed-shared-update-v2"], -}; - -const PLATFORM_SELECTORS: Record> = { - twitter: { - authenticated: [ - "[data-testid='AppTabBar_Profile_Link']", - "[data-testid='SideNav_AccountSwitcher_Button']", - "a[aria-label*='Profile']", - ], - editor: [ - "[data-testid='tweetTextarea_0']", - "[role='textbox'][contenteditable='true']", - ], - submit: [ - "[data-testid='tweetButton']", - "[data-testid='tweetButtonInline']", - ], - replyEditor: [ - "[data-testid='tweetTextarea_0']", - "[role='textbox'][contenteditable='true']", - ], - replySubmit: [ - "[data-testid='tweetButton']", - "[data-testid='tweetButtonInline']", - "button[type='submit']", - ], - likeButton: ["[data-testid='like']", "button[aria-label*='Like']"], - likedButton: ["[data-testid='unlike']", "button[aria-label*='Unlike']"], - feedItems: ["article", "[data-testid='tweet']"], - searchItems: ["article", "[data-testid='tweet']"], - }, - linkedin: { - authenticated: [ - "a[href*='/in/']", - "img.global-nav__me-photo", - "button.global-nav__primary-link-me-menu-trigger", - ], - composerOpen: [ - "button.share-box-feed-entry__trigger", - "button.artdeco-button--muted", - ], - editor: [ - "[role='textbox'][contenteditable='true']", - ".ql-editor[contenteditable='true']", - ], - submit: [ - "button.share-actions__primary-action", - "button.artdeco-button--primary[type='submit']", - ], - feedItems: [".feed-shared-update-v2", "article", ".update-components-text"], - searchItems: [".reusable-search__result-container", ".feed-shared-update-v2", "article"], - }, -}; - -export function getPlatformSelectors(platform: string): PlatformSelectors { - const overrides = PLATFORM_SELECTORS[platform] ?? {}; - return { - authenticated: overrides.authenticated ?? GENERIC_SELECTORS.authenticated, - composerOpen: overrides.composerOpen ?? GENERIC_SELECTORS.composerOpen, - editor: overrides.editor ?? GENERIC_SELECTORS.editor, - submit: overrides.submit ?? GENERIC_SELECTORS.submit, - replyEditor: overrides.replyEditor ?? overrides.editor ?? GENERIC_SELECTORS.replyEditor, - replySubmit: overrides.replySubmit ?? overrides.submit ?? GENERIC_SELECTORS.replySubmit, - likeButton: overrides.likeButton ?? GENERIC_SELECTORS.likeButton, - likedButton: overrides.likedButton ?? GENERIC_SELECTORS.likedButton, - followButton: overrides.followButton ?? GENERIC_SELECTORS.followButton, - followingButton: overrides.followingButton ?? GENERIC_SELECTORS.followingButton, - feedItems: overrides.feedItems ?? GENERIC_SELECTORS.feedItems, - searchItems: overrides.searchItems ?? overrides.feedItems ?? GENERIC_SELECTORS.searchItems, - }; -} diff --git a/src/main/budget-enforcement-service.ts b/src/main/budget-enforcement-service.ts deleted file mode 100644 index 6c4bac83..00000000 --- a/src/main/budget-enforcement-service.ts +++ /dev/null @@ -1,237 +0,0 @@ -import type { AppDatabase } from "./database"; -import type { NotificationOptions } from "./notification-service"; -import type { BudgetPolicyRecord, BudgetStatusSummary } from "@shared/types"; - -interface BudgetEnforcementDependencies { - db: AppDatabase; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; - notify: (options: NotificationOptions) => void; - publishDomainChanged: () => void; -} - -export interface BudgetGateResult { - allowed: boolean; - blockedBy: Array<{ - policyId: string; - scopeType: string; - scopeId: string; - spent: number; - limit: number; - }>; -} - -/** - * Returns a human-readable label for a budget policy scope. - * Looks up entity names from the database for agent and project scopes. - */ -function getScopeLabel( - db: AppDatabase, - policy: BudgetPolicyRecord, - logger: { warn: (...args: unknown[]) => void }, -): string { - if (policy.scopeType === "agent") { - try { - const agent = db.core.entity.getAgent(policy.scopeId); - return `Agent "${agent.name}"`; - } catch (err) { - logger.warn(`[budget] getAgent failed for scope ${policy.scopeId}:`, err instanceof Error ? err.message : String(err)); - return `Agent ${policy.scopeId.slice(0, 8)}`; - } - } - if (policy.scopeType === "project") { - try { - const row = db.queryAll<{ name: string }>("select name from projects where id = ?", policy.scopeId); - return row.length > 0 ? `Project "${row[0].name}"` : `Project ${policy.scopeId.slice(0, 8)}`; - } catch (err) { - logger.warn(`[budget] project name lookup failed for scope ${policy.scopeId}:`, err instanceof Error ? err.message : String(err)); - return `Project ${policy.scopeId.slice(0, 8)}`; - } - } - return "Company budget"; -} - -export function createBudgetEnforcementService({ - db, - logger, - notify, - publishDomainChanged, -}: BudgetEnforcementDependencies) { - /** - * Evaluates whether a new run should be allowed based on active budget policies. - * - * Per D-01 (strictest-wins): if ANY policy scope is exhausted, the run is blocked. - * Per D-02: if no policies exist, the run is allowed (unlimited). - * Per D-04/D-05: this only blocks NEW dispatches -- in-flight runs are unaffected. - */ - function evaluateBudgetGate( - companyId: string, - agentId: string, - projectId: string | null, - ): BudgetGateResult { - const policies = db.core.budget.getActivePoliciesForRun(companyId, agentId, projectId); - if (policies.length === 0) { - return { allowed: true, blockedBy: [] }; - } - - const blockedBy: BudgetGateResult["blockedBy"] = []; - for (const policy of policies) { - if (!policy.hardStopEnabled) continue; - const spent = db.core.budget.getSpentInWindow(policy); - if (spent >= policy.amount) { - blockedBy.push({ - policyId: policy.id, - scopeType: policy.scopeType, - scopeId: policy.scopeId, - spent, - limit: policy.amount, - }); - } - } - - return { allowed: blockedBy.length === 0, blockedBy }; - } - - /** - * Checks all active policies for the given run context and creates/updates - * budget incidents at warn and hard-stop thresholds. - * - * Per D-07: fires both warn and hard-stop in the same code path. - * Per D-08: deduplicates incidents via upsertBudgetIncident. - */ - function checkAndCreateIncidents( - companyId: string, - agentId: string, - projectId: string | null, - ): void { - const policies = db.core.budget.getActivePoliciesForRun(companyId, agentId, projectId); - - for (const policy of policies) { - // amount <= 0 disables the policy (and would otherwise divide by zero below). - if (policy.amount <= 0) continue; - - const spent = db.core.budget.getSpentInWindow(policy); - const utilization = spent / policy.amount; - const warnThreshold = policy.warnPercent / 100; - const scopeLabel = getScopeLabel(db, policy, logger); - - if (utilization >= warnThreshold) { - db.core.budget.upsertBudgetIncident(policy, "warn_threshold", spent); - if (policy.notifyEnabled) { - notify({ - title: "Budget Warning", - body: `${scopeLabel} at ${Math.round(utilization * 100)}% of budget ($${(spent / 100).toFixed(2)} / $${(policy.amount / 100).toFixed(2)})`, - urgency: "informational", - navigation: { section: "costs" }, - batchKey: "budget_warning", - }); - } - } - - if (utilization >= 1.0 && policy.hardStopEnabled) { - db.core.budget.upsertBudgetIncident(policy, "hard_stop", spent); - if (policy.notifyEnabled) { - notify({ - title: "Budget Exhausted", - body: `${scopeLabel} budget exhausted - new runs blocked`, - urgency: "critical", - navigation: { section: "costs" }, - batchKey: "budget_exhaustion", - }); - } - } - } - - publishDomainChanged(); - } - - /** - * Checks if a policy's limit was increased above the observed spend amount, - * and auto-resolves open incidents if so. - * - * Per D-06: fires auto_resolved_limit_increase status. - */ - function checkAutoResolve(companyId: string, policyId: string): void { - const policy = db.core.budget.getBudgetPolicy(policyId); - if (!policy) return; - - const spent = db.core.budget.getSpentInWindow(policy); - let resolved = false; - - if (spent < policy.amount) { - const count = db.core.budget.resolveIncidentsForPolicy(policyId, "auto_resolved_limit_increase"); - if (count > 0) resolved = true; - } - - const warnAmount = Math.floor((policy.amount * policy.warnPercent) / 100); - if (spent < warnAmount) { - const count = db.core.budget.resolveWarnIncidentsForPolicy(policyId, "auto_resolved_limit_increase"); - if (count > 0) resolved = true; - } - - if (resolved) { - unpauseBudgetBlockedAgents(companyId); - logger.info(`Budget auto-resolve: policy ${policyId} incidents resolved (spent=${spent}, limit=${policy.amount})`); - publishDomainChanged(); - } - } - - function unpauseBudgetBlockedAgents(companyId: string): void { - const paused = db.queryAll<{ id: string; budgetMonthlyUsd: number; spentMonthlyUsd: number }>( - `SELECT id, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd - FROM agents WHERE company_id = ? AND status = 'paused' AND budget_monthly_usd > 0`, - companyId, - ); - for (const agent of paused) { - if (agent.budgetMonthlyUsd > agent.spentMonthlyUsd) { - db.queryAll("UPDATE agents SET status = 'idle', updated_at = ? WHERE id = ?", new Date().toISOString(), agent.id); - logger.info(`[budget] Auto-unpaused agent ${agent.id}: budget $${agent.budgetMonthlyUsd} > spent $${agent.spentMonthlyUsd}`); - } - } - } - - /** - * Closes incidents whose calendar month window has ended. - * Per D-06: window rollover cleanup. - */ - function autoCloseExpiredIncidents(companyId: string): number { - const count = db.core.budget.autoCloseExpiredIncidents(companyId); - if (count > 0) { - logger.info(`Budget auto-close: ${count} expired incident(s) for company ${companyId}`); - publishDomainChanged(); - } - return count; - } - - /** - * Returns a summary of all budget policies and their current spend status. - */ - function getBudgetStatus(companyId: string): BudgetStatusSummary { - const policies = db.core.budget.listBudgetPolicies(companyId); - const openIncidents = db.core.budget.listBudgetIncidents(companyId, "open"); - - return { - policies: policies.map((policy) => { - const spent = db.core.budget.getSpentInWindow(policy); - const hasOpenIncident = openIncidents.some((i) => i.policyId === policy.id); - return { - policyId: policy.id, - scopeType: policy.scopeType, - scopeId: policy.scopeId, - amount: policy.amount, - spent, - warnPercent: policy.warnPercent, - hardStopEnabled: policy.hardStopEnabled, - hasOpenIncident, - }; - }), - }; - } - - return { - evaluateBudgetGate, - checkAndCreateIncidents, - checkAutoResolve, - autoCloseExpiredIncidents, - getBudgetStatus, - }; -} diff --git a/src/main/checkpoint-engine.ts b/src/main/checkpoint-engine.ts deleted file mode 100644 index d90d645f..00000000 --- a/src/main/checkpoint-engine.ts +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Checkpoint Engine - * - * Creates approval checkpoints based on company executionMode. - * In ai_cofounder mode, key orchestration junctures pause for user confirmation. - * In ai_ceo mode, only high-risk actions require approval. - * - * Policy decisions (which types require review, which can be auto-approved) - * are centralized in execution-policy.ts — the single source of truth. - */ - -import type { AppDatabase } from "./database"; -import type { ApprovalType, ExecutionMode, SectionId } from "@shared/types"; -import type { ThreadIntegrationService } from "./thread-integration"; -import { - CHECKPOINT_TASK_TYPES, - STRATEGY_DOCUMENT_TYPES, -} from "./execution-policy"; -import { classifyUnknownError } from "./errors/index.js"; - -interface CheckpointDeps { - db: AppDatabase; - logger: { info: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; - threadIntegration: ThreadIntegrationService; - publishDomainChanged: () => void; - notify: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string } }) => void; -} - -export function getCompanyExecutionMode(db: AppDatabase, companyId: string): ExecutionMode { - return db.core.company.getCompanyExecutionMode(companyId) as ExecutionMode; -} - -export function createCheckpointEngine(deps: CheckpointDeps) { - const { db, logger, threadIntegration, publishDomainChanged, notify } = deps; - - return { - /** - * Called when a task transitions to in_progress for the first time. - * In co-founder mode, creates a plan_review checkpoint for top-level - * non-code tasks so the user can review the plan before execution - * begins. Subtasks inherit their parent's review — creating a - * checkpoint for every subtask made the whole team stall on a - * waterfall of approvals that the operator had no chance to process - * in real time. - */ - onTaskStarted(taskId: string, companyId: string, agentId: string | null): string | null { - try { - const mode = getCompanyExecutionMode(db, companyId); - if (mode !== "ai_cofounder") return null; - - const task = db.core.entity.getTask(taskId); - const taskType = db.core.tasks.getTaskType(taskId); - - // Only create plan checkpoints for non-code task types - if (!taskType || !CHECKPOINT_TASK_TYPES.has(taskType)) return null; - - // Subtasks inherit the parent's plan review; creating a fresh - // checkpoint per subtask produces an unbounded approval fan-out - // that blocks the assignee's heartbeat (shouldPauseHeartbeat) - // the moment delegation starts. - if (task.parentId) return null; - - const approvalId = db.core.approvals.requestApproval({ - companyId, - relatedTaskId: taskId, - requestedByAgentId: agentId, - type: "plan_review", - payloadSummary: `Review plan for: ${task.title}`.slice(0, 280), - impactSummary: `Task "${task.title}" is starting. Review the scope and approach before execution proceeds.`.slice(0, 400), - payloadJson: JSON.stringify({ taskId, taskTitle: task.title, taskType }), - }); - - threadIntegration.onApprovalCreated(approvalId, companyId, taskId, "plan_review", `Plan review: ${task.title}`); - - notify({ - title: "Plan Review Needed", - body: `"${task.title}" needs your review before work begins`, - urgency: "informational", - navigation: { section: "approvals", entityId: approvalId }, - }); - - publishDomainChanged(); - return approvalId; - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "checkpoint.on_task_started.failed", - message: "onTaskStarted failed", - }); - logger.error(`[${classified.code}] ${classified.message}: ${err instanceof Error ? err.message : String(err)}`); - return null; - } - }, - - /** - * Called when a document is created in co-founder mode. - * Creates a draft_review checkpoint so the user can review before - * the document is considered final. - */ - onDocumentDrafted(companyId: string, documentId: string, documentTitle: string, documentType: string, authorAgentId: string | null, taskId: string | null): string | null { - try { - const mode = getCompanyExecutionMode(db, companyId); - if (mode !== "ai_cofounder") return null; - - // Strategy-related document types get strategy_review instead - const approvalType: ApprovalType = STRATEGY_DOCUMENT_TYPES.has(documentType) - ? "strategy_review" - : "draft_review"; - - const approvalId = db.core.approvals.requestApproval({ - companyId, - relatedTaskId: taskId, - requestedByAgentId: authorAgentId, - type: approvalType, - payloadSummary: `Review ${documentType.replaceAll("_", " ")}: ${documentTitle}`.slice(0, 280), - impactSummary: `New ${documentType.replaceAll("_", " ")} drafted. Please review before it becomes final.`.slice(0, 400), - payloadJson: JSON.stringify({ documentId, documentTitle, documentType }), - }); - - threadIntegration.onApprovalCreated(approvalId, companyId, taskId, approvalType, `${approvalType}: ${documentTitle}`); - - notify({ - title: "Draft Review Needed", - body: `"${documentTitle}" needs your review`, - urgency: "informational", - navigation: { section: "approvals", entityId: approvalId }, - }); - - publishDomainChanged(); - return approvalId; - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "checkpoint.on_document_drafted.failed", - message: "onDocumentDrafted failed", - }); - logger.error(`[${classified.code}] ${classified.message}: ${err instanceof Error ? err.message : String(err)}`); - return null; - } - }, - - /** - * Checks if a company in ai_cofounder mode has unresolved checkpoints - * that should pause heartbeat for an agent. - */ - shouldPauseHeartbeat(companyId: string, agentId: string): boolean { - try { - const mode = getCompanyExecutionMode(db, companyId); - if (mode !== "ai_cofounder") return false; - - // Check for unresolved wait states for THIS agent's threads (not company-wide) - if (threadIntegration.hasUnresolvedWaitStatesForAgent(companyId, agentId)) { - return true; - } - - // Check for pending approvals related to this agent's tasks - return db.core.approvals.hasPendingReviewApprovalForAgent(companyId, agentId); - } catch (err) { - logger.error(`[checkpoint] shouldPauseHeartbeat failed: ${err instanceof Error ? err.message : String(err)}`); - return true; - } - }, - - /** - * Returns execution mode for a company. Convenience accessor. - */ - getExecutionMode(companyId: string): ExecutionMode { - return getCompanyExecutionMode(db, companyId); - }, - }; -} diff --git a/src/main/connector-auth-service.ts b/src/main/connector-auth-service.ts deleted file mode 100644 index 8c21cc24..00000000 --- a/src/main/connector-auth-service.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { spawn } from "node:child_process"; -import { writeFileSync } from "node:fs"; -import { homedir, tmpdir } from "node:os"; -import { join } from "node:path"; -import { randomBytes } from "node:crypto"; -import { spawnSync } from "node:child_process"; -import log from "electron-log/main.js"; - -function quoteShell(value: string) { - return `'${value.replace(/'/g, `'"'"'`)}'`; -} - -function escapeAppleScript(value: string) { - return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); -} - -/* ------------------------------------------------------------------ */ -/* Shared terminal spawning — used by generic install flows */ -/* ------------------------------------------------------------------ */ - -function writeWindowsBatchFile(lines: string[]): string { - const fileName = `agent-company-${randomBytes(6).toString("hex")}.bat`; - const batchPath = join(tmpdir(), fileName); - writeFileSync(batchPath, lines.join("\r\n"), { encoding: "utf8" }); - return batchPath; -} - -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], { - detached: true, - stdio: "ignore", - }); - child.unref(); - return true; - } - - if (process.platform === "win32") { - const child = spawn("cmd.exe", ["/c", "start", "", "cmd.exe", "/k", script], { - detached: true, - stdio: "ignore", - shell: false, - }); - child.unref(); - return true; - } - - // Linux — try $TERMINAL first, then a broad list of common emulators. - // Supported list documented in docs/platform-support.md. - const linuxCandidates: Array<[string, string[]]> = []; - const envTerminal = process.env.TERMINAL?.trim(); - if (envTerminal) { - linuxCandidates.push([envTerminal, ["-e", "sh", "-lc", script]]); - } - linuxCandidates.push( - ["x-terminal-emulator", ["-e", "sh", "-lc", script]], - ["gnome-terminal", ["--", "sh", "-lc", script]], - ["konsole", ["-e", "sh", "-lc", script]], - ["xfce4-terminal", ["-e", `sh -lc ${quoteShell(script)}`]], - ["kitty", ["sh", "-lc", script]], - ["alacritty", ["-e", "sh", "-lc", script]], - ["wezterm", ["start", "--", "sh", "-lc", script]], - ["tilix", ["-e", "sh", "-lc", script]], - ["terminator", ["-e", `sh -lc ${quoteShell(script)}`]], - ); - - for (const [binary, args] of linuxCandidates) { - const availability = spawnSync("sh", ["-lc", `command -v ${quoteShell(binary)}`], { - stdio: "ignore", - }); - if ((availability.status ?? 1) !== 0) { - continue; - } - try { - const child = spawn(binary, args, { - detached: true, - stdio: "ignore", - }); - child.unref(); - return true; - } catch (err) { - log.warn(`[connector-auth] Failed to spawn terminal ${binary}; trying next candidate:`, err instanceof Error ? err.message : String(err)); - } - } - - throw new Error("No supported terminal application was found."); -} - -/* ------------------------------------------------------------------ */ -/* Generic terminal command (for install flows, etc.) */ -/* ------------------------------------------------------------------ */ - -const TERMINAL_COMMAND_MAP: Record = { - install_node_darwin: { - title: "Install Node.js", - unix: "brew install node@22", - win32: null, - }, - install_node_win32: { - title: "Install Node.js", - unix: null, - win32: "winget install -e --id OpenJS.NodeJS.LTS", - }, - install_node_linux: { - title: "Install Node.js", - unix: `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash && \\. "$HOME/.nvm/nvm.sh" && nvm install 22`, - win32: null, - }, - install_claude_unix: { - title: "Install Claude Code", - unix: "curl -fsSL https://claude.ai/install.sh | bash", - win32: null, - }, - install_claude_win32: { - title: "Install Claude Code", - unix: null, - win32: "irm https://claude.ai/install.ps1 | iex", - }, - install_codex: { - title: "Install Codex", - unix: "npm i -g @openai/codex", - win32: "npm i -g @openai/codex", - }, - install_gemini: { - title: "Install Gemini CLI", - unix: "npm install -g @google/gemini-cli", - win32: "npm install -g @google/gemini-cli", - }, -}; - -export async function openGenericTerminal(input: { commandKey: string }) { - const spec = TERMINAL_COMMAND_MAP[input.commandKey]; - if (!spec) { - throw new Error(`Unknown terminal command key: ${input.commandKey}`); - } - - const cwd = process.env.HOME || homedir() || process.cwd(); - const command = process.platform === "win32" ? spec.win32 : spec.unix; - if (!command) { - throw new Error(`Command "${input.commandKey}" is not available on this platform.`); - } - - if (process.platform === "win32") { - const batchPath = writeWindowsBatchFile([ - `@echo off`, - `echo AgentCompany - ${spec.title}`, - `echo.`, - `cd /d "${cwd}"`, - command, - `echo.`, - `echo Done. You can close this terminal.`, - `pause`, - ]); - return spawnTerminalWithScript(`"${batchPath}"`, spec.title, cwd); - } - - const shell = process.env.SHELL || "/bin/zsh"; - const script = [ - "clear", - `echo ${quoteShell(`AgentCompany — ${spec.title}`)}`, - "echo", - `cd ${quoteShell(cwd)}`, - command, - "echo", - `echo ${quoteShell("Done. You can close this terminal.")}`, - `exec ${quoteShell(shell)} -l`, - ].join("; "); - return spawnTerminalWithScript(script, spec.title, cwd); -} diff --git a/src/main/connector-definitions-docs.ts b/src/main/connector-definitions-docs.ts deleted file mode 100644 index a7517eb7..00000000 --- a/src/main/connector-definitions-docs.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Per-auth-kind configuration documentation builders for the Settings → - * Providers panel. Extracted from `connector-definitions.ts` to keep that - * file under the 400-line cap. - */ - -import type { PiOAuthProviderId } from "./connector-definitions"; - -export function buildOAuthDoc(label: string, oauthId: PiOAuthProviderId): string { - return [ - `# ${label}`, - "", - "Authenticate via OAuth in your system browser. AgentCompany opens", - "the provider's authorization page; the redirect handler runs locally on", - "`http://localhost:53692/callback`.", - "", - `OAuth provider id: \`${oauthId}\`.`, - "", - "Tokens are encrypted by the OS keychain (or per-profile vault) and", - "stored in the `credentials` table. Tokens are refreshed automatically", - "before each run (60 second window).", - ].join("\n"); -} - -export function buildApiKeyDoc(label: string, envVar: string): string { - return [ - `# ${label}`, - "", - `API key authentication. Either paste the literal key or use a system`, - `environment variable name (default: \`${envVar}\`).`, - "", - "Keys are encrypted at rest via OS keychain (or per-profile vault).", - ].join("\n"); -} - -export function buildCloudDoc(label: string, body: string): string { - return [`# ${label}`, "", body].join("\n"); -} diff --git a/src/main/connector-definitions-lookup.ts b/src/main/connector-definitions-lookup.ts deleted file mode 100644 index 52bdf812..00000000 --- a/src/main/connector-definitions-lookup.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { CONNECTORS, type ConnectorDefinition } from "./connector-definitions"; - -export function findConnectorDefinition(id: string): ConnectorDefinition | undefined { - return CONNECTORS.find((connector) => connector.id === id); -} - -export function listFeaturedOnboardingConnectors(): ConnectorDefinition[] { - return CONNECTORS.filter((connector) => connector.onboardingFeatured === true); -} diff --git a/src/main/connector-definitions.ts b/src/main/connector-definitions.ts deleted file mode 100644 index cdd29e85..00000000 --- a/src/main/connector-definitions.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Pi-mono connector catalog. - * - * The catalog is pure declarative data — there is no adapter module, no - * embedded CLI command, and no capability matrix. All provider dispatch is - * handled by pi-mono (`@mariozechner/pi-ai`) at runtime, which keys off the - * `provider` field and the auth descriptor. - * - * Shape and invariants are validated by `tests/unit/connector-catalog.test.ts`: - * - * - Exactly 26 entries: 5 OAuth, 18 API key, 3 Cloud - * - Each entry references a pi-ai `KnownProvider` (or one of the two - * Fireworks ids resolved locally in `src/main/model-resolver.ts`) - * - OAuth entries carry one of the five pi-ai OAuth provider ids - * - API-key entries carry an `envKey` environment variable name - * - The onboarding rail includes at least the `claude-pro` connector - * - * Entries live in three companion files to keep every module under the - * 400-line cap: - * - * - `connector-definitions/oauth.ts` — 5 OAuth providers - * - `connector-definitions/apikey.ts` — 18 API-key providers - * - `connector-definitions/cloud.ts` — 3 Cloud providers - */ - -import type { KnownProvider } from "@mariozechner/pi-ai"; -import type { ConnectorId } from "@shared/types"; -import { OAUTH_CONNECTORS, API_KEY_CONNECTORS, CLOUD_CONNECTORS, LOCAL_CONNECTORS } from "./connector-definitions/index"; - -/** - * OAuth provider id recognised by the AgentCompany credential layer. These - * match pi-ai's five built-in OAuth handler ids verbatim. - */ -export type PiOAuthProviderId = - | "anthropic" - | "openai-codex" - | "github-copilot" - | "google-gemini-cli" - | "google-antigravity"; - -export interface ConnectorAuthOAuth { - type: "oauth"; - oauthId: PiOAuthProviderId; -} - -export interface ConnectorAuthApiKey { - type: "api_key"; - /** Fallback environment variable name (e.g. `ANTHROPIC_API_KEY`). */ - envKey: string; -} - -export interface ConnectorAuthAws { - type: "aws"; -} - -export interface ConnectorAuthAzure { - type: "azure"; -} - -export interface ConnectorAuthGcpAdc { - type: "gcp_adc"; -} - -export interface ConnectorAuthLocal { - type: "local"; - /** Pre-filled base URL the onboarding card shows on first save. */ - defaultBaseUrl: string; -} - -export type ConnectorAuth = - | ConnectorAuthOAuth - | ConnectorAuthApiKey - | ConnectorAuthAws - | ConnectorAuthAzure - | ConnectorAuthGcpAdc - | ConnectorAuthLocal; - -export type LocalModelResolverProvider = "fireworks" | "fireworks-firepass" | "ollama" | "lm-studio"; -export type ConnectorProvider = KnownProvider | LocalModelResolverProvider; - -export interface ConnectorDefinition { - /** Stable AgentCompany id; the `connectors` table primary key. */ - id: ConnectorId; - /** pi-ai `KnownProvider` id (or a locally-resolved provider for Fireworks). */ - provider: ConnectorProvider; - /** Human-readable label for the Settings panel and onboarding rail. */ - label: string; - /** One-line explanation shown under the label. */ - description: string; - /** pi-ai model id used when the user has not picked a model yet. */ - defaultModel: string; - /** Declarative auth descriptor; drives the credential resolver and OAuth flow. */ - auth: ConnectorAuth; - /** Whether to surface this connector in the first-run onboarding picker. */ - onboardingFeatured?: boolean; - /** Optional extra guidance for the Settings panel. */ - notes?: string; -} - -export const CONNECTORS: ConnectorDefinition[] = [ - ...OAUTH_CONNECTORS, - ...API_KEY_CONNECTORS, - ...CLOUD_CONNECTORS, - ...LOCAL_CONNECTORS, -]; diff --git a/src/main/connector-definitions/apikey.ts b/src/main/connector-definitions/apikey.ts deleted file mode 100644 index db6a2aa6..00000000 --- a/src/main/connector-definitions/apikey.ts +++ /dev/null @@ -1,177 +0,0 @@ -/** - * API-key pi-mono connectors. - * - * Each entry maps to a pi-ai `KnownProvider` from the pinned - * `@mariozechner/pi-ai` runtime, except for the two - * Fireworks entries, which are resolved locally in `src/main/model-resolver.ts`. - * - * `envKey` is the standard environment variable pi-mono reads when no - * `auth.json` entry is present. AgentCompany's credential store also honours - * it as a fallback so the Settings panel can tell users which variable to - * set. - */ - -import type { ConnectorDefinition } from "../connector-definitions"; - -export const API_KEY_CONNECTORS: ConnectorDefinition[] = [ - { - id: "anthropic", - provider: "anthropic", - label: "Anthropic API", - description: - "Direct Anthropic Messages API. Use this for production workloads where OAuth subscription tiers are not appropriate.", - defaultModel: "claude-sonnet-4-5", - auth: { type: "api_key", envKey: "ANTHROPIC_API_KEY" }, - onboardingFeatured: true, - }, - { - id: "openai", - provider: "openai", - label: "OpenAI API", - description: - "OpenAI Responses + Chat Completions endpoints. Covers GPT-5 family and Codex deployments.", - defaultModel: "gpt-5.4", - auth: { type: "api_key", envKey: "OPENAI_API_KEY" }, - onboardingFeatured: true, - }, - { - id: "google", - provider: "google", - label: "Google Gemini API", - description: - "Google Gemini Generative Language API. Uses the standard GEMINI_API_KEY environment variable.", - defaultModel: "gemini-2.5-pro", - auth: { type: "api_key", envKey: "GEMINI_API_KEY" }, - }, - { - id: "mistral", - provider: "mistral", - label: "Mistral", - description: "Mistral La Plateforme — Codestral, Devstral, and Mistral Medium/Large families.", - defaultModel: "mistral-medium-latest", - auth: { type: "api_key", envKey: "MISTRAL_API_KEY" }, - }, - { - id: "groq", - provider: "groq", - label: "Groq", - description: - "Groq LPU cloud. High-throughput inference for Llama 3, Qwen, DeepSeek, and Groq Compound.", - defaultModel: "groq/compound", - auth: { type: "api_key", envKey: "GROQ_API_KEY" }, - }, - { - id: "cerebras", - provider: "cerebras", - label: "Cerebras", - description: "Cerebras Inference cloud — wafer-scale hardware for Qwen, Llama, and GPT-OSS.", - defaultModel: "qwen-3-235b-a22b-instruct-2507", - auth: { type: "api_key", envKey: "CEREBRAS_API_KEY" }, - }, - { - id: "xai", - provider: "xai", - label: "xAI", - description: "xAI Grok API including Grok 4 Fast and Grok Code Fast.", - defaultModel: "grok-4-fast", - auth: { type: "api_key", envKey: "XAI_API_KEY" }, - }, - { - id: "openrouter", - provider: "openrouter", - label: "OpenRouter", - description: - "OpenRouter aggregator. Access Anthropic, OpenAI, Google, open-weights, and community models through one key.", - defaultModel: "anthropic/claude-sonnet-4.5", - auth: { type: "api_key", envKey: "OPENROUTER_API_KEY" }, - }, - { - id: "vercel-ai-gateway", - provider: "vercel-ai-gateway", - label: "Vercel AI Gateway", - description: - "Vercel's multi-provider proxy. Request models by `provider/model` slug and share one billing profile.", - defaultModel: "anthropic/claude-sonnet-4.5", - auth: { type: "api_key", envKey: "AI_GATEWAY_API_KEY" }, - }, - { - id: "zai", - provider: "zai", - label: "Z.AI", - description: "Z.AI GLM-4.5/4.6 family — coding-tuned Chinese models with tool use.", - defaultModel: "glm-4.6", - auth: { type: "api_key", envKey: "ZAI_API_KEY" }, - }, - { - id: "opencode", - provider: "opencode", - label: "OpenCode Zen", - description: - "OpenCode Zen managed endpoint. Pi-mono uses the same OPENCODE_API_KEY as OpenCode Go.", - defaultModel: "claude-sonnet-4.5", - auth: { type: "api_key", envKey: "OPENCODE_API_KEY" }, - }, - { - id: "opencode-go", - provider: "opencode-go", - label: "OpenCode Go", - description: - "OpenCode Go managed endpoint. Shares OPENCODE_API_KEY with OpenCode Zen.", - defaultModel: "kimi-k2.5", - auth: { type: "api_key", envKey: "OPENCODE_API_KEY" }, - }, - { - id: "huggingface", - provider: "huggingface", - label: "Hugging Face", - description: - "Hugging Face Inference Endpoints. Hosts Kimi K2, GLM, DeepSeek, MiniMax, and other open-weights.", - defaultModel: "moonshotai/Kimi-K2.5", - auth: { type: "api_key", envKey: "HF_TOKEN" }, - }, - { - id: "kimi-coding", - provider: "kimi-coding", - label: "Kimi For Coding", - description: - "Moonshot AI Kimi For Coding endpoint — tuned for agentic coding workloads.", - defaultModel: "kimi-for-coding", - auth: { type: "api_key", envKey: "KIMI_API_KEY" }, - }, - { - id: "minimax", - provider: "minimax", - label: "MiniMax", - description: "MiniMax international endpoint for M2 coding models.", - defaultModel: "MiniMax-M2.7", - auth: { type: "api_key", envKey: "MINIMAX_API_KEY" }, - }, - { - id: "minimax-cn", - provider: "minimax-cn", - label: "MiniMax (China)", - description: "MiniMax mainland China endpoint. Uses a separate key from the international tier.", - defaultModel: "MiniMax-M2.7", - auth: { type: "api_key", envKey: "MINIMAX_CN_API_KEY" }, - }, - { - id: "fireworks", - provider: "fireworks", - label: "Fireworks AI", - description: - "Fireworks inference cloud. Resolved locally through `src/main/model-resolver.ts` — pi-ai does not ship a Fireworks catalog entry.", - defaultModel: "accounts/fireworks/models/kimi-k2.5-turbo", - auth: { type: "api_key", envKey: "FIREWORKS_API_KEY" }, - }, - { - id: "fireworks-firepass", - provider: "fireworks-firepass", - label: "Fireworks Fire Pass", - description: - "Fireworks Fire Pass — $7/week subscription for unlimited Kimi K2.6 Turbo. Uses the same FIREWORKS_API_KEY; the Fire Pass entitlement is attached to the account.", - defaultModel: "accounts/fireworks/routers/kimi-k2p6-turbo", - auth: { type: "api_key", envKey: "FIREWORKS_API_KEY" }, - notes: - "Fire Pass routes through the dedicated router id accounts/fireworks/routers/kimi-k2p6-turbo on both the OpenAI- and Anthropic-compat endpoints. See https://docs.fireworks.ai/firepass.", - }, -]; diff --git a/src/main/connector-definitions/cloud.ts b/src/main/connector-definitions/cloud.ts deleted file mode 100644 index 1661091d..00000000 --- a/src/main/connector-definitions/cloud.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Cloud pi-mono connectors. - * - * Cloud providers have bespoke credential discovery — multi-variable AWS / - * Azure setups, or gcloud Application Default Credentials for Vertex. The - * `auth.type` marker tells the credential resolver which discovery path to - * run in the pinned `@mariozechner/pi-ai` runtime. - */ - -import type { ConnectorDefinition } from "../connector-definitions"; - -export const CLOUD_CONNECTORS: ConnectorDefinition[] = [ - { - id: "amazon-bedrock", - provider: "amazon-bedrock", - label: "AWS Bedrock", - description: - "Anthropic, Amazon Nova, and Llama models served through AWS Bedrock. Honours standard AWS credential discovery (profile, IAM keys, Bedrock bearer tokens, ECS roles, IRSA).", - defaultModel: "us.anthropic.claude-sonnet-4-20250514-v1:0", - auth: { type: "aws" }, - onboardingFeatured: true, - notes: - "Credentials resolved from AWS_PROFILE | AWS_ACCESS_KEY_ID+AWS_SECRET_ACCESS_KEY | AWS_BEARER_TOKEN_BEDROCK | AWS_CONTAINER_CREDENTIALS_* | AWS_WEB_IDENTITY_TOKEN_FILE. Region defaults to us-east-1.", - }, - { - id: "azure-openai", - provider: "azure-openai-responses", - label: "Azure OpenAI", - description: - "Azure-hosted OpenAI deployments via the Responses API. Requires AZURE_OPENAI_API_KEY plus a resource identifier.", - defaultModel: "gpt-5.4", - auth: { type: "azure" }, - notes: - "Provide AZURE_OPENAI_API_KEY plus AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME. Optional AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT_NAME_MAP.", - }, - { - id: "google-vertex", - provider: "google-vertex", - label: "Google Vertex AI", - description: - "Gemini, Claude, and third-party models on Google Vertex AI. Uses Application Default Credentials from `gcloud auth application-default login` or GOOGLE_APPLICATION_CREDENTIALS.", - defaultModel: "gemini-2.5-pro", - auth: { type: "gcp_adc" }, - notes: - "Set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION. Optional GOOGLE_CLOUD_API_KEY takes precedence over ADC when present.", - }, -]; diff --git a/src/main/connector-definitions/index.ts b/src/main/connector-definitions/index.ts deleted file mode 100644 index 380227e0..00000000 --- a/src/main/connector-definitions/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Barrel for the connector catalog partition files. The three per-auth - * modules live side-by-side instead of next to `connector-definitions.ts` - * so `ls src/main/` stays skimmable; this re-export exists so existing - * imports like `./connector-definitions-data-oauth` continue to resolve - * via `./connector-definitions/oauth` with the same symbol names. - */ - -export { OAUTH_CONNECTORS } from "./oauth"; -export { API_KEY_CONNECTORS } from "./apikey"; -export { CLOUD_CONNECTORS } from "./cloud"; -export { LOCAL_CONNECTORS } from "./local"; diff --git a/src/main/connector-definitions/local.ts b/src/main/connector-definitions/local.ts deleted file mode 100644 index ad4ef44c..00000000 --- a/src/main/connector-definitions/local.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Local pi-mono connectors. - * - * Ollama and LM Studio both expose an OpenAI-compatible - * `/v1/chat/completions` endpoint, so they are routed through pi-ai's - * `openai-completions` API path with a per-installation `baseUrl` that - * the user enters during onboarding. The provider ids are deliberately - * absent from `@mariozechner/pi-ai`'s `KnownProvider` set — model - * dispatch resolves them locally via `src/main/model-resolver.ts` the - * same way `fireworks` and `fireworks-firepass` do. - * - * No environment variable name accompanies the auth descriptor: a local - * server's address is a user choice, never read from `process.env`. - */ - -import type { ConnectorDefinition } from "../connector-definitions"; - -export const LOCAL_CONNECTORS: ConnectorDefinition[] = [ - { - id: "ollama", - provider: "ollama", - label: "Ollama", - description: - "Local Ollama server (https://ollama.com) — runs open-weights models on your own machine through its OpenAI-compatible endpoint.", - defaultModel: "llama3.2", - auth: { type: "local", defaultBaseUrl: "http://localhost:11434/v1" }, - notes: - "Ollama exposes /v1/chat/completions and /v1/models. The default port is 11434; override with a loopback or private-network address.", - }, - { - id: "lm-studio", - provider: "lm-studio", - label: "LM Studio", - description: - "Local LM Studio server (https://lmstudio.ai) — host any loaded model through its OpenAI-compatible endpoint.", - defaultModel: "local-model", - auth: { type: "local", defaultBaseUrl: "http://localhost:1234/v1" }, - notes: - "Enable LM Studio's local server from the Developer tab; the default port is 1234. Use a loopback or private-network address.", - }, -]; diff --git a/src/main/connector-definitions/oauth.ts b/src/main/connector-definitions/oauth.ts deleted file mode 100644 index a19b6bb3..00000000 --- a/src/main/connector-definitions/oauth.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * OAuth-based pi-mono connectors. - * - * Each entry targets one of the five built-in OAuth providers from the - * pinned `@mariozechner/pi-ai` runtime. The - * runtime opens the provider's browser auth flow, stores the refreshed - * token in the `credentials` table, and passes it as the API key when - * invoking pi-ai. - * - * The `oauthId` surfaced here matches pi-ai's five registered provider ids - * verbatim (`anthropic` / `openai-codex` / `github-copilot` / - * `google-gemini-cli` / `google-antigravity`) and is passed straight to - * `getOAuthProvider`. - */ - -import type { ConnectorDefinition } from "../connector-definitions"; - -export const OAUTH_CONNECTORS: ConnectorDefinition[] = [ - { - id: "claude-pro", - provider: "anthropic", - label: "Claude Pro/Max", - description: - "Anthropic Claude via Claude Pro / Max subscription OAuth. Runs entirely through pi-mono's built-in OAuth handler; no API key required.", - defaultModel: "claude-sonnet-4-5", - auth: { type: "oauth", oauthId: "anthropic" }, - onboardingFeatured: true, - notes: - "Requires an active Claude Pro or Max subscription. Tokens refresh automatically.", - }, - { - id: "openai-codex", - provider: "openai-codex", - label: "ChatGPT Plus/Pro (Codex)", - description: - "OpenAI Codex via a ChatGPT Plus or Pro subscription. Personal-use only — production workloads should use the OpenAI API connector.", - defaultModel: "gpt-5.3-codex", - auth: { type: "oauth", oauthId: "openai-codex" }, - onboardingFeatured: true, - notes: "Personal use only; requires ChatGPT Plus or Pro.", - }, - { - id: "github-copilot", - provider: "github-copilot", - label: "GitHub Copilot", - description: - "Models exposed through a GitHub Copilot subscription. Supports github.com and GitHub Enterprise Server.", - defaultModel: "claude-opus-4.5", - auth: { type: "oauth", oauthId: "github-copilot" }, - notes: - "If a model shows 'not supported', enable it in VS Code: Copilot Chat → model selector → Enable.", - }, - { - id: "gemini-cli", - provider: "google-gemini-cli", - label: "Google Gemini CLI", - description: - "Google Gemini models via Cloud Code Assist OAuth. Free tier works with any Google account (rate-limited).", - defaultModel: "gemini-2.5-pro", - auth: { type: "oauth", oauthId: "google-gemini-cli" }, - notes: - "For paid Cloud Code Assist, set GOOGLE_CLOUD_PROJECT. Google-gemini-cli OAuth provider id in pi-ai.", - }, - { - id: "antigravity", - provider: "google-antigravity", - label: "Google Antigravity", - description: - "Google Antigravity sandbox with Gemini 3, Claude, and GPT-OSS models. Free with any Google account.", - defaultModel: "claude-sonnet-4-5", - auth: { type: "oauth", oauthId: "google-antigravity" }, - notes: "Maps to pi-ai OAuth provider id `google-antigravity`.", - }, -]; diff --git a/src/main/connector-health-service.ts b/src/main/connector-health-service.ts deleted file mode 100644 index bfe4a085..00000000 --- a/src/main/connector-health-service.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { getEnvApiKey } from "@mariozechner/pi-ai"; -import type { AppDatabase } from "./database"; -import { getConnectorDefinition, isPiKnownProvider, parseEnvBindingText } from "./connectors"; -import type { ConnectorId } from "@shared/types"; -import type { CredentialStore } from "./credentials"; - -interface ConnectorHealthDependencies { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; - credentialStore: CredentialStore; -} - -type HealthState = { - status: "ready" | "auth_required" | "not_installed" | "error"; - authState: "ok" | "required" | "error" | "unknown"; - lastError: string | null; -}; - -export function createConnectorHealthService({ - db, - logger, - publishDomainChanged, - credentialStore, -}: ConnectorHealthDependencies) { - function randomFallbackCompanyId() { - const snapshot = db.projection.snapshot.listSnapshot(); - return snapshot.companies[0]?.id ?? "00000000-0000-0000-0000-000000000000"; - } - - function evaluateCredential(id: ConnectorId): HealthState { - const definition = getConnectorDefinition(id); - const stored = credentialStore.read(id); - - switch (definition.auth.type) { - case "oauth": { - if (stored?.kind !== "oauth") { - return { status: "auth_required", authState: "required", lastError: "OAuth login required." }; - } - const creds = stored.value; - const expires = typeof creds.expires === "number" ? creds.expires : null; - if (expires !== null && expires <= Date.now()) { - return { status: "auth_required", authState: "required", lastError: "OAuth token expired." }; - } - return { status: "ready", authState: "ok", lastError: null }; - } - case "api_key": { - if (stored?.kind === "api_key") { - return { status: "ready", authState: "ok", lastError: null }; - } - if (isPiKnownProvider(definition.provider) && getEnvApiKey(definition.provider)) { - return { status: "ready", authState: "ok", lastError: null }; - } - // Re-parse envBindingText on every probe: it is user-editable and must - // not be cached into credentialStore. An explicit binding for the - // connector's declared envKey (non-empty value) counts as ready. - const connector = db.core.connectors.findConnector(id); - const boundValue = connector - ? parseEnvBindingText(connector.envBindingText)[definition.auth.envKey] - : undefined; - if (boundValue && boundValue.length > 0) { - return { status: "ready", authState: "ok", lastError: null }; - } - return { - status: "auth_required", - authState: "required", - lastError: `API key required (${definition.auth.envKey}).`, - }; - } - case "aws": { - if (stored?.kind !== "aws") { - return { status: "auth_required", authState: "required", lastError: "AWS credentials not configured." }; - } - const cfg = stored.value; - if (cfg.authMode === "profile" && !cfg.awsProfile) { - return { status: "error", authState: "error", lastError: "AWS profile missing." }; - } - if (cfg.authMode === "iam" && (!cfg.accessKeyId || !cfg.secretAccessKey)) { - return { status: "error", authState: "error", lastError: "AWS IAM keys missing." }; - } - if (cfg.authMode === "bearer" && !cfg.bearerToken) { - return { status: "error", authState: "error", lastError: "AWS bearer token missing." }; - } - return { status: "ready", authState: "ok", lastError: null }; - } - case "azure": { - if (stored?.kind !== "azure") { - return { status: "auth_required", authState: "required", lastError: "Azure credentials not configured." }; - } - const cfg = stored.value; - if (!cfg.apiKey) { - return { status: "error", authState: "error", lastError: "Azure OpenAI API key missing." }; - } - if (!cfg.baseUrl && !cfg.resourceName) { - return { status: "error", authState: "error", lastError: "Azure requires baseUrl or resourceName." }; - } - return { status: "ready", authState: "ok", lastError: null }; - } - case "gcp_adc": { - if (stored?.kind !== "gcp_adc") { - return { status: "auth_required", authState: "required", lastError: "GCP ADC not configured." }; - } - const cfg = stored.value; - if (!cfg.project || !cfg.location) { - return { status: "error", authState: "error", lastError: "GCP project/location missing." }; - } - return { status: "ready", authState: "ok", lastError: null }; - } - case "local": { - if (stored?.kind !== "local") { - return { status: "auth_required", authState: "required", lastError: "Local server URL not configured." }; - } - if (!stored.value.baseUrl) { - return { status: "error", authState: "error", lastError: "Local server URL missing." }; - } - return { status: "ready", authState: "ok", lastError: null }; - } - } - } - - async function checkConnector(id: ConnectorId) { - const companyId = db.core.settings.getCurrentCompanyId() ?? randomFallbackCompanyId(); - - db.core.connectors.updateConnectorHealth({ - id, - status: "detected", - authState: db.core.connectors.getConnector(id).authState, - version: null, - lastError: null, - }); - publishDomainChanged(); - - try { - const result = evaluateCredential(id); - db.core.connectors.updateConnectorHealth({ - id, - status: result.status, - authState: result.authState, - version: null, - lastError: result.lastError, - }); - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "connector.tested", - entityType: "connector", - entityId: id, - detail: result.status, - }); - logger.info(`[connector] Health check for ${id}: ${result.status}`); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - logger.error(`[connector] Health check failed for ${id}: ${errorMessage}`); - db.core.connectors.updateConnectorHealth({ - id, - status: "error", - authState: "unknown", - version: null, - lastError: errorMessage, - }); - } - publishDomainChanged(); - } - - return { - checkConnector, - randomFallbackCompanyId, - }; -} diff --git a/src/main/connector-matching.ts b/src/main/connector-matching.ts deleted file mode 100644 index da0c278c..00000000 --- a/src/main/connector-matching.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { ConnectorId, TaskType } from "@shared/types"; -import { CONNECTORS } from "./connectors"; - -export const ROLE_DEPARTMENT_HINTS: Record = { - engineering: "code", - research: "research", - marketing: "content", - product: "content", - hr: "management", - finance: "management", - executive: "management", - design: "content", - customer_support: "content", - operations: "management", - sales: "content", - legal: "management", -}; - -export function inferTaskType(department: string | null | undefined): TaskType { - if (!department) return "general"; - const lower = department.toLowerCase(); - return ROLE_DEPARTMENT_HINTS[lower] ?? "general"; -} - -export function getConnectorStrengths(connectorId: ConnectorId): string { - const definition = CONNECTORS.find((c) => c.id === connectorId); - if (!definition) return "General-purpose AI connector."; - return definition.description; -} diff --git a/src/main/connector-model-policy.ts b/src/main/connector-model-policy.ts deleted file mode 100644 index 669b13d7..00000000 --- a/src/main/connector-model-policy.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { ConnectorId } from "@shared/types"; -import { getConnectorDefinition } from "./connectors"; -import { resolveModels } from "./model-resolver"; - -interface ConnectorModelPolicyDeps { - getConnector: (id: ConnectorId) => { id: ConnectorId; label?: string | null; model: string | null }; - getDisabledModels: (companyId: string, connectorId: string) => Array<{ id: string; label: string }>; -} - -/** - * Adapter over AppDatabase that returns the structural shape consumed by - * `getConnectorModelPolicy` / `validateConnectorModelSelection`. Callers - * pass an `AppDatabase`-ish object; the helper unwraps the two typed - * domain modules so we do not repeat the closure literal at every site. - */ -export function connectorPolicyDepsFromDb(db: { - core: { - connectors: { getConnector: (id: ConnectorId) => { id: ConnectorId; label?: string | null; model: string | null } }; - settings: { getDisabledModels: (companyId: string, connectorId: string) => Array<{ id: string; label: string }> }; - }; -}): ConnectorModelPolicyDeps { - return { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (cid, connId) => db.core.settings.getDisabledModels(cid, connId), - }; -} - -export interface ConnectorModelPolicyResult { - connectorId: ConnectorId; - connectorLabel: string; - enabledModels: Array<{ id: string; label: string }>; - defaultModel: string | null; -} - -function uniqueModels(models: Array<{ id: string; label: string }>) { - const byId = new Map(); - for (const model of models) { - const id = model.id.trim(); - if (!id) continue; - if (!byId.has(id)) { - byId.set(id, { id, label: model.label || id }); - } - } - return Array.from(byId.values()); -} - -/** - * Returns the models available for a given pi-ai provider id, going through - * `resolveModels` so that providers not in pi-ai's built-in catalog (currently - * the two Fireworks connectors, which serve `accounts/fireworks/routers/...` - * and curated `accounts/fireworks/models/...` ids) are represented in the UI - * model picker instead of collapsing to an empty list. - */ -function listProviderModels(provider: string): Array<{ id: string; label: string }> { - return resolveModels(provider).map((model) => ({ id: model.id, label: model.name })); -} - -export function getConnectorModelPolicy( - deps: ConnectorModelPolicyDeps, - companyId: string, - connectorId: ConnectorId, -): ConnectorModelPolicyResult { - const connector = deps.getConnector(connectorId); - const definition = getConnectorDefinition(connectorId); - const disabledModels = new Set(deps.getDisabledModels(companyId, connectorId).map((model) => model.id)); - - const catalog = listProviderModels(definition.provider); - const enabledModels = uniqueModels(catalog).filter((model) => !disabledModels.has(model.id)); - - return { - connectorId, - connectorLabel: connector.label?.trim() || definition.label, - enabledModels, - defaultModel: connector.model?.trim() || definition.defaultModel, - }; -} - -export function validateConnectorModelSelection( - deps: ConnectorModelPolicyDeps, - companyId: string, - connectorId: ConnectorId, - model: string | null | undefined, -): { ok: true; effectiveModel: string | null } | { ok: false; error: string } { - const policy = getConnectorModelPolicy(deps, companyId, connectorId); - const selectedModel = model?.trim() || null; - - if (policy.enabledModels.length === 0) { - return { - ok: false, - error: `${policy.connectorLabel} has no enabled models available.`, - }; - } - - if (selectedModel) { - if (!policy.enabledModels.some((entry) => entry.id === selectedModel)) { - return { - ok: false, - error: `${policy.connectorLabel} does not allow model "${selectedModel}".`, - }; - } - return { ok: true, effectiveModel: selectedModel }; - } - - if (policy.defaultModel && policy.enabledModels.some((entry) => entry.id === policy.defaultModel)) { - return { ok: true, effectiveModel: policy.defaultModel }; - } - - return { ok: true, effectiveModel: policy.enabledModels[0]?.id ?? null }; -} - -/** - * Pi-mono catalog does not have free-form compat connectors; every connector - * has a fixed pi-ai provider. The configuration-level model validator is a - * no-op retained for IPC contract compatibility. - */ -export function validateConnectorConfigurationModel( - _connectorId: ConnectorId, - _model: string | null | undefined, -): { ok: true } | { ok: false; error: string } { - return { ok: true }; -} diff --git a/src/main/connectors.ts b/src/main/connectors.ts deleted file mode 100644 index 34858856..00000000 --- a/src/main/connectors.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { getProviders, type KnownProvider } from "@mariozechner/pi-ai"; -import type { CapabilityMatrix, ConnectorId, ConnectorRecord } from "@shared/types"; -import { CONNECTORS, type ConnectorDefinition, type ConnectorProvider, type LocalModelResolverProvider } from "./connector-definitions"; -import { buildApiKeyDoc, buildCloudDoc, buildOAuthDoc } from "./connector-definitions-docs"; -export { CONNECTORS } from "./connector-definitions"; -export type { ConnectorDefinition, ConnectorProvider, LocalModelResolverProvider } from "./connector-definitions"; -export { findConnectorDefinition, listFeaturedOnboardingConnectors } from "./connector-definitions-lookup"; - -const RESERVED_ENV_BINDING_KEYS = new Set([ - "PATH", - "HOME", - "USER", - "SHELL", - "NODE_OPTIONS", - "ELECTRON_RUN_AS_NODE", - "DYLD_INSERT_LIBRARIES", - "LD_PRELOAD", - "PWD", -]); - -const LOCAL_MODEL_RESOLVER_PROVIDERS: ReadonlySet = new Set([ - "fireworks", - "fireworks-firepass", - "ollama", - "lm-studio", -]); -const PI_KNOWN_PROVIDER_IDS: ReadonlySet = new Set(getProviders()); - -/** - * Pi-mono drives all provider dispatch through pi-ai, so the adapter-era - * capability matrix now collapses to a uniform baseline. These values are - * still written into the `connectors` table for legacy UI surfaces that read - * them, but the worker and resolver no longer branch on them. - */ -const PI_MONO_CAPABILITIES: CapabilityMatrix = { - sessionResume: true, - gracefulCancel: true, - modelDiscovery: true, - structuredTranscript: true, - costAttribution: true, -}; - -export function getConnectorDefinition(id: string) { - const definition = CONNECTORS.find((entry) => entry.id === id); - if (!definition) { - throw new Error(`Unknown connector: ${id}`); - } - return definition; -} - -export function isPiKnownProvider(provider: string): provider is KnownProvider { - return PI_KNOWN_PROVIDER_IDS.has(provider); -} - -export function isLocalModelResolverProvider(provider: string): provider is LocalModelResolverProvider { - return LOCAL_MODEL_RESOLVER_PROVIDERS.has(provider as LocalModelResolverProvider); -} - -export function getConnectorProvider(id: ConnectorId): ConnectorProvider { - return getConnectorDefinition(id).provider; -} - -export function getConnectorKnownProvider(id: ConnectorId): KnownProvider | null { - const provider = getConnectorProvider(id); - return isPiKnownProvider(provider) ? provider : null; -} - -export function parseEnvBindingText(text: string): Record { - const bindings: Record = {}; - for (const rawLine of text.split(/\r?\n/)) { - const line = rawLine.trim(); - if (!line || line.startsWith("#")) continue; - const [envKey, ...rest] = line.split("="); - const key = envKey?.trim(); - const value = rest.join("=").trim(); - if (!key || !value) continue; - bindings[key] = value; - } - return bindings; -} - -export function listInvalidEnvBindingKeys(text: string): string[] { - return Object.keys(parseEnvBindingText(text)).filter((key) => { - return RESERVED_ENV_BINDING_KEYS.has(key) || key.startsWith("AGENT_COMPANY_"); - }); -} - -export { PI_MONO_CAPABILITIES }; - -export function renderConnectorConfigurationDoc(definition: ConnectorDefinition): string { - return renderConfigurationDoc(definition); -} - -function renderConfigurationDoc(definition: ConnectorDefinition): string { - switch (definition.auth.type) { - case "oauth": - return buildOAuthDoc(definition.label, definition.auth.oauthId); - case "api_key": - return buildApiKeyDoc(definition.label, definition.auth.envKey); - case "aws": - return buildCloudDoc( - definition.label, - "Credentials are discovered via the standard AWS chain (profile, IAM keys, Bedrock bearer token, ECS roles, or IRSA).", - ); - case "azure": - return buildCloudDoc( - definition.label, - "Provide AZURE_OPENAI_API_KEY plus AZURE_OPENAI_BASE_URL or AZURE_OPENAI_RESOURCE_NAME.", - ); - case "gcp_adc": - return buildCloudDoc( - definition.label, - "Uses Google Cloud Application Default Credentials. Run `gcloud auth application-default login` or set GOOGLE_APPLICATION_CREDENTIALS.", - ); - case "local": - return buildCloudDoc( - definition.label, - `OpenAI-compatible local server. Default base URL: ${definition.auth.defaultBaseUrl}. Configure under Onboarding → Providers (Advanced) and pick a model id that your server actually serves.`, - ); - } -} - -export function buildDefaultConnectorRows(existing: Array> = []): ConnectorRecord[] { - const byId = new Map(existing.map((record) => [record.id, record])); - return CONNECTORS.map((definition) => { - const existingRecord = byId.get(definition.id); - return { - id: definition.id, - label: definition.label, - description: definition.description, - status: existingRecord?.status ?? "not_installed", - version: existingRecord?.version ?? null, - authState: existingRecord?.authState ?? "unknown", - lastCheckedAt: existingRecord?.lastCheckedAt ?? null, - lastError: existingRecord?.lastError ?? null, - model: existingRecord?.model ?? definition.defaultModel, - envBindingText: existingRecord?.envBindingText ?? "", - notes: existingRecord?.notes ?? definition.notes ?? "", - configurationDoc: renderConfigurationDoc(definition), - capabilityMatrix: PI_MONO_CAPABILITIES, - }; - }); -} diff --git a/src/main/constants.ts b/src/main/constants.ts deleted file mode 100644 index ea65bcf5..00000000 --- a/src/main/constants.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Task and workspace locks are considered stale after 15 minutes. The window - * covers heartbeat cadence, worst-case model/tool round trips, and shutdown - * recovery margin while still releasing abandoned work within one operator - * session. - */ -export const STALE_LOCK_TIMEOUT_MS = 15 * 60 * 1000; - -export const DOCUMENT_LIFECYCLE_PROCESSOR_DEFAULTS = { - /** Five attempts cover transient filesystem/indexing failures without hiding a broken hook. */ - maxAttempts: 5, - /** Document hooks are local metadata side effects; 60s separates a dead handler from a slow one. */ - staleRunningMs: 60_000, - /** Keeps a burst of document hooks efficient while bounding one sweep's synchronous work. */ - batchSize: 32, - /** Recovers crash leftovers quickly without turning idle profiles into polling loops. */ - sweepIntervalMs: 15_000, -} as const; diff --git a/src/main/credentials/credential-resolver.ts b/src/main/credentials/credential-resolver.ts deleted file mode 100644 index 9ec90062..00000000 --- a/src/main/credentials/credential-resolver.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { getOAuthProvider } from "@mariozechner/pi-ai/oauth"; -import { getEnvApiKey } from "@mariozechner/pi-ai"; -import { isAwsBedrockEndpointUrl, isLocalConnectorBaseUrl } from "@shared/contracts/schemas-credentials"; -import { getConnectorDefinition, isPiKnownProvider } from "@main/connectors"; -import { UpstreamError } from "../errors/index.js"; -import { CredentialStore } from "./credential-store"; -import type { OAuthCredentialPayload, StoredCredentialPayload } from "./types"; - -const REFRESH_WINDOW_MS = 60_000; - -export type CredentialErrorCode = - | "CREDENTIAL_MISSING" - | "CREDENTIAL_EXPIRED" - | "CREDENTIAL_INVALID" - | "CREDENTIAL_REFRESH_FAILED"; - -export class CredentialError extends UpstreamError { - readonly connectorId: string; - - constructor( - code: CredentialErrorCode, - connectorId: string, - message?: string, - ) { - super({ - code, - message: message ?? code, - context: { connectorId }, - }); - this.name = "CredentialError"; - this.connectorId = connectorId; - } -} - -export interface ResolvedCredential { - apiKey: string; - extraEnv?: Record; - /** Base URL for OpenAI-compatible local servers (Ollama, LM Studio). */ - baseUrl?: string; -} - -export class CredentialResolver { - private readonly refreshLocks = new Map>(); - - constructor(private readonly store: CredentialStore) {} - - async resolve(connectorId: string): Promise { - const definition = getConnectorDefinition(connectorId); - if (!definition.auth) { - throw new CredentialError("CREDENTIAL_INVALID", connectorId, `Connector ${connectorId} has no auth schema.`); - } - const auth = definition.auth; - const stored = this.store.read(connectorId); - - switch (auth.type) { - case "oauth": { - if (!auth.oauthId) { - throw new CredentialError("CREDENTIAL_INVALID", connectorId, `OAuth auth is missing oauthId.`); - } - if (stored?.kind !== "oauth") { - throw new CredentialError("CREDENTIAL_MISSING", connectorId, `OAuth not yet completed for ${connectorId}.`); - } - await this.refreshIfNeeded(connectorId, auth.oauthId, stored.value); - const fresh = this.store.read(connectorId); - if (fresh?.kind !== "oauth") { - throw new CredentialError("CREDENTIAL_INVALID", connectorId); - } - const provider = getOAuthProvider(auth.oauthId); - if (!provider) throw new CredentialError("CREDENTIAL_INVALID", connectorId, `Unknown OAuth provider: ${auth.oauthId}`); - return { apiKey: provider.getApiKey(fresh.value as never) }; - } - case "api_key": { - if (stored?.kind === "api_key") { - if (stored.value.source === "literal") { - return { apiKey: stored.value.value }; - } - // Only the connector's own declared envKey may be read from process.env. - // Arbitrary env var names would let a malicious payload exfil secrets - // like CSC_KEY_PASSWORD or AWS_SECRET_ACCESS_KEY by routing them to a - // provider as the "api key". - if (stored.value.value !== auth.envKey) { - throw new CredentialError( - "CREDENTIAL_INVALID", - connectorId, - `Env var ${stored.value.value} is not permitted for connector ${connectorId}.`, - ); - } - const fromEnv = process.env[stored.value.value]; - if (!fromEnv) throw new CredentialError("CREDENTIAL_MISSING", connectorId, `Env var ${stored.value.value} is not set.`); - return { apiKey: fromEnv }; - } - if (isPiKnownProvider(definition.provider)) { - const envKey = getEnvApiKey(definition.provider); - if (envKey) return { apiKey: envKey }; - } - throw new CredentialError("CREDENTIAL_MISSING", connectorId, `No credential or env API key for ${connectorId}.`); - } - case "azure": { - if (stored?.kind !== "azure") { - throw new CredentialError("CREDENTIAL_MISSING", connectorId); - } - const cfg = stored.value; - const env: Record = { AZURE_OPENAI_API_KEY: cfg.apiKey }; - if (cfg.baseUrl) env.AZURE_OPENAI_BASE_URL = cfg.baseUrl; - if (cfg.resourceName) env.AZURE_OPENAI_RESOURCE_NAME = cfg.resourceName; - if (cfg.apiVersion) env.AZURE_OPENAI_API_VERSION = cfg.apiVersion; - if (cfg.deploymentMap && Object.keys(cfg.deploymentMap).length > 0) { - env.AZURE_OPENAI_DEPLOYMENT_NAME_MAP = Object.entries(cfg.deploymentMap) - .map(([k, v]) => `${k}=${v}`) - .join(","); - } - return { apiKey: cfg.apiKey, extraEnv: env }; - } - case "aws": { - if (stored?.kind !== "aws") { - throw new CredentialError("CREDENTIAL_MISSING", connectorId); - } - const cfg = stored.value; - const env: Record = { AWS_REGION: cfg.region ?? "us-east-1" }; - if (cfg.authMode === "profile" && cfg.awsProfile) env.AWS_PROFILE = cfg.awsProfile; - if (cfg.authMode === "iam") { - if (!cfg.accessKeyId || !cfg.secretAccessKey) { - throw new CredentialError("CREDENTIAL_INVALID", connectorId, "IAM auth requires both accessKeyId and secretAccessKey."); - } - env.AWS_ACCESS_KEY_ID = cfg.accessKeyId; - env.AWS_SECRET_ACCESS_KEY = cfg.secretAccessKey; - if (cfg.sessionToken) env.AWS_SESSION_TOKEN = cfg.sessionToken; - } - if (cfg.authMode === "bearer") { - if (!cfg.bearerToken) { - throw new CredentialError("CREDENTIAL_INVALID", connectorId, "Bearer auth requires a bearerToken."); - } - env.AWS_BEARER_TOKEN_BEDROCK = cfg.bearerToken; - } - if (cfg.forceCache) env.AWS_BEDROCK_FORCE_CACHE = "1"; - if (cfg.endpointUrl) { - if (!isAwsBedrockEndpointUrl(cfg.endpointUrl)) { - throw new CredentialError( - "CREDENTIAL_INVALID", - connectorId, - "AWS Bedrock endpointUrl must be an HTTPS AWS Bedrock runtime endpoint or a private endpoint.", - ); - } - env.AWS_ENDPOINT_URL_BEDROCK_RUNTIME = cfg.endpointUrl; - } - if (cfg.skipAuth) env.AWS_BEDROCK_SKIP_AUTH = "1"; - if (cfg.forceHttp1) env.AWS_BEDROCK_FORCE_HTTP1 = "1"; - return { apiKey: "", extraEnv: env }; - } - case "gcp_adc": { - if (stored?.kind !== "gcp_adc") { - throw new CredentialError("CREDENTIAL_MISSING", connectorId); - } - const cfg = stored.value; - const env: Record = { GOOGLE_CLOUD_PROJECT: cfg.project, GOOGLE_CLOUD_LOCATION: cfg.location }; - if (cfg.credentialsPath) env.GOOGLE_APPLICATION_CREDENTIALS = cfg.credentialsPath; - return { apiKey: "", extraEnv: env }; - } - case "local": { - if (stored?.kind !== "local") { - throw new CredentialError("CREDENTIAL_MISSING", connectorId); - } - if (!isLocalConnectorBaseUrl(stored.value.baseUrl)) { - throw new CredentialError( - "CREDENTIAL_INVALID", - connectorId, - "Local connector baseUrl must use localhost, loopback, or a private IP host.", - ); - } - // Ollama and LM Studio ignore the bearer value but the OpenAI SDK - // refuses an empty string, so we hand it the connector id as a - // stable non-empty placeholder. The actual transport is keyed off - // `baseUrl`, surfaced to the worker through the stream model. - return { apiKey: connectorId, baseUrl: stored.value.baseUrl }; - } - default: { - const exhaustive: never = auth; - throw new CredentialError("CREDENTIAL_INVALID", connectorId, `Unsupported auth descriptor: ${JSON.stringify(exhaustive)}`); - } - } - } - - private async refreshIfNeeded(connectorId: string, oauthId: string, creds: OAuthCredentialPayload): Promise { - if (typeof creds.expires !== "number" || !Number.isFinite(creds.expires)) return; - if (Date.now() < creds.expires - REFRESH_WINDOW_MS) return; - - const existing = this.refreshLocks.get(connectorId); - if (existing) { - await existing; - return; - } - - const promise = (async () => { - const provider = getOAuthProvider(oauthId); - if (!provider) { - throw new CredentialError("CREDENTIAL_INVALID", connectorId, `Unknown OAuth provider: ${oauthId}`); - } - try { - const refreshed = await provider.refreshToken(creds as never); - const payload: StoredCredentialPayload = { kind: "oauth", value: refreshed as OAuthCredentialPayload }; - const expiresAt = typeof refreshed.expires === "number" && Number.isFinite(refreshed.expires) - ? new Date(refreshed.expires).toISOString() - : null; - this.store.saveRefreshedOAuth(connectorId, payload, expiresAt); - } catch (error) { - this.store.setStatus(connectorId, "expired", error instanceof Error ? error.message : String(error)); - throw new CredentialError("CREDENTIAL_REFRESH_FAILED", connectorId, error instanceof Error ? error.message : String(error)); - } - })(); - - this.refreshLocks.set(connectorId, promise); - try { - await promise; - } finally { - this.refreshLocks.delete(connectorId); - } - } -} diff --git a/src/main/credentials/credential-store.ts b/src/main/credentials/credential-store.ts deleted file mode 100644 index 19db1a7d..00000000 --- a/src/main/credentials/credential-store.ts +++ /dev/null @@ -1,180 +0,0 @@ -import type { AppDatabase } from "@main/database"; -import type { CredentialBackend, CredentialKind } from "@main/database/credentials"; -import type { CredentialStatus } from "@main/database/credentials"; -import { credentialPayloadSchema, type CredentialSummary } from "@shared/contracts/schemas-credentials"; -import { z } from "zod"; -import { UpstreamError } from "../errors/index.js"; -import type { StoredCredentialPayload } from "./types"; - -const HINT_SUFFIX_LEN = 4; -const HINT_PREFIX_LEN = 6; - -const oauthCredentialPayloadSchema = z.object({ - refresh: z.string().min(1), - access: z.string().min(1), - expires: z.number().finite(), -}).passthrough(); - -const storedCredentialPayloadSchema = z.union([ - credentialPayloadSchema, - z.object({ kind: z.literal("oauth"), value: oauthCredentialPayloadSchema }), -]); - -export class CredentialStoreReadError extends UpstreamError { - readonly connectorId: string; - - constructor(connectorId: string, message: string) { - super({ - code: "CREDENTIAL_INVALID", - message, - context: { connectorId }, - }); - this.name = "CredentialStoreReadError"; - this.connectorId = connectorId; - } -} - -function maskApiKey(value: string): string { - if (value.length <= HINT_PREFIX_LEN + HINT_SUFFIX_LEN) { - return `${value.slice(0, 2)}...`; - } - const prefix = value.slice(0, HINT_PREFIX_LEN); - const suffix = value.slice(-HINT_SUFFIX_LEN); - return `${prefix}...${suffix}`; -} - -export function deriveDisplayHint(payload: StoredCredentialPayload): string { - switch (payload.kind) { - case "api_key": - return payload.value.source === "literal" - ? maskApiKey(payload.value.value) - : `env:${payload.value.value}`; - case "azure": - return payload.value.resourceName - ? `azure:${payload.value.resourceName}` - : `azure:${maskApiKey(payload.value.apiKey)}`; - case "aws": - if (payload.value.authMode === "profile") return `aws:profile=${payload.value.awsProfile ?? "?"}`; - if (payload.value.authMode === "iam") return `aws:iam=${maskApiKey(payload.value.accessKeyId ?? "?")}`; - return `aws:bearer`; - case "gcp_adc": - return `gcp:${payload.value.project}@${payload.value.location}`; - case "oauth": { - const expiresMs = payload.value.expires; - const expiresLabel = typeof expiresMs === "number" && Number.isFinite(expiresMs) - ? new Date(expiresMs).toISOString() - : "no-expiry"; - return `oauth:expires=${expiresLabel}`; - } - case "local": - return `local:${payload.value.baseUrl}`; - } -} - -export interface CredentialStoreDeps { - db: AppDatabase; -} - -function formatCredentialPayloadError(error: z.ZodError): string { - return error.issues - .map((issue) => { - const path = issue.path.length > 0 ? issue.path.join(".") : "payload"; - return `${path}: ${issue.message}`; - }) - .join("; "); -} - -function parseStoredCredentialPayload( - connectorId: string, - kind: CredentialKind, - json: string, -): StoredCredentialPayload { - let value: unknown; - try { - value = JSON.parse(json); - } catch { - throw new CredentialStoreReadError(connectorId, "Stored credential payload is not valid JSON."); - } - const parsed = storedCredentialPayloadSchema.safeParse({ kind, value }); - if (!parsed.success) { - throw new CredentialStoreReadError( - connectorId, - `Stored credential payload failed schema validation: ${formatCredentialPayloadError(parsed.error)}`, - ); - } - return parsed.data as StoredCredentialPayload; -} - -export class CredentialStore { - constructor(private readonly deps: CredentialStoreDeps) {} - - list(): CredentialSummary[] { - return this.deps.db.core.credentials.list().map((row) => ({ - connectorId: row.connectorId, - kind: row.kind as CredentialKind, - displayHint: row.displayHint, - status: row.status, - expiresAt: row.expiresAt, - lastRefreshedAt: row.lastRefreshedAt, - lastError: row.lastError, - updatedAt: row.updatedAt, - })); - } - - /** Encrypts and stores a credential. Caller is responsible for kind/connectorId match. */ - save(connectorId: string, payload: StoredCredentialPayload, expiresAt: string | null = null): CredentialSummary { - const json = JSON.stringify(payload.value); - const { backend, payload: ciphertext } = this.deps.db.vault.encrypt(json); - const stored = this.deps.db.core.credentials.upsert({ - connectorId, - kind: payload.kind, - backend: backend as CredentialBackend, - ciphertext, - displayHint: deriveDisplayHint(payload), - status: "active", - expiresAt, - lastRefreshedAt: null, - lastError: null, - }); - return { - connectorId: stored.connectorId, - kind: stored.kind, - displayHint: stored.displayHint, - status: stored.status, - expiresAt: stored.expiresAt, - lastRefreshedAt: stored.lastRefreshedAt, - lastError: stored.lastError, - updatedAt: stored.updatedAt, - }; - } - - /** Decrypts and returns the typed credential payload. Returns null when missing. */ - read(connectorId: string): StoredCredentialPayload | null { - const row = this.deps.db.core.credentials.get(connectorId); - if (!row) return null; - const json = this.deps.db.vault.decrypt( - row.backend, - Buffer.isBuffer(row.ciphertext) ? row.ciphertext : Buffer.from(row.ciphertext), - ); - return parseStoredCredentialPayload(connectorId, row.kind, json); - } - - remove(connectorId: string): void { - this.deps.db.core.credentials.remove(connectorId); - } - - setStatus(connectorId: string, status: CredentialStatus, lastError: string | null = null): void { - this.deps.db.core.credentials.setStatus(connectorId, status, lastError); - } - - /** Replaces the OAuth ciphertext after a successful refresh. */ - saveRefreshedOAuth(connectorId: string, payload: StoredCredentialPayload, expiresAt: string | null): void { - const { backend, payload: ciphertext } = this.deps.db.vault.encrypt(JSON.stringify(payload.value)); - this.deps.db.core.credentials.markRefreshed( - connectorId, - backend as CredentialBackend, - ciphertext, - expiresAt, - ); - } -} diff --git a/src/main/credentials/index.ts b/src/main/credentials/index.ts deleted file mode 100644 index a886f453..00000000 --- a/src/main/credentials/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CredentialStore, deriveDisplayHint } from "./credential-store"; -export { CredentialResolver, CredentialError, type ResolvedCredential } from "./credential-resolver"; -export { OAuthLoginService } from "./oauth-login-service"; -export type { StoredCredentialPayload, OAuthCredentialPayload, CredentialKind } from "./types"; diff --git a/src/main/credentials/oauth-login-service.ts b/src/main/credentials/oauth-login-service.ts deleted file mode 100644 index 73881468..00000000 --- a/src/main/credentials/oauth-login-service.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { shell } from "electron"; -import { getOAuthProvider, type OAuthLoginCallbacks } from "@mariozechner/pi-ai/oauth"; -import type { DesktopEvent } from "@shared/types"; -import { getConnectorDefinition } from "@main/connectors"; -import { CredentialStore } from "./credential-store"; -import type { OAuthCredentialPayload } from "./types"; - -interface PendingPrompt { - connectorId: string; - resolve: (value: string) => void; - reject: (reason: Error) => void; -} - -export interface OAuthLoginServiceDeps { - store: CredentialStore; - emitEvent: (event: DesktopEvent) => void; - /** Refresh the connector's health row after a successful login so its - * `status` flips from `auth_required` to `ready` without waiting for the - * next bootstrap pass. */ - refreshConnectorHealth: (connectorId: string) => Promise; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; -} - -export class OAuthLoginService { - private readonly active = new Map(); - private readonly prompts = new Map(); - private readonly manualCodes = new Map(); - - constructor(private readonly deps: OAuthLoginServiceDeps) {} - - async start(connectorId: string): Promise { - const definition = getConnectorDefinition(connectorId); - if (!definition.auth || definition.auth.type !== "oauth" || !definition.auth.oauthId) { - throw new Error(`Connector ${connectorId} does not use OAuth.`); - } - const oauthId = definition.auth.oauthId; - const provider = getOAuthProvider(oauthId); - if (!provider) { - throw new Error(`Unknown OAuth provider: ${oauthId}`); - } - - if (this.active.has(connectorId)) { - throw new Error(`OAuth login already in progress for ${connectorId}.`); - } - const controller = new AbortController(); - this.active.set(connectorId, controller); - this.deps.emitEvent({ type: "oauth:status", connectorId, status: "in_progress" }); - - let lastAuthUrl: string | undefined; - let lastAuthInstructions: string | undefined; - - const callbacks: OAuthLoginCallbacks = { - onAuth: ({ url, instructions }: { url: string; instructions?: string }) => { - lastAuthUrl = url; - lastAuthInstructions = instructions; - void shell.openExternal(url); - this.deps.emitEvent({ - type: "oauth:auth-url", - connectorId, - url, - instructions, - }); - }, - onProgress: (message: string) => { - this.deps.emitEvent({ type: "oauth:progress", connectorId, message }); - }, - onPrompt: ({ message, placeholder, allowEmpty }: { message: string; placeholder?: string; allowEmpty?: boolean }) => { - return new Promise((resolve, reject) => { - const requestId = randomUUID(); - this.prompts.set(requestId, { connectorId, resolve, reject }); - this.deps.emitEvent({ - type: "oauth:prompt-request", - connectorId, - requestId, - message, - placeholder, - allowEmpty, - }); - }); - }, - onManualCodeInput: () => { - return new Promise((resolve, reject) => { - const requestId = randomUUID(); - this.manualCodes.set(requestId, { connectorId, resolve, reject }); - this.deps.emitEvent({ - type: "oauth:manual-code-request", - connectorId, - requestId, - authUrl: lastAuthUrl, - instructions: lastAuthInstructions, - }); - }); - }, - signal: controller.signal, - }; - - try { - const credentials = await provider.login(callbacks); - const expiresAt = typeof credentials.expires === "number" && Number.isFinite(credentials.expires) - ? new Date(credentials.expires).toISOString() - : null; - this.deps.store.save( - connectorId, - { kind: "oauth", value: credentials as OAuthCredentialPayload }, - expiresAt, - ); - await this.deps.refreshConnectorHealth(connectorId); - this.deps.emitEvent({ type: "oauth:status", connectorId, status: "active" }); - this.deps.emitEvent({ type: "credentials-changed", connectorId }); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - const status = controller.signal.aborted ? "cancelled" : "error"; - this.deps.emitEvent({ type: "oauth:status", connectorId, status, errorMessage: status === "error" ? message : undefined }); - throw error; - } finally { - this.active.delete(connectorId); - this.failPending(connectorId, "OAuth login session ended."); - } - } - - cancel(connectorId: string): void { - const controller = this.active.get(connectorId); - if (controller) { - controller.abort(); - } - this.failPending(connectorId, "Cancelled by user."); - } - - submitPromptResponse(requestId: string, value: string): boolean { - const pending = this.prompts.get(requestId); - if (!pending) return false; - this.prompts.delete(requestId); - pending.resolve(value); - return true; - } - - submitManualCode(requestId: string, code: string): boolean { - const pending = this.manualCodes.get(requestId); - if (!pending) return false; - this.manualCodes.delete(requestId); - pending.resolve(code); - return true; - } - - private failPending(connectorId: string, reason: string) { - for (const [id, pending] of this.prompts) { - if (pending.connectorId !== connectorId) continue; - pending.reject(new Error(reason)); - this.prompts.delete(id); - } - for (const [id, pending] of this.manualCodes) { - if (pending.connectorId !== connectorId) continue; - pending.reject(new Error(reason)); - this.manualCodes.delete(id); - } - } -} diff --git a/src/main/credentials/types.ts b/src/main/credentials/types.ts deleted file mode 100644 index a247bab3..00000000 --- a/src/main/credentials/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { - ApiKeyValue, - AwsCredential, - AzureCredential, - GcpAdcCredential, - LocalCredential, -} from "@shared/contracts/schemas-credentials"; - -/** - * pi-ai's `OAuthCredentials` shape. - * - * Mirrored locally as a type-only declaration to avoid pulling pi runtime - * symbols into modules that only need the shape. The actual contract is - * enforced by pi at runtime via the OAuth provider interface. - */ -export interface OAuthCredentialPayload { - refresh: string; - access: string; - expires: number; - /** Provider-specific extra fields (e.g. github copilot domain) */ - [key: string]: unknown; -} - -export type StoredCredentialPayload = - | { kind: "oauth"; value: OAuthCredentialPayload } - | { kind: "api_key"; value: ApiKeyValue } - | { kind: "azure"; value: AzureCredential } - | { kind: "aws"; value: AwsCredential } - | { kind: "gcp_adc"; value: GcpAdcCredential } - | { kind: "local"; value: LocalCredential }; - -export type CredentialKind = StoredCredentialPayload["kind"]; diff --git a/src/main/database-base.ts b/src/main/database-base.ts deleted file mode 100644 index 4f9dab76..00000000 --- a/src/main/database-base.ts +++ /dev/null @@ -1,427 +0,0 @@ -import { mkdirSync, rmSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; -import { DatabaseSync, type SQLInputValue } from "node:sqlite"; -import { buildThreadMethods } from "./database/threads"; -import { buildCompanyMethods } from "./database/company"; -import { buildAgentMethods } from "./database/agents"; -import { buildTaskMethods } from "./database/tasks"; -import { buildMessageMethods } from "./database/messages"; -import { buildRunMethods } from "./database/runs"; -import { buildSnapshotMethods } from "./database/snapshot"; -import { buildSettingsMethods } from "./database/settings"; -import { buildConnectorMethods } from "./database/connectors-crud"; -import { buildWorkspaceMethods } from "./database/workspaces"; -import { buildApprovalMethods } from "./database/approvals"; -import { buildSocialMethods } from "./database/social"; -import { buildActivityMethods } from "./database/activity"; -import { buildSkillMethods } from "./database/skills"; -import { buildBudgetMethods } from "./database/budget"; -import { buildEntityCrudMethods } from "./database/entity-crud"; -import { listInvalidEnvBindingKeys, parseEnvBindingText } from "./connectors"; -import { buildDocumentMethods } from "./database/documents"; -import { buildAutomationMethods } from "./database/automation"; -import { buildKnowledgeMethods } from "./database/knowledge"; -import { buildWakeupMethods } from "./database/wakeup"; -import { buildBackupMethods } from "./database/backup"; -import { buildSessionEntryMethods } from "./database/session-entries"; -import { buildInboxProjectionMethods } from "./database/inbox-projections"; -import { buildDocumentLifecycleEventMethods } from "./database/document-lifecycle-events"; -import { buildCredentialMethods, type CredentialBackend } from "./database/credentials"; -import { BOSS_FIREWORKS_API_KEY } from "./boss-seed"; -import { buildModelCapabilityMethods } from "./database/model-capabilities-crud"; -import { MODEL_CAPABILITY_SEED } from "./model-capability-seed"; -import { initializeDatabase } from "./database/schema"; -import { SecretVault } from "./vault"; - -function nowIso() { - return new Date().toISOString(); -} - -function assertWritableDirectory(dir: string, label: string): void { - const probePath = join(dir, `.agentcompany-${label}-write-probe-${process.pid}-${Date.now()}`); - try { - writeFileSync(probePath, "", { encoding: "utf8", flag: "wx" }); - } finally { - rmSync(probePath, { force: true }); - } -} - -export interface AppDatabaseCoreModules { - threads: ReturnType; - company: ReturnType; - agents: ReturnType; - tasks: ReturnType; - messages: ReturnType; - runs: ReturnType; - settings: ReturnType; - connectors: ReturnType; - workspaces: ReturnType; - approvals: ReturnType; - social: ReturnType; - activity: ReturnType; - skills: ReturnType; - budget: ReturnType; - entity: ReturnType; - documents: ReturnType; - knowledge: ReturnType; - backup: ReturnType; - credentials: ReturnType; - modelCapabilities: ReturnType; -} - -export interface AppDatabaseAutomationModules { - rules: ReturnType; - wakeup: ReturnType; -} - -export interface AppDatabaseProjectionModules { - snapshot: ReturnType; - sessionEntries: ReturnType; - inbox: ReturnType; - documentLifecycleEvents: ReturnType; -} - -export class AppDatabaseBase { - readonly profileDir: string; - readonly dbPath: string; - readonly logsDir: string; - readonly artifactsDir: string; - readonly backupsDir: string; - readonly appVersion: string; - readonly vault: SecretVault; - protected db: DatabaseSync; - private transactionDepth = 0; - private savepointCounter = 0; - - public readonly core: AppDatabaseCoreModules; - public readonly automation: AppDatabaseAutomationModules; - public readonly projection: AppDatabaseProjectionModules; - - constructor(rootDir: string, options: { isPackaged?: boolean; appVersion?: string } = {}) { - this.profileDir = rootDir; - this.dbPath = join(rootDir, "profile.sqlite"); - this.logsDir = join(rootDir, "logs"); - this.artifactsDir = join(rootDir, "artifacts"); - this.backupsDir = join(rootDir, "backups"); - // Stamped into backup manifests so an operator looking at an old - // snapshot can tell which build produced it. Callers (bootstrap) - // pass `electron.app.getVersion()`; tests omit it. - this.appVersion = options.appVersion ?? "unknown"; - mkdirSync(rootDir, { recursive: true }); - mkdirSync(this.logsDir, { recursive: true }); - assertWritableDirectory(this.logsDir, "logs"); - mkdirSync(this.artifactsDir, { recursive: true }); - mkdirSync(this.backupsDir, { recursive: true }); - this.vault = new SecretVault(rootDir, { isPackaged: options.isPackaged }); - this.db = this.openConnection(); - - const getDb = () => this.db; - const ra = (sql: string, ...params: SQLInputValue[]) => this.readAll(sql, ...params); - const tx = (op: () => T) => this.transaction(op); - - const activity = buildActivityMethods(getDb, ra); - const settings = buildSettingsMethods(getDb, ra, { - profileDir: this.profileDir, logsDir: this.logsDir, - artifactsDir: this.artifactsDir, backupsDir: this.backupsDir, - }); - const connectors = buildConnectorMethods(getDb, ra); - const snapshot = buildSnapshotMethods(getDb, ra, { - getCurrentCompanyId: () => settings.getCurrentCompanyId(), - getSetting: (key) => this.getSetting(key), - readConnectors: () => connectors.readConnectors(), - profileDir: this.profileDir, - vaultBackendLabel: () => this.vault.getBackendLabel(), - }); - const threads = buildThreadMethods(getDb, ra); - const entity = buildEntityCrudMethods(getDb, ra, tx, { - addActivity: (input) => activity.addActivity(input), - vault: this.vault, - listInvalidEnvBindingKeys, - parseEnvBindingText, - }); - const documents = buildDocumentMethods(getDb, ra, tx); - const runs = buildRunMethods(getDb, ra, tx, { logsDir: this.logsDir }); - const company = buildCompanyMethods(getDb, ra, tx, { - getSetting: (key) => this.getSetting(key), - setSetting: (key, value) => this.setSetting(key, value), - listSnapshot: (options) => snapshot.listSnapshot(options), - addComment: (input) => activity.addComment(input), - }); - const agents = buildAgentMethods(getDb, ra, tx, { - getAgent: (id) => entity.getAgent(id), - wouldCreateAgentCycle: (agentId, reportsTo) => this.wouldCreateAgentCycle(agentId, reportsTo), - recordConfigRevision: (input) => documents.recordConfigRevision(input), - cancelRunForDeletion: (runId, taskId, workspaceId, summary) => runs.cancelRunForDeletion(runId, taskId, workspaceId, summary), - addActivity: (input) => activity.addActivity(input), - }); - const approvals = buildApprovalMethods(getDb, ra, tx, { - getAgent: (id) => entity.getAgent(id), - }); - const tasks = buildTaskMethods(getDb, ra, tx, { - addComment: (input) => activity.addComment(input), - addActivity: (input) => activity.addActivity(input), - requestApproval: (input) => approvals.requestApproval(input), - setHeartbeat: (agentId, enabled, intervalSec) => agents.setHeartbeat(agentId, enabled, intervalSec), - }); - const messages = buildMessageMethods(getDb, ra, { - getAgent: (id) => entity.getAgent(id), - addActivity: (input) => activity.addActivity(input), - transaction: tx, - }); - const workspaces = buildWorkspaceMethods(getDb, ra, tx); - const social = buildSocialMethods(getDb, ra, tx); - const skills = buildSkillMethods(getDb, ra); - const budget = buildBudgetMethods(getDb, ra, tx); - const automationRules = buildAutomationMethods(getDb, ra, { - addActivity: (input) => activity.addActivity(input), - }); - const knowledge = buildKnowledgeMethods(getDb, ra); - const wakeup = buildWakeupMethods(getDb, ra, tx); - const sessionEntries = buildSessionEntryMethods(getDb, ra, tx); - const inbox = buildInboxProjectionMethods(getDb); - const documentLifecycleEvents = buildDocumentLifecycleEventMethods(getDb, ra); - const credentials = buildCredentialMethods(getDb, ra, tx); - const modelCapabilities = buildModelCapabilityMethods(getDb, ra, tx); - const backup = buildBackupMethods({ - getDb, setDb: (db) => { this.db = db; }, - openConnection: () => this.openConnection(), - init: () => this.init(), - close: () => this.close(), - profileDir: this.profileDir, dbPath: this.dbPath, - logsDir: this.logsDir, artifactsDir: this.artifactsDir, - backupsDir: this.backupsDir, - appVersion: this.appVersion, - }); - - this.core = { - threads, - company, - agents, - tasks, - messages, - runs, - settings, - connectors, - workspaces, - approvals, - social, - activity, - skills, - budget, - entity, - documents, - knowledge, - backup, - credentials, - modelCapabilities, - }; - this.automation = { rules: automationRules, wakeup }; - this.projection = { snapshot, sessionEntries, inbox, documentLifecycleEvents }; - } - - // ─── Lifecycle ───────────────────────────────────────────────────────────── - - init() { - const ra = (sql: string, ...params: SQLInputValue[]) => this.readAll(sql, ...params); - const tx = (op: () => T) => this.transaction(op); - initializeDatabase(this.db, ra, tx, (reason) => this.core.backup.createAutomaticBackup(reason)); - this.core.connectors.seedConnectors(); - this.seedBossFireworksCredential(); - this.core.modelCapabilities.seedModelCapabilities(MODEL_CAPABILITY_SEED); - // Crash-recovery: a run still at `running` on boot means the worker - // died mid-turn. Flip it to `interrupted`, surface the related task - // as `blocked` for operator attention, and release workspace locks. - // This is the only mutation the startup path is permitted to make; - // all other "data-repair" passes have moved to explicit runtime - // state-machine guards (see `tasks-status.ts`) or maintenance IPC. - this._lastInterruptedCount = this.interruptStaleRuns(); - this.core.settings.purgeExpiredRunLogs(); - this.automation.wakeup.purgeExpiredWakeupRequests(); - } - - close() { this.db.close(); } - - // Boss edition bootstraps the Fireworks Fire Pass credential so the - // onboarding card renders as "active" on first launch. Public builds leave - // `BOSS_FIREWORKS_API_KEY` empty and this call is a no-op. Guard against - // overwriting an existing credential so upgrades and user edits survive. - private seedBossFireworksCredential() { - if (!BOSS_FIREWORKS_API_KEY) return; - const connectorId = "fireworks-firepass"; - if (this.core.credentials.get(connectorId)) return; - const payload = JSON.stringify({ source: "literal", value: BOSS_FIREWORKS_API_KEY }); - const { backend, payload: ciphertext } = this.vault.encrypt(payload); - this.core.credentials.upsert({ - connectorId, - kind: "api_key", - backend: backend as CredentialBackend, - ciphertext, - displayHint: `${BOSS_FIREWORKS_API_KEY.slice(0, 6)}...${BOSS_FIREWORKS_API_KEY.slice(-4)}`, - status: "active", - }); - } - - // ─── Internal helper: relock releaseAllWorkspaceLocks is used by - // crash-recovery below; callers should prefer - // `db.core.workspaces.releaseAllWorkspaceLocks()` directly. - // - // ─── Internal infrastructure ─────────────────────────────────────────────── - protected _lastInterruptedCount = 0; - get lastInterruptedCount(): number { return this._lastInterruptedCount; } - - interruptStaleRuns(): number { - const ts = nowIso(); - let interruptedCount = 0; - this.transaction(() => { - // Capture the run ids this sweep intends to interrupt BEFORE - // mutating anything. The old code scoped the downstream task + - // lease cleanup with `WHERE finished_at = ?` against the freshly - // stamped timestamp — safe in isolation, but ISO-millisecond - // ties with an earlier interrupted run are possible in principle - // and would clean unrelated leases. Pinning the set to explicit - // ids removes that dependency on timestamp uniqueness entirely. - const staleRuns = this.db - .prepare("SELECT id FROM runs WHERE status = 'running'") - .all() as Array<{ id: string }>; - if (staleRuns.length === 0) { - // Nothing to interrupt; still let agent/workspace recovery run - // so a boot that crashed while workers were already idle can - // still reset agent rows parked at `status = 'running'`. - this.db.prepare("update agents set status = 'idle', updated_at = ? where status = 'running'").run(ts); - this.core.workspaces.releaseAllWorkspaceLocks(); - return; - } - const runIds = staleRuns.map((r) => r.id); - const placeholders = runIds.map(() => "?").join(","); - this.db - .prepare( - `update runs set status = 'interrupted', error_message = 'AgentCompany restarted before the run could report completion.', finished_at = ?, updated_at = ? where id in (${placeholders})`, - ) - .run(ts, ts, ...runIds); - interruptedCount = runIds.length; - this.db - .prepare( - `update tasks set status = 'blocked', updated_at = ? where id in (select task_id from runs where id in (${placeholders})) and status in ('in_progress', 'todo')`, - ) - .run(ts, ...runIds); - this.db - .prepare( - `delete from task_leases where run_id in (${placeholders})`, - ) - .run(...runIds); - this.db.prepare("update agents set status = 'idle', updated_at = ? where status = 'running'").run(ts); - this.core.workspaces.releaseAllWorkspaceLocks(); - }); - return interruptedCount; - } - - recoverStaleLocks(): Array<{ taskId: string; companyId: string; title: string }> { - const now = new Date().toISOString(); - const stale = this.readAll<{ id: string; companyId: string; title: string }>( - `SELECT t.id, t.company_id AS companyId, t.title - FROM task_leases l - JOIN tasks t ON t.id = l.task_id - LEFT JOIN runs r ON r.id = l.run_id - WHERE l.expires_at < ? - AND t.status = 'in_progress' - AND (r.id IS NULL OR r.status != 'running')`, - now, - ); - const ts = nowIso(); - for (const task of stale) { - this.db.prepare("delete from task_leases where task_id = ?").run(task.id); - this.db - .prepare( - `UPDATE tasks SET status = 'todo', updated_at = ? WHERE id = ?`, - ) - .run(ts, task.id); - } - return stale.map((t) => ({ taskId: t.id, companyId: t.companyId, title: t.title })); - } - - protected incrementActiveSprintVelocity(companyId: string, delta: number) { - this.core.entity.incrementActiveSprintVelocity(companyId, delta); - } - - protected getSetting(key: string): string | null { - const row = this.db.prepare("select value from settings where key = ?").get(key) as { value: string } | undefined; - return row?.value ?? null; - } - - protected setSetting(key: string, value: string) { - this.db.prepare("insert into settings (key, value) values (?, ?) on conflict(key) do update set value = excluded.value").run(key, value); - } - - protected readAll(sql: string, ...params: SQLInputValue[]): T[] { - return this.db.prepare(sql).all(...params) as T[]; - } - - protected wouldCreateAgentCycle(agentId: string, reportsTo: string | null) { - if (!reportsTo) return false; - if (reportsTo === agentId) return true; - const visited = new Set([agentId]); - let currentId: string | null = reportsTo; - while (currentId) { - if (visited.has(currentId)) return true; - visited.add(currentId); - const current = this.db.prepare("select reports_to as reportsTo from agents where id = ?").get(currentId) as { reportsTo: string | null } | undefined; - currentId = current?.reportsTo ?? null; - } - return false; - } - - protected openConnection(): DatabaseSync { - const db = new DatabaseSync(this.dbPath, { timeout: 5000 }); - db.exec("pragma journal_mode = WAL;"); - db.exec("pragma busy_timeout = 5000;"); - db.exec("pragma synchronous = NORMAL;"); - db.exec("pragma foreign_keys = ON;"); - return db; - } - - protected transaction(operation: () => T): T { - if (this.transactionDepth > 0) { - const savepoint = `agentcompany_tx_${this.savepointCounter}`; - this.savepointCounter += 1; - this.db.exec(`SAVEPOINT ${savepoint}`); - this.transactionDepth += 1; - try { - const result = operation(); - this.db.exec(`RELEASE SAVEPOINT ${savepoint}`); - return result; - } catch (error) { - this.db.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`); - this.db.exec(`RELEASE SAVEPOINT ${savepoint}`); - throw error; - } finally { - this.transactionDepth -= 1; - } - } - - this.db.exec("BEGIN IMMEDIATE"); - this.transactionDepth += 1; - try { - const result = operation(); - this.db.exec("COMMIT"); - return result; - } catch (error) { - this.db.exec("ROLLBACK"); - throw error; - } finally { - this.transactionDepth -= 1; - } - } - - /** - * Run `operation` inside a `BEGIN IMMEDIATE` transaction. Public - * surface for callers outside the database module that need to bind - * multiple writes into one atomic unit — the inbox projection closure - * is the canonical example, where the append to the session shadow, - * the thread event, and the delivered-mark all have to commit - * together or roll back together. - */ - withTransaction(operation: () => T): T { - return this.transaction(operation); - } - -} diff --git a/src/main/database.ts b/src/main/database.ts deleted file mode 100644 index 2ddc73ed..00000000 --- a/src/main/database.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { SQLInputValue } from "node:sqlite"; -import { AppDatabaseBase } from "./database-base"; - -export { STALE_LOCK_TIMEOUT_MS } from "./constants"; - -/** - * AppDatabase — concrete persistence surface wired to the grouped - * modules declared on AppDatabaseBase. New code must call the owning - * module directly (e.g. `db.core.tasks.saveTask(...)`); the ESLint - * rule in .eslintrc enforces this. - * - * The only members living here are cross-cutting composites whose - * single-module home does not exist yet (createHireRequest, - * rollbackConfigRevision) and the raw-SQL escape hatch, and backups - * which need the open/close lifecycle plumbing owned by this class. - */ -export class AppDatabase extends AppDatabaseBase { - /** - * Create a hire request by persisting the provisional agent row and - * its approval atomically. The composition spans `core.agents` and - * `core.approvals`, so it lives here until a dedicated hiring module - * owns both sides. - */ - createHireRequest(input: Parameters[0]) { - return this.core.entity.createHireRequest(input, { - saveAgent: (agentInput) => this.core.agents.saveAgent(agentInput), - requestApproval: (approvalInput) => this.core.approvals.requestApproval(approvalInput), - }); - } - - /** - * Roll back an agent configuration revision. Spans documents - * (revision store), core.entity (agent lookup), and a recorded - * rollback entry — again a multi-module composite the subclass - * carries until a dedicated agent-config module owns the flow. - */ - rollbackConfigRevision(agentId: string, revisionId: string, companyId: string) { - return this.core.documents.rollbackConfigRevision(agentId, revisionId, companyId, { - getConfigRevision: (rid, cid) => this.core.documents.getConfigRevision(rid, cid), - getAgent: (id) => this.core.entity.getAgent(id), - recordConfigRevision: (input) => this.core.documents.recordConfigRevision(input), - }); - } - - /** - * Raw-SQL escape hatch. Not part of the public API. New callers MUST - * add a typed method on the appropriate `database/.ts` and - * route through there. Retained only for legacy automation - * bookkeeping that predates the module split; see - * `.planning/review2/02-persistence-ipc.md` DB-001 for the migration - * list. - * - * @internal - */ - queryAll(sql: string, ...params: SQLInputValue[]): T[] { return this.readAll(sql, ...params); } -} diff --git a/src/main/database/activity.ts b/src/main/database/activity.ts deleted file mode 100644 index 2a8239ca..00000000 --- a/src/main/database/activity.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import type { CommentRecord } from "@shared/types"; -import { normalizeMarkdownText } from "@shared/markdown-text"; -import type { ReadAll } from "./helpers"; -import { nowIso } from "./helpers"; - -export function buildActivityMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, -) { - return { - addActivity(input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) { - getDb() - .prepare("insert into activity (id, company_id, actor, action, entity_type, entity_id, detail, created_at) values (?, ?, ?, ?, ?, ?, ?, ?)") - .run(randomUUID(), input.companyId, input.actor, input.action, input.entityType, input.entityId, input.detail, nowIso()); - }, - - addComment(input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }): CommentRecord { - const taskRow = getDb().prepare("select company_id from tasks where id = ?").get(input.taskId) as { company_id: string } | undefined; - if (!taskRow) throw new Error("Task not found."); - if (taskRow.company_id !== input.companyId) throw new Error("Task does not belong to this company."); - const body = normalizeMarkdownText(input.body); - const id = randomUUID(); - const ts = nowIso(); - getDb().prepare( - "insert into task_comments (id, company_id, task_id, author_agent_id, author_name, body, created_at) values (?, ?, ?, ?, ?, ?, ?)", - ).run(id, input.companyId, input.taskId, input.authorAgentId, input.authorName, body, ts); - return { id, companyId: input.companyId, taskId: input.taskId, authorAgentId: input.authorAgentId, authorName: input.authorName, body, createdAt: ts }; - }, - - listComments(taskId: string): CommentRecord[] { - return readAll( - "select id, company_id as companyId, task_id as taskId, author_agent_id as authorAgentId, author_name as authorName, body, created_at as createdAt from task_comments where task_id = ? order by created_at asc", - taskId, - ); - }, - - /** - * Returns the `limit` most recent task comments (author_name + body + - * createdAt) for a given set of task ids since `sinceIso`. Used by - * GET /api/agents/me/standup to build the "recent comments" feed. - */ - listRecentTaskComments( - taskIds: string[], - sinceIso: string, - limit: number, - ): Array<{ - id: string; - taskId: string; - authorName: string; - body: string; - createdAt: string; - }> { - if (taskIds.length === 0) return []; - const placeholders = taskIds.map(() => "?").join(","); - return readAll( - `select id, task_id as taskId, author_name as authorName, body, created_at as createdAt from task_comments where task_id in (${placeholders}) and created_at > ? order by created_at desc limit ?`, - ...taskIds, - sinceIso, - limit, - ); - }, - }; -} diff --git a/src/main/database/agent-permissions.ts b/src/main/database/agent-permissions.ts deleted file mode 100644 index 294b1eef..00000000 --- a/src/main/database/agent-permissions.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { type ReadAll, type Transaction, nowIso, parseJson, toBoolean } from "./helpers"; - -/** - * Agent permission, runtime-state, and heartbeat-policy helpers extracted - * from agents-hierarchy.ts. Every method is spread into the final - * `buildAgentMethods` result so AppDatabase call-sites remain unchanged. - */ -export function buildAgentPermissionMethods( - getDb: () => DatabaseSync, - _readAll: ReadAll, - _transaction: Transaction, -) { - return { - getAgentPermissions(agentId: string): Record { - const row = getDb() - .prepare("SELECT permissions_json FROM agents WHERE id = ?") - .get(agentId) as { permissions_json: string } | undefined; - return parseJson>(row?.permissions_json, {}); - }, - - setAgentPermission( - agentId: string, - companyId: string, - permissionKey: string, - enabled: boolean, - ): void { - const row = getDb() - .prepare("SELECT permissions_json FROM agents WHERE id = ?") - .get(agentId) as { permissions_json: string } | undefined; - const current = parseJson>(row?.permissions_json, {}); - if (enabled) { - current[permissionKey] = true; - } else { - delete current[permissionKey]; - } - const ts = nowIso(); - getDb() - .prepare( - "UPDATE agents SET permissions_json = ?, updated_at = ? WHERE id = ? AND company_id = ?", - ) - .run(JSON.stringify(current), ts, agentId, companyId); - }, - - hasAgentPermission(agentId: string, permissionKey: string): boolean { - const row = getDb() - .prepare("SELECT permissions_json FROM agents WHERE id = ?") - .get(agentId) as { permissions_json: string } | undefined; - const perms = parseJson>(row?.permissions_json, {}); - return perms[permissionKey] === true; - }, - - getRuntimeState(agentId: string): Record { - const row = getDb() - .prepare("SELECT runtime_state_json FROM agents WHERE id = ?") - .get(agentId) as { runtime_state_json: string | null } | undefined; - return parseJson>(row?.runtime_state_json, {}); - }, - - setRuntimeState( - agentId: string, - companyId: string, - state: Record, - ): void { - const ts = nowIso(); - getDb() - .prepare( - "UPDATE agents SET runtime_state_json = ?, updated_at = ? WHERE id = ? AND company_id = ?", - ) - .run(JSON.stringify(state), ts, agentId, companyId); - }, - - getHeartbeatPolicy(agentId: string): { - enabled: boolean; - intervalSec: number; - cooldownSec: number; - maxConcurrentRuns: number; - wakeOnDemand: boolean; - } { - const row = getDb() - .prepare( - "SELECT heartbeat_enabled, heartbeat_interval_sec, heartbeat_policy_json FROM agents WHERE id = ?", - ) - .get(agentId) as - | { - heartbeat_enabled: number; - heartbeat_interval_sec: number; - heartbeat_policy_json: string | null; - } - | undefined; - if (!row) throw new Error(`Agent ${agentId} not found.`); - const policy = parseJson>(row.heartbeat_policy_json, {}); - return { - enabled: toBoolean(row.heartbeat_enabled), - intervalSec: row.heartbeat_interval_sec ?? 120, - cooldownSec: typeof policy.cooldownSec === "number" ? policy.cooldownSec : 10, - maxConcurrentRuns: - typeof policy.maxConcurrentRuns === "number" ? policy.maxConcurrentRuns : 1, - wakeOnDemand: policy.wakeOnDemand !== false, - }; - }, - - setHeartbeatPolicy( - agentId: string, - companyId: string, - policy: { - enabled?: boolean; - intervalSec?: number; - cooldownSec?: number; - maxConcurrentRuns?: number; - wakeOnDemand?: boolean; - }, - ): void { - const row = getDb() - .prepare( - "SELECT heartbeat_enabled, heartbeat_interval_sec, heartbeat_policy_json FROM agents WHERE id = ?", - ) - .get(agentId) as - | { - heartbeat_enabled: number; - heartbeat_interval_sec: number; - heartbeat_policy_json: string | null; - } - | undefined; - if (!row) throw new Error(`Agent ${agentId} not found.`); - const current = parseJson>(row.heartbeat_policy_json, {}); - const merged = { - enabled: policy.enabled ?? toBoolean(row.heartbeat_enabled), - intervalSec: policy.intervalSec ?? row.heartbeat_interval_sec ?? 120, - cooldownSec: - policy.cooldownSec ?? - (typeof current.cooldownSec === "number" ? current.cooldownSec : 10), - maxConcurrentRuns: - policy.maxConcurrentRuns ?? - (typeof current.maxConcurrentRuns === "number" ? current.maxConcurrentRuns : 1), - wakeOnDemand: policy.wakeOnDemand ?? (current.wakeOnDemand !== false), - }; - const policyJson = JSON.stringify({ - cooldownSec: merged.cooldownSec, - maxConcurrentRuns: merged.maxConcurrentRuns, - wakeOnDemand: merged.wakeOnDemand, - }); - const ts = nowIso(); - getDb() - .prepare( - "UPDATE agents SET heartbeat_enabled = ?, heartbeat_interval_sec = ?, heartbeat_policy_json = ?, updated_at = ? WHERE id = ? AND company_id = ?", - ) - .run(merged.enabled ? 1 : 0, merged.intervalSec, policyJson, ts, agentId, companyId); - }, - }; -} diff --git a/src/main/database/agents-crud.ts b/src/main/database/agents-crud.ts deleted file mode 100644 index 57fc1f86..00000000 --- a/src/main/database/agents-crud.ts +++ /dev/null @@ -1,348 +0,0 @@ -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { AgentModelStrategy, AgentRecord, AgentRoleLevel, ConnectorId } from "@shared/types"; -import { - type ReadAll, - type Transaction, - ensureId, - normalizeOptionalId, - nowIso, -} from "./helpers"; -export function buildAgentCrudMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - getAgent: (id: string) => AgentRecord; - wouldCreateAgentCycle: (agentId: string, reportsTo: string | null) => boolean; - recordConfigRevision: (input: { - companyId: string; - agentId: string; - changedKeys: string[]; - configBefore: Record; - configAfter: Record; - source?: string; - rolledBackFromRevisionId?: string | null; - createdByAgentId?: string | null; - createdByUserId?: string | null; - }) => string; - cancelRunForDeletion: (runId: string, taskId: string | null, workspaceId: string | null, summary: string) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - }, -) { - return { - saveAgent(input: { - id?: string | null; - companyId: string; - name: string; - role: string; - title: string; - department?: string | null; - status: AgentRecord["status"]; - reportsTo?: string | null; - connectorId: ConnectorId; - workspaceId?: string | null; - model?: string | null; - metadataJson?: string; - capabilities: string; - budgetMonthlyUsd: number; - /** Optional explicit seniority; inferred from role/title when omitted. */ - roleLevel?: AgentRoleLevel; - /** - * Model routing strategy (v39+). `explicit` pins the agent to - * `connectorId + model`; `auto` lets the dispatcher pick at run - * time. Omitting this leaves the existing column untouched on - * update, and uses the DB default ('explicit') on insert. - */ - modelStrategy?: AgentModelStrategy; - }): string { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const metadataJson = input.metadataJson ?? "{}"; - const department = input.department ?? null; - const reportsTo = normalizeOptionalId(input.reportsTo); - if (deps.wouldCreateAgentCycle(id, reportsTo)) { - throw new Error("Agent reporting relationship would create a cycle."); - } - const existing = getDb() - .prepare("select id from agents where id = ? and company_id = ?") - .get(id, input.companyId) as { id: string } | undefined; - if (existing) { - // Snapshot before-config for revision tracking - const beforeAgent = getDb() - .prepare( - "SELECT name, role, title, department, capabilities, connector_id, model, model_strategy, role_level, budget_monthly_usd, metadata_json FROM agents WHERE id = ? AND company_id = ?", - ) - .get(id, input.companyId) as Record | undefined; - // Preserve existing modelStrategy and roleLevel when the caller omits - // them, so non-related updates (e.g. updateAgentWorkspaceBinding) do - // not accidentally flip routing or seniority. - const effectiveStrategy = input.modelStrategy ?? (beforeAgent?.model_strategy as string | undefined) ?? "explicit"; - const effectiveRoleLevel = input.roleLevel ?? (beforeAgent?.role_level as string | undefined) ?? "ic"; - getDb() - .prepare( - "update agents set name = ?, role = ?, title = ?, department = ?, status = ?, reports_to = ?, connector_id = ?, workspace_id = ?, model = ?, model_strategy = ?, role_level = ?, metadata_json = ?, capabilities = ?, budget_monthly_usd = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run( - input.name, - input.role, - input.title, - department, - input.status, - reportsTo, - input.connectorId, - normalizeOptionalId(input.workspaceId), - normalizeOptionalId(input.model), - effectiveStrategy, - effectiveRoleLevel, - metadataJson, - input.capabilities, - input.budgetMonthlyUsd, - ts, - id, - input.companyId, - ); - // Record config revision if fields changed - if (beforeAgent) { - const afterConfig = { - name: input.name, - role: input.role, - title: input.title, - department, - capabilities: input.capabilities, - connectorId: input.connectorId, - model: normalizeOptionalId(input.model), - budgetMonthlyUsd: input.budgetMonthlyUsd, - metadataJson, - }; - const beforeConfig = { - name: beforeAgent.name, - role: beforeAgent.role, - title: beforeAgent.title, - department: beforeAgent.department, - capabilities: beforeAgent.capabilities, - connectorId: beforeAgent.connector_id, - model: beforeAgent.model, - budgetMonthlyUsd: beforeAgent.budget_monthly_usd, - metadataJson: beforeAgent.metadata_json, - }; - const changedKeys = Object.keys(afterConfig).filter( - (k) => - JSON.stringify((afterConfig as Record)[k]) !== - JSON.stringify((beforeConfig as Record)[k]), - ); - if (changedKeys.length > 0) { - try { - deps.recordConfigRevision({ - companyId: input.companyId, - agentId: id, - changedKeys, - configBefore: beforeConfig, - configAfter: afterConfig, - }); - } catch (err) { - log.warn(`[database/agents] recordConfigRevision failed for agent ${id}:`, err instanceof Error ? err.message : String(err)); - } - } - } - } else { - const insertStrategy = input.modelStrategy ?? "explicit"; - const insertRoleLevel = input.roleLevel ?? "ic"; - getDb() - .prepare( - "insert into agents (id, company_id, name, role, title, department, status, reports_to, connector_id, workspace_id, model, model_strategy, role_level, capabilities, budget_monthly_usd, spent_monthly_usd, metadata_json, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?)", - ) - .run( - id, - input.companyId, - input.name, - input.role, - input.title, - department, - input.status, - reportsTo, - input.connectorId, - normalizeOptionalId(input.workspaceId), - normalizeOptionalId(input.model), - insertStrategy, - insertRoleLevel, - input.capabilities, - input.budgetMonthlyUsd, - metadataJson, - ts, - ts, - ); - } - return id; - }, - - deleteAgent(id: string, companyId: string): void { - const activeAgentRuns = readAll<{ id: string; taskId: string | null; workspaceId: string | null }>( - "select id, task_id as taskId, workspace_id as workspaceId from runs where agent_id = ? and company_id = ? and status in ('queued', 'running')", - id, - companyId, - ); - transaction(() => { - for (const run of activeAgentRuns) { - deps.cancelRunForDeletion(run.id, run.taskId, run.workspaceId, "Agent deleted."); - } - getDb() - .prepare( - "update tasks set assignee_agent_id = null where assignee_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare( - "update goals set owner_agent_id = null where owner_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare( - "update projects set lead_agent_id = null where lead_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare("update agents set reports_to = null where reports_to = ? and company_id = ?") - .run(id, companyId); - // Clean up orphaned approvals referencing this agent - getDb() - .prepare( - "update approvals set requested_by_agent_id = null where requested_by_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare( - "update approvals set related_agent_id = null where related_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - // Clean up meetings organized by this agent - getDb() - .prepare( - "update meetings set organizer_agent_id = null where organizer_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - // Clean up documents authored/reviewed by this agent - getDb() - .prepare( - "update documents set author_agent_id = null where author_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare( - "update documents set reviewer_agent_id = null where reviewer_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - // Clean up knowledge entries authored by this agent - getDb() - .prepare( - "update knowledge_base set author_agent_id = null where author_agent_id = ? and company_id = ?", - ) - .run(id, companyId); - // Remove wakeup requests for this agent - getDb() - .prepare("DELETE FROM wakeup_requests WHERE agent_id = ? AND company_id = ?") - .run(id, companyId); - getDb().prepare("delete from agents where id = ? and company_id = ?").run(id, companyId); - }); - }, - - updateAgentStatus(agentId: string, status: string): void { - const ts = new Date().toISOString(); - getDb() - .prepare("update agents set status = ?, updated_at = ? where id = ?") - .run(status, ts, agentId); - }, - - hasAgentAssignedTasks(agentId: string, companyId: string): boolean { - const row = getDb() - .prepare( - "select 1 from tasks where assignee_agent_id = ? and company_id = ? and status in ('todo', 'in_progress', 'blocked') limit 1", - ) - .get(agentId, companyId); - return !!row; - }, - - isAgentPendingApproval(agentId: string): boolean { - const row = getDb() - .prepare("select status from agents where id = ?") - .get(agentId) as { status: string } | undefined; - return row?.status === "pending_approval"; - }, - - findMentionedAgentIds(companyId: string, text: string): string[] { - if (!text.includes("@")) return []; - const mentionTokens = new Set(); - const mentionRegex = /@([\p{L}\p{N} _-]{1,80})(?=[\s,!?.;:\])}>]|$)/gu; - for (const match of text.toLowerCase().matchAll(mentionRegex)) { - const token = match[1]?.trim(); - if (token) mentionTokens.add(token); - } - if (mentionTokens.size === 0) return []; - - const patterns = Array.from(mentionTokens).flatMap((token) => { - const words = token.split(/\s+/).filter(Boolean); - return words.length > 1 ? [token, words[0]!] : [token]; - }); - const placeholders = patterns.map(() => "lower(name) = ? or lower(role) = ? or lower(title) = ?").join(" or "); - const params: SQLInputValue[] = [companyId]; - for (const p of patterns) { - params.push(p, p, p); - } - const agents = readAll<{ id: string; name: string; role: string; title: string }>( - `SELECT id, name, role, title FROM agents WHERE company_id = ? AND (${placeholders})`, - ...params, - ); - if (agents.length === 0) return []; - - const lowerText = text.toLowerCase(); - // Per-alias agent set. Storing a `Set` (not an array) means the - // same agent contributing the same string via multiple fields - // (e.g. name === role === "CEO") collapses to one entry. Before - // this fix the duplicate push made the alias look non-unique, the - // unique-alias filter dropped it, and every @mention in a scaffold - // where role mirrored name silently missed. - const aliasMap = new Map>(); - const registerAlias = (alias: string, agentId: string) => { - const normalized = alias.trim().toLowerCase(); - if (!normalized) return; - const existing = aliasMap.get(normalized) ?? new Set(); - existing.add(agentId); - aliasMap.set(normalized, existing); - }; - for (const agent of agents) { - registerAlias(agent.name, agent.id); - registerAlias(agent.role, agent.id); - registerAlias(agent.title, agent.id); - } - - const matched = new Set(); - // Only aliases that unambiguously resolve to a single agent are - // treated as mentions. Two agents sharing a role ("CEO" appearing - // twice in the company) make `@ceo` ambiguous and we refuse to - // pick one silently. - const uniqueAliases = [...aliasMap.entries()] - .filter(([, ids]) => ids.size === 1) - .sort((a, b) => b[0].length - a[0].length); - for (const [alias, ids] of uniqueAliases) { - const pattern = `@${alias}`; - const idx = lowerText.indexOf(pattern); - if (idx === -1) continue; - const afterIdx = idx + pattern.length; - if (afterIdx >= lowerText.length || /[\s,!?.;:\])}>]/.test(lowerText[afterIdx]!)) { - const [onlyId] = ids; - if (onlyId) matched.add(onlyId); - } - } - return [...matched]; - }, - - countActiveRunsForAgent(agentId: string, companyId: string): number { - const row = getDb() - .prepare( - "SELECT COUNT(*) as cnt FROM runs WHERE agent_id = ? AND company_id = ? AND status IN ('queued', 'running')", - ) - .get(agentId, companyId) as { cnt: number } | undefined; - return row?.cnt ?? 0; - }, - }; -} diff --git a/src/main/database/agents-hierarchy.ts b/src/main/database/agents-hierarchy.ts deleted file mode 100644 index 051d6c07..00000000 --- a/src/main/database/agents-hierarchy.ts +++ /dev/null @@ -1,331 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { AgentRecord } from "@shared/types"; -import { - type ReadAll, - type Transaction, - nowIso, - toBoolean, -} from "./helpers"; - -/** - * Agent row shape returned by listAgentsForApi. Mirrors the historical - * inline SQL projection in routes-agents.ts so HTTP response bodies - * stay byte-stable. heartbeatEnabled is exposed as a boolean. - */ -export type AgentApiRow = { - id: string; - companyId: string; - name: string; - role: string; - title: string | null; - department: string | null; - status: string; - reportsTo: string | null; - connectorId: string; - workspaceId: string | null; - model: string | null; - capabilities: string | null; - budgetMonthlyUsd: number | null; - spentMonthlyUsd: number | null; - metadataJson: string; - heartbeatEnabled: boolean; - heartbeatIntervalSec: number | null; - lastHeartbeatAt: string | null; - createdAt: string; - updatedAt: string; -}; - - -export function buildAgentHierarchyMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - _transaction: Transaction, - _deps: { - getAgent: (id: string) => AgentRecord; - }, -) { - return { - getChainOfCommand(agentId: string): AgentRecord[] { - const rows = readAll( - `WITH RECURSIVE chain AS ( - SELECT id, company_id as companyId, name, role, title, department, status, - reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, - model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, - spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, - heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, - last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt, - 0 as depth - FROM agents WHERE id = ? - UNION ALL - SELECT a.id, a.company_id, a.name, a.role, a.title, a.department, a.status, - a.reports_to, a.connector_id, a.workspace_id, - a.model, a.capabilities, a.role_level, a.model_strategy, a.budget_monthly_usd, - a.spent_monthly_usd, a.metadata_json, - a.heartbeat_enabled, a.heartbeat_interval_sec, - a.last_heartbeat_at, a.session_id, a.created_at, a.updated_at, - c.depth + 1 - FROM agents a JOIN chain c ON a.id = c.reportsTo - WHERE c.depth < 20 - ) - SELECT * FROM chain ORDER BY depth`, - agentId, - ); - // Skip self (depth 0); return ancestors from direct manager upward. - return rows.slice(1).map((record) => ({ - ...record, - heartbeatEnabled: toBoolean(record.heartbeatEnabled), - })) as AgentRecord[]; - }, - - getDirectReports(agentId: string, companyId: string): AgentRecord[] { - return readAll( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt from agents where company_id = ? and reports_to = ?", - companyId, - agentId, - ).map((record) => ({ - ...record, - heartbeatEnabled: toBoolean(record.heartbeatEnabled), - })) as AgentRecord[]; - }, - - setHeartbeat(agentId: string, enabled: boolean, intervalSec: number): void { - getDb() - .prepare( - "update agents set heartbeat_enabled = ?, heartbeat_interval_sec = ?, updated_at = ? where id = ?", - ) - .run(enabled ? 1 : 0, intervalSec, nowIso(), agentId); - }, - - markHeartbeatAt(agentId: string): void { - getDb() - .prepare("update agents set last_heartbeat_at = ? where id = ?") - .run(nowIso(), agentId); - }, - - /** - * Returns all agents for a company with the full API projection used - * by GET /api/companies/:companyId/agents. Mirrors the historical - * inline SQL and maps heartbeat_enabled into a boolean. - */ - listAgentsForApi(companyId: string): AgentApiRow[] { - return readAll( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, created_at as createdAt, updated_at as updatedAt from agents where company_id = ? order by created_at asc", - companyId, - ).map((a) => ({ ...a, heartbeatEnabled: Boolean(a.heartbeatEnabled) })) as AgentApiRow[]; - }, - - /** - * Returns the slim direct-reports projection used by - * GET /api/agents/me/standup — only (id, name, role, status). - */ - listDirectReportsForStandup( - companyId: string, - managerId: string, - ): Array<{ id: string; name: string; role: string; status: string }> { - return readAll( - "select id, name, role, status from agents where company_id = ? and reports_to = ? order by created_at asc", - companyId, - managerId, - ); - }, - - /** - * Returns per-report task-status counts for the standup aggregation. - * Joins agents with their tasks and aggregates statuses (in_progress, - * in_review, blocked, done). - */ - listReportStatusesForStandup(companyId: string, managerId: string): Array<{ - id: string; - name: string; - role: string; - status: string; - tasksInProgress: number; - tasksInReview: number; - tasksBlocked: number; - tasksDone: number; - }> { - return readAll( - `select agents.id as id, agents.name as name, agents.role as role, agents.status as status, - coalesce(sum(case when tasks.status = 'in_progress' then 1 else 0 end), 0) as tasksInProgress, - coalesce(sum(case when tasks.status = 'in_review' then 1 else 0 end), 0) as tasksInReview, - coalesce(sum(case when tasks.status = 'blocked' then 1 else 0 end), 0) as tasksBlocked, - coalesce(sum(case when tasks.status = 'done' then 1 else 0 end), 0) as tasksDone - from agents - left join tasks on tasks.assignee_agent_id = agents.id and tasks.company_id = agents.company_id - where agents.company_id = ? and agents.reports_to = ? - group by agents.id, agents.name, agents.role, agents.status - order by agents.created_at asc`, - companyId, - managerId, - ); - }, - - /** - * Returns the duplicate-detection projection used by - * POST /api/companies/:id/agents to reject hires with a name that - * already belongs to a non-terminated agent. - */ - listExistingAgentsForHireCheck( - companyId: string, - ): Array<{ id: string; name: string; role: string }> { - return readAll<{ id: string; name: string; role: string }>( - "select id, name, role from agents where company_id = ? and status != 'terminated'", - companyId, - ); - }, - - listHeartbeatEligibleAgents(companyId: string): AgentRecord[] { - return readAll( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt from agents where company_id = ? and heartbeat_enabled = 1 and status not in ('terminated', 'paused', 'error', 'pending_approval')", - companyId, - ).map((record) => ({ - ...record, - heartbeatEnabled: toBoolean(record.heartbeatEnabled), - })) as AgentRecord[]; - }, - - getCeoForCompany( - companyId: string, - ): { id: string; name: string; lastHeartbeatAt: string | null } | null { - const row = getDb() - .prepare( - "select id, name, last_heartbeat_at as lastHeartbeatAt from agents where company_id = ? and reports_to is null and status != 'terminated' limit 1", - ) - .get(companyId) as - | { id: string; name: string; lastHeartbeatAt: string | null } - | undefined; - return row ?? null; - }, - - listActiveAgentsForCompany( - companyId: string, - ): Array<{ - id: string; - name: string; - department: string | null; - heartbeatIntervalSec: number | null; - lastHeartbeatAt: string | null; - }> { - return readAll<{ - id: string; - name: string; - department: string | null; - heartbeatIntervalSec: number | null; - lastHeartbeatAt: string | null; - }>( - "select id, name, department, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt from agents where company_id = ? and status not in ('terminated', 'paused', 'pending_approval')", - companyId, - ); - }, - - getIdleAgentsForDepartment( - companyId: string, - department: string, - ): Array<{ id: string; name: string }> { - return readAll( - "select id, name from agents where company_id = ? and department = ? and status in ('idle', 'active') order by spent_monthly_usd asc", - companyId, - department, - ); - }, - - getManagerForAgent( - agentId: string, - ): { id: string; name: string; companyId: string } | null { - const agent = getDb() - .prepare("select reports_to, company_id from agents where id = ?") - .get(agentId) as { reports_to: string | null; company_id: string } | undefined; - if (!agent || !agent.reports_to) return null; - const manager = getDb() - .prepare("select id, name from agents where id = ?") - .get(agent.reports_to) as { id: string; name: string } | undefined; - return manager ? { ...manager, companyId: agent.company_id } : null; - }, - - resetMonthlyBudgets(companyId: string): void { - getDb() - .prepare( - "update agents set spent_monthly_usd = 0, updated_at = ? where company_id = ? and spent_monthly_usd > 0", - ) - .run(nowIso(), companyId); - }, - - /** - * Returns ids of non-terminated agents in a department. Used by - * `resolveMessageWakeTargets` to fan out "department" channel messages. - */ - listDepartmentAgentIds(companyId: string, department: string): string[] { - return readAll<{ id: string }>( - "select id from agents where company_id = ? and department = ? and status != 'terminated'", - companyId, - department, - ).map((row) => row.id); - }, - - /** - * Returns ids of every agent that is eligible to receive a routine - * company-wide broadcast. Paused, pending-approval, and terminated - * agents are excluded — they should not be woken by normal chatter; - * only incidents reach the broader pingable set. Used by - * `resolveMessageWakeTargets` for the "company" channel so the - * semantic matches Slack (all-hands) rather than board-only. - */ - listCompanyBroadcastAgentIds(companyId: string): string[] { - return readAll<{ id: string }>( - "select id from agents where company_id = ? and status not in ('terminated', 'paused', 'pending_approval')", - companyId, - ).map((row) => row.id); - }, - - /** - * Returns ids of agents that can receive incident pings: everybody not - * terminated or still pending approval. - */ - listIncidentPingableAgentIds(companyId: string): string[] { - return readAll<{ id: string }>( - "select id from agents where company_id = ? and status not in ('terminated', 'pending_approval')", - companyId, - ).map((row) => row.id); - }, - - /** - * Returns the agent's display name, or null if the agent no longer - * exists. Used for notification subject lines. - */ - findAgentName(agentId: string): string | null { - const row = getDb() - .prepare("select name from agents where id = ? limit 1") - .get(agentId) as { name: string } | undefined; - return row?.name ?? null; - }, - - /** - * Returns (id, name) pairs for the given ids, scoped to company. Used - * for batched name resolution when fanning out message wake targets. - */ - listAgentNamesByIds(companyId: string, agentIds: readonly string[]): Array<{ id: string; name: string }> { - if (agentIds.length === 0) return []; - const placeholders = agentIds.map(() => "?").join(","); - return readAll<{ id: string; name: string }>( - `select id, name from agents where id in (${placeholders}) and company_id = ?`, - ...agentIds, - companyId, - ); - }, - - /** - * Returns ids of active agents with the given ids, filtered to the - * company scope. Used by project-channel wake targeting to drop - * terminated members before pinging. - */ - listActiveAgentIdsFromIds(companyId: string, agentIds: readonly string[]): string[] { - if (agentIds.length === 0) return []; - const placeholders = agentIds.map(() => "?").join(","); - return readAll<{ id: string }>( - `select id from agents where id in (${placeholders}) and company_id = ? and status != 'terminated'`, - ...agentIds, - companyId, - ).map((row) => row.id); - }, - }; -} diff --git a/src/main/database/agents.ts b/src/main/database/agents.ts deleted file mode 100644 index 456d077a..00000000 --- a/src/main/database/agents.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { AgentRecord } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { buildAgentCrudMethods } from "./agents-crud"; -import { buildAgentHierarchyMethods } from "./agents-hierarchy"; -import { buildAgentPermissionMethods } from "./agent-permissions"; - -export function buildAgentMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - getAgent: (id: string) => AgentRecord; - wouldCreateAgentCycle: (agentId: string, reportsTo: string | null) => boolean; - recordConfigRevision: (input: { - companyId: string; - agentId: string; - changedKeys: string[]; - configBefore: Record; - configAfter: Record; - source?: string; - rolledBackFromRevisionId?: string | null; - createdByAgentId?: string | null; - createdByUserId?: string | null; - }) => string; - cancelRunForDeletion: (runId: string, taskId: string | null, workspaceId: string | null, summary: string) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - }, -) { - return { - ...buildAgentCrudMethods(getDb, readAll, transaction, deps), - ...buildAgentHierarchyMethods(getDb, readAll, transaction, { getAgent: deps.getAgent }), - ...buildAgentPermissionMethods(getDb, readAll, transaction), - }; -} diff --git a/src/main/database/approvals.ts b/src/main/database/approvals.ts deleted file mode 100644 index 25da7786..00000000 --- a/src/main/database/approvals.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { ApprovalRecord } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { normalizeOptionalId, nowIso, parseJson, toBoolean } from "./helpers"; - -export interface ApprovalPolicyRecord { - approvalType: string; - scopeType: string; - blocksExecution: boolean; - requiredMode: "any" | "ai_ceo" | "ai_cofounder"; - autoApprovable: boolean; -} - -export function buildApprovalMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - getAgent: (id: string) => { companyId: string; status: string }; - }, -) { - return { - getApprovalRecord(id: string) { - const row = getDb() - .prepare( - "select id, company_id as companyId, related_task_id as relatedTaskId, requested_by_agent_id as requestedByAgentId, related_agent_id as relatedAgentId, 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 where id = ?", - ) - .get(id) as (ApprovalRecord & { payloadJson: string | null; relatedAgentId: string | null }) | undefined; - if (!row) throw new Error(`Approval not found: ${id}`); - return row; - }, - - /** - * Non-throwing lookup by id. Returns null when the approval does not - * exist. Used by approval routes that need to branch on 404 rather - * than catching an exception. - */ - findApprovalById(id: string): (ApprovalRecord & { payloadJson: string | null; relatedAgentId: string | null }) | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, related_task_id as relatedTaskId, requested_by_agent_id as requestedByAgentId, related_agent_id as relatedAgentId, 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 where id = ?", - ) - .get(id) as (ApprovalRecord & { payloadJson: string | null; relatedAgentId: string | null }) | undefined; - return row ?? null; - }, - - requestApproval(input: { - companyId: string; - relatedTaskId?: string | null; - requestedByAgentId?: string | null; - relatedAgentId?: string | null; - type: string; - payloadSummary: string; - impactSummary: string; - payloadJson?: string | null; - }) { - const id = randomUUID(); - const ts = nowIso(); - let relatedAgentId = normalizeOptionalId(input.relatedAgentId); - if (!relatedAgentId && input.type === "hire_agent" && input.payloadJson) { - try { - const payload = JSON.parse(input.payloadJson) as { agentId?: string }; - relatedAgentId = payload.agentId ?? null; - } catch (error) { - log.warn( - `[db/approvals] malformed payloadJson on hire_agent request for company ${input.companyId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - if (input.type === "hire_agent") { - if (!relatedAgentId) { - throw new Error("hire_agent approvals require a linked pending agent."); - } - const agent = deps.getAgent(relatedAgentId); - if (agent.companyId !== input.companyId) { - throw new Error(`Agent ${relatedAgentId} does not belong to company ${input.companyId}.`); - } - if (agent.status !== "pending_approval") { - throw new Error(`hire_agent approvals can only target agents pending approval. Current status: ${agent.status}.`); - } - } - getDb() - .prepare( - "insert into approvals (id, company_id, related_task_id, requested_by_agent_id, related_agent_id, type, payload_summary, impact_summary, payload_json, decision_note, state, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, '', 'pending', ?, ?)", - ) - .run( - id, input.companyId, normalizeOptionalId(input.relatedTaskId), - normalizeOptionalId(input.requestedByAgentId), relatedAgentId, - input.type, input.payloadSummary, input.impactSummary, - input.payloadJson ?? null, ts, ts, - ); - return id; - }, - - decideApproval(input: { companyId?: string | null; approvalId: string; state: string; decisionNote: string }) { - const approval = getDb() - .prepare( - "select id, company_id as companyId, related_task_id as relatedTaskId, requested_by_agent_id as requestedByAgentId, related_agent_id as relatedAgentId, 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 where id = ?", - ) - .get(input.approvalId) as (ApprovalRecord & { payloadJson: string | null; relatedAgentId: string | null }) | undefined; - if (!approval) throw new Error(`Approval not found: ${input.approvalId}`); - if (input.companyId && approval.companyId !== input.companyId) { - throw new Error(`Approval ${input.approvalId} does not belong to company ${input.companyId}.`); - } - if (!["pending", "revision_requested"].includes(approval.state)) { - throw new Error(`Approval ${input.approvalId} is already ${approval.state} and cannot be re-decided.`); - } - const ts = nowIso(); - transaction(() => { - getDb() - .prepare("update approvals set state = ?, decision_note = ?, updated_at = ? where id = ?") - .run(input.state, input.decisionNote, ts, input.approvalId); - if (approval.type === "hire_agent") { - const agentId = approval.relatedAgentId - ?? parseJson<{ agentId?: string } | null>(approval.payloadJson, null)?.agentId - ?? null; - if (!agentId) { - throw new Error(`hire_agent approval ${input.approvalId} has no linked agent — cannot resolve hire target. Ensure relatedAgentId or payloadJson.agentId is set.`); - } - if (input.state === "approved") { - const result = getDb() - .prepare("update agents set status = 'idle', updated_at = ? where id = ? and company_id = ? and status = 'pending_approval'") - .run(ts, agentId, approval.companyId); - if (result.changes === 0) { - throw new Error(`hire_agent approval ${input.approvalId} could not activate agent ${agentId}; the agent is missing or no longer pending approval.`); - } - } - if (input.state === "rejected") { - const result = getDb() - .prepare("update agents set status = 'terminated', updated_at = ? where id = ? and company_id = ? and status = 'pending_approval'") - .run(ts, agentId, approval.companyId); - if (result.changes === 0) { - throw new Error(`hire_agent approval ${input.approvalId} could not reject agent ${agentId}; the agent is missing or no longer pending approval.`); - } - } - } - }); - }, - - deleteApproval(id: string, companyId: string) { - getDb().prepare("delete from approvals where id = ? and company_id = ?").run(id, companyId); - }, - - /** - * Returns the requesting agent's pending approvals for standup - * aggregation (id, type, state, payloadSummary, decisionNote). - */ - listAgentPendingApprovals( - companyId: string, - agentId: string, - ): Array<{ - id: string; - type: string; - state: string; - payloadSummary: string | null; - decisionNote: string | null; - }> { - return readAll( - "select id, type, state, payload_summary as payloadSummary, decision_note as decisionNote from approvals where company_id = ? and requested_by_agent_id = ? and state = 'pending' order by created_at desc", - companyId, - agentId, - ); - }, - - /** - * Returns up to `limit` of the requesting agent's resolved approvals - * for standup aggregation (state != 'pending'). - */ - listAgentResolvedApprovals( - companyId: string, - agentId: string, - limit = 5, - ): Array<{ - id: string; - type: string; - state: string; - payloadSummary: string | null; - decisionNote: string | null; - }> { - return readAll( - "select id, type, state, payload_summary as payloadSummary, decision_note as decisionNote from approvals where company_id = ? and requested_by_agent_id = ? and state != 'pending' order by created_at desc limit ?", - companyId, - agentId, - limit, - ); - }, - - /** - * Returns pending `hire_agent` approval payloads for a company, used - * during hire-request creation to detect duplicate names across - * concurrent requests. - */ - listPendingHireApprovalPayloads( - companyId: string, - ): Array<{ payloadJson: string | null }> { - return readAll<{ payloadJson: string | null }>( - "select payload_json as payloadJson from approvals where company_id = ? and type = 'hire_agent' and state = 'pending'", - companyId, - ); - }, - - /** - * Returns the full approval row projection used by - * GET /api/companies/:id/approvals. Optional filters match the - * historical inline SQL behaviour. - */ - listApprovalsForApi(companyId: string, filters: { - requestedByAgentId?: string; - relatedTaskId?: string; - statuses?: string[] | null; - }): Array<{ - id: string; - companyId: string; - relatedTaskId: string | null; - relatedAgentId: string | null; - requestedByAgentId: string | null; - type: string; - payloadSummary: string | null; - impactSummary: string | null; - payloadJson: string | null; - decisionNote: string | null; - state: string; - createdAt: string; - updatedAt: string; - }> { - let sql = "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 where company_id = ?"; - const args: SQLInputValue[] = [companyId]; - if (filters.requestedByAgentId) { - sql += " and requested_by_agent_id = ?"; - args.push(filters.requestedByAgentId); - } - if (filters.relatedTaskId) { - sql += " and related_task_id = ?"; - args.push(filters.relatedTaskId); - } - if (filters.statuses && filters.statuses.length > 0) { - sql += ` and state in (${filters.statuses.map(() => "?").join(", ")})`; - args.push(...filters.statuses); - } - sql += " order by created_at desc"; - return readAll(sql, ...args); - }, - - getApprovalPolicy(approvalType: string): ApprovalPolicyRecord | null { - const row = getDb() - .prepare( - "select approval_type as approvalType, scope_type as scopeType, blocks_execution as blocksExecution, required_mode as requiredMode, auto_approvable as autoApprovable from approval_policies where approval_type = ?", - ) - .get(approvalType) as { - approvalType: string; - scopeType: string; - blocksExecution: number; - requiredMode: "any" | "ai_ceo" | "ai_cofounder"; - autoApprovable: number; - } | undefined; - return row - ? { - approvalType: row.approvalType, - scopeType: row.scopeType, - blocksExecution: toBoolean(row.blocksExecution), - requiredMode: row.requiredMode, - autoApprovable: toBoolean(row.autoApprovable), - } - : null; - }, - - getBlockingApproval(companyId: string, agentId: string, taskId: string | null): ApprovalRecord | null { - const company = getDb() - .prepare("select execution_mode as executionMode from companies where id = ?") - .get(companyId) as { executionMode: "ai_ceo" | "ai_cofounder" } | undefined; - if (!company) { - throw new Error(`Company not found for approval gate: ${companyId}`); - } - const rows = readAll( - `select id, company_id as companyId, related_task_id as relatedTaskId, - requested_by_agent_id as requestedByAgentId, related_agent_id as relatedAgentId, - a.type, payload_summary as payloadSummary, impact_summary as impactSummary, - payload_json as payloadJson, decision_note as decisionNote, state, - a.created_at as createdAt, a.updated_at as updatedAt - from approvals a - inner join approval_policies p on p.approval_type = a.type - where a.company_id = ? - and a.state = 'pending' - and p.blocks_execution = 1 - and (p.required_mode = 'any' or p.required_mode = ?) - and ( - (p.scope_type = 'related_agent' and a.related_agent_id = ?) - or ( - p.scope_type = 'requester_or_task' - and ( - a.requested_by_agent_id = ? - or (? is not null and a.related_task_id = ?) - ) - ) - ) - order by a.created_at asc limit 1`, - companyId, - company.executionMode, - agentId, - agentId, - taskId, - taskId, - ); - return rows.length > 0 ? rows[0] : null; - }, - - resubmitApproval(approvalId: string, companyId: string): void { - const ts = nowIso(); - getDb().prepare( - "UPDATE approvals SET state = 'pending', decision_note = '', updated_at = ? WHERE id = ? AND company_id = ? AND state = 'revision_requested'", - ).run(ts, approvalId, companyId); - }, - - addApprovalComment(input: { - companyId: string; approvalId: string; authorAgentId?: string | null; - authorUserId?: string | null; body: string; - }): string { - const id = randomUUID(); - const ts = nowIso(); - getDb().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 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, - })); - }, - - linkTaskToApproval(taskId: string, approvalId: string, companyId: string, linkedByAgentId?: string | null): void { - getDb().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 { - getDb().prepare( - "DELETE FROM task_approval_links WHERE task_id = ? AND approval_id = ?", - ).run(taskId, approvalId); - }, - - listApprovalsForTask(taskId: string): string[] { - return 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 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 { - if (taskIds.length === 0) return; - const ts = nowIso(); - transaction(() => { - const stmt = getDb().prepare( - "INSERT OR IGNORE INTO task_approval_links (task_id, approval_id, company_id, linked_by_agent_id, created_at) VALUES (?, ?, ?, ?, ?)", - ); - for (const taskId of taskIds) { - stmt.run(taskId, approvalId, companyId, linkedByAgentId ?? null, ts); - } - }); - }, - - /** - * Returns the first pending approval linked to a task (id + type), - * or null when none exists. Used by task-quality-gates to decide - * whether an in-review task still has a blocking approval. - */ - findPendingApprovalForTask(companyId: string, taskId: string): { id: string; type: string } | null { - const row = getDb() - .prepare( - `SELECT id, type FROM approvals - WHERE company_id = ? AND related_task_id = ? AND state = 'pending' - LIMIT 1`, - ) - .get(companyId, taskId) as { id: string; type: string } | undefined; - return row ?? null; - }, - - /** - * Returns every approval in the company whose `type` matches exactly. - * Used by the approvals POST route to enforce ordering invariants - * (e.g. "approve_ceo_strategy must trail hire_agent"). - */ - listCompanyApprovalsByType(companyId: string, type: string): Array<{ id: string; state: string }> { - return readAll<{ id: string; state: string }>( - `SELECT id, state FROM approvals WHERE company_id = ? AND type = ? ORDER BY created_at ASC`, - companyId, - type, - ); - }, - - /** - * Returns true when the given agent has a pending review-type approval - * against one of their tasks. Used by checkpoint-engine to decide - * whether heartbeat should pause in co-founder mode. - */ - hasPendingReviewApprovalForAgent(companyId: string, agentId: string): boolean { - const row = getDb() - .prepare( - `SELECT 1 as hit FROM approvals a - JOIN tasks t ON a.related_task_id = t.id - JOIN approval_policies p ON p.approval_type = a.type - WHERE a.company_id = ? AND a.state = 'pending' - AND t.assignee_agent_id = ? - AND p.blocks_execution = 1 - LIMIT 1`, - ) - .get(companyId, agentId) as { hit: number } | undefined; - return row !== undefined; - }, - }; -} diff --git a/src/main/database/automation.ts b/src/main/database/automation.ts deleted file mode 100644 index f3f0139b..00000000 --- a/src/main/database/automation.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import type { WorkflowPipelineRecord } from "@shared/types"; -import type { ReadAll, SqliteRow } from "./helpers"; -import { ensureId, nowIso } from "./helpers"; - -export function buildAutomationMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - deps: { - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - }, -) { - return { - saveAutomationRule(input: { - id?: string | null; companyId: string; name: string; description?: string; - trigger: string; conditionsJson?: string; action: string; actionConfigJson?: string; - sourceDepartment?: string | null; targetDepartment?: string | null; - priority?: number; status?: string; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from automation_rules where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Automation rule ${id} does not belong to company ${input.companyId}`); - } - if (existing) { - getDb().prepare( - "update automation_rules set name = ?, description = ?, trigger = ?, conditions_json = ?, action = ?, action_config_json = ?, source_department = ?, target_department = ?, priority = ?, status = ?, updated_at = ? where id = ? and company_id = ?", - ).run(input.name, input.description ?? "", input.trigger, input.conditionsJson ?? "{}", input.action, input.actionConfigJson ?? "{}", input.sourceDepartment ?? null, input.targetDepartment ?? null, input.priority ?? 50, input.status ?? "active", ts, id, input.companyId); - } else { - getDb().prepare( - "insert into automation_rules (id, company_id, name, description, trigger, conditions_json, action, action_config_json, source_department, target_department, priority, status, execution_count, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)", - ).run(id, input.companyId, input.name, input.description ?? "", input.trigger, input.conditionsJson ?? "{}", input.action, input.actionConfigJson ?? "{}", input.sourceDepartment ?? null, input.targetDepartment ?? null, input.priority ?? 50, input.status ?? "active", ts, ts); - } - deps.addActivity({ companyId: input.companyId, actor: "system", action: existing ? "updated" : "created", entityType: "automation_rule", entityId: id, detail: `${existing ? "Updated" : "Created"} automation rule: ${input.name}` }); - return id; - }, - - deleteAutomationRule(id: string, companyId: string) { - getDb().prepare("delete from automation_rules where id = ? and company_id = ?").run(id, companyId); - }, - - listAutomationRuleNames(companyId: string): Set { - return new Set( - readAll<{ name: string }>( - "select name from automation_rules where company_id = ?", - companyId, - ).map((row) => row.name), - ); - }, - - toggleAutomationRule(id: string, companyId: string, status: "active" | "paused") { - getDb().prepare("update automation_rules set status = ?, updated_at = ? where id = ? and company_id = ?").run(status, nowIso(), id, companyId); - }, - - recordAutomationExecution(ruleId: string, companyId: string, ruleName: string, trigger: string, action: string, detail: string) { - const id = randomUUID(); - const ts = nowIso(); - getDb().prepare("insert into automation_log (id, company_id, rule_id, rule_name, trigger, action, detail, executed_at) values (?, ?, ?, ?, ?, ?, ?, ?)").run(id, companyId, ruleId, ruleName, trigger, action, detail, ts); - getDb().prepare("update automation_rules set execution_count = execution_count + 1, last_executed_at = ? where id = ? and company_id = ?").run(ts, ruleId, companyId); - }, - - getAutomationLog(companyId: string) { - return readAll<{ ruleId: string; ruleName: string; trigger: string; action: string; executedAt: string }>( - "select rule_id as ruleId, rule_name as ruleName, trigger, action, executed_at as executedAt from automation_log where company_id = ? order by executed_at desc limit 100", - companyId, - ); - }, - - listActiveAutomationRules(companyId: string, trigger: string): Array<{ - id: string; name: string; trigger: string; conditionsJson: string; - action: string; actionConfigJson: string; sourceDepartment: string | null; - targetDepartment: string | null; priority: number; - }> { - return readAll( - "select id, name, trigger, conditions_json as conditionsJson, action, action_config_json as actionConfigJson, source_department as sourceDepartment, target_department as targetDepartment, priority from automation_rules where company_id = ? and trigger = ? and status = 'active' order by priority desc", - companyId, trigger, - ); - }, - - saveWorkflow(input: { - id?: string | null; companyId: string; name: string; description?: string; - stepsJson?: string; triggerType: string; triggerConfigJson?: string; status?: string; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from workflow_pipelines where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Workflow ${id} does not belong to company ${input.companyId}`); - } - if (existing) { - getDb().prepare( - "update workflow_pipelines set name = ?, description = ?, steps_json = ?, trigger_type = ?, trigger_config_json = ?, status = ?, updated_at = ? where id = ? and company_id = ?", - ).run(input.name, input.description ?? "", input.stepsJson ?? "[]", input.triggerType, input.triggerConfigJson ?? "{}", input.status ?? "draft", ts, id, input.companyId); - } else { - getDb().prepare( - "insert into workflow_pipelines (id, company_id, name, description, steps_json, trigger_type, trigger_config_json, status, current_step_index, run_count, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, 0, 0, ?, ?)", - ).run(id, input.companyId, input.name, input.description ?? "", input.stepsJson ?? "[]", input.triggerType, input.triggerConfigJson ?? "{}", input.status ?? "draft", ts, ts); - } - deps.addActivity({ companyId: input.companyId, actor: "system", action: existing ? "updated" : "created", entityType: "workflow", entityId: id, detail: `${existing ? "Updated" : "Created"} workflow: ${input.name}` }); - return id; - }, - - getWorkflowRecord(id: string, companyId: string): WorkflowPipelineRecord | null { - const row = getDb().prepare( - "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 id = ? and company_id = ?", - ).get(id, companyId) as WorkflowPipelineRecord | undefined; - return row ?? null; - }, - - updateWorkflowExecution(input: { - id: string; companyId: string; status: string; - currentStepIndex: number; stepsJson: string; - incrementRunCount?: boolean; lastRunAt?: string | null; - }) { - const ts = nowIso(); - const runCountClause = input.incrementRunCount ? ", run_count = run_count + 1" : ""; - const lastRunAt = input.lastRunAt ?? null; - getDb().prepare( - `update workflow_pipelines - set status = ?, current_step_index = ?, steps_json = ?, last_run_at = ?, updated_at = ?${runCountClause} - where id = ? and company_id = ?`, - ).run(input.status, input.currentStepIndex, input.stepsJson, lastRunAt, ts, input.id, input.companyId); - }, - - deleteWorkflow(id: string, companyId: string) { - getDb().prepare("delete from workflow_pipelines where id = ? and company_id = ?").run(id, companyId); - }, - - listTriggerableWorkflows(companyId: string, triggerType: string): WorkflowPipelineRecord[] { - return 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", - companyId, triggerType, - ) as WorkflowPipelineRecord[]; - }, - }; -} diff --git a/src/main/database/backup.ts b/src/main/database/backup.ts deleted file mode 100644 index 2fabad83..00000000 --- a/src/main/database/backup.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { chmodSync, cpSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; -import { copyFile, cp, rm } from "node:fs/promises"; -import { execFileSync } from "node:child_process"; -import { join } from "node:path"; -import { DatabaseSync, backup as backupDatabase } from "node:sqlite"; -import log from "electron-log/main.js"; - -function readSchemaVersion(db: DatabaseSync): number { - const row = db - .prepare("select coalesce(max(version), 0) as v from schema_migrations") - .get() as { v: number } | undefined; - return row?.v ?? 0; -} - -function readGitSha(): string | null { - try { - const out = execFileSync("git", ["rev-parse", "HEAD"], { - stdio: ["ignore", "pipe", "ignore"], - cwd: process.cwd(), - timeout: 1000, - }); - const sha = out.toString("utf8").trim(); - return sha.length === 40 ? sha : null; - } catch (e) { - log.warn( - "[database/backup] git rev-parse HEAD failed; manifest.gitSha will be null", - e instanceof Error ? e.message : String(e), - ); - return null; - } -} - -function timestampSegment(): string { - // Filesystem-safe variant of ISO 8601 (YYYYMMDD-HHmmss-SSS). - const now = new Date(); - const pad = (n: number, w = 2) => n.toString().padStart(w, "0"); - return ( - `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}-` + - `${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}-` + - `${pad(now.getUTCMilliseconds(), 3)}` - ); -} - -async function copyIfExists(source: string, destination: string) { - if (!existsSync(source)) { - return; - } - await copyFile(source, destination); -} - -export function buildBackupMethods( - deps: { - getDb: () => DatabaseSync; - setDb: (db: DatabaseSync) => void; - openConnection: () => DatabaseSync; - init: () => void; - close: () => void; - profileDir: string; - dbPath: string; - logsDir: string; - artifactsDir: string; - backupsDir: string; - appVersion: string; - }, -) { - return { - /** - * Take a synchronous snapshot of the profile before a destructive or - * risky operation (currently: pre-migration). Named so the operator - * can tell snapshots apart by reason and target schema version. - * - * Uses `VACUUM INTO` + `cpSync` rather than the async `exportBackup` - * path so the caller — `runMigrations`, which is synchronous — can - * block on the backup without any async plumbing. The returned path - * is absolute so a failed migration can surface the recovery point - * in logs verbatim. - * - * Failure modes are reported by throwing. There is no fallback: if - * we cannot take a snapshot we must not touch the schema. - */ - createAutomaticBackup(reason: string): string { - if (!reason || reason.includes("/") || reason.includes("\\")) { - throw new Error(`createAutomaticBackup: invalid reason "${reason}"`); - } - const db = deps.getDb(); - const schemaVersion = readSchemaVersion(db); - const segment = `${reason}-v${schemaVersion}-${timestampSegment()}`; - const targetDir = join(deps.backupsDir, segment); - mkdirSync(deps.backupsDir, { recursive: true }); - mkdirSync(targetDir, { recursive: true }); - - // VACUUM INTO takes a single consistent snapshot of the live DB - // while the connection is held open — no WAL checkpoint dance, no - // torn writes, works on sqlite3 ≥ 3.27. The destination must not - // exist; `mkdirSync` above only created the parent directory. - // - // Safety invariant under WAL mode: VACUUM INTO opens an implicit - // read transaction that sees every committed frame including those - // still in profile.sqlite-wal. DO NOT add PRAGMA wal_checkpoint - // here — a TRUNCATE checkpoint would fight concurrent writers and - // buys nothing for the snapshot; a PASSIVE checkpoint is redundant. - const dbTarget = join(targetDir, "profile.sqlite").replace(/'/g, "''"); - db.exec(`VACUUM INTO '${dbTarget}'`); - - // Side-car files (logs + artifacts) ride along so operators - // restoring from this snapshot see the same run history the - // migration saw. `cpSync` is recursive and force-overwrites. - if (existsSync(deps.logsDir)) { - cpSync(deps.logsDir, join(targetDir, "logs"), { recursive: true, force: true }); - } - if (existsSync(deps.artifactsDir)) { - cpSync(deps.artifactsDir, join(targetDir, "artifacts"), { recursive: true, force: true }); - } - - const manifest = { - reason, - schemaVersion, - appVersion: deps.appVersion, - createdAt: new Date().toISOString(), - gitSha: readGitSha(), - }; - writeFileSync( - join(targetDir, "backup-manifest.json"), - `${JSON.stringify(manifest, null, 2)}\n`, - { encoding: "utf8" }, - ); - log.info(`[database/backup] automatic snapshot "${reason}" written to ${targetDir}`); - return targetDir; - }, - - exportBackup(targetDir: string) { - mkdirSync(targetDir, { recursive: true }); - deps.getDb().exec("PRAGMA wal_checkpoint(TRUNCATE);"); - const copyJobs = [ - backupDatabase(deps.getDb(), join(targetDir, "profile.sqlite")), - cp(deps.logsDir, join(targetDir, "logs"), { recursive: true, force: true }), - cp(deps.artifactsDir, join(targetDir, "artifacts"), { recursive: true, force: true }), - copyIfExists(`${deps.dbPath}-wal`, join(targetDir, "profile.sqlite-wal")), - copyIfExists(`${deps.dbPath}-shm`, join(targetDir, "profile.sqlite-shm")), - ]; - return Promise.all(copyJobs); - }, - - async restoreFromBackup(sourceDir: string) { - const sourceDbPath = join(sourceDir, "profile.sqlite"); - if (!existsSync(sourceDbPath)) { - throw new Error("Backup directory is missing profile.sqlite."); - } - - // Validate - const currentSchemaVersion = - (deps.getDb() - .prepare("select coalesce(max(version), 0) as v from schema_migrations") - .get() as { v: number } | undefined)?.v ?? 0; - const validationDb = new DatabaseSync(sourceDbPath); - try { - const requiredTables = ["settings", "companies", "connectors"] as const; - for (const table of requiredTables) { - const row = validationDb - .prepare("select name from sqlite_master where type = 'table' and name = ?") - .get(table) as { name: string } | undefined; - if (!row) { - throw new Error(`Backup is missing the required table "${table}".`); - } - } - const hasMigrationsTable = validationDb - .prepare("select name from sqlite_master where type = 'table' and name = 'schema_migrations'") - .get() as { name: string } | undefined; - if (!hasMigrationsTable) { - throw new Error( - `Backup is missing schema_migrations. Expected schema version ${currentSchemaVersion}.`, - ); - } - const backupVersion = - (validationDb - .prepare("select coalesce(max(version), 0) as v from schema_migrations") - .get() as { v: number } | undefined)?.v ?? 0; - if (backupVersion < currentSchemaVersion) { - throw new Error( - `Backup schema version ${backupVersion} is older than current ${currentSchemaVersion}. Restore would lose migrations.`, - ); - } - } finally { - validationDb.close(); - } - - const recoveryDir = join(deps.backupsDir, `pre-restore-${Date.now()}`); - mkdirSync(recoveryDir, { recursive: true }); - deps.getDb().exec("PRAGMA wal_checkpoint(TRUNCATE);"); - await Promise.all([ - backupDatabase(deps.getDb(), join(recoveryDir, "profile.sqlite")), - cp(deps.logsDir, join(recoveryDir, "logs"), { recursive: true, force: true }), - cp(deps.artifactsDir, join(recoveryDir, "artifacts"), { recursive: true, force: true }), - copyIfExists(join(deps.profileDir, "vault.key"), join(recoveryDir, "vault.key")), - copyIfExists(join(deps.profileDir, "agent-api-signing.key"), join(recoveryDir, "agent-api-signing.key")), - copyIfExists(`${deps.dbPath}-wal`, join(recoveryDir, "profile.sqlite-wal")), - copyIfExists(`${deps.dbPath}-shm`, join(recoveryDir, "profile.sqlite-shm")), - ]); - - deps.close(); - try { - await applyBackup(sourceDir); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - try { - await applyBackup(recoveryDir); - } catch (recoveryError) { - const recoveryMessage = - recoveryError instanceof Error ? recoveryError.message : String(recoveryError); - try { - deps.setDb(deps.openConnection()); - deps.init(); - } catch (reopenError) { - log.error(`[database/backup] Reopen failed after restore/recovery failure:`, reopenError instanceof Error ? reopenError.message : String(reopenError)); - } - throw new Error( - `Restore failed: ${message}. Recovery also failed: ${recoveryMessage}. Previous profile is at ${recoveryDir}.`, - ); - } - throw new Error(`Restore failed. Previous profile was recovered from ${recoveryDir}. ${message}`); - } - }, - }; - - async function applyBackup(sourceDir: string) { - await rm(deps.dbPath, { force: true }); - await rm(`${deps.dbPath}-wal`, { force: true }); - await rm(`${deps.dbPath}-shm`, { force: true }); - - await copyFile(join(sourceDir, "profile.sqlite"), deps.dbPath); - await copyIfExists(join(sourceDir, "profile.sqlite-wal"), `${deps.dbPath}-wal`); - await copyIfExists(join(sourceDir, "profile.sqlite-shm"), `${deps.dbPath}-shm`); - - await rm(deps.logsDir, { recursive: true, force: true }); - await rm(deps.artifactsDir, { recursive: true, force: true }); - mkdirSync(deps.logsDir, { recursive: true }); - mkdirSync(deps.artifactsDir, { recursive: true }); - - if (existsSync(join(sourceDir, "logs"))) { - await cp(join(sourceDir, "logs"), deps.logsDir, { recursive: true, force: true }); - } - if (existsSync(join(sourceDir, "artifacts"))) { - await cp(join(sourceDir, "artifacts"), deps.artifactsDir, { recursive: true, force: true }); - } - await copyIfExists(join(sourceDir, "vault.key"), join(deps.profileDir, "vault.key")); - await copyIfExists(join(sourceDir, "agent-api-signing.key"), join(deps.profileDir, "agent-api-signing.key")); - if (existsSync(join(deps.profileDir, "vault.key"))) { - chmodSync(join(deps.profileDir, "vault.key"), 0o600); - } - if (existsSync(join(deps.profileDir, "agent-api-signing.key"))) { - chmodSync(join(deps.profileDir, "agent-api-signing.key"), 0o600); - } - - deps.setDb(deps.openConnection()); - deps.init(); - } -} diff --git a/src/main/database/budget.ts b/src/main/database/budget.ts deleted file mode 100644 index 97747dba..00000000 --- a/src/main/database/budget.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { BudgetIncidentRecord, BudgetPolicyRecord } from "@shared/types"; -import type { ReadAll, SqliteRow, Transaction } from "./helpers"; -import { nowIso } from "./helpers"; - -function mapPolicyRow(r: SqliteRow): BudgetPolicyRecord { - return { - id: r.id, - companyId: r.company_id, - scopeType: r.scope_type, - scopeId: r.scope_id, - metric: r.metric, - windowKind: r.window_kind, - amount: r.amount, - warnPercent: r.warn_percent, - hardStopEnabled: !!r.hard_stop_enabled, - notifyEnabled: !!r.notify_enabled, - isActive: !!r.is_active, - createdAt: r.created_at, - updatedAt: r.updated_at, - }; -} - -export function buildBudgetMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - function getCalendarMonthWindow(): { start: string; end: string } { - const now = new Date(); - const year = now.getUTCFullYear(); - const month = now.getUTCMonth(); - const start = new Date(Date.UTC(year, month, 1)).toISOString(); - const end = new Date(Date.UTC(year, month + 1, 1)).toISOString(); - return { start, end }; - } - - return { - saveBudgetPolicy(input: { - id?: string | null; - companyId: string; - scopeType: string; - scopeId: string; - metric?: string; - windowKind?: string; - amount: number; - warnPercent?: number; - hardStopEnabled?: boolean; - notifyEnabled?: boolean; - isActive?: boolean; - }): string { - const ts = nowIso(); - const metric = input.metric ?? "billed_cents"; - const windowKind = input.windowKind ?? "calendar_month_utc"; - const scopedExisting = input.id - ? [] - : readAll<{ id: string; createdAt: string }>( - `SELECT id, created_at as createdAt - FROM budget_policies - WHERE company_id = ? AND scope_type = ? AND scope_id = ? AND metric = ? AND window_kind = ? - ORDER BY created_at ASC`, - input.companyId, - input.scopeType, - input.scopeId, - metric, - windowKind, - ); - const existing = input.id - ? getDb() - .prepare("SELECT id, created_at as createdAt FROM budget_policies WHERE id = ?") - .get(input.id) as { id: string; createdAt: string } | undefined - : scopedExisting[0]; - const staleIds = input.id ? [] : scopedExisting.slice(1).map((policy) => policy.id); - const id = existing?.id ?? input.id ?? randomUUID(); - const createdAt = existing?.createdAt ?? ts; - getDb() - .prepare( - `INSERT OR REPLACE INTO budget_policies - (id, company_id, scope_type, scope_id, metric, window_kind, amount, warn_percent, - hard_stop_enabled, notify_enabled, is_active, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - ) - .run( - id, input.companyId, input.scopeType, input.scopeId, - metric, windowKind, - input.amount, input.warnPercent ?? 80, - (input.hardStopEnabled ?? true) ? 1 : 0, - (input.notifyEnabled ?? true) ? 1 : 0, - (input.isActive ?? true) ? 1 : 0, createdAt, ts, - ); - if (staleIds.length > 0) { - const placeholders = staleIds.map(() => "?").join(", "); - getDb() - .prepare(`UPDATE budget_policies SET is_active = 0, updated_at = ? WHERE id IN (${placeholders})`) - .run(ts, ...staleIds); - } - return id; - }, - - deleteBudgetPolicy(companyId: string, policyId: string): void { - transaction(() => { - getDb().prepare("DELETE FROM budget_incidents WHERE policy_id = ?").run(policyId); - getDb().prepare("DELETE FROM budget_policies WHERE id = ? AND company_id = ?").run(policyId, companyId); - }); - }, - - listBudgetPolicies(companyId: string): BudgetPolicyRecord[] { - return readAll( - "SELECT * FROM budget_policies WHERE company_id = ? ORDER BY scope_type, created_at", - companyId, - ).map(mapPolicyRow); - }, - - getBudgetPolicy(policyId: string): BudgetPolicyRecord | null { - const r = getDb().prepare("SELECT * FROM budget_policies WHERE id = ?").get(policyId) as SqliteRow | undefined; - if (!r) return null; - return mapPolicyRow(r); - }, - - getActivePoliciesForRun(companyId: string, agentId: string, projectId: string | null): BudgetPolicyRecord[] { - const sql = projectId - ? `SELECT * FROM budget_policies - WHERE company_id = ? AND is_active = 1 - AND ( - (scope_type = 'company' AND scope_id = ?) - OR (scope_type = 'agent' AND scope_id = ?) - OR (scope_type = 'project' AND scope_id = ?) - )` - : `SELECT * FROM budget_policies - WHERE company_id = ? AND is_active = 1 - AND ( - (scope_type = 'company' AND scope_id = ?) - OR (scope_type = 'agent' AND scope_id = ?) - )`; - const params: SQLInputValue[] = projectId - ? [companyId, companyId, agentId, projectId] - : [companyId, companyId, agentId]; - return readAll(sql, ...params).map(mapPolicyRow); - }, - - getCalendarMonthWindow, - - getSpentInWindow(policy: BudgetPolicyRecord): number { - const { start, end } = getCalendarMonthWindow(); - let sql: string; - let params: SQLInputValue[]; - if (policy.scopeType === "agent") { - sql = "SELECT COALESCE(SUM(amount_usd), 0) * 100 as total_cents FROM cost_entries WHERE company_id = ? AND created_at >= ? AND created_at < ? AND agent_id = ?"; - params = [policy.companyId, start, end, policy.scopeId]; - } else if (policy.scopeType === "project") { - sql = "SELECT COALESCE(SUM(amount_usd), 0) * 100 as total_cents FROM cost_entries WHERE company_id = ? AND created_at >= ? AND created_at < ? AND project_id = ?"; - params = [policy.companyId, start, end, policy.scopeId]; - } else { - sql = "SELECT COALESCE(SUM(amount_usd), 0) * 100 as total_cents FROM cost_entries WHERE company_id = ? AND created_at >= ? AND created_at < ?"; - params = [policy.companyId, start, end]; - } - const row = getDb().prepare(sql).get(...params) as { total_cents: number } | undefined; - return Math.round(row?.total_cents ?? 0); - }, - - upsertBudgetIncident( - policy: BudgetPolicyRecord, - thresholdType: "warn_threshold" | "hard_stop", - amountObserved: number, - ): string { - const { start, end } = getCalendarMonthWindow(); - const existing = getDb() - .prepare( - "SELECT id FROM budget_incidents WHERE policy_id = ? AND window_start = ? AND threshold_type = ? AND status = 'open'", - ) - .get(policy.id, start, thresholdType) as { id: string } | undefined; - - const ts = nowIso(); - if (existing) { - getDb() - .prepare("UPDATE budget_incidents SET amount_observed = ?, updated_at = ? WHERE id = ?") - .run(amountObserved, ts, existing.id); - return existing.id; - } - - const id = randomUUID(); - getDb() - .prepare( - `INSERT INTO budget_incidents - (id, company_id, policy_id, scope_type, scope_id, metric, window_kind, - window_start, window_end, threshold_type, amount_limit, amount_observed, - status, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'open', ?, ?)`, - ) - .run( - id, policy.companyId, policy.id, policy.scopeType, policy.scopeId, - policy.metric, policy.windowKind, start, end, thresholdType, - policy.amount, amountObserved, ts, ts, - ); - return id; - }, - - listBudgetIncidents(companyId: string, statusFilter: string = "all"): BudgetIncidentRecord[] { - const sql = statusFilter === "all" - ? "SELECT * FROM budget_incidents WHERE company_id = ? ORDER BY created_at DESC" - : "SELECT * FROM budget_incidents WHERE company_id = ? AND status = ? ORDER BY created_at DESC"; - const rows = statusFilter === "all" - ? readAll(sql, companyId) - : readAll(sql, companyId, statusFilter); - return rows.map((r) => ({ - id: r.id, companyId: r.company_id, policyId: r.policy_id, - scopeType: r.scope_type, scopeId: r.scope_id, metric: r.metric, - windowKind: r.window_kind, windowStart: r.window_start, windowEnd: r.window_end, - thresholdType: r.threshold_type, amountLimit: r.amount_limit, - amountObserved: r.amount_observed, status: r.status, - resolvedAt: r.resolved_at, createdAt: r.created_at, updatedAt: r.updated_at, - })); - }, - - resolveBudgetIncident(incidentId: string, companyId: string): void { - const ts = nowIso(); - getDb() - .prepare( - "UPDATE budget_incidents SET status = 'resolved', resolved_at = ?, updated_at = ? WHERE id = ? AND company_id = ? AND status = 'open'", - ) - .run(ts, ts, incidentId, companyId); - }, - - resolveIncidentsForPolicy(policyId: string, resolutionStatus: string): number { - const ts = nowIso(); - const result = getDb() - .prepare( - "UPDATE budget_incidents SET status = ?, resolved_at = ?, updated_at = ? WHERE policy_id = ? AND status = 'open'", - ) - .run(resolutionStatus, ts, ts, policyId); - return Number(result.changes); - }, - - resolveWarnIncidentsForPolicy(policyId: string, resolutionStatus: string): number { - const ts = nowIso(); - const result = getDb() - .prepare( - "UPDATE budget_incidents SET status = ?, resolved_at = ?, updated_at = ? WHERE policy_id = ? AND status = 'open' AND threshold_type = 'warn_threshold'", - ) - .run(resolutionStatus, ts, ts, policyId); - return Number(result.changes); - }, - - autoCloseExpiredIncidents(companyId: string): number { - const ts = nowIso(); - const result = getDb() - .prepare( - "UPDATE budget_incidents SET status = 'auto_closed', resolved_at = ?, updated_at = ? WHERE company_id = ? AND status = 'open' AND window_end <= ?", - ) - .run(ts, ts, companyId, ts); - return Number(result.changes); - }, - }; -} diff --git a/src/main/database/company-crud.ts b/src/main/database/company-crud.ts deleted file mode 100644 index 996899e4..00000000 --- a/src/main/database/company-crud.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import type { ProfileSnapshot } from "@shared/types"; -import { - type ReadAll, - type Transaction, - nowIso, -} from "./helpers"; - -export function buildCompanyCrudMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - getSetting: (key: string) => string | null; - setSetting: (key: string, value: string) => void; - listSnapshot: (options: { companyId?: string | null }) => ProfileSnapshot; - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - }, -) { - return { - saveCompany(input: { - id?: string | null; - name: string; - description: string; - status: string; - autoApproveHires?: boolean; - reviewDeliverables?: boolean; - executionMode?: string; - }): string { - const id = input.id && input.id.length > 0 ? input.id : randomUUID(); - const ts = nowIso(); - const autoApprove = input.autoApproveHires ? 1 : 0; - const reviewDeliverables = input.reviewDeliverables ? 1 : 0; - const executionMode = input.executionMode ?? "ai_ceo"; - const existing = getDb() - .prepare("select id from companies where id = ?") - .get(id) as { id: string } | undefined; - if (existing) { - getDb() - .prepare( - "update companies set name = ?, description = ?, status = ?, auto_approve_hires = ?, review_deliverables = ?, execution_mode = ?, updated_at = ? where id = ?", - ) - .run(input.name, input.description, input.status, autoApprove, reviewDeliverables, executionMode, ts, id); - } else { - getDb() - .prepare( - "insert into companies (id, name, description, status, auto_approve_hires, review_deliverables, execution_mode, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run(id, input.name, input.description, input.status, autoApprove, reviewDeliverables, executionMode, ts, ts); - if (!deps.getSetting("current_company_id")) { - deps.setSetting("current_company_id", id); - } - } - return id; - }, - - deleteCompany(companyId: string): void { - transaction(() => { - try { - getDb() - .prepare( - "delete from agent_message_reads where message_id in (select id from agent_messages where company_id = ?)", - ) - .run(companyId); - } catch (err) { - if (!(err instanceof Error) || !err.message.includes("no such table")) throw err; - } - try { - getDb() - .prepare("delete from agent_message_mentions where company_id = ?") - .run(companyId); - } catch (err) { - if (!(err instanceof Error) || !err.message.includes("no such table")) throw err; - } - // New table cleanup (budget_incidents before budget_policies due to FK) - getDb().prepare("delete from budget_incidents where company_id = ?").run(companyId); - getDb().prepare("delete from budget_policies where company_id = ?").run(companyId); - // agent_skill_assignments references company_skills -- delete before skills - try { - getDb() - .prepare( - "delete from agent_skill_assignments where skill_id in (select id from company_skills where company_id = ?)", - ) - .run(companyId); - } catch (err) { - if (!(err instanceof Error) || !err.message.includes("no such table")) throw err; - } - getDb().prepare("delete from company_skills where company_id = ?").run(companyId); - getDb().prepare("delete from task_sessions where company_id = ?").run(companyId); - getDb().prepare("delete from wakeup_requests where company_id = ?").run(companyId); - // Thread runtime tables (events + participants cascade from threads via FK) - getDb().prepare("delete from thread_wait_states where company_id = ?").run(companyId); - getDb().prepare("delete from conversation_threads where company_id = ?").run(companyId); - getDb().prepare("delete from cost_entries where company_id = ?").run(companyId); - getDb().prepare("delete from activity where company_id = ?").run(companyId); - getDb().prepare("delete from task_comments where company_id = ?").run(companyId); - getDb().prepare("delete from runs where company_id = ?").run(companyId); - getDb().prepare("delete from approvals where company_id = ?").run(companyId); - getDb().prepare("delete from tasks where company_id = ?").run(companyId); - getDb().prepare("delete from projects where company_id = ?").run(companyId); - getDb().prepare("delete from goals where company_id = ?").run(companyId); - getDb().prepare("delete from agents where company_id = ?").run(companyId); - getDb().prepare("delete from secrets where company_id = ?").run(companyId); - getDb().prepare("delete from workspaces where company_id = ?").run(companyId); - for (const table of [ - "automation_rules", - "automation_log", - "agent_messages", - "workflow_pipelines", - "meetings", - "documents", - "knowledge_base", - "sprints", - "browser_actions", - "social_accounts", - ]) { - try { - getDb().prepare(`delete from ${table} where company_id = ?`).run(companyId); - } catch (err) { - // Only tolerate "no such table" — re-throw anything else (disk error, etc.) - if (!(err instanceof Error) || !err.message.includes("no such table")) throw err; - } - } - getDb().prepare("delete from companies where id = ?").run(companyId); - if (deps.getSetting("current_company_id") === companyId) { - const next = getDb() - .prepare("select id from companies order by created_at asc limit 1") - .get() as { id: string } | undefined; - if (next) { - deps.setSetting("current_company_id", next.id); - } else { - deps.setSetting("current_company_id", ""); - } - } - }); - }, - - getCompanyStatus(companyId: string): string | null { - const row = getDb() - .prepare("select status from companies where id = ?") - .get(companyId) as { status: string } | undefined; - return row?.status ?? null; - }, - - getCompanyBasic(companyId: string): { name: string; description: string } | null { - const row = getDb() - .prepare("select name, description from companies where id = ?") - .get(companyId) as { name: string; description: string } | undefined; - return row ?? null; - }, - - listActiveCompanyIds(): Array<{ id: string; name: string }> { - return readAll<{ id: string; name: string }>( - "select id, name from companies where status = 'active'", - ); - }, - - getCompanyExecutionMode(companyId: string): string { - const row = getDb() - .prepare("SELECT execution_mode FROM companies WHERE id = ? LIMIT 1") - .get(companyId) as { execution_mode: string } | undefined; - return row?.execution_mode ?? "ai_ceo"; - }, - - getCompanyApprovalSettings(companyId: string): { autoApproveHires: boolean; reviewDeliverables: boolean } | null { - const row = getDb() - .prepare("SELECT auto_approve_hires, review_deliverables FROM companies WHERE id = ? LIMIT 1") - .get(companyId) as { auto_approve_hires: number; review_deliverables: number } | undefined; - if (!row) return null; - return { - autoApproveHires: row.auto_approve_hires === 1, - reviewDeliverables: row.review_deliverables === 1, - }; - }, - }; -} diff --git a/src/main/database/company-metrics.ts b/src/main/database/company-metrics.ts deleted file mode 100644 index 6cd57670..00000000 --- a/src/main/database/company-metrics.ts +++ /dev/null @@ -1,370 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { - CompanyMetrics, - AgentMetrics, - RunStatus, - StandupReport, -} from "@shared/types"; -import { type ReadAll, type Transaction } from "./helpers"; - -/** - * Dashboard-aggregate read queries extracted from company-settings.ts. - * Covers getCompanyMetrics and getStandupReport. Every method is spread - * into the final `buildCompanyMethods` result so AppDatabase call-sites - * remain unchanged. - */ -export function buildCompanyMetricsMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - _transaction: Transaction, -) { - return { - getCompanyMetrics(companyId: string, days: number = 30): CompanyMetrics { - const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString(); - const db = getDb(); - - const agentRows = readAll<{ - id: string; name: string; status: string; - }>( - `select id, name, status from agents where company_id = ? order by created_at asc`, - companyId, - ); - const activeAgentRows = agentRows.filter( - (a) => a.status !== "pending_approval" && a.status !== "terminated", - ); - - const totalAgents = activeAgentRows.length; - const activeAgents = agentRows.filter( - (a) => a.status === "active" || a.status === "running", - ).length; - - const totalTasks = (db.prepare( - "select count(*) as c from tasks where company_id = ?", - ).get(companyId) as { c: number }).c; - const completedTasks = (db.prepare( - "select count(*) as c from tasks where company_id = ? and status = 'done'", - ).get(companyId) as { c: number }).c; - const blockedTasks = (db.prepare( - "select count(*) as c from tasks where company_id = ? and status = 'blocked'", - ).get(companyId) as { c: number }).c; - - const recentRunStats = db.prepare( - `select - count(*) as totalRuns, - sum(case when status = 'succeeded' then 1 else 0 end) as successful, - sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed - from runs where company_id = ? and created_at > ?`, - ).get(companyId, cutoff) as { totalRuns: number; successful: number | null; failed: number | null }; - const totalRuns = recentRunStats.totalRuns ?? 0; - const successfulRuns = recentRunStats.successful ?? 0; - const failedRuns = recentRunStats.failed ?? 0; - - const totalCost = (db.prepare( - "select coalesce(sum(amount_usd), 0) as s from cost_entries where company_id = ?", - ).get(companyId) as { s: number }).s; - - const recentTasksDone = (db.prepare( - "select count(*) as c from tasks where company_id = ? and status = 'done' and updated_at > ?", - ).get(companyId, cutoff) as { c: number }).c; - - const taskAggRows = readAll<{ - agentId: string; - done: number; - assigned: number; - cancelled: number; - }>( - `select assignee_agent_id as agentId, - sum(case when status = 'done' then 1 else 0 end) as done, - sum(case when status != 'done' and status != 'cancelled' then 1 else 0 end) as assigned, - sum(case when status = 'cancelled' then 1 else 0 end) as cancelled - from tasks - where company_id = ? and assignee_agent_id is not null - group by assignee_agent_id`, - companyId, - ); - const taskAggMap = new Map(taskAggRows.map((row) => [row.agentId, row])); - - const runRecentAggRows = readAll<{ - agentId: string; - total: number; - succeeded: number; - failed: number; - }>( - `select agent_id as agentId, - count(*) as total, - sum(case when status = 'succeeded' then 1 else 0 end) as succeeded, - sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed - from runs - where company_id = ? and created_at > ? - group by agent_id`, - companyId, - cutoff, - ); - const runRecentAggMap = new Map(runRecentAggRows.map((row) => [row.agentId, row])); - - const runDurationRows = readAll<{ - agentId: string; - avgDurationSec: number | null; - lastActiveAt: string | null; - }>( - `select agent_id as agentId, - avg((julianday(finished_at) - julianday(started_at)) * 86400.0) as avgDurationSec, - max(created_at) as lastActiveAt - from runs - where company_id = ? and started_at is not null and finished_at is not null - group by agent_id`, - companyId, - ); - const runDurationMap = new Map(runDurationRows.map((row) => [row.agentId, row])); - - const lastActiveRows = readAll<{ agentId: string; lastActiveAt: string }>( - `select agent_id as agentId, max(created_at) as lastActiveAt - from runs where company_id = ? group by agent_id`, - companyId, - ); - const lastActiveMap = new Map(lastActiveRows.map((row) => [row.agentId, row.lastActiveAt])); - - const costAggRows = readAll<{ agentId: string; totalCost: number }>( - `select agent_id as agentId, coalesce(sum(amount_usd), 0) as totalCost - from cost_entries where company_id = ? and agent_id is not null - group by agent_id`, - companyId, - ); - const costAggMap = new Map(costAggRows.map((row) => [row.agentId, row.totalCost])); - - const reviewCycleRows = readAll<{ actor: string; cycles: number }>( - `select actor, count(*) as cycles - from activity - where company_id = ? - and action in ('task.status_changed', 'task.updated', 'task.auto_assigned') - group by actor`, - companyId, - ); - const reviewCycleMap = new Map(reviewCycleRows.map((row) => [row.actor, row.cycles])); - - const agentMetrics: AgentMetrics[] = activeAgentRows.map((agent) => { - const taskAgg = taskAggMap.get(agent.id); - const runRecent = runRecentAggMap.get(agent.id); - const runDur = runDurationMap.get(agent.id); - const succeeded = runRecent?.succeeded ?? 0; - const total = runRecent?.total ?? 0; - return { - agentId: agent.id, - agentName: agent.name, - tasksCompleted: taskAgg?.done ?? 0, - tasksAssigned: taskAgg?.assigned ?? 0, - tasksFailed: taskAgg?.cancelled ?? 0, - successRate: total > 0 ? Math.round((succeeded / total) * 100) : 0, - avgRunDurationSec: Math.round(runDur?.avgDurationSec ?? 0), - totalCostUsd: costAggMap.get(agent.id) ?? 0, - runsTotal: total, - runsSucceeded: succeeded, - runsFailed: runRecent?.failed ?? 0, - reviewCycles: reviewCycleMap.get(agent.id) ?? 0, - lastActiveAt: lastActiveMap.get(agent.id) ?? null, - }; - }); - - return { - totalAgents, - activeAgents, - totalTasks, - completedTasks, - blockedTasks, - totalRuns, - successfulRuns, - failedRuns, - overallSuccessRate: totalRuns > 0 ? Math.round((successfulRuns / totalRuns) * 100) : 0, - totalCostUsd: totalCost, - avgCostPerTask: completedTasks > 0 ? totalCost / completedTasks : 0, - throughputTasksPerDay: days > 0 ? recentTasksDone / days : 0, - agentMetrics, - }; - }, - - getStandupReport(companyId: string): StandupReport { - const db = getDb(); - const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); - - type AgentRow = { - id: string; name: string; role: string; status: StandupReport["agentReports"][number]["status"]; - budgetMonthlyUsd: number; spentMonthlyUsd: number; - }; - const agents = readAll( - `select id, name, role, status, - budget_monthly_usd as budgetMonthlyUsd, - spent_monthly_usd as spentMonthlyUsd - from agents - where company_id = ? and status != 'terminated' and status != 'pending_approval' - order by created_at asc`, - companyId, - ); - - const recentCompletedTasksCount = (db.prepare( - "select count(*) as c from tasks where company_id = ? and status = 'done' and updated_at > ?", - ).get(companyId, oneDayAgo) as { c: number }).c; - - const recentRunStats = db.prepare( - `select - count(*) as total, - sum(case when status = 'succeeded' then 1 else 0 end) as succeeded, - sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed - from runs where company_id = ? and created_at > ?`, - ).get(companyId, oneDayAgo) as { total: number; succeeded: number | null; failed: number | null }; - const recentRunsTotal = recentRunStats.total ?? 0; - const successfulRuns = recentRunStats.succeeded ?? 0; - const failedRuns = recentRunStats.failed ?? 0; - - const blockedTaskRows = readAll<{ id: string; title: string; assigneeAgentId: string | null }>( - `select id, title, assignee_agent_id as assigneeAgentId - from tasks where company_id = ? and status = 'blocked'`, - companyId, - ); - - const pendingApprovals = (db.prepare( - "select count(*) as c from approvals where company_id = ? and state = 'pending'", - ).get(companyId) as { c: number }).c; - - const activeSprint = db.prepare( - `select name, velocity_points as velocityPoints, completed_points as completedPoints - from sprints where company_id = ? and status = 'active' order by start_date desc limit 1`, - ).get(companyId) as { name: string; velocityPoints: number; completedPoints: number } | undefined; - - const urgentUnread = (db.prepare( - `select count(*) as c - from agent_messages messages - left join agent_message_reads reads - on reads.message_id = messages.id and reads.agent_id = '__board__' - where messages.company_id = ? - and reads.read_at is null - and (messages.priority = 'urgent' or messages.channel = 'incident')`, - ).get(companyId) as { c: number }).c; - - const tasksByAgentRows = readAll<{ - agentId: string; inProgress: number; blocked: number; completed24h: number; - }>( - `select assignee_agent_id as agentId, - sum(case when status = 'in_progress' then 1 else 0 end) as inProgress, - sum(case when status = 'blocked' then 1 else 0 end) as blocked, - sum(case when status = 'done' and updated_at > ? then 1 else 0 end) as completed24h - from tasks - where company_id = ? and assignee_agent_id is not null - group by assignee_agent_id`, - oneDayAgo, - companyId, - ); - const tasksByAgent = new Map(tasksByAgentRows.map((row) => [row.agentId, row])); - - const recentRunsByAgent = readAll<{ - agentId: string; runCount: number; lastStatus: string | null; lastAt: string | null; - }>( - `select agent_id as agentId, - count(*) as runCount, - (select status from runs r2 where r2.agent_id = runs.agent_id and r2.company_id = runs.company_id and r2.created_at > ? order by created_at desc limit 1) as lastStatus, - max(created_at) as lastAt - from runs - where company_id = ? and created_at > ? - group by agent_id`, - oneDayAgo, - companyId, - oneDayAgo, - ); - const runsByAgent = new Map(recentRunsByAgent.map((row) => [row.agentId, row])); - - const costByAgentRows = readAll<{ agentId: string; cost24h: number }>( - `select agent_id as agentId, coalesce(sum(amount_usd), 0) as cost24h - from cost_entries - where company_id = ? and agent_id is not null and created_at > ? - group by agent_id`, - companyId, - oneDayAgo, - ); - const costByAgent = new Map(costByAgentRows.map((row) => [row.agentId, row.cost24h])); - - const reviewByAgentRows = readAll<{ actor: string; cycles: number }>( - `select actor, count(*) as cycles - from activity - where company_id = ? and created_at > ? - and action in ('task.status_changed', 'task.updated', 'task.auto_assigned') - group by actor`, - companyId, - oneDayAgo, - ); - const reviewByAgent = new Map(reviewByAgentRows.map((row) => [row.actor, row.cycles])); - - const agentNameMap = new Map(agents.map((a) => [a.id, a.name])); - - const companyHighlights: string[] = []; - const blockers: string[] = []; - if (recentCompletedTasksCount > 0) { - companyHighlights.push(`${recentCompletedTasksCount} task(s) completed in last 24h`); - } - if (recentRunsTotal > 0) { - companyHighlights.push( - `${recentRunsTotal} runs (${successfulRuns} succeeded, ${failedRuns} failed)`, - ); - } - for (const task of blockedTaskRows) { - const assigneeName = task.assigneeAgentId ? agentNameMap.get(task.assigneeAgentId) ?? null : null; - blockers.push(`${task.title} — blocked (${assigneeName ?? "unassigned"})`); - } - if (activeSprint) { - const pct = activeSprint.velocityPoints > 0 - ? Math.round((activeSprint.completedPoints / activeSprint.velocityPoints) * 100) - : 0; - companyHighlights.push( - `Sprint "${activeSprint.name}": ${activeSprint.completedPoints}/${activeSprint.velocityPoints} pts (${pct}%)`, - ); - } - if (urgentUnread > 0) { - blockers.push(`${urgentUnread} urgent unread message(s) need attention`); - } - - const totalBudget = agents.reduce((sum, a) => sum + a.budgetMonthlyUsd, 0); - const totalSpent = agents.reduce((sum, a) => sum + a.spentMonthlyUsd, 0); - const budgetUtilization = totalBudget > 0 ? Math.round((totalSpent / totalBudget) * 100) : 0; - - const agentReports = agents.map((agent) => { - const taskAgg = tasksByAgent.get(agent.id); - const runAgg = runsByAgent.get(agent.id); - const completed24h = taskAgg?.completed24h ?? 0; - const runs24h = runAgg?.runCount ?? 0; - const reviewedTasks = reviewByAgent.get(agent.id) ?? 0; - const highlights: string[] = []; - if (completed24h > 0) highlights.push(`Completed ${completed24h} task(s)`); - if (runs24h > 0) highlights.push(`${runs24h} run(s) in last 24h`); - if (reviewedTasks > 0) highlights.push(`${reviewedTasks} status update(s)`); - return { - agentId: agent.id, - agentName: agent.name, - role: agent.role, - status: agent.status, - tasksInProgress: taskAgg?.inProgress ?? 0, - tasksCompleted24h: completed24h, - tasksBlocked: taskAgg?.blocked ?? 0, - lastRunStatus: (runAgg?.lastStatus ?? null) as RunStatus | null, - lastRunAt: runAgg?.lastAt ?? null, - costLast24h: costByAgent.get(agent.id) ?? 0, - highlights, - }; - }); - - const summaryParts: string[] = []; - if (agents.length > 0) summaryParts.push(`${agents.length} active agents`); - summaryParts.push(`${recentCompletedTasksCount} tasks done`); - if (blockedTaskRows.length > 0) summaryParts.push(`${blockedTaskRows.length} blocked`); - if (pendingApprovals > 0) summaryParts.push(`${pendingApprovals} pending approvals`); - - return { - companyId, - generatedAt: new Date().toISOString(), - summary: summaryParts.join(" · "), - agentReports, - companyHighlights, - blockers, - pendingApprovals, - budgetUtilization, - }; - }, - }; -} diff --git a/src/main/database/company-settings.ts b/src/main/database/company-settings.ts deleted file mode 100644 index 64959ab8..00000000 --- a/src/main/database/company-settings.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ProfileSnapshot } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; - -/** - * Company-scoped read endpoints that do not belong to a single domain - * CRUD module. - * - * Sidebar badges used to live here as a server-side aggregation - * (`getSidebarBadges`) — it has been deleted. The desktop app is - * local-first and the renderer already holds every row the badges - * would count via `ProfileSnapshot`, so the aggregation became a - * second source of truth that drifted from the inbox query whenever - * messages were read between snapshot refreshes. Derivation now lives - * in `src/shared/sidebar-badges.ts::deriveSidebarBadges`. - */ -export function buildCompanySettingsMethods( - _getDb: () => DatabaseSync, - readAll: ReadAll, - _transaction: Transaction, - _deps: { - listSnapshot: (options: { companyId?: string | null }) => ProfileSnapshot; - }, -) { - return { - /** - * Returns the raw inputs for the GET /api/companies/:id/dashboard - * endpoint: agent statuses, task statuses, and the last 20 activity rows. - * Route code aggregates counts by status on top of this raw data. - */ - getDashboardSnapshot(companyId: string): { - agents: Array<{ id: string; status: string }>; - tasks: Array<{ id: string; status: string }>; - recentActivity: Array<{ - id: string; - companyId: string; - actor: string; - action: string; - entityType: string; - entityId: string; - detail: string | null; - createdAt: string; - }>; - } { - return { - agents: readAll<{ id: string; status: string }>( - "select id, status from agents where company_id = ?", - companyId, - ), - tasks: readAll<{ id: string; status: string }>( - "select id, status from tasks where company_id = ?", - companyId, - ), - recentActivity: readAll<{ - id: string; companyId: string; actor: string; action: string; - entityType: string; entityId: string; detail: string | null; createdAt: string; - }>( - "select id, company_id as companyId, actor, action, entity_type as entityType, entity_id as entityId, detail, created_at as createdAt from activity where company_id = ? order by created_at desc limit 20", - companyId, - ), - }; - }, - }; -} diff --git a/src/main/database/company.ts b/src/main/database/company.ts deleted file mode 100644 index 9c165a8c..00000000 --- a/src/main/database/company.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ProfileSnapshot } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { buildCompanyCrudMethods } from "./company-crud"; -import { buildCompanyMetricsMethods } from "./company-metrics"; -import { buildCompanySettingsMethods } from "./company-settings"; - -export function buildCompanyMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - getSetting: (key: string) => string | null; - setSetting: (key: string, value: string) => void; - listSnapshot: (options: { companyId?: string | null }) => ProfileSnapshot; - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - }, -) { - return { - ...buildCompanyCrudMethods(getDb, readAll, transaction, deps), - ...buildCompanySettingsMethods(getDb, readAll, transaction, { listSnapshot: deps.listSnapshot }), - ...buildCompanyMetricsMethods(getDb, readAll, transaction), - }; -} diff --git a/src/main/database/config-revisions.ts b/src/main/database/config-revisions.ts deleted file mode 100644 index 487f3666..00000000 --- a/src/main/database/config-revisions.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import type { AgentRecord } from "@shared/types"; -import type { ReadAll, SqliteRow, Transaction } from "./helpers"; -import { nowIso, parseJson } from "./helpers"; - -/** - * Agent config-revision helpers extracted from documents.ts. Spread into - * the final `buildDocumentMethods` result so AppDatabase call-sites remain - * unchanged. - */ -export function buildConfigRevisionMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - recordConfigRevision(input: { - companyId: string; agentId: string; changedKeys: string[]; - configBefore: Record; configAfter: Record; - source?: string; rolledBackFromRevisionId?: string | null; - createdByAgentId?: string | null; createdByUserId?: string | null; - }): string { - const id = randomUUID(); - const ts = nowIso(); - const lastRev = getDb().prepare( - "SELECT MAX(revision_number) as maxRev FROM agent_config_revisions WHERE agent_id = ?" - ).get(input.agentId) as { maxRev: number | null } | undefined; - const revisionNumber = (lastRev?.maxRev ?? 0) + 1; - getDb().prepare( - "INSERT INTO agent_config_revisions (id, company_id, agent_id, revision_number, changed_keys, config_before, config_after, source, rolled_back_from_revision_id, created_by_agent_id, created_by_user_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - ).run( - id, input.companyId, input.agentId, revisionNumber, - JSON.stringify(input.changedKeys), JSON.stringify(input.configBefore), - JSON.stringify(input.configAfter), input.source ?? "patch", - input.rolledBackFromRevisionId ?? null, input.createdByAgentId ?? null, - input.createdByUserId ?? null, ts - ); - return id; - }, - - listConfigRevisions(agentId: string, companyId: string): Array<{ - id: string; agentId: string; revisionNumber: number; changedKeys: string[]; - source: string; rolledBackFromRevisionId: string | null; - createdByAgentId: string | null; createdByUserId: string | null; createdAt: string; - }> { - return readAll( - "SELECT id, agent_id, revision_number, changed_keys, source, rolled_back_from_revision_id, created_by_agent_id, created_by_user_id, created_at FROM agent_config_revisions WHERE agent_id = ? AND company_id = ? ORDER BY revision_number DESC", - agentId, companyId - ).map((row) => ({ - id: row.id, agentId: row.agent_id, revisionNumber: row.revision_number, - changedKeys: parseJson(row.changed_keys, []), - source: row.source, rolledBackFromRevisionId: row.rolled_back_from_revision_id ?? null, - createdByAgentId: row.created_by_agent_id ?? null, - createdByUserId: row.created_by_user_id ?? null, createdAt: row.created_at, - })); - }, - - getConfigRevision(revisionId: string, companyId: string): { - id: string; agentId: string; revisionNumber: number; changedKeys: string[]; - configBefore: Record; configAfter: Record; - source: string; rolledBackFromRevisionId: string | null; - createdByAgentId: string | null; createdByUserId: string | null; createdAt: string; - } { - const row = getDb().prepare( - "SELECT * FROM agent_config_revisions WHERE id = ? AND company_id = ?" - ).get(revisionId, companyId) as { - id: string; agent_id: string; revision_number: number; changed_keys: string; - config_before: string; config_after: string; source: string; - rolled_back_from_revision_id: string | null; - created_by_agent_id: string | null; created_by_user_id: string | null; created_at: string; - } | undefined; - if (!row) throw new Error(`Config revision ${revisionId} not found.`); - return { - id: row.id, agentId: row.agent_id, revisionNumber: row.revision_number, - changedKeys: parseJson(row.changed_keys, []), - configBefore: parseJson>(row.config_before, {}), - configAfter: parseJson>(row.config_after, {}), - source: row.source, rolledBackFromRevisionId: row.rolled_back_from_revision_id ?? null, - createdByAgentId: row.created_by_agent_id ?? null, - createdByUserId: row.created_by_user_id ?? null, createdAt: row.created_at, - }; - }, - - rollbackConfigRevision(agentId: string, revisionId: string, companyId: string, selfDeps: { - getConfigRevision: (revisionId: string, companyId: string) => { - id: string; agentId: string; revisionNumber: number; changedKeys: string[]; - configBefore: Record; configAfter: Record; - source: string; rolledBackFromRevisionId: string | null; - createdByAgentId: string | null; createdByUserId: string | null; createdAt: string; - }; - getAgent: (id: string) => AgentRecord; - recordConfigRevision: (input: { - companyId: string; agentId: string; changedKeys: string[]; - configBefore: Record; configAfter: Record; - source?: string; rolledBackFromRevisionId?: string | null; - createdByAgentId?: string | null; createdByUserId?: string | null; - }) => string; - }): string { - return transaction(() => { - const revision = selfDeps.getConfigRevision(revisionId, companyId); - if (revision.agentId !== agentId) throw new Error("Revision does not belong to this agent."); - const before = revision.configBefore as Record; - const ts = nowIso(); - getDb().prepare( - "UPDATE agents SET name = ?, role = ?, title = ?, department = ?, capabilities = ?, connector_id = ?, model = ?, budget_monthly_usd = ?, metadata_json = ?, updated_at = ? WHERE id = ? AND company_id = ?" - ).run( - before.name ?? "", before.role ?? "", before.title ?? "", before.department ?? null, - before.capabilities ?? "", before.connectorId ?? before.connector_id ?? "", - before.model ?? null, before.budgetMonthlyUsd ?? before.budget_monthly_usd ?? 0, - before.metadataJson ?? before.metadata_json ?? "{}", ts, agentId, companyId - ); - const agent = selfDeps.getAgent(agentId); - const currentConfig = { name: agent.name, role: agent.role, title: agent.title, department: agent.department, capabilities: agent.capabilities, connectorId: agent.connectorId, model: agent.model, budgetMonthlyUsd: agent.budgetMonthlyUsd, metadataJson: agent.metadataJson }; - return selfDeps.recordConfigRevision({ - companyId, agentId, - changedKeys: revision.changedKeys, - configBefore: currentConfig, - configAfter: before, - source: "rollback", - rolledBackFromRevisionId: revisionId, - }); - }); - }, - }; -} diff --git a/AgentCompany-New/src/main/database/connection.ts b/src/main/database/connection.ts similarity index 100% rename from AgentCompany-New/src/main/database/connection.ts rename to src/main/database/connection.ts diff --git a/src/main/database/connectors-crud.ts b/src/main/database/connectors-crud.ts deleted file mode 100644 index 8adbf1e5..00000000 --- a/src/main/database/connectors-crud.ts +++ /dev/null @@ -1,191 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { ConnectorId, ConnectorRecord } from "@shared/types"; -import type { ReadAll } from "./helpers"; -import { nowIso } from "./helpers"; -import { - CONNECTORS, - getConnectorDefinition, - buildDefaultConnectorRows, - renderConnectorConfigurationDoc, - PI_MONO_CAPABILITIES, -} from "../connectors"; - - -export function buildConnectorMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, -) { - function readConnectors(): ConnectorRecord[] { - const rows = readAll<{ - id: string; label: string; description: string; status: ConnectorRecord["status"]; - version: string | null; auth_state: ConnectorRecord["authState"]; - last_checked_at: string | null; last_error: string | null; model: string | null; - env_binding_text: string; notes: string; - }>( - "select id, label, description, status, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors order by label asc", - ); - const result: ConnectorRecord[] = []; - for (const row of rows) { - let definition; - try { - definition = getConnectorDefinition(row.id as ConnectorId); - } catch (err) { - log.warn(`[database/connectors] Unknown connector id ${row.id}; skipping row:`, err instanceof Error ? err.message : String(err)); - continue; - } - result.push({ - id: row.id as ConnectorId, - label: row.label, - description: row.description, - status: row.status, - version: row.version, - authState: row.auth_state, - lastCheckedAt: row.last_checked_at, - lastError: row.last_error, - model: row.model, - envBindingText: row.env_binding_text, - notes: row.notes, - configurationDoc: renderConnectorConfigurationDoc(definition), - capabilityMatrix: PI_MONO_CAPABILITIES, - }); - } - return result; - } - - return { - readConnectors, - - saveConnector(input: { - id: ConnectorId; - model: string | null; - envBindingText: string; - notes: string; - }) { - getDb() - .prepare( - "update connectors set model = ?, env_binding_text = ?, notes = ?, updated_at = ? where id = ?", - ) - .run(input.model, input.envBindingText, input.notes, nowIso(), input.id); - }, - - updateConnectorHealth(input: { - id: ConnectorId; - status: string; - authState: string; - version: string | null; - lastError: string | null; - }) { - getDb() - .prepare( - "update connectors set status = ?, auth_state = ?, version = ?, last_checked_at = ?, last_error = ?, updated_at = ? where id = ?", - ) - .run(input.status, input.authState, input.version, nowIso(), input.lastError, nowIso(), input.id); - }, - - findConnector(id: ConnectorId): ConnectorRecord | null { - const row = getDb() - .prepare( - "select id, label, description, status, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors where id = ?", - ) - .get(id) as - | { - id: string; - label: string; - description: string; - status: ConnectorRecord["status"]; - version: string | null; - auth_state: ConnectorRecord["authState"]; - last_checked_at: string | null; - last_error: string | null; - model: string | null; - env_binding_text: string; - notes: string; - } - | undefined; - if (!row) return null; - let definition; - try { - definition = getConnectorDefinition(row.id as ConnectorId); - } catch (err) { - log.warn(`[database/connectors] Unknown connector id ${row.id} in findConnector:`, err instanceof Error ? err.message : String(err)); - return null; - } - return { - id: row.id as ConnectorId, - label: row.label, - description: row.description, - status: row.status, - version: row.version, - authState: row.auth_state, - lastCheckedAt: row.last_checked_at, - lastError: row.last_error, - model: row.model, - envBindingText: row.env_binding_text, - notes: row.notes, - configurationDoc: renderConnectorConfigurationDoc(definition), - capabilityMatrix: PI_MONO_CAPABILITIES, - }; - }, - - getConnector(id: ConnectorId): ConnectorRecord { - const result = this.findConnector(id); - if (!result) throw new Error(`Connector not found: ${id}`); - return result; - }, - - seedConnectors() { - // Drop any connector row that is not declared in the pi-mono catalog. - const validIds = CONNECTORS.map((c) => `'${c.id}'`).join(","); - getDb().prepare(`delete from connectors where id not in (${validIds})`).run(); - - const currentRows = readAll>( - "select id, label, description, status, version, auth_state as authState, last_checked_at as lastCheckedAt, last_error as lastError, model, env_binding_text as envBindingText, notes from connectors", - ); - - const merged = buildDefaultConnectorRows(currentRows); - // `command` column stays in the schema as NOT NULL for legacy reasons; - // pi-mono has no CLI so we always write an empty string. Column is - // never read by runtime code. - const statement = getDb().prepare( - "insert or replace into connectors (id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes, updated_at) values (?, ?, ?, ?, '', ?, ?, ?, ?, ?, ?, ?, ?)", - ); - const updatedAt = nowIso(); - for (const row of merged) { - statement.run( - row.id, row.label, row.description, row.status, - row.version, row.authState, row.lastCheckedAt, - row.lastError, row.model, row.envBindingText, row.notes, updatedAt, - ); - } - - // One-time migration: mark connectors actively used by agents as - // model-pool-managed so they remain visible to the CEO after the opt-in - // policy change. Connectors not used by any agent stay unmanaged and - // will not appear in CEO prompts until the user explicitly enables - // models for them in Settings > Model Management. - const migrationKey = "migration:model_pool_opt_in_v1"; - const migrated = readAll<{ value: string }>("SELECT value FROM settings WHERE key = ?", migrationKey); - if (migrated.length === 0) { - const usedIds = new Set( - readAll<{ connector_id: string }>( - "SELECT DISTINCT connector_id FROM agents WHERE status NOT IN ('terminated')", - ).map((r) => r.connector_id), - ); - const upsert = getDb().prepare( - "INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value", - ); - for (const id of usedIds) { - const hasSettings = readAll<{ key: string }>( - "SELECT key FROM settings WHERE key = ?", - `disabled_models:${id}`, - ); - if (hasSettings.length === 0) { - upsert.run(`disabled_models:${id}`, "[]"); - } - } - upsert.run(migrationKey, "1"); - } - }, - }; -} diff --git a/src/main/database/cost-entries.ts b/src/main/database/cost-entries.ts deleted file mode 100644 index 934b1e94..00000000 --- a/src/main/database/cost-entries.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import { type ReadAll, type Transaction, nowIso } from "./helpers"; - -/** - * cost_entries writer extracted from runs.ts. Spread into the final - * `buildRunMethods` result so AppDatabase call-sites remain unchanged. - * - * Note: finishRun still reads SUM(cost_entries.amount_usd) inline. The - * SUM query stays in runs.ts to keep the run-aggregate read path local to - * the rest of finishRun. - */ -export function buildCostEntryMethods( - getDb: () => DatabaseSync, - _readAll: ReadAll, - _transaction: Transaction, -) { - return { - /** - * Single writer for `cost_entries`. CostWriter calls this per - * `message_end`; tests also call it to simulate per-turn cost. - * finishRun reads SUM(cost_entries) for the run-level aggregate, - * so this is the authoritative path for cost attribution. - */ - recordCostEntry(input: { - runId: string; - companyId: string; - agentId: string; - taskId: string | null; - connectorId: string; - amountUsd: number | null; - unattributed: boolean; - }): string { - const id = randomUUID(); - const ts = nowIso(); - const projectRow = input.taskId - ? getDb().prepare("SELECT project_id FROM tasks WHERE id = ?").get(input.taskId) as { project_id: string | null } | undefined - : undefined; - const projectId = projectRow?.project_id ?? null; - getDb() - .prepare( - "insert into cost_entries (id, company_id, run_id, task_id, agent_id, connector_id, amount_usd, unattributed, project_id, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run( - id, input.companyId, input.runId, input.taskId, input.agentId, - input.connectorId, input.amountUsd, - input.unattributed ? 1 : 0, projectId, ts, - ); - return id; - }, - }; -} diff --git a/src/main/database/crash-recovery-helpers.ts b/src/main/database/crash-recovery-helpers.ts deleted file mode 100644 index 9f1eadca..00000000 --- a/src/main/database/crash-recovery-helpers.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Pure helpers for crash-recovery logic, extracted for testability. - * - * These encode the behavioral contract of the corresponding AppDatabase methods: - * - interruptStaleRuns - * - retryInterruptedTask - * - markInterruptedTaskFailed - * - * The helpers take narrowly-typed "statement runner" interfaces so they can be - * exercised in unit tests without a live SQLite connection. - */ - -export interface StaleRunDb { - /** Update all running runs to 'interrupted' and return number of rows changed. */ - interruptRunningRuns(ts: string): number; - /** Mark tasks associated with interrupted runs as 'blocked'. */ - blockInterruptedTasks(ts: string): void; - /** Delete task lease rows whose run is now interrupted. */ - clearInterruptedTaskLeases(): void; - /** Reset all running agents to idle. */ - resetAgentsToIdle(ts: string): void; - /** Release all workspace locks. */ - releaseAllWorkspaceLocks(): void; -} - -export interface RetryTaskDb { - /** Set task status to 'todo'. */ - setTaskTodo(ts: string, taskId: string): void; - /** Reset retry_count and last_failure_at. */ - resetTaskRetryFields(ts: string, taskId: string): void; -} - -export interface FailTaskDb { - /** Set task status to 'cancelled'. */ - setTaskCancelled(ts: string, taskId: string): void; -} - -/** - * Transactionally marks all running runs as interrupted and associated tasks - * as blocked. Returns the number of interrupted runs. - */ -export function interruptStaleRunsLogic( - db: StaleRunDb, - transaction: (fn: () => void) => void, - nowIso: () => string, -): number { - let interruptedCount = 0; - transaction(() => { - const ts = nowIso(); - interruptedCount = db.interruptRunningRuns(ts); - if (interruptedCount > 0) { - db.blockInterruptedTasks(ts); - } - db.clearInterruptedTaskLeases(); - db.resetAgentsToIdle(ts); - db.releaseAllWorkspaceLocks(); - }); - return interruptedCount; -} - -/** Resets a task to 'todo' and clears its retry state. */ -export function retryInterruptedTaskLogic( - db: RetryTaskDb, - taskId: string, - nowIso: () => string, -): void { - const ts = nowIso(); - db.setTaskTodo(ts, taskId); - db.resetTaskRetryFields(ts, taskId); -} - -/** Marks a task as 'cancelled'. */ -export function markInterruptedTaskFailedLogic( - db: FailTaskDb, - taskId: string, - nowIso: () => string, -): void { - const ts = nowIso(); - db.setTaskCancelled(ts, taskId); -} diff --git a/src/main/database/credentials.ts b/src/main/database/credentials.ts deleted file mode 100644 index 1c8b8692..00000000 --- a/src/main/database/credentials.ts +++ /dev/null @@ -1,178 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ReadAll, Transaction } from "./helpers"; -import { nowIso } from "./helpers"; - -export type CredentialKind = "oauth" | "api_key" | "aws" | "azure" | "gcp_adc" | "local"; -export type CredentialStatus = "active" | "expired" | "revoked" | "error"; -export type CredentialBackend = "safe_storage" | "vault"; - -export interface CredentialRow { - connectorId: string; - kind: CredentialKind; - backend: CredentialBackend; - ciphertext: Uint8Array; - displayHint: string; - status: CredentialStatus; - expiresAt: string | null; - lastRefreshedAt: string | null; - lastError: string | null; - createdAt: string; - updatedAt: string; -} - -export interface UpsertCredentialInput { - connectorId: string; - kind: CredentialKind; - backend: CredentialBackend; - ciphertext: Uint8Array; - displayHint?: string; - status?: CredentialStatus; - expiresAt?: string | null; - lastRefreshedAt?: string | null; - lastError?: string | null; -} - -function rowToRecord(row: { - connector_id: string; - kind: string; - backend: string; - ciphertext: Uint8Array; - display_hint: string; - status: string; - expires_at: string | null; - last_refreshed_at: string | null; - last_error: string | null; - created_at: string; - updated_at: string; -}): CredentialRow { - return { - connectorId: row.connector_id, - kind: row.kind as CredentialKind, - backend: row.backend as CredentialBackend, - ciphertext: row.ciphertext, - displayHint: row.display_hint, - status: row.status as CredentialStatus, - expiresAt: row.expires_at, - lastRefreshedAt: row.last_refreshed_at, - lastError: row.last_error, - createdAt: row.created_at, - updatedAt: row.updated_at, - }; -} - -export function buildCredentialMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - const COLUMNS = - "connector_id, kind, backend, ciphertext, display_hint, status, expires_at, last_refreshed_at, last_error, created_at, updated_at"; - type RawRow = { - connector_id: string; - kind: string; - backend: string; - ciphertext: Uint8Array; - display_hint: string; - status: string; - expires_at: string | null; - last_refreshed_at: string | null; - last_error: string | null; - created_at: string; - updated_at: string; - }; - - function list(): CredentialRow[] { - const rows = readAll( - `select ${COLUMNS} from credentials order by connector_id asc`, - ); - return rows.map(rowToRecord); - } - - function get(connectorId: string): CredentialRow | null { - const rows = readAll( - `select ${COLUMNS} from credentials where connector_id = ?`, - connectorId, - ); - return rows[0] ? rowToRecord(rows[0]) : null; - } - - function upsert(input: UpsertCredentialInput): CredentialRow { - return transaction(() => { - const existing = get(input.connectorId); - const now = nowIso(); - if (existing) { - getDb() - .prepare( - "update credentials set kind = ?, backend = ?, ciphertext = ?, display_hint = ?, status = ?, expires_at = ?, last_refreshed_at = ?, last_error = ?, updated_at = ? where connector_id = ?", - ) - .run( - input.kind, - input.backend, - input.ciphertext, - input.displayHint ?? existing.displayHint, - input.status ?? existing.status, - input.expiresAt === undefined ? existing.expiresAt : input.expiresAt, - input.lastRefreshedAt === undefined ? existing.lastRefreshedAt : input.lastRefreshedAt, - input.lastError === undefined ? existing.lastError : input.lastError, - now, - input.connectorId, - ); - } else { - getDb() - .prepare( - "insert into credentials (connector_id, kind, backend, ciphertext, display_hint, status, expires_at, last_refreshed_at, last_error, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run( - input.connectorId, - input.kind, - input.backend, - input.ciphertext, - input.displayHint ?? "", - input.status ?? "active", - input.expiresAt ?? null, - input.lastRefreshedAt ?? null, - input.lastError ?? null, - now, - now, - ); - } - const record = get(input.connectorId); - if (!record) throw new Error(`Failed to persist credential: ${input.connectorId}`); - return record; - }); - } - - function remove(connectorId: string): void { - transaction(() => { - getDb().prepare("delete from credentials where connector_id = ?").run(connectorId); - }); - } - - function setStatus( - connectorId: string, - status: CredentialStatus, - lastError: string | null = null, - ): void { - getDb() - .prepare( - "update credentials set status = ?, last_error = ?, updated_at = ? where connector_id = ?", - ) - .run(status, lastError, nowIso(), connectorId); - } - - function markRefreshed( - connectorId: string, - backend: CredentialBackend, - ciphertext: Uint8Array, - expiresAt: string | null, - ): void { - const ts = nowIso(); - getDb() - .prepare( - "update credentials set backend = ?, ciphertext = ?, expires_at = ?, last_refreshed_at = ?, status = 'active', last_error = null, updated_at = ? where connector_id = ?", - ) - .run(backend, ciphertext, expiresAt, ts, ts, connectorId); - } - - return { list, get, upsert, remove, setStatus, markRefreshed }; -} diff --git a/src/main/database/document-lifecycle-events.ts b/src/main/database/document-lifecycle-events.ts deleted file mode 100644 index 4db89abd..00000000 --- a/src/main/database/document-lifecycle-events.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { ReadAll } from "./helpers"; -import { nowIso } from "./helpers"; - -/** - * Document-lifecycle event row shape returned by listers. - * `status` moves `pending -> running -> (succeeded | failed)`. `attempts` - * tracks how many processor passes have tried this hook so a sweeper can - * bound retries without losing the ledger. - */ -export interface DocumentLifecycleEventRow { - id: string; - companyId: string; - documentId: string; - hookType: string; - status: "pending" | "running" | "succeeded" | "failed"; - attempts: number; - lastError: string | null; - payloadJson: string; - createdAt: string; - updatedAt: string; - completedAt: string | null; -} - -export interface EnqueueInput { - companyId: string; - documentId: string; - hookType: string; - payloadJson?: string; -} - -export interface ClaimBatchInput { - /** Upper bound on rows claimed in one pass. */ - limit: number; - /** Rows whose `attempts` have already reached this cap stay `pending` and are not claimed here; a dead-letter sweep surfaces them separately. */ - maxAttempts: number; - /** When provided, only claim rows for the given document so the post-commit immediate drain stays scoped. */ - documentId?: string; -} - -export function buildDocumentLifecycleEventMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, -) { - return { - enqueue(input: EnqueueInput): string { - const id = randomUUID(); - const ts = nowIso(); - getDb().prepare( - `INSERT INTO document_lifecycle_events - (id, company_id, document_id, hook_type, status, attempts, last_error, payload_json, created_at, updated_at, completed_at) - VALUES (?, ?, ?, ?, 'pending', 0, NULL, ?, ?, ?, NULL)`, - ).run( - id, - input.companyId, - input.documentId, - input.hookType, - input.payloadJson ?? "{}", - ts, - ts, - ); - return id; - }, - - /** - * Atomically claim up to `limit` pending events, flipping each to - * `running` and incrementing `attempts` in a single statement. - * Returns the claimed rows so the processor can dispatch them - * without racing another worker against the same ids. Rows that - * have already reached `maxAttempts` stay `pending` here — the - * operator sees them via `listExhausted` and either retries - * manually or purges. - */ - claimPendingBatch(input: ClaimBatchInput): DocumentLifecycleEventRow[] { - const ts = nowIso(); - const documentScope = input.documentId ? "AND document_id = ?" : ""; - const selectSql = ` - SELECT id FROM document_lifecycle_events - WHERE status = 'pending' AND attempts < ? ${documentScope} - ORDER BY created_at ASC - LIMIT ? - `; - const updateSql = ` - UPDATE document_lifecycle_events - SET status = 'running', attempts = attempts + 1, updated_at = ? - WHERE id IN (${selectSql}) - RETURNING id, company_id, document_id, hook_type, status, attempts, last_error, payload_json, created_at, updated_at, completed_at - `; - const params: SQLInputValue[] = [ts, input.maxAttempts]; - if (input.documentId) params.push(input.documentId); - params.push(input.limit); - const raw = readAll(updateSql, ...params); - return raw.map(mapLedgerRow); - }, - - /** - * Rescue rows that were claimed by a prior process but never - * reached `succeeded` or `failed` (typically because the process - * crashed mid-hook). Rows whose `updated_at` is older than - * `cutoffIso` move back to `pending` so the next `claimPendingBatch` - * picks them up; `attempts` is NOT rewound because the earlier - * claim already counted against the cap. - */ - reclaimStaleRunning(cutoffIso: string): number { - const ts = nowIso(); - const result = getDb().prepare( - "UPDATE document_lifecycle_events SET status = 'pending', updated_at = ? WHERE status = 'running' AND updated_at < ?", - ).run(ts, cutoffIso); - return Number(result.changes ?? 0); - }, - - markSucceeded(id: string): void { - const ts = nowIso(); - getDb().prepare( - "UPDATE document_lifecycle_events SET status = 'succeeded', last_error = NULL, updated_at = ?, completed_at = ? WHERE id = ?", - ).run(ts, ts, id); - }, - - markFailed(id: string, error: string): void { - const ts = nowIso(); - getDb().prepare( - "UPDATE document_lifecycle_events SET status = 'failed', last_error = ?, updated_at = ? WHERE id = ?", - ).run(error.slice(0, 2000), ts, id); - }, - - /** - * Return to `pending` after a handler failure that the caller wants - * the processor to retry (e.g. transient network failure). The - * attempt counter is preserved so the cap still bounds retries. - */ - markRetryable(id: string, error: string): void { - const ts = nowIso(); - getDb().prepare( - "UPDATE document_lifecycle_events SET status = 'pending', last_error = ?, updated_at = ? WHERE id = ?", - ).run(error.slice(0, 2000), ts, id); - }, - - listPendingForDocument(documentId: string): DocumentLifecycleEventRow[] { - return readRows(readAll, - "SELECT id, company_id, document_id, hook_type, status, attempts, last_error, payload_json, created_at, updated_at, completed_at FROM document_lifecycle_events WHERE document_id = ? AND status = 'pending' ORDER BY created_at ASC", - documentId, - ); - }, - - listFailedForCompany(companyId: string, limit = 200): DocumentLifecycleEventRow[] { - return readRows(readAll, - "SELECT id, company_id, document_id, hook_type, status, attempts, last_error, payload_json, created_at, updated_at, completed_at FROM document_lifecycle_events WHERE company_id = ? AND status = 'failed' ORDER BY updated_at DESC LIMIT ?", - companyId, - limit, - ); - }, - - /** - * Rows that have reached the attempt cap without succeeding. Surfaced - * to operators so a failing hook is visible instead of disappearing - * into the `pending` queue once the cap locks it out. - */ - listExhausted(maxAttempts: number, limit = 200): DocumentLifecycleEventRow[] { - return readRows(readAll, - "SELECT id, company_id, document_id, hook_type, status, attempts, last_error, payload_json, created_at, updated_at, completed_at FROM document_lifecycle_events WHERE status = 'pending' AND attempts >= ? ORDER BY updated_at DESC LIMIT ?", - maxAttempts, - limit, - ); - }, - }; -} - -interface LedgerRawRow { - id: string; - company_id: string; - document_id: string; - hook_type: string; - status: "pending" | "running" | "succeeded" | "failed"; - attempts: number; - last_error: string | null; - payload_json: string; - created_at: string; - updated_at: string; - completed_at: string | null; -} - -function mapLedgerRow(row: LedgerRawRow): DocumentLifecycleEventRow { - return { - id: row.id, - companyId: row.company_id, - documentId: row.document_id, - hookType: row.hook_type, - status: row.status, - attempts: row.attempts, - lastError: row.last_error, - payloadJson: row.payload_json, - createdAt: row.created_at, - updatedAt: row.updated_at, - completedAt: row.completed_at, - }; -} - -function readRows( - readAll: ReadAll, - sql: string, - ...params: SQLInputValue[] -): DocumentLifecycleEventRow[] { - return readAll(sql, ...params).map(mapLedgerRow); -} diff --git a/src/main/database/documents-work-products.ts b/src/main/database/documents-work-products.ts deleted file mode 100644 index 669da673..00000000 --- a/src/main/database/documents-work-products.ts +++ /dev/null @@ -1,475 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { statSync } from "node:fs"; -import { isAbsolute, resolve as resolvePath, relative as relativePath } from "node:path"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import { - workProductProviderEnum, - workProductReviewStateEnum, - workProductStatusEnum, - workProductTypeEnum, - type WorkProductProvider, - type WorkProductReviewState, - type WorkProductStatus, - type WorkProductType, -} from "@shared/contracts"; -import type { ReadAll, Transaction } from "./helpers"; -import { normalizeOptionalId, nowIso } from "./helpers"; - -function resolveWorkspaceRoot( - getDb: () => DatabaseSync, - companyId: string, - workspaceId: string | null, - taskId: string | null, - runId: string | null, -): string | null { - if (workspaceId) { - const row = getDb().prepare( - "SELECT local_path AS localPath FROM workspaces WHERE id = ? AND company_id = ?", - ).get(workspaceId, companyId) as { localPath: string } | undefined; - if (row?.localPath) return row.localPath; - } - if (taskId) { - const row = getDb().prepare( - "SELECT w.local_path AS localPath FROM tasks t JOIN workspaces w ON w.id = t.workspace_id WHERE t.id = ? AND t.company_id = ?", - ).get(taskId, companyId) as { localPath: string } | undefined; - if (row?.localPath) return row.localPath; - } - if (runId) { - const row = getDb().prepare( - "SELECT w.local_path AS localPath FROM runs r JOIN workspaces w ON w.id = r.workspace_id WHERE r.id = ? AND r.company_id = ?", - ).get(runId, companyId) as { localPath: string } | undefined; - if (row?.localPath) return row.localPath; - } - return null; -} - -function listCompanyWorkspaceRoots( - getDb: () => DatabaseSync, - companyId: string, -): string[] { - return (getDb() - .prepare( - "SELECT local_path AS localPath FROM workspaces WHERE company_id = ? AND local_path IS NOT NULL ORDER BY is_primary DESC, created_at ASC", - ) - .all(companyId) as Array<{ localPath: string }>) - .map((row) => row.localPath) - .filter((localPath) => localPath.length > 0); -} - -function orderedUnique(values: Array): string[] { - const seen = new Set(); - const unique: string[] = []; - for (const value of values) { - if (!value || seen.has(value)) continue; - seen.add(value); - unique.push(value); - } - return unique; -} - -function fileExists(targetPath: string): boolean { - try { - return statSync(targetPath).isFile(); - } catch { - return false; - } -} - -function joinWorkspaceRelative(root: string, rel: string): string | null { - if (isAbsolute(rel)) return null; - const joined = resolvePath(root, rel); - const within = relativePath(root, joined); - if (within.startsWith("..") || isAbsolute(within)) return null; - return joined; -} - -function parseWorkProductType(value: string): WorkProductType { - return workProductTypeEnum.parse(value); -} - -function parseWorkProductProvider(value: string): WorkProductProvider { - return workProductProviderEnum.parse(value); -} - -function parseWorkProductStatus(value: string): WorkProductStatus { - return workProductStatusEnum.parse(value); -} - -function parseWorkProductReviewState(value: string): WorkProductReviewState { - return workProductReviewStateEnum.parse(value); -} - -export class WorkProductScopeError extends Error { - constructor( - public readonly reference: "task" | "project" | "workspace", - message: string, - ) { - super(message); - this.name = "WorkProductScopeError"; - } -} - -function resolveWorkProductScope( - getDb: () => DatabaseSync, - input: { - companyId: string; - taskId?: string | null; - projectId?: string | null; - workspaceId?: string | null; - }, -): { taskId: string | null; projectId: string | null; workspaceId: string | null } { - const taskId = normalizeOptionalId(input.taskId); - let taskProjectId: string | null = null; - let taskWorkspaceId: string | null = null; - if (taskId) { - const task = getDb() - .prepare("SELECT project_id AS projectId, workspace_id AS workspaceId FROM tasks WHERE id = ? AND company_id = ? LIMIT 1") - .get(taskId, input.companyId) as { projectId: string | null; workspaceId: string | null } | undefined; - if (!task) { - throw new WorkProductScopeError("task", "Work product task does not belong to the current company"); - } - taskProjectId = task.projectId ?? null; - taskWorkspaceId = task.workspaceId ?? null; - } - - let projectId = input.projectId === undefined - ? taskProjectId - : normalizeOptionalId(input.projectId); - if (taskId && projectId !== taskProjectId) { - throw new WorkProductScopeError("project", "Work product project must match the task project"); - } - if (taskId) { - projectId = taskProjectId; - } - if (projectId) { - const project = getDb() - .prepare("SELECT id FROM projects WHERE id = ? AND company_id = ? LIMIT 1") - .get(projectId, input.companyId) as { id: string } | undefined; - if (!project) { - throw new WorkProductScopeError("project", "Work product project does not belong to the current company"); - } - } - - const requestedWorkspaceId = normalizeOptionalId(input.workspaceId); - if (taskWorkspaceId && requestedWorkspaceId && requestedWorkspaceId !== taskWorkspaceId) { - throw new WorkProductScopeError("workspace", "Work product workspace must match the task workspace"); - } - const workspaceId = taskWorkspaceId ?? requestedWorkspaceId; - if (workspaceId) { - const workspace = getDb() - .prepare("SELECT id, project_id AS projectId FROM workspaces WHERE id = ? AND company_id = ? LIMIT 1") - .get(workspaceId, input.companyId) as { id: string; projectId: string | null } | undefined; - if (!workspace) { - throw new WorkProductScopeError("workspace", "Work product workspace does not belong to the current company"); - } - if (projectId && workspace.projectId !== projectId) { - throw new WorkProductScopeError("workspace", "Work product workspace project must match the work product project"); - } - } - - return { taskId, projectId, workspaceId }; -} - -export function buildWorkProductMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - createWorkProduct(input: { - companyId: string; taskId: string | null; projectId?: string | null; - workspaceId?: string | null; - type: WorkProductType; provider: WorkProductProvider; externalId?: string | null; - title: string; url?: string | null; status?: WorkProductStatus; reviewState?: WorkProductReviewState; - isPrimary?: boolean; summary?: string | null; metadataJson?: string | null; - createdByRunId?: string | null; - }): string { - return transaction(() => { - const id = randomUUID(); - const ts = nowIso(); - const scope = resolveWorkProductScope(getDb, input); - const type = parseWorkProductType(input.type); - const provider = parseWorkProductProvider(input.provider); - const status = input.status !== undefined ? parseWorkProductStatus(input.status) : "active"; - const reviewState = input.reviewState !== undefined ? parseWorkProductReviewState(input.reviewState) : "none"; - if (input.isPrimary && scope.taskId && status !== "archived") { - getDb().prepare( - "UPDATE work_products SET is_primary = 0, updated_at = ? WHERE company_id = ? AND task_id = ? AND type = ? AND status <> 'archived'", - ).run(ts, input.companyId, scope.taskId, type); - } - getDb().prepare( - `INSERT INTO work_products (id, company_id, project_id, task_id, workspace_id, type, provider, external_id, title, url, status, review_state, is_primary, summary, metadata_json, created_by_run_id, last_touched_by_run_id, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - ).run( - id, input.companyId, scope.projectId, scope.taskId, - scope.workspaceId, - type, provider, input.externalId ?? null, - input.title, input.url ?? null, status, - reviewState, input.isPrimary ? 1 : 0, - input.summary ?? null, input.metadataJson ?? null, - input.createdByRunId ?? null, input.createdByRunId ?? null, ts, ts, - ); - return id; - }); - }, - - findWorkProductByExternalId( - companyId: string, - provider: WorkProductProvider, - externalId: string, - workspaceId: string | null, - ): { id: string; taskId: string | null } | null { - const parsedProvider = parseWorkProductProvider(provider); - if (workspaceId) { - const row = getDb() - .prepare( - "SELECT id, task_id as taskId FROM work_products WHERE company_id = ? AND workspace_id = ? AND provider = ? AND external_id = ? LIMIT 1", - ) - .get(companyId, workspaceId, parsedProvider, externalId) as - | { id: string; taskId: string | null } - | undefined; - return row ?? null; - } - const row = getDb() - .prepare( - "SELECT id, task_id as taskId FROM work_products WHERE company_id = ? AND workspace_id IS NULL AND provider = ? AND external_id = ? LIMIT 1", - ) - .get(companyId, parsedProvider, externalId) as - | { id: string; taskId: string | null } - | undefined; - return row ?? null; - }, - - updateWorkProduct( - id: string, - companyId: string, - patch: { - type?: WorkProductType; - provider?: WorkProductProvider; - externalId?: string | null; - workspaceId?: string | null; - title?: string; - url?: string | null; - status?: WorkProductStatus; - reviewState?: WorkProductReviewState; - isPrimary?: boolean; - summary?: string | null; - metadataJson?: string | null; - lastTouchedByRunId?: string | null; - }, - ): number { - return transaction(() => { - const current = getDb().prepare( - "SELECT task_id as taskId, type, status, is_primary as isPrimary FROM work_products WHERE id = ? AND company_id = ?", - ).get(id, companyId) as - | { taskId: string | null; type: string; status: string; isPrimary: number } - | undefined; - if (!current) return 0; - - const ts = nowIso(); - const nextType = patch.type !== undefined ? parseWorkProductType(patch.type) : parseWorkProductType(current.type); - const nextStatus = patch.status !== undefined ? parseWorkProductStatus(patch.status) : parseWorkProductStatus(current.status); - const parsedProvider = patch.provider !== undefined ? parseWorkProductProvider(patch.provider) : undefined; - const parsedReviewState = patch.reviewState !== undefined ? parseWorkProductReviewState(patch.reviewState) : undefined; - const parsedWorkspaceId = patch.workspaceId !== undefined - ? resolveWorkProductScope(getDb, { - companyId, - taskId: current.taskId, - workspaceId: patch.workspaceId, - }).workspaceId - : undefined; - const nextIsPrimary = patch.isPrimary ?? Boolean(current.isPrimary); - if (nextIsPrimary && current.taskId && nextStatus !== "archived") { - getDb().prepare( - "UPDATE work_products SET is_primary = 0, updated_at = ? WHERE company_id = ? AND task_id = ? AND type = ? AND status <> 'archived' AND id <> ?", - ).run(ts, companyId, current.taskId, nextType, id); - } - - const sets: string[] = ["updated_at = ?"]; - const values: SQLInputValue[] = [ts]; - const map: Array<[keyof typeof patch, string, (v: unknown) => SQLInputValue]> = [ - ["type", "type", () => nextType], - ["provider", "provider", () => parsedProvider ?? null], - ["externalId", "external_id", (v) => (v as string | null) ?? null], - ["workspaceId", "workspace_id", () => parsedWorkspaceId ?? null], - ["title", "title", (v) => (v as string) ?? null], - ["url", "url", (v) => (v as string | null) ?? null], - ["status", "status", () => nextStatus], - ["reviewState", "review_state", () => parsedReviewState ?? null], - ["isPrimary", "is_primary", (v) => (v ? 1 : 0)], - ["summary", "summary", (v) => (v as string | null) ?? null], - ["metadataJson", "metadata_json", (v) => (v as string | null) ?? null], - ["lastTouchedByRunId", "last_touched_by_run_id", (v) => (v as string | null) ?? null], - ]; - for (const [key, col, coerce] of map) { - if (patch[key] !== undefined) { - sets.push(`${col} = ?`); - values.push(coerce(patch[key])); - } - } - values.push(id, companyId); - const result = getDb() - .prepare(`UPDATE work_products SET ${sets.join(", ")} WHERE id = ? AND company_id = ?`) - .run(...values); - return Number(result.changes ?? 0); - }); - }, - - resolveWorkProductTarget( - workProductId: string, - companyId: string, - ): - | { kind: "url" | "path"; value: string } - | { kind: "error"; reason: "not_found" | "archived" | "no_target" | "workspace_unresolved" | "path_escape" | "path_missing"; detail: string } { - const row = getDb().prepare( - "SELECT provider, external_id, url, status, task_id, created_by_run_id, last_touched_by_run_id, workspace_id FROM work_products WHERE id = ? AND company_id = ?", - ).get(workProductId, companyId) as - | { provider: string; external_id: string | null; url: string | null; status: string; task_id: string | null; created_by_run_id: string | null; last_touched_by_run_id: string | null; workspace_id: string | null } - | undefined; - if (!row) return { kind: "error", reason: "not_found", detail: `No work_product row with id=${workProductId}` }; - if (row.status === "archived") return { kind: "error", reason: "archived", detail: "Work product is archived (retirement tombstone)" }; - - if (row.url && row.url.length > 0) return { kind: "url", value: row.url }; - if (row.provider !== "filesystem" || !row.external_id) { - return { kind: "error", reason: "no_target", detail: `provider=${row.provider} external_id=${row.external_id ?? "null"} url=null` }; - } - - const workspaceRoots = orderedUnique([ - resolveWorkspaceRoot( - getDb, - companyId, - row.workspace_id, - row.task_id, - row.last_touched_by_run_id ?? row.created_by_run_id, - ), - ...listCompanyWorkspaceRoots(getDb, companyId), - ]); - let firstCandidate: string | null = null; - for (const workspaceRoot of workspaceRoots) { - const absolute = joinWorkspaceRelative(workspaceRoot, row.external_id); - if (!absolute) { - return { kind: "error", reason: "path_escape", detail: `external_id=${row.external_id} escapes workspace root ${workspaceRoot}` }; - } - firstCandidate ??= absolute; - if (fileExists(absolute)) { - return { kind: "path", value: absolute }; - } - } - - if (firstCandidate) { - return { - kind: "error", - reason: "path_missing", - detail: `No registered company workspace contains ${row.external_id}; first candidate was ${firstCandidate}`, - }; - } - - return { - kind: "error", - reason: "workspace_unresolved", - detail: `workspace_id=${row.workspace_id ?? "null"} task_id=${row.task_id ?? "null"} run_id=${row.last_touched_by_run_id ?? row.created_by_run_id ?? "null"} — none led to a workspace with a local_path`, - }; - }, - - listWorkProductsForTask(taskId: string, companyId: string) { - return readAll<{ - id: string; company_id: string; project_id: string | null; task_id: string; - workspace_id: string | null; - 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; last_touched_by_run_id: string | null; - created_at: string; updated_at: string; - }>( - "SELECT * FROM work_products WHERE task_id = ? AND company_id = ? AND status <> 'archived' 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, - workspaceId: r.workspace_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, - lastTouchedByRunId: r.last_touched_by_run_id, - createdAt: r.created_at, updatedAt: r.updated_at, - })); - }, - - listWorkProductsForCompany(companyId: string, limit = 500) { - return readAll<{ - id: string; company_id: string; project_id: string | null; task_id: string | null; - workspace_id: string | null; - 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; last_touched_by_run_id: string | null; - created_at: string; updated_at: string; - }>( - "SELECT * FROM work_products WHERE company_id = ? AND status <> 'archived' ORDER BY updated_at DESC LIMIT ?", - companyId, limit, - ).map((r) => ({ - id: r.id, companyId: r.company_id, projectId: r.project_id, taskId: r.task_id, - workspaceId: r.workspace_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, - lastTouchedByRunId: r.last_touched_by_run_id, - createdAt: r.created_at, updatedAt: r.updated_at, - })); - }, - - deleteWorkProduct(id: string, companyId: string): number { - const result = getDb() - .prepare("DELETE FROM work_products WHERE id = ? AND company_id = ?") - .run(id, companyId); - return Number(result.changes ?? 0); - }, - - archiveWorkProductsByExternalPaths(input: { - companyId: string; - workspaceId: string | null; - provider: WorkProductProvider; - paths: string[]; - lastTouchedByRunId: string | null; - }): Array<{ id: string; externalId: string }> { - if (input.paths.length === 0) return []; - const provider = parseWorkProductProvider(input.provider); - const ts = nowIso(); - const CHUNK = 500; - const workspaceClause = input.workspaceId - ? "AND workspace_id = ?" - : "AND workspace_id IS NULL"; - const results: Array<{ id: string; externalId: string }> = []; - for (let i = 0; i < input.paths.length; i += CHUNK) { - const chunk = input.paths.slice(i, i + CHUNK); - const placeholders = chunk.map(() => "?").join(", "); - const params: SQLInputValue[] = [ - input.lastTouchedByRunId ?? null, - ts, - input.companyId, - provider, - ]; - if (input.workspaceId) params.push(input.workspaceId); - params.push(...chunk); - const rows = readAll<{ id: string; external_id: string }>( - `UPDATE work_products - SET status = 'archived', - last_touched_by_run_id = ?, - updated_at = ? - WHERE company_id = ? - AND provider = ? - ${workspaceClause} - AND external_id IN (${placeholders}) - AND status <> 'archived' - RETURNING id, external_id`, - ...params, - ); - for (const row of rows) { - results.push({ id: row.id, externalId: row.external_id }); - } - } - return results; - }, - }; -} diff --git a/src/main/database/documents.ts b/src/main/database/documents.ts deleted file mode 100644 index 338f223d..00000000 --- a/src/main/database/documents.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import { canonicalizeJsonString, jsonStringArraySchema } from "@shared/contracts"; -import type { ReadAll, Transaction } from "./helpers"; -import { ensureId, nowIso } from "./helpers"; -import { buildConfigRevisionMethods } from "./config-revisions"; -import { buildWorkProductMethods } from "./documents-work-products"; - -/** - * Document row shape returned by listDocuments — used by - * GET /api/companies/:companyId/documents. Mirrors the historical inline - * SQL projection so HTTP response bodies stay byte-stable for clients. - */ -export type DocumentListRow = { - id: string; - companyId: string; - type: string; - title: string; - content: string; - authorAgentId: string; - reviewerAgentId: string | null; - projectId: string | null; - goalId: string | null; - parentDocId: string | null; - version: number; - status: string; - tagsJson: string; - latestRevisionId: string | null; - createdAt: string; - updatedAt: string; -}; - -/** - * Document lookup row used by the PATCH document handler — narrower - * projection without parent_doc_id / latest_revision_id / timestamps. - */ -export type DocumentLookupRow = { - id: string; - companyId: string; - type: string; - title: string; - content: string; - authorAgentId: string; - reviewerAgentId: string | null; - projectId: string | null; - goalId: string | null; - version: number; - status: string; - tagsJson: string; -}; - -export function buildDocumentMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - ...buildConfigRevisionMethods(getDb, readAll, transaction), - ...buildWorkProductMethods(getDb, readAll, transaction), - saveDocument(input: { - id?: string | null; companyId: string; type: string; title: string; content?: string; - authorAgentId?: string | null; reviewerAgentId?: string | null; projectId?: string | null; - goalId?: string | null; parentDocId?: string | null; version?: number; status?: string; tagsJson?: string; - sourceRunId?: string | null; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from documents where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Document ${id} does not belong to company ${input.companyId}`); - } - const tagsJson = canonicalizeJsonString(input.tagsJson, jsonStringArraySchema, []); - if (existing) { - getDb().prepare( - "update documents set type = ?, title = ?, content = ?, author_agent_id = ?, reviewer_agent_id = ?, project_id = ?, goal_id = ?, parent_doc_id = ?, version = ?, status = ?, tags_json = ?, source_run_id = coalesce(?, source_run_id), updated_at = ? where id = ? and company_id = ?", - ).run(input.type, input.title, input.content ?? "", input.authorAgentId ?? null, input.reviewerAgentId ?? null, input.projectId ?? null, input.goalId ?? null, input.parentDocId ?? null, input.version ?? 1, input.status ?? "draft", tagsJson, input.sourceRunId ?? null, ts, id, input.companyId); - } else { - getDb().prepare( - "insert into documents (id, company_id, type, title, content, author_agent_id, reviewer_agent_id, project_id, goal_id, parent_doc_id, version, status, tags_json, source_run_id, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ).run(id, input.companyId, input.type, input.title, input.content ?? "", input.authorAgentId ?? null, input.reviewerAgentId ?? null, input.projectId ?? null, input.goalId ?? null, input.parentDocId ?? null, input.version ?? 1, input.status ?? "draft", tagsJson, input.sourceRunId ?? null, ts, ts); - } - return id; - }, - - /** - * Returns all documents for a company, ordered by updated_at desc. - * Used by GET /api/companies/:companyId/documents. - */ - listDocuments(companyId: string): DocumentListRow[] { - return readAll( - "select id, company_id as companyId, type, title, content, author_agent_id as authorAgentId, reviewer_agent_id as reviewerAgentId, project_id as projectId, goal_id as goalId, parent_doc_id as parentDocId, version, status, tags_json as tagsJson, latest_revision_id as latestRevisionId, created_at as createdAt, updated_at as updatedAt from documents where company_id = ? order by updated_at desc", - companyId, - ).map((d) => ({ ...d, latestRevisionId: d.latestRevisionId ?? null })); - }, - - /** - * Returns the lookup row needed for PATCH /api/companies/:companyId/documents/:documentId. - * Returns null when the document is missing or belongs to another company. - */ - getDocumentForUpdate( - documentId: string, - companyId: string, - ): DocumentLookupRow | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, type, title, content, author_agent_id as authorAgentId, reviewer_agent_id as reviewerAgentId, project_id as projectId, goal_id as goalId, version, status, tags_json as tagsJson from documents where id = ? and company_id = ? limit 1", - ) - .get(documentId, companyId) as DocumentLookupRow | undefined; - return row ?? null; - }, - - updateDocumentStatus(id: string, companyId: string, status: string): void { - getDb().prepare( - "UPDATE documents SET status = ?, updated_at = ? WHERE id = ? AND company_id = ?", - ).run(status, nowIso(), id, companyId); - }, - - deleteDocument(id: string, companyId: string) { - getDb().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 = getDb().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; - getDb().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); - getDb().prepare( - "UPDATE documents SET version = ?, latest_revision_id = ?, updated_at = ? WHERE id = ? AND company_id = ?", - ).run(revisionNumber, id, ts, input.documentId, input.companyId); - return { id, revisionNumber }; - }, - - getDocumentLatestRevisionId(documentId: string, companyId: string): string | null { - const row = getDb().prepare( - "SELECT latest_revision_id FROM documents WHERE id = ? AND company_id = ?", - ).get(documentId, companyId) as { latest_revision_id: string | null } | undefined; - return row?.latest_revision_id ?? null; - }, - - /** - * Returns up to `limit` documents of the given types for a company that - * are either authored by `authorAgentId` or were created at/after the - * task's createdAt. Used by the deliverable-review gate when a task is - * advanced to "done". - */ - listImportantDocsForReview(input: { - companyId: string; - types: readonly string[]; - authorAgentId: string | null; - taskId: string; - limit?: number; - }): Array<{ id: string; type: string; title: string }> { - const limit = input.limit ?? 10; - const placeholders = input.types.map(() => "?").join(", "); - return readAll<{ id: string; type: string; title: string }>( - `select id, type, title from documents where company_id = ? and type in (${placeholders}) - and (author_agent_id = ? or created_at >= (select created_at from tasks where id = ?)) - order by created_at desc limit ?`, - input.companyId, - ...input.types, - input.authorAgentId ?? "", - input.taskId, - limit, - ); - }, - - listDocumentRevisions(documentId: string, companyId: string) { - return 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, - })); - }, - - // ── Task-Document Links ── - - linkDocumentToTask(taskId: string, documentId: string, companyId: string, key: string): string { - const id = randomUUID(); - const ts = nowIso(); - getDb().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 { - getDb().prepare( - "DELETE FROM task_documents WHERE task_id = ? AND key = ? AND company_id = ?", - ).run(taskId, key.toLowerCase(), companyId); - }, - - listDocumentsForTask(taskId: string, companyId: string) { - return 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, - })); - }, - - }; -} diff --git a/src/main/database/entity-crud.ts b/src/main/database/entity-crud.ts deleted file mode 100644 index 880a0832..00000000 --- a/src/main/database/entity-crud.ts +++ /dev/null @@ -1,308 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { AgentRecord, ConnectorId, TaskRecord } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { activeRunIdSql, ensureId, normalizeOptionalId, nowIso } from "./helpers"; - -/** - * Goal row shape returned by listGoals / getGoalForUpdate. Mirrors the - * historical inline SQL projection in routes-work-graph.ts so HTTP - * responses stay byte-stable. - */ -export type GoalListRow = { - id: string; - companyId: string; - title: string; - description: string; - parentId: string | null; - ownerAgentId: string | null; - status: string; - createdAt: string; - updatedAt: string; -}; - -/** - * Project row shape returned by listProjects / getProjectForUpdate. - * Mirrors the historical inline SQL projection in routes-work-graph.ts. - */ -export type ProjectListRow = { - id: string; - companyId: string; - goalId: string | null; - name: string; - description: string; - leadAgentId: string | null; - status: string; - targetDate: string | null; - createdAt: string; - updatedAt: string; -}; - -export function buildEntityCrudMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - _deps: { - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - vault: { encrypt: (v: string) => { backend: string; payload: Uint8Array }; decrypt: (backend: "safe_storage" | "vault", ciphertext: Buffer) => string }; - listInvalidEnvBindingKeys: (t: string) => string[]; - parseEnvBindingText: (t: string) => Record; - }, -) { - const { vault, listInvalidEnvBindingKeys, parseEnvBindingText } = _deps; - return { - getTask(id: string): TaskRecord { - const row = getDb() - .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, ${activeRunIdSql("tasks")} as activeRunId, cost_usd as costUsd, task_type as taskType, requires_user_review as requiresUserReview, requires_filesystem as requiresFilesystem, 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.requiresFilesystem = Boolean(row.requiresFilesystem); - row.startedAt = row.startedAt ?? null; - row.completedAt = row.completedAt ?? null; - row.cancelledAt = row.cancelledAt ?? null; - return row; - }, - - getAgent(id: string): AgentRecord { - const row = getDb() - .prepare( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt from agents where id = ?", - ) - .get(id) as AgentRecord | undefined; - if (!row) throw new Error(`Agent not found: ${id}`); - row.heartbeatEnabled = Boolean(row.heartbeatEnabled); - return row; - }, - - findAgent(id: string): AgentRecord | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt from agents where id = ?", - ) - .get(id) as AgentRecord | undefined; - if (!row) return null; - row.heartbeatEnabled = Boolean(row.heartbeatEnabled); - return row; - }, - - /** - * Returns all goals for a company. Used by GET /api/companies/:id/goals. - */ - listGoals(companyId: string): GoalListRow[] { - return readAll( - "select id, company_id as companyId, title, description, parent_id as parentId, owner_agent_id as ownerAgentId, status, created_at as createdAt, updated_at as updatedAt from goals where company_id = ? order by created_at asc", - companyId, - ); - }, - - /** - * Returns the goal lookup row used by PATCH /api/goals/:goalId. - * Returns null when the goal is missing or belongs to another company. - */ - getGoalForUpdate(goalId: string, companyId: string): GoalListRow | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, title, description, parent_id as parentId, owner_agent_id as ownerAgentId, status, created_at as createdAt, updated_at as updatedAt from goals where id = ? and company_id = ? limit 1", - ) - .get(goalId, companyId) as GoalListRow | undefined; - return row ?? null; - }, - - /** - * Returns all projects for a company. Used by - * GET /api/companies/:id/projects. - */ - listProjects(companyId: string): ProjectListRow[] { - return readAll( - "select id, company_id as companyId, goal_id as goalId, name, description, lead_agent_id as leadAgentId, status, target_date as targetDate, created_at as createdAt, updated_at as updatedAt from projects where company_id = ? order by created_at desc", - companyId, - ); - }, - - /** - * Returns the project lookup row used by PATCH /api/projects/:projectId. - * Returns null when the project is missing or belongs to another company. - */ - getProjectForUpdate(projectId: string, companyId: string): ProjectListRow | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, goal_id as goalId, name, description, lead_agent_id as leadAgentId, status, target_date as targetDate, created_at as createdAt, updated_at as updatedAt from projects where id = ? and company_id = ? limit 1", - ) - .get(projectId, companyId) as ProjectListRow | undefined; - return row ?? null; - }, - - saveGoal(input: { id?: string | null; companyId: string; title: string; description: string; parentId?: string | null; ownerAgentId?: string | null; status: string }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare("select id from goals where id = ? and company_id = ?").get(id, input.companyId) as { id: string } | undefined; - if (existing) { - getDb() - .prepare( - "update goals set title = ?, description = ?, parent_id = ?, owner_agent_id = ?, status = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run(input.title, input.description, normalizeOptionalId(input.parentId), normalizeOptionalId(input.ownerAgentId), input.status, ts, id, input.companyId); - } else { - getDb() - .prepare( - "insert into goals (id, company_id, title, description, parent_id, owner_agent_id, status, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run(id, input.companyId, input.title, input.description, normalizeOptionalId(input.parentId), normalizeOptionalId(input.ownerAgentId), input.status, ts, ts); - } - return id; - }, - - saveProject(input: { id?: string | null; companyId: string; goalId?: string | null; name: string; description: string; leadAgentId?: string | null; targetDate?: string | null; status: string }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare("select id from projects where id = ? and company_id = ?").get(id, input.companyId) as { id: string } | undefined; - if (existing) { - getDb() - .prepare( - "update projects set goal_id = ?, name = ?, description = ?, lead_agent_id = ?, status = ?, target_date = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run(normalizeOptionalId(input.goalId), input.name, input.description, normalizeOptionalId(input.leadAgentId), input.status, normalizeOptionalId(input.targetDate), ts, id, input.companyId); - } else { - getDb() - .prepare( - "insert into projects (id, company_id, goal_id, name, description, lead_agent_id, status, target_date, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run(id, input.companyId, normalizeOptionalId(input.goalId), input.name, input.description, normalizeOptionalId(input.leadAgentId), input.status, normalizeOptionalId(input.targetDate), ts, ts); - } - return id; - }, - - saveSecret(input: { id?: string | null; companyId: string; name: string; description: string; value: string }) { - const id = ensureId(input.id ?? null); - const encrypted = vault.encrypt(input.value); - const ts = nowIso(); - const existing = getDb().prepare("select id, company_id as companyId from secrets where id = ?").get(id) as - | { id: string; companyId: string } - | undefined; - if (existing) { - if (existing.companyId !== input.companyId) { - throw new Error("Secrets cannot be moved across companies."); - } - getDb() - .prepare("update secrets set name = ?, description = ?, backend = ?, ciphertext = ?, updated_at = ? where id = ? and company_id = ?") - .run(input.name, input.description, encrypted.backend, encrypted.payload, ts, id, input.companyId); - } else { - getDb() - .prepare("insert into secrets (id, company_id, name, description, backend, ciphertext, updated_at, created_at) values (?, ?, ?, ?, ?, ?, ?, ?)") - .run(id, input.companyId, input.name, input.description, encrypted.backend, encrypted.payload, ts, ts); - } - return id; - }, - - resolveSecretEnv(bindingText: string, companyId: string): Record { - const invalidKeys = new Set(listInvalidEnvBindingKeys(bindingText)); - const bindings = parseEnvBindingText(bindingText); - const result: Record = {}; - for (const [envKey, rawValue] of Object.entries(bindings)) { - if (invalidKeys.has(envKey)) continue; - const row = getDb().prepare("select backend, ciphertext from secrets where company_id = ? and name = ?").get(companyId, rawValue) as - | { backend: "safe_storage" | "vault"; ciphertext: Uint8Array } - | undefined; - if (row) { - result[envKey] = vault.decrypt(row.backend, Buffer.from(row.ciphertext)); - } else { - result[envKey] = rawValue; - } - } - return result; - }, - - deleteGoal(id: string, companyId: string) { - transaction(() => { - getDb().prepare("update goals set parent_id = null where parent_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("update projects set goal_id = null where goal_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("update tasks set goal_id = null where goal_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("delete from goals where id = ? and company_id = ?").run(id, companyId); - }); - }, - - deleteProject(id: string, companyId: string) { - transaction(() => { - getDb().prepare("update tasks set project_id = null where project_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("update workspaces set project_id = null where project_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("delete from projects where id = ? and company_id = ?").run(id, companyId); - }); - }, - - deleteSecret(id: string, companyId: string) { - transaction(() => { - getDb() - .prepare("update social_accounts set credential_secret_id = null, updated_at = ? where credential_secret_id = ? and company_id = ?") - .run(nowIso(), id, companyId); - getDb().prepare("delete from secrets where id = ? and company_id = ?").run(id, companyId); - }); - }, - - countActiveGoalsForCompany(companyId: string): number { - const row = getDb().prepare( - "select count(*) as cnt from goals where company_id = ? and status in ('active', 'planned')", - ).get(companyId) as { cnt: number }; - return row.cnt; - }, - - createHireRequest(input: { - companyId: string; requestedByAgentId?: string | null; - name: string; role: string; title: string; department?: string | null; - reportsTo?: string | null; connectorId: ConnectorId; workspaceId?: string | null; - model?: string | null; metadataJson?: string; capabilities: string; - budgetMonthlyUsd: number; payloadSummary: string; impactSummary: string; - payloadJson?: string | null; - }, selfDeps: { - saveAgent: (input: { - companyId: string; name: string; role: string; title: string; - department: string | null; status: AgentRecord["status"]; - reportsTo: string | null; connectorId: ConnectorId; - workspaceId: string | null; model: string | null; - metadataJson: string; capabilities: string; budgetMonthlyUsd: number; - modelStrategy?: "explicit" | "auto"; - }) => string; - requestApproval: (input: { - companyId: string; requestedByAgentId: string | null; - relatedAgentId: string; type: string; - payloadSummary: string; impactSummary: string; - payloadJson: string | null; - }) => string; - }) { - return transaction(() => { - const agentId = selfDeps.saveAgent({ - companyId: input.companyId, name: input.name, role: input.role, - title: input.title, department: input.department ?? null, - status: "pending_approval", reportsTo: input.reportsTo ?? null, - connectorId: input.connectorId, workspaceId: input.workspaceId ?? null, - model: input.model ?? null, metadataJson: input.metadataJson ?? "{}", - capabilities: input.capabilities, budgetMonthlyUsd: input.budgetMonthlyUsd, - // Agents hired by the CEO (or any other agent) default to `auto`: - // the dispatcher will pick the cheapest enabled model that - // clears their inferred task profile. User-driven form saves - // flip this to 'explicit' at the IPC handler. - modelStrategy: "auto", - }); - const approvalId = selfDeps.requestApproval({ - companyId: input.companyId, - requestedByAgentId: input.requestedByAgentId ?? null, - relatedAgentId: agentId, - type: "hire_agent", - payloadSummary: input.payloadSummary, - impactSummary: input.impactSummary, - payloadJson: input.payloadJson ?? null, - }); - return { agentId, approvalId }; - }); - }, - - incrementActiveSprintVelocity(companyId: string, delta: number) { - const ts = nowIso(); - const today = ts.slice(0, 10); - getDb().prepare( - "update sprints set completed_points = max(0, completed_points + ?), updated_at = ? where company_id = ? and status = 'active' and start_date <= ? and end_date >= ?", - ).run(delta, ts, companyId, today, today); - }, - }; -} diff --git a/src/main/database/helpers.ts b/src/main/database/helpers.ts deleted file mode 100644 index 80f4c21c..00000000 --- a/src/main/database/helpers.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { SQLInputValue } from "node:sqlite"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SqliteRow represents dynamic row shapes from node:sqlite; callers narrow via explicit column reads -export type SqliteRow = Record; -export type ReadAll = (sql: string, ...params: SQLInputValue[]) => T[]; -export type Transaction = (operation: () => T) => T; - -export const BOARD_READER_ID = "__board__"; - -export function nowIso(): string { - return new Date().toISOString(); -} - -export function parseJson(value: string | null | undefined, fallback: T): T { - if (!value) return fallback; - try { - return JSON.parse(value) as T; - } catch { - return fallback; - } -} - -export function ensureId(id: string | null | undefined): string { - return id && id.length > 0 ? id : randomUUID(); -} - -export function normalizeOptionalId(id: string | null | undefined): string | null { - return id && id.length > 0 ? id : null; -} - -export function toBoolean(value: unknown): boolean { - return value === true || value === 1 || value === "1"; -} - -export function taskPriorityOrderSql(columnName: string): string { - return `case ${columnName} - when 'critical' then 4 - when 'high' then 3 - when 'medium' then 2 - when 'low' then 1 - else 0 - end`; -} - -export function activeRunIdSql(taskTableAlias: string): string { - return `(select l.run_id - from task_leases l - join runs r on r.id = l.run_id - where l.task_id = ${taskTableAlias}.id - and r.status in ('queued', 'running') - limit 1)`; -} diff --git a/src/main/database/inbox-projections.ts b/src/main/database/inbox-projections.ts deleted file mode 100644 index f6ebdb26..00000000 --- a/src/main/database/inbox-projections.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { nowIso } from "./helpers"; - -/** - * Ledger accessor for `agent_message_projections`. - * - * The projection path (inbox → session shadow) used to assume - * `markAgentInboxDelivered` acted as its completion mark, but that - * write lived outside the transaction that appended to the shadow - * and wrote the thread event. A crash in that window produced a - * replay that double-inserted both. The ledger is the idempotent - * gate: a single `INSERT OR IGNORE` per `(message_id, session_id)` - * short-circuits the rest of the projection closure when the pair - * has already committed. - */ -export function buildInboxProjectionMethods(getDb: () => DatabaseSync) { - return { - /** - * Attempt to claim a projection slot. Returns true when this call - * wrote a fresh row, false when the pair was already recorded. - * Callers run this inside the same transaction that performs the - * shadow append, the thread-event write, and the delivered mark, - * so either all four writes commit or none do. - */ - claimProjection(messageId: string, sessionId: string): boolean { - const result = getDb().prepare( - "INSERT OR IGNORE INTO agent_message_projections (message_id, session_id, projected_at) VALUES (?, ?, ?)", - ).run(messageId, sessionId, nowIso()); - return Number(result.changes ?? 0) > 0; - }, - - /** - * Purge ledger rows for sessions no agent currently references as - * its active `session_id`. A rotated session is never read again — - * its ledger entries only exist to prevent replays against that - * specific shadow, which no future run will touch. The safety - * margin (rows younger than the cutoff are preserved) covers - * rotations that happen mid-sweep so a race cannot strip the - * ledger under an active run. - */ - purgeOrphanProjections(cutoffIso: string): number { - const result = getDb().prepare( - `DELETE FROM agent_message_projections - WHERE projected_at < ? - AND session_id NOT IN (SELECT session_id FROM agents WHERE session_id IS NOT NULL)`, - ).run(cutoffIso); - return Number(result.changes ?? 0); - }, - }; -} diff --git a/src/main/database/index.ts b/src/main/database/index.ts deleted file mode 100644 index f3d04130..00000000 --- a/src/main/database/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { AppDatabase, STALE_LOCK_TIMEOUT_MS } from "../database"; diff --git a/src/main/database/knowledge.ts b/src/main/database/knowledge.ts deleted file mode 100644 index addef3d7..00000000 --- a/src/main/database/knowledge.ts +++ /dev/null @@ -1,281 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { canonicalizeJsonString, jsonArraySchema, jsonStringArraySchema, meetingActionItemArraySchema } from "@shared/contracts"; -import type { ReadAll } from "./helpers"; -import { ensureId, nowIso } from "./helpers"; - -/** - * Meeting row shape returned by listMeetings / getMeeting — used by - * meeting routes. Mirrors the historical inline SQL projection so HTTP - * response bodies stay byte-stable. - */ -export type MeetingListRow = { - id: string; - companyId: string; - type: string; - title: string; - organizerAgentId: string; - participantAgentIds: string; - scheduledAt: string; - durationMinutes: number; - agendaJson: string; - notesJson: string | null; - decisionsJson: string | null; - actionItemsJson: string | null; - status: string; - createdAt: string; - updatedAt: string; -}; - -const MEETING_LIST_COLUMNS = - "select id, company_id as companyId, type, title, organizer_agent_id as organizerAgentId, participant_agent_ids as participantAgentIds, scheduled_at as scheduledAt, duration_minutes as durationMinutes, agenda_json as agendaJson, notes_json as notesJson, decisions_json as decisionsJson, action_items_json as actionItemsJson, status, created_at as createdAt, updated_at as updatedAt from meetings"; - -/** - * Sprint row shape returned by listSprints — used by - * GET /api/companies/:companyId/sprints. Mirrors the historical inline - * SQL projection. - */ -export type SprintListRow = { - id: string; - companyId: string; - name: string; - goal: string; - startDate: string; - endDate: string; - status: string; - retrospectiveNotes: string | null; - velocityPoints: number; - completedPoints: number; - createdAt: string; - updatedAt: string; -}; - -/** - * Knowledge entry row shape returned by listKnowledgeEntries — used by - * GET /api/companies/:companyId/knowledge. Mirrors the historical inline - * SQL projection so HTTP responses stay byte-stable. - */ -export type KnowledgeListRow = { - id: string; - companyId: string; - category: string; - topic: string; - content: string; - authorAgentId: string; - importance: string; - tagsJson: string; - referencedEntityType: string | null; - referencedEntityId: string | null; - createdAt: string; - updatedAt: string; -}; - -export function buildKnowledgeMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, -) { - return { - listMeetings(companyId: string): MeetingListRow[] { - return readAll( - `${MEETING_LIST_COLUMNS} where company_id = ? order by scheduled_at desc`, - companyId, - ); - }, - - getMeeting(meetingId: string, companyId: string): MeetingListRow | null { - const row = getDb() - .prepare(`${MEETING_LIST_COLUMNS} where id = ? and company_id = ? limit 1`) - .get(meetingId, companyId) as MeetingListRow | undefined; - return row ?? null; - }, - - saveMeeting(input: { - id?: string | null; companyId: string; type: string; title: string; organizerAgentId?: string | null; - participantAgentIds?: string; scheduledAt: string; durationMinutes?: number; - agendaJson?: string; notesJson?: string; decisionsJson?: string; actionItemsJson?: string; - status?: string; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from meetings where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Meeting ${id} does not belong to company ${input.companyId}`); - } - const participantAgentIds = canonicalizeJsonString(input.participantAgentIds, jsonStringArraySchema, []); - const agendaJson = canonicalizeJsonString(input.agendaJson, jsonArraySchema, []); - const notesJson = canonicalizeJsonString(input.notesJson, jsonArraySchema, []); - const decisionsJson = canonicalizeJsonString(input.decisionsJson, jsonArraySchema, []); - const actionItemsJson = canonicalizeJsonString(input.actionItemsJson, meetingActionItemArraySchema, []); - if (existing) { - getDb().prepare( - "update meetings set type = ?, title = ?, organizer_agent_id = ?, participant_agent_ids = ?, scheduled_at = ?, duration_minutes = ?, agenda_json = ?, notes_json = ?, decisions_json = ?, action_items_json = ?, status = ?, updated_at = ? where id = ? and company_id = ?", - ).run(input.type, input.title, input.organizerAgentId ?? null, participantAgentIds, input.scheduledAt, input.durationMinutes ?? 30, agendaJson, notesJson, decisionsJson, actionItemsJson, input.status ?? "scheduled", ts, id, input.companyId); - } else { - getDb().prepare( - "insert into meetings (id, company_id, type, title, organizer_agent_id, participant_agent_ids, scheduled_at, duration_minutes, agenda_json, notes_json, decisions_json, action_items_json, status, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ).run(id, input.companyId, input.type, input.title, input.organizerAgentId ?? null, participantAgentIds, input.scheduledAt, input.durationMinutes ?? 30, agendaJson, notesJson, decisionsJson, actionItemsJson, input.status ?? "scheduled", ts, ts); - } - return id; - }, - - deleteMeeting(id: string, companyId: string) { - getDb().prepare("delete from meetings where id = ? and company_id = ?").run(id, companyId); - }, - - saveKnowledgeEntry(input: { - id?: string | null; companyId: string; category: string; topic: string; content: string; - authorAgentId?: string | null; importance?: string; tagsJson?: string; - referencedEntityType?: string | null; referencedEntityId?: string | null; - sourceRunId?: string | null; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from knowledge_base where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Knowledge entry ${id} does not belong to company ${input.companyId}`); - } - const tagsJson = canonicalizeJsonString(input.tagsJson, jsonStringArraySchema, []); - if (existing) { - getDb().prepare( - "update knowledge_base set category = ?, topic = ?, content = ?, author_agent_id = ?, importance = ?, tags_json = ?, referenced_entity_type = ?, referenced_entity_id = ?, source_run_id = coalesce(?, source_run_id), updated_at = ? where id = ? and company_id = ?", - ).run(input.category, input.topic, input.content, input.authorAgentId ?? null, input.importance ?? "medium", tagsJson, input.referencedEntityType ?? null, input.referencedEntityId ?? null, input.sourceRunId ?? null, ts, id, input.companyId); - } else { - getDb().prepare( - "insert into knowledge_base (id, company_id, category, topic, content, author_agent_id, importance, tags_json, referenced_entity_type, referenced_entity_id, source_run_id, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ).run(id, input.companyId, input.category, input.topic, input.content, input.authorAgentId ?? null, input.importance ?? "medium", tagsJson, input.referencedEntityType ?? null, input.referencedEntityId ?? null, input.sourceRunId ?? null, ts, ts); - } - return id; - }, - - deleteKnowledgeEntry(id: string, companyId: string) { - getDb().prepare("delete from knowledge_base where id = ? and company_id = ?").run(id, companyId); - }, - - /** - * Returns all knowledge entries for a company, ordered by updated_at desc. - * Used by GET /api/companies/:companyId/knowledge. - */ - listKnowledgeEntries(companyId: string): KnowledgeListRow[] { - return readAll( - "select id, company_id as companyId, category, topic, content, author_agent_id as authorAgentId, importance, tags_json as tagsJson, referenced_entity_type as referencedEntityType, referenced_entity_id as referencedEntityId, created_at as createdAt, updated_at as updatedAt from knowledge_base where company_id = ? order by updated_at desc", - companyId, - ); - }, - - saveSprint(input: { - id?: string | null; companyId: string; name: string; goal?: string; - startDate: string; endDate: string; status?: string; retrospectiveNotes?: string; - velocityPoints?: number; completedPoints?: number; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const existing = getDb().prepare( - "select company_id as companyId from sprints where id = ?", - ).get(id) as { companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new Error(`Sprint ${id} does not belong to company ${input.companyId}`); - } - if (existing) { - getDb().prepare( - "update sprints set name = ?, goal = ?, start_date = ?, end_date = ?, status = ?, retrospective_notes = ?, velocity_points = ?, completed_points = ?, updated_at = ? where id = ? and company_id = ?", - ).run(input.name, input.goal ?? "", input.startDate, input.endDate, input.status ?? "planning", input.retrospectiveNotes ?? "", input.velocityPoints ?? 0, input.completedPoints ?? 0, ts, id, input.companyId); - } else { - getDb().prepare( - "insert into sprints (id, company_id, name, goal, start_date, end_date, status, retrospective_notes, velocity_points, completed_points, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ).run(id, input.companyId, input.name, input.goal ?? "", input.startDate, input.endDate, input.status ?? "planning", input.retrospectiveNotes ?? "", input.velocityPoints ?? 0, input.completedPoints ?? 0, ts, ts); - } - return id; - }, - - deleteSprint(id: string, companyId: string) { - getDb().prepare("delete from sprints where id = ? and company_id = ?").run(id, companyId); - }, - - /** - * Collects the set of deliverable signals produced by a single run. - * Each signal reflects a distinct artifact surface: - * - * - knowledge entry bound to the run (or written during its window) - * - document bound to the run (or written during its window) - * - filesystem `work_product` registered with `created_by_run_id = run` - * - substantial task comment (>100 chars) posted during the run window - * - * The caller in `automation-run-completion` decides which signals are - * acceptable for a given task type, so schema changes to any of the - * source tables surface here rather than in an opaque boolean. - */ - collectRunDeliverableSignals( - runId: string, - companyId: string, - taskId: string, - ): { - hasKnowledgeEntry: boolean; - hasDocument: boolean; - hasWorkProduct: boolean; - hasSubstantialComment: boolean; - } { - const causalKnowledge = readAll<{ id: string }>( - "select id from knowledge_base where company_id = ? and source_run_id = ? limit 1", - companyId, runId, - ); - const legacyKnowledge = causalKnowledge.length === 0 - ? readAll<{ id: string }>( - "select id from knowledge_base where company_id = ? and source_run_id is null and created_at >= (select started_at from runs where id = ?) limit 1", - companyId, runId, - ) - : []; - - const causalDocs = readAll<{ id: string }>( - "select id from documents where company_id = ? and source_run_id = ? limit 1", - companyId, runId, - ); - const legacyDocs = causalDocs.length === 0 - ? readAll<{ id: string }>( - "select id from documents where company_id = ? and source_run_id is null and created_at >= (select started_at from runs where id = ?) limit 1", - companyId, runId, - ) - : []; - - // Pre-v45 provenance was frozen at creation; post-v45 every upsert - // refreshes `last_touched_by_run_id`. Querying by either side keeps - // the deliverable signal correct for a run that edited a pre-existing - // work product as well as a run that created a new one. - // - // `status <> 'archived'` excludes retirement tombstones: a run - // whose only filesystem action was deleting the file stamps - // `last_touched_by_run_id` onto the archived row, and without - // this filter the deliverable gate would count the removal as a - // produced artifact and let the task advance to review. - const workProducts = readAll<{ id: string }>( - "select id from work_products where company_id = ? and status <> 'archived' and (last_touched_by_run_id = ? or created_by_run_id = ?) limit 1", - companyId, runId, runId, - ); - - const recentComments = readAll<{ body: string }>( - "select body from task_comments where task_id = ? and created_at >= (select started_at from runs where id = ?) and length(body) > 100", - taskId, runId, - ); - - return { - hasKnowledgeEntry: causalKnowledge.length > 0 || legacyKnowledge.length > 0, - hasDocument: causalDocs.length > 0 || legacyDocs.length > 0, - hasWorkProduct: workProducts.length > 0, - hasSubstantialComment: recentComments.length > 0, - }; - }, - - /** - * Returns all sprints for a company, ordered by start_date desc. - * Used by GET /api/companies/:companyId/sprints. - */ - listSprints(companyId: string): SprintListRow[] { - return readAll( - "select id, company_id as companyId, name, goal, start_date as startDate, end_date as endDate, status, retrospective_notes as retrospectiveNotes, velocity_points as velocityPoints, completed_points as completedPoints, created_at as createdAt, updated_at as updatedAt from sprints where company_id = ? order by start_date desc", - companyId, - ); - }, - }; -} diff --git a/src/main/database/messages.ts b/src/main/database/messages.ts deleted file mode 100644 index 8de63874..00000000 --- a/src/main/database/messages.ts +++ /dev/null @@ -1,409 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { AgentMessageRecord, AgentRecord } from "@shared/types"; -import { normalizeMarkdownText } from "@shared/markdown-text"; -import { - BOARD_READER_ID, - type ReadAll, - type Transaction, - nowIso, -} from "./helpers"; - -export function buildMessageMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - deps: { - getAgent: (id: string) => AgentRecord; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - transaction: Transaction; - }, -) { - /** Write the @mention fan-out rows for a freshly-persisted message. - * Idempotent: the primary key is (message_id, agent_id), so a retry - * driven by a steer/wake race never duplicates rows. Skipping the - * sender keeps self-mentions out of the join so an agent talking - * about itself ("cc @me …") cannot inflate its own inbox. */ - function insertMessageMentions( - messageId: string, - companyId: string, - fromAgentId: string, - mentionedAgentIds: Iterable, - createdAt: string, - ): void { - const stmt = getDb().prepare( - "insert or ignore into agent_message_mentions (message_id, agent_id, company_id, created_at) values (?, ?, ?, ?)", - ); - for (const agentId of mentionedAgentIds) { - if (!agentId || agentId === fromAgentId || agentId === BOARD_READER_ID) continue; - stmt.run(messageId, agentId, companyId, createdAt); - } - } - return { - sendAgentMessage(input: { - companyId: string; - fromAgentId: string; - toAgentId?: string | null; - channel?: string; - channelTargetId?: string | null; - subject: string; - body: string; - priority?: string; - parentMessageId?: string | null; - attachmentsJson?: string; - senderKind?: "agent" | "human" | "system"; - /** Agent IDs parsed out of the body's @mentions. Persisted into - * `agent_message_mentions` alongside the row so the inbox queries - * can surface the message to mentioned agents without re-parsing - * every body at read time. Empty / absent = no mention fan-out. */ - mentionedAgentIds?: readonly string[]; - }): string { - const channel = input.channel ?? "direct"; - if (channel === "direct" && !input.toAgentId) { - throw new Error("Direct messages require a recipient."); - } - if (channel === "direct" && input.toAgentId === input.fromAgentId) { - throw new Error("Direct messages require two distinct participants."); - } - const senderKind = input.senderKind - ?? (input.fromAgentId === BOARD_READER_ID ? "human" : "agent"); - const body = normalizeMarkdownText(input.body); - const id = randomUUID(); - const createdAt = nowIso(); - // Single transaction: the row, its self-read receipt, and its - // mention fan-out must land atomically. The self-read receipt - // makes "author has read their own message" an invariant in the - // join table — without it, every message a sender posts inflates - // their own sidebar / inbox / channel unread counts until they - // happen to re-open the channel, because `readAt` is derived from - // `agent_message_reads` per viewer. - deps.transaction(() => { - getDb() - .prepare( - "insert into agent_messages (id, company_id, from_agent_id, to_agent_id, sender_kind, channel, channel_target_id, subject, body, priority, parent_message_id, attachments_json, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run( - id, - input.companyId, - input.fromAgentId, - input.toAgentId ?? null, - senderKind, - channel, - input.channelTargetId ?? null, - input.subject, - body, - input.priority ?? "normal", - input.parentMessageId ?? null, - input.attachmentsJson ?? "[]", - createdAt, - ); - getDb() - .prepare( - "insert into agent_message_reads (message_id, agent_id, read_at) values (?, ?, ?)", - ) - .run(id, input.fromAgentId, createdAt); - if (input.mentionedAgentIds && input.mentionedAgentIds.length > 0) { - insertMessageMentions(id, input.companyId, input.fromAgentId, input.mentionedAgentIds, createdAt); - } - }); - deps.addActivity({ - companyId: input.companyId, - actor: input.fromAgentId, - action: "sent_message", - entityType: "agent_message", - entityId: id, - detail: `Message: ${input.subject}`, - }); - return id; - }, - - getAgentMessage(messageId: string, companyId: string): AgentMessageRecord | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, from_agent_id as fromAgentId, to_agent_id as toAgentId, sender_kind as senderKind, channel, channel_target_id as channelTargetId, subject, body, priority, parent_message_id as parentMessageId, attachments_json as attachmentsJson, created_at as createdAt from agent_messages where id = ? and company_id = ?", - ) - .get(messageId, companyId) as Omit | undefined; - if (!row) return null; - // `readAt` is a per-viewer computed field resolved from - // agent_message_reads at the callers that need it (inbox - // projection, renderer snapshot). This single-row lookup has no - // viewer context, so the field is surfaced as `null`. - return { ...row, readAt: null }; - }, - - listAgentMessages( - companyId: string, - opts?: { - agentId?: string; - messageId?: string; - channel?: string; - channelTargetId?: string | null; - unreadOnly?: boolean; - limit?: number; - }, - ): AgentMessageRecord[] { - const limit = opts?.limit ?? 200; - // `readAt` is resolved from `agent_message_reads` further down, - // per viewer (BOARD_READER_ID for the operator-wide path, the - // specific agent id for the per-agent path). The column lives - // outside the row itself since v49. - const selectCols = - "select id, company_id as companyId, from_agent_id as fromAgentId, to_agent_id as toAgentId, sender_kind as senderKind, channel, channel_target_id as channelTargetId, subject, body, priority, parent_message_id as parentMessageId, attachments_json as attachmentsJson, created_at as createdAt from agent_messages"; - let sql = `${selectCols} where company_id = ?`; - const params: SQLInputValue[] = [companyId]; - if (opts?.messageId) { - sql += " and id = ?"; - params.push(opts.messageId); - } - if (opts?.channel) { - sql += " and channel = ?"; - params.push(opts.channel); - } - if (opts?.channelTargetId !== undefined && opts?.channelTargetId !== null) { - sql += " and channel_target_id = ?"; - params.push(opts.channelTargetId); - } - - if (!opts?.agentId) { - sql += " order by created_at desc"; - if (limit > 0) { - sql += " limit ?"; - params.push(limit); - } - const rows = readAll>(sql, ...params).reverse(); - const boardReadReceiptMap = new Map( - readAll<{ messageId: string; readAt: string }>( - `select reads.message_id as messageId, reads.read_at as readAt - from agent_message_reads reads - join agent_messages messages on messages.id = reads.message_id - where reads.agent_id = ? and messages.company_id = ?`, - BOARD_READER_ID, - companyId, - ).map((row) => [row.messageId, row.readAt]), - ); - let result = rows.map((message) => ({ - ...message, - readAt: boardReadReceiptMap.get(message.id) ?? null, - })); - if (opts?.unreadOnly) { - result = result.filter((message) => !message.readAt); - } - return result; - } - - let department: string | null = null; - try { - const agent = deps.getAgent(opts.agentId); - if (agent.companyId === companyId) { - department = agent.department; - } - } catch (err) { - log.warn(`[database/messages] getAgent failed for ${opts.agentId}; department filter disabled:`, err instanceof Error ? err.message : String(err)); - department = null; - } - - const relevantProjectIds = new Set(); - for (const row of readAll<{ projectId: string | null }>( - "select distinct project_id as projectId from tasks where company_id = ? and assignee_agent_id = ? and project_id is not null", - companyId, - opts.agentId, - )) { - if (row.projectId) relevantProjectIds.add(row.projectId); - } - for (const row of readAll<{ id: string }>( - "select id from projects where company_id = ? and lead_agent_id = ?", - companyId, - opts.agentId, - )) { - relevantProjectIds.add(row.id); - } - - const visibilityClauses: string[] = [ - "from_agent_id = ?", - "(channel = 'direct' and to_agent_id = ?)", - "channel in ('company','incident')", - "id in (select message_id from agent_message_mentions where agent_id = ? and company_id = ?)", - ]; - const visibilityParams: SQLInputValue[] = [opts.agentId, opts.agentId, opts.agentId, companyId]; - if (department) { - visibilityClauses.push("(channel = 'department' and channel_target_id = ?)"); - visibilityParams.push(department); - } - if (relevantProjectIds.size > 0) { - const placeholders = Array.from(relevantProjectIds).map(() => "?").join(","); - visibilityClauses.push(`(channel = 'project' and channel_target_id in (${placeholders}))`); - visibilityParams.push(...Array.from(relevantProjectIds)); - } - sql += ` and (${visibilityClauses.join(" or ")})`; - params.push(...visibilityParams); - sql += " order by created_at desc"; - if (limit > 0) { - sql += " limit ?"; - params.push(limit); - } - const rows = readAll>(sql, ...params).reverse(); - - const readReceiptMap = new Map( - readAll<{ messageId: string; readAt: string }>( - `select reads.message_id as messageId, reads.read_at as readAt - from agent_message_reads reads - join agent_messages messages on messages.id = reads.message_id - where reads.agent_id = ? and messages.company_id = ?`, - opts.agentId, - companyId, - ).map((row) => [row.messageId, row.readAt]), - ); - - let messages = rows.map((message) => { - if (message.fromAgentId === opts.agentId) { - return { ...message, readAt: message.createdAt }; - } - return { - ...message, - readAt: readReceiptMap.get(message.id) ?? null, - }; - }); - if (opts?.unreadOnly) { - messages = messages.filter((message) => !message.readAt); - } - return messages; - }, - - searchMessages( - companyId: string, - query: string, - opts?: { - channel?: string; - channelTargetId?: string | null; - limit?: number; - }, - ): AgentMessageRecord[] { - const escaped = query.replace(/[\\%_]/g, "\\$&"); - const pattern = `%${escaped}%`; - let sql = `SELECT id, company_id AS companyId, from_agent_id AS fromAgentId, - to_agent_id AS toAgentId, sender_kind AS senderKind, channel, channel_target_id AS channelTargetId, - subject, body, priority, parent_message_id AS parentMessageId, - attachments_json AS attachmentsJson, created_at AS createdAt - FROM agent_messages WHERE company_id = ? AND (subject LIKE ? ESCAPE '\\' OR body LIKE ? ESCAPE '\\')`; - const params: SQLInputValue[] = [companyId, pattern, pattern]; - if (opts?.channel) { - sql += " AND channel = ?"; - params.push(opts.channel); - } - if (opts?.channelTargetId !== undefined && opts?.channelTargetId !== null) { - sql += " AND channel_target_id = ?"; - params.push(opts.channelTargetId); - } - sql += " ORDER BY created_at DESC LIMIT ?"; - params.push(opts?.limit ?? 50); - // Operator-facing search has no viewer context — `readAt` is - // surfaced as `null`. Callers that need per-viewer read state - // pull it from `agent_message_reads` separately (inbox projection, - // snapshot). - return readAll>(sql, ...params).map((row) => ({ ...row, readAt: null })); - }, - - markMessageReadForReader( - messageId: string, - companyId: string, - readerAgentId?: string | null, - ): void { - const ts = nowIso(); - getDb() - .prepare( - `insert into agent_message_reads (message_id, agent_id, read_at) - select id, ?, ? - from agent_messages - where id = ? and company_id = ? - on conflict(message_id, agent_id) do update set read_at = excluded.read_at`, - ) - .run(readerAgentId ?? BOARD_READER_ID, ts, messageId, companyId); - }, - - /** - * List unread inbox messages for an agent, chronologically oldest-first, - * for pi-native transcript injection. Uses the same channel-subscription - * visibility rules as listAgentMessages (direct/company/incident always, - * department when agent belongs, project when assigned/lead). - * - * "Unread" is defined uniformly across every channel: no row in - * `agent_message_reads` for (message_id, agent_id). The row's - * `readAt` field is always `null` here because callers want the - * unread set — per-viewer read state lives exclusively in the - * `agent_message_reads` join table since v49 dropped the redundant - * `agent_messages.read_at` column. - * - * Messages where `from_agent_id = agentId` are excluded (agents don't - * inject their own sent messages back into their transcript). - */ - listAgentInboxUnread(companyId: string, agentId: string): AgentMessageRecord[] { - let department: string | null = null; - try { - const agent = deps.getAgent(agentId); - if (agent.companyId === companyId) { - department = agent.department; - } - } catch (err) { - log.warn(`[database/messages] getAgent failed for ${agentId} in listAgentInboxUnread; department filter disabled:`, err instanceof Error ? err.message : String(err)); - department = null; - } - - const relevantProjectIds = new Set(); - for (const row of readAll<{ projectId: string | null }>( - "select distinct project_id as projectId from tasks where company_id = ? and assignee_agent_id = ? and project_id is not null", - companyId, - agentId, - )) { - if (row.projectId) relevantProjectIds.add(row.projectId); - } - for (const row of readAll<{ id: string }>( - "select id from projects where company_id = ? and lead_agent_id = ?", - companyId, - agentId, - )) { - relevantProjectIds.add(row.id); - } - - const visibilityClauses: string[] = [ - "(channel = 'direct' and to_agent_id = ?)", - "channel in ('company','incident')", - // @mention fan-out: a DM addressed to someone else still lands - // in my inbox when I'm mentioned in the body, because the - // dispatcher persisted (message_id, agent_id) into - // `agent_message_mentions` at write time. Without this clause a - // "@CEO please update" inside a human ↔ engineer chat woke CEO - // with an empty inbox and produced silence instead of a reply. - "id in (select message_id from agent_message_mentions where agent_id = ? and company_id = ?)", - ]; - const visibilityParams: SQLInputValue[] = [agentId, agentId, companyId]; - if (department) { - visibilityClauses.push("(channel = 'department' and channel_target_id = ?)"); - visibilityParams.push(department); - } - if (relevantProjectIds.size > 0) { - const placeholders = Array.from(relevantProjectIds).map(() => "?").join(","); - visibilityClauses.push(`(channel = 'project' and channel_target_id in (${placeholders}))`); - visibilityParams.push(...Array.from(relevantProjectIds)); - } - - const selectCols = - "select id, company_id as companyId, from_agent_id as fromAgentId, to_agent_id as toAgentId, sender_kind as senderKind, channel, channel_target_id as channelTargetId, subject, body, priority, parent_message_id as parentMessageId, attachments_json as attachmentsJson, created_at as createdAt from agent_messages"; - const sql = `${selectCols} where company_id = ? and from_agent_id != ? and (${visibilityClauses.join(" or ")}) order by created_at asc`; - const rows = readAll>(sql, companyId, agentId, ...visibilityParams).map((row) => ({ ...row, readAt: null })); - - const readIds = new Set( - readAll<{ messageId: string }>( - `select reads.message_id as messageId - from agent_message_reads reads - join agent_messages messages on messages.id = reads.message_id - where reads.agent_id = ? and messages.company_id = ?`, - agentId, - companyId, - ).map((row) => row.messageId), - ); - - return rows.filter((message) => !readIds.has(message.id)); - }, - - }; -} diff --git a/AgentCompany-New/src/main/database/migrations/001-initial.ts b/src/main/database/migrations/001-initial.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/001-initial.ts rename to src/main/database/migrations/001-initial.ts diff --git a/AgentCompany-New/src/main/database/migrations/002-collaboration.ts b/src/main/database/migrations/002-collaboration.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/002-collaboration.ts rename to src/main/database/migrations/002-collaboration.ts diff --git a/AgentCompany-New/src/main/database/migrations/003-onboarding.ts b/src/main/database/migrations/003-onboarding.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/003-onboarding.ts rename to src/main/database/migrations/003-onboarding.ts diff --git a/AgentCompany-New/src/main/database/migrations/004-files-posts.ts b/src/main/database/migrations/004-files-posts.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/004-files-posts.ts rename to src/main/database/migrations/004-files-posts.ts diff --git a/AgentCompany-New/src/main/database/migrations/005-chat-read-state.ts b/src/main/database/migrations/005-chat-read-state.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/005-chat-read-state.ts rename to src/main/database/migrations/005-chat-read-state.ts diff --git a/AgentCompany-New/src/main/database/migrations/006-app-state.ts b/src/main/database/migrations/006-app-state.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/006-app-state.ts rename to src/main/database/migrations/006-app-state.ts diff --git a/AgentCompany-New/src/main/database/migrations/007-skill-hardening.ts b/src/main/database/migrations/007-skill-hardening.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/007-skill-hardening.ts rename to src/main/database/migrations/007-skill-hardening.ts diff --git a/AgentCompany-New/src/main/database/migrations/008-provider-health.ts b/src/main/database/migrations/008-provider-health.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/008-provider-health.ts rename to src/main/database/migrations/008-provider-health.ts diff --git a/AgentCompany-New/src/main/database/migrations/009-social-governance.ts b/src/main/database/migrations/009-social-governance.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/009-social-governance.ts rename to src/main/database/migrations/009-social-governance.ts diff --git a/AgentCompany-New/src/main/database/migrations/010-file-handoff-security.ts b/src/main/database/migrations/010-file-handoff-security.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/010-file-handoff-security.ts rename to src/main/database/migrations/010-file-handoff-security.ts diff --git a/AgentCompany-New/src/main/database/migrations/011-board-interventions.ts b/src/main/database/migrations/011-board-interventions.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/011-board-interventions.ts rename to src/main/database/migrations/011-board-interventions.ts diff --git a/AgentCompany-New/src/main/database/migrations/012-compliance-controls.ts b/src/main/database/migrations/012-compliance-controls.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/012-compliance-controls.ts rename to src/main/database/migrations/012-compliance-controls.ts diff --git a/AgentCompany-New/src/main/database/migrations/013-search-documents.ts b/src/main/database/migrations/013-search-documents.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/013-search-documents.ts rename to src/main/database/migrations/013-search-documents.ts diff --git a/AgentCompany-New/src/main/database/migrations/014-provider-policy-usage.ts b/src/main/database/migrations/014-provider-policy-usage.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/014-provider-policy-usage.ts rename to src/main/database/migrations/014-provider-policy-usage.ts diff --git a/AgentCompany-New/src/main/database/migrations/015-identity-access.ts b/src/main/database/migrations/015-identity-access.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/015-identity-access.ts rename to src/main/database/migrations/015-identity-access.ts diff --git a/AgentCompany-New/src/main/database/migrations/016-org-governance.ts b/src/main/database/migrations/016-org-governance.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/016-org-governance.ts rename to src/main/database/migrations/016-org-governance.ts diff --git a/AgentCompany-New/src/main/database/migrations/017-operations-controls.ts b/src/main/database/migrations/017-operations-controls.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/017-operations-controls.ts rename to src/main/database/migrations/017-operations-controls.ts diff --git a/AgentCompany-New/src/main/database/migrations/018-sdlc-controls.ts b/src/main/database/migrations/018-sdlc-controls.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/018-sdlc-controls.ts rename to src/main/database/migrations/018-sdlc-controls.ts diff --git a/AgentCompany-New/src/main/database/migrations/019-audit-replay.ts b/src/main/database/migrations/019-audit-replay.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/019-audit-replay.ts rename to src/main/database/migrations/019-audit-replay.ts diff --git a/AgentCompany-New/src/main/database/migrations/020-rollback-snapshots.ts b/src/main/database/migrations/020-rollback-snapshots.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/020-rollback-snapshots.ts rename to src/main/database/migrations/020-rollback-snapshots.ts diff --git a/AgentCompany-New/src/main/database/migrations/021-provider-auth-broker.ts b/src/main/database/migrations/021-provider-auth-broker.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/021-provider-auth-broker.ts rename to src/main/database/migrations/021-provider-auth-broker.ts diff --git a/AgentCompany-New/src/main/database/migrations/022-provider-rate-limit-observations.ts b/src/main/database/migrations/022-provider-rate-limit-observations.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/022-provider-rate-limit-observations.ts rename to src/main/database/migrations/022-provider-rate-limit-observations.ts diff --git a/AgentCompany-New/src/main/database/migrations/023-provider-request-runtime.ts b/src/main/database/migrations/023-provider-request-runtime.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/023-provider-request-runtime.ts rename to src/main/database/migrations/023-provider-request-runtime.ts diff --git a/AgentCompany-New/src/main/database/migrations/024-task-run-provider-request.ts b/src/main/database/migrations/024-task-run-provider-request.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/024-task-run-provider-request.ts rename to src/main/database/migrations/024-task-run-provider-request.ts diff --git a/AgentCompany-New/src/main/database/migrations/025-chat-message-delivery.ts b/src/main/database/migrations/025-chat-message-delivery.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/025-chat-message-delivery.ts rename to src/main/database/migrations/025-chat-message-delivery.ts diff --git a/AgentCompany-New/src/main/database/migrations/026-browser-platform-governance.ts b/src/main/database/migrations/026-browser-platform-governance.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/026-browser-platform-governance.ts rename to src/main/database/migrations/026-browser-platform-governance.ts diff --git a/AgentCompany-New/src/main/database/migrations/027-social-audit-records.ts b/src/main/database/migrations/027-social-audit-records.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/027-social-audit-records.ts rename to src/main/database/migrations/027-social-audit-records.ts diff --git a/AgentCompany-New/src/main/database/migrations/028-migration-cutover-journal.ts b/src/main/database/migrations/028-migration-cutover-journal.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/028-migration-cutover-journal.ts rename to src/main/database/migrations/028-migration-cutover-journal.ts diff --git a/AgentCompany-New/src/main/database/migrations/029-file-handoff-records.ts b/src/main/database/migrations/029-file-handoff-records.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/029-file-handoff-records.ts rename to src/main/database/migrations/029-file-handoff-records.ts diff --git a/AgentCompany-New/src/main/database/migrations/030-approval-source-refs.ts b/src/main/database/migrations/030-approval-source-refs.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/030-approval-source-refs.ts rename to src/main/database/migrations/030-approval-source-refs.ts diff --git a/AgentCompany-New/src/main/database/migrations/031-provider-request-workspace.ts b/src/main/database/migrations/031-provider-request-workspace.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/031-provider-request-workspace.ts rename to src/main/database/migrations/031-provider-request-workspace.ts diff --git a/AgentCompany-New/src/main/database/migrations/032-browser-action-metadata.ts b/src/main/database/migrations/032-browser-action-metadata.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/032-browser-action-metadata.ts rename to src/main/database/migrations/032-browser-action-metadata.ts diff --git a/AgentCompany-New/src/main/database/migrations/033-audit-event-immutability.ts b/src/main/database/migrations/033-audit-event-immutability.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/033-audit-event-immutability.ts rename to src/main/database/migrations/033-audit-event-immutability.ts diff --git a/AgentCompany-New/src/main/database/migrations/034-provider-auth-sessions.ts b/src/main/database/migrations/034-provider-auth-sessions.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/034-provider-auth-sessions.ts rename to src/main/database/migrations/034-provider-auth-sessions.ts diff --git a/AgentCompany-New/src/main/database/migrations/035-task-run-isolation.ts b/src/main/database/migrations/035-task-run-isolation.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/035-task-run-isolation.ts rename to src/main/database/migrations/035-task-run-isolation.ts diff --git a/AgentCompany-New/src/main/database/migrations/036-additional-connectors.ts b/src/main/database/migrations/036-additional-connectors.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/036-additional-connectors.ts rename to src/main/database/migrations/036-additional-connectors.ts diff --git a/AgentCompany-New/src/main/database/migrations/037-custom-providers.ts b/src/main/database/migrations/037-custom-providers.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/037-custom-providers.ts rename to src/main/database/migrations/037-custom-providers.ts diff --git a/AgentCompany-New/src/main/database/migrations/038-provider-auth-profile-cascade.ts b/src/main/database/migrations/038-provider-auth-profile-cascade.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/038-provider-auth-profile-cascade.ts rename to src/main/database/migrations/038-provider-auth-profile-cascade.ts diff --git a/AgentCompany-New/src/main/database/migrations/039-audit-immutability-org-teardown.ts b/src/main/database/migrations/039-audit-immutability-org-teardown.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/039-audit-immutability-org-teardown.ts rename to src/main/database/migrations/039-audit-immutability-org-teardown.ts diff --git a/AgentCompany-New/src/main/database/migrations/040-documents-knowledge-automation.ts b/src/main/database/migrations/040-documents-knowledge-automation.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/040-documents-knowledge-automation.ts rename to src/main/database/migrations/040-documents-knowledge-automation.ts diff --git a/AgentCompany-New/src/main/database/migrations/041-task-subtasks-delete.ts b/src/main/database/migrations/041-task-subtasks-delete.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/041-task-subtasks-delete.ts rename to src/main/database/migrations/041-task-subtasks-delete.ts diff --git a/AgentCompany-New/src/main/database/migrations/042-approval-notes-meetings-sprints.ts b/src/main/database/migrations/042-approval-notes-meetings-sprints.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/042-approval-notes-meetings-sprints.ts rename to src/main/database/migrations/042-approval-notes-meetings-sprints.ts diff --git a/AgentCompany-New/src/main/database/migrations/043-composio-integration.ts b/src/main/database/migrations/043-composio-integration.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/043-composio-integration.ts rename to src/main/database/migrations/043-composio-integration.ts diff --git a/AgentCompany-New/src/main/database/migrations/044-mention-wake-state.ts b/src/main/database/migrations/044-mention-wake-state.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/044-mention-wake-state.ts rename to src/main/database/migrations/044-mention-wake-state.ts diff --git a/AgentCompany-New/src/main/database/migrations/045-connector-grants.ts b/src/main/database/migrations/045-connector-grants.ts similarity index 100% rename from AgentCompany-New/src/main/database/migrations/045-connector-grants.ts rename to src/main/database/migrations/045-connector-grants.ts diff --git a/src/main/database/migrations/baseline-v56.ts b/src/main/database/migrations/baseline-v56.ts deleted file mode 100644 index f28801aa..00000000 --- a/src/main/database/migrations/baseline-v56.ts +++ /dev/null @@ -1,263 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; - -export const BASELINE_SCHEMA_VERSION = 56; -export const BASELINE_SCHEMA_NAME = "baseline_v56"; - -export const BASELINE_TABLE_SQL = [ - "CREATE TABLE activity (id text primary key, company_id text not null, actor text not null, action text not null, entity_type text not null, entity_id text not null, detail text not null, created_at text not null)", - "CREATE TABLE agent_config_revisions (id TEXT PRIMARY KEY, company_id TEXT NOT NULL, agent_id TEXT NOT NULL, revision_number INTEGER NOT NULL, changed_keys TEXT NOT NULL DEFAULT '[]', config_before TEXT NOT NULL, config_after TEXT NOT NULL, source TEXT NOT NULL DEFAULT 'patch', rolled_back_from_revision_id TEXT, created_by_agent_id TEXT, created_by_user_id TEXT, created_at TEXT NOT NULL, FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE)", - "CREATE TABLE agent_message_mentions (\n message_id TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n company_id TEXT NOT NULL,\n created_at TEXT NOT NULL,\n PRIMARY KEY (message_id, agent_id)\n )", - "CREATE TABLE agent_message_projections (\n message_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n projected_at TEXT NOT NULL,\n PRIMARY KEY (message_id, session_id)\n )", - "CREATE TABLE agent_message_reads (message_id text not null, agent_id text not null, read_at text not null, primary key (message_id, agent_id))", - "CREATE TABLE agent_messages (id text primary key, company_id text not null, from_agent_id text not null, to_agent_id text, channel text not null default 'direct', channel_target_id text, subject text not null, body text not null, priority text not null default 'normal', parent_message_id text, attachments_json text not null default '[]', created_at text not null, sender_kind TEXT NOT NULL DEFAULT 'agent')", - "CREATE TABLE agent_skill_assignments (agent_id TEXT NOT NULL, skill_id TEXT NOT NULL, created_at TEXT NOT NULL, PRIMARY KEY (agent_id, skill_id), FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE, FOREIGN KEY (skill_id) REFERENCES company_skills(id) ON DELETE CASCADE)", - "CREATE TABLE agents (id text primary key, company_id text not null, name text not null, role text not null, title text not null, status text not null, reports_to text, connector_id text not null, workspace_id text, model text, capabilities text not null, budget_monthly_usd real not null default 0, spent_monthly_usd real not null default 0, metadata_json text not null default '{}', created_at text not null, updated_at text not null, department text, permissions_json TEXT NOT NULL DEFAULT '{}', heartbeat_policy_json TEXT, runtime_state_json TEXT, role_level TEXT NOT NULL DEFAULT 'ic', session_id TEXT, model_strategy TEXT NOT NULL DEFAULT 'explicit', heartbeat_enabled integer not null default 0, heartbeat_interval_sec integer not null default 120, last_heartbeat_at text)", - "CREATE TABLE 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 TABLE approvals (id text primary key, company_id text not null, related_task_id text, requested_by_agent_id text, type text not null, payload_summary text not null, impact_summary text not null, payload_json text, decision_note text not null default '', state text not null, created_at text not null, updated_at text not null, related_agent_id text)", - "CREATE TABLE automation_log (id text primary key, company_id text not null, rule_id text not null, rule_name text not null, trigger text not null, action text not null, detail text not null default '', executed_at text not null)", - "CREATE TABLE automation_rules (id text primary key, company_id text not null, name text not null, description text not null default '', trigger text not null, conditions_json text not null default '{}', action text not null, action_config_json text not null default '{}', source_department text, target_department text, priority integer not null default 50, status text not null default 'active', execution_count integer not null default 0, last_executed_at text, created_at text not null, updated_at text not null)", - "CREATE TABLE browser_actions (id text primary key, company_id text not null references companies(id) on delete cascade, social_account_id text not null references social_accounts(id) on delete cascade, agent_id text not null references agents(id) on delete cascade, task_id text, action_type text not null default 'custom_script', payload_json text not null default '{}', status text not null default 'queued', result_summary text not null default '', screenshot_path text, approval_id text, error_message text, started_at text, finished_at text, created_at text not null default (datetime('now')), updated_at text not null default (datetime('now')))", - "CREATE TABLE budget_incidents (id TEXT PRIMARY KEY, company_id TEXT NOT NULL, policy_id TEXT NOT NULL REFERENCES budget_policies(id), scope_type TEXT NOT NULL, scope_id TEXT NOT NULL, metric TEXT NOT NULL, window_kind TEXT NOT NULL, window_start TEXT NOT NULL, window_end TEXT NOT NULL, threshold_type TEXT NOT NULL, amount_limit INTEGER NOT NULL, amount_observed INTEGER NOT NULL, status TEXT NOT NULL DEFAULT 'open', resolved_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL)", - "CREATE TABLE budget_policies (id TEXT PRIMARY KEY, company_id TEXT NOT NULL, scope_type TEXT NOT NULL, scope_id TEXT NOT NULL, metric TEXT NOT NULL DEFAULT 'billed_cents', window_kind TEXT NOT NULL DEFAULT 'calendar_month_utc', amount INTEGER NOT NULL DEFAULT 0, warn_percent INTEGER NOT NULL DEFAULT 80, hard_stop_enabled INTEGER NOT NULL DEFAULT 1, notify_enabled INTEGER NOT NULL DEFAULT 1, is_active INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL)", - "CREATE TABLE companies (id text primary key, name text not null, description text not null, status text not null, created_at text not null, updated_at text not null, auto_approve_hires integer not null default 0, review_deliverables integer not null default 0, execution_mode text not null default 'ai_ceo')", - "CREATE TABLE \"company_skills\" (id TEXT PRIMARY KEY, company_id TEXT NOT NULL, key TEXT NOT NULL, slug TEXT NOT NULL, name TEXT NOT NULL, description TEXT, source_type TEXT NOT NULL DEFAULT 'local_path', source_locator TEXT, source_ref TEXT, trust_level TEXT NOT NULL DEFAULT 'markdown_only', compatibility TEXT NOT NULL DEFAULT 'compatible', file_inventory TEXT NOT NULL DEFAULT '[]', metadata TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL)", - "CREATE TABLE connector_model_pool_settings (\n company_id TEXT NOT NULL,\n connector_id TEXT NOT NULL,\n disabled_models_json TEXT NOT NULL DEFAULT '[]',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (company_id, connector_id),\n FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE\n )", - "CREATE TABLE connectors (id text primary key, label text not null, description text not null, status text not null, command text not null, version text, auth_state text not null, last_checked_at text, last_error text, model text, env_binding_text text not null, notes text not null, updated_at text, capability_json text)", - "CREATE TABLE conversation_events (\n id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL REFERENCES conversation_threads(id) ON DELETE CASCADE,\n actor_id TEXT NOT NULL,\n actor_type TEXT NOT NULL,\n event_type TEXT NOT NULL,\n body TEXT NOT NULL,\n metadata_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL\n )", - "CREATE TABLE conversation_participants (\n thread_id TEXT NOT NULL REFERENCES conversation_threads(id) ON DELETE CASCADE,\n participant_id TEXT NOT NULL,\n participant_type TEXT NOT NULL,\n role TEXT NOT NULL DEFAULT 'member',\n joined_at TEXT NOT NULL,\n PRIMARY KEY (thread_id, participant_id)\n )", - "CREATE TABLE conversation_threads (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n title TEXT NOT NULL,\n type TEXT NOT NULL DEFAULT 'task',\n related_entity_type TEXT,\n related_entity_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )", - "CREATE TABLE cost_entries (id text primary key, company_id text not null, run_id text not null, task_id text, agent_id text, connector_id text not null, amount_usd real, unattributed integer not null default 0, created_at text not null, project_id TEXT)", - "CREATE TABLE credentials (\n connector_id TEXT PRIMARY KEY,\n kind TEXT NOT NULL,\n backend TEXT NOT NULL,\n ciphertext BLOB NOT NULL,\n display_hint TEXT NOT NULL DEFAULT '',\n status TEXT NOT NULL DEFAULT 'active',\n expires_at TEXT,\n last_refreshed_at TEXT,\n last_error TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )", - "CREATE TABLE document_lifecycle_events (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n document_id TEXT NOT NULL,\n hook_type TEXT NOT NULL,\n status TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n last_error TEXT,\n payload_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n completed_at TEXT\n )", - "CREATE TABLE 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 TABLE documents (id text primary key, company_id text not null, type text not null, title text not null, content text not null default '', author_agent_id text, reviewer_agent_id text, project_id text, goal_id text, parent_doc_id text, version integer not null default 1, status text not null default 'draft', tags_json text not null default '[]', created_at text not null, updated_at text not null, latest_revision_id TEXT, source_run_id TEXT)", - "CREATE TABLE goals (id text primary key, company_id text not null, title text not null, description text not null, parent_id text, owner_agent_id text, status text not null, created_at text not null, updated_at text not null)", - "CREATE TABLE knowledge_base (id text primary key, company_id text not null, category text not null, topic text not null, content text not null, author_agent_id text, importance text not null default 'medium', tags_json text not null default '[]', referenced_entity_type text, referenced_entity_id text, created_at text not null, updated_at text not null, source_run_id TEXT)", - "CREATE TABLE meetings (id text primary key, company_id text not null, type text not null, title text not null, organizer_agent_id text, participant_agent_ids text not null default '[]', scheduled_at text not null, duration_minutes integer not null default 30, agenda_json text not null default '[]', notes_json text not null default '[]', decisions_json text not null default '[]', action_items_json text not null default '[]', status text not null default 'scheduled', created_at text not null, updated_at text not null)", - "CREATE TABLE model_capabilities (\n provider TEXT NOT NULL,\n model_id TEXT NOT NULL,\n reasoning INTEGER NOT NULL,\n coding INTEGER NOT NULL,\n writing INTEGER NOT NULL,\n tier TEXT NOT NULL,\n cost_per_mtok_out REAL NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (provider, model_id)\n )", - "CREATE TABLE projects (id text primary key, company_id text not null, goal_id text, name text not null, description text not null, lead_agent_id text, status text not null, target_date text, created_at text not null, updated_at text not null)", - "CREATE TABLE run_events (id INTEGER PRIMARY KEY AUTOINCREMENT, company_id TEXT NOT NULL, run_id TEXT NOT NULL, agent_id TEXT NOT NULL, seq INTEGER NOT NULL, event_type TEXT NOT NULL, stream TEXT, level TEXT, message TEXT, payload TEXT, created_at TEXT NOT NULL, FOREIGN KEY (run_id) REFERENCES runs(id) ON DELETE CASCADE)", - "CREATE TABLE \"runs\" (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n task_id TEXT,\n agent_id TEXT NOT NULL,\n workspace_id TEXT,\n connector_id TEXT NOT NULL,\n status TEXT NOT NULL,\n summary TEXT NOT NULL,\n error_message TEXT,\n exit_code INTEGER,\n signal TEXT,\n model TEXT,\n cost_usd REAL,\n unattributed_cost INTEGER NOT NULL DEFAULT 0,\n actor_type TEXT,\n actor_id TEXT,\n started_at TEXT,\n finished_at TEXT,\n log_path TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n , usage_status TEXT NOT NULL DEFAULT 'pre_first_message')", - "CREATE TABLE schema_migrations (version integer primary key, name text not null, applied_at text not null)", - "CREATE TABLE secrets (id text primary key, company_id text not null, name text not null, description text not null, backend text not null, ciphertext blob not null, updated_at text not null, created_at text not null, unique(company_id, name))", - "CREATE TABLE session_entries (\n id TEXT PRIMARY KEY,\n task_session_id TEXT NOT NULL,\n sequence INTEGER NOT NULL,\n kind TEXT NOT NULL,\n role TEXT,\n payload_json TEXT NOT NULL,\n is_superseded INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL\n )", - "CREATE TABLE settings (key text primary key, value text not null)", - "CREATE TABLE social_accounts (id text primary key, company_id text not null references companies(id) on delete cascade, platform text not null default 'other', account_name text not null, display_name text not null default '', profile_url text not null default '', credential_secret_id text, status text not null default 'login_required', require_approval integer not null default 1, metadata_json text not null default '{}', last_used_at text, created_at text not null default (datetime('now')), updated_at text not null default (datetime('now')))", - "CREATE TABLE sprints (id text primary key, company_id text not null, name text not null, goal text not null default '', start_date text not null, end_date text not null, status text not null default 'planning', retrospective_notes text not null default '', velocity_points integer not null default 0, completed_points integer not null default 0, created_at text not null, updated_at text not null)", - "CREATE TABLE 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 TABLE task_comments (id text primary key, company_id text not null, task_id text not null, author_agent_id text, author_name text not null, body text not null, created_at text not null)", - "CREATE TABLE 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 TABLE \"task_sessions\" (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n agent_id TEXT NOT NULL,\n adapter_type TEXT NOT NULL,\n last_run_id TEXT,\n last_error TEXT,\n run_count INTEGER NOT NULL DEFAULT 0,\n total_input_tokens INTEGER NOT NULL DEFAULT 0,\n total_output_tokens INTEGER NOT NULL DEFAULT 0,\n rotated_at TEXT,\n rotation_reason TEXT,\n handoff_markdown TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )", - "CREATE TABLE \"tasks\" (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n project_id TEXT,\n goal_id TEXT,\n parent_id TEXT,\n title TEXT NOT NULL,\n description TEXT NOT NULL,\n assignee_agent_id TEXT,\n workspace_id TEXT,\n status TEXT NOT NULL,\n priority TEXT NOT NULL,\n active_run_id TEXT,\n cost_usd REAL NOT NULL DEFAULT 0,\n task_type TEXT NOT NULL DEFAULT 'general',\n requires_user_review INTEGER NOT NULL DEFAULT 0,\n retry_count INTEGER NOT NULL DEFAULT 0,\n last_failure_at TEXT,\n checkout_run_id TEXT,\n execution_locked_at TEXT,\n started_at TEXT,\n completed_at TEXT,\n cancelled_at TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n , requires_filesystem INTEGER NOT NULL DEFAULT 0, active_session_id text)", - "CREATE TABLE thread_subscriptions (\n thread_id TEXT NOT NULL REFERENCES conversation_threads(id) ON DELETE CASCADE,\n subscriber_id TEXT NOT NULL,\n subscriber_type TEXT NOT NULL,\n notify_on TEXT NOT NULL DEFAULT 'all',\n subscribed_at TEXT NOT NULL,\n PRIMARY KEY (thread_id, subscriber_id)\n )", - "CREATE TABLE thread_wait_states (\n id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL REFERENCES conversation_threads(id) ON DELETE CASCADE,\n company_id TEXT NOT NULL,\n waiting_for TEXT NOT NULL,\n related_approval_id TEXT,\n reason TEXT NOT NULL,\n created_at TEXT NOT NULL,\n resolved_at TEXT\n )", - "CREATE TABLE wakeup_requests (id TEXT PRIMARY KEY, company_id TEXT NOT NULL, agent_id TEXT NOT NULL, source TEXT NOT NULL, trigger_detail TEXT, reason TEXT, payload TEXT, status TEXT NOT NULL DEFAULT 'queued', coalesced_count INTEGER NOT NULL DEFAULT 0, requested_by_actor_type TEXT, requested_by_actor_id TEXT, idempotency_key TEXT, run_id TEXT, requested_at TEXT NOT NULL, claimed_at TEXT, finished_at TEXT, error TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, context_snapshot TEXT)", - "CREATE TABLE \"work_products\" (\n id TEXT PRIMARY KEY,\n company_id TEXT NOT NULL,\n project_id TEXT,\n task_id TEXT,\n type TEXT NOT NULL,\n provider TEXT NOT NULL,\n external_id TEXT,\n title TEXT NOT NULL,\n url TEXT,\n status TEXT NOT NULL DEFAULT 'active',\n review_state TEXT NOT NULL DEFAULT 'none',\n is_primary INTEGER NOT NULL DEFAULT 0,\n summary TEXT,\n metadata_json TEXT,\n created_by_run_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL, workspace_id TEXT, last_touched_by_run_id TEXT,\n FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE\n )", - "CREATE TABLE workflow_pipelines (id text primary key, company_id text not null, name text not null, description text not null default '', steps_json text not null default '[]', trigger_type text not null, trigger_config_json text not null default '{}', status text not null default 'draft', current_step_index integer not null default 0, run_count integer not null default 0, last_run_at text, created_at text not null, updated_at text not null)", - "CREATE TABLE workspaces (id text primary key, company_id text not null, name text not null, local_path text not null, repo_url text not null, repo_ref text not null, project_id text, state text not null, is_primary integer not null default 0, created_at text not null, updated_at text not null, lock_holder_run_id text, lock_acquired_at text)", -] as const; - -export const BASELINE_INDEX_SQL = [ - "CREATE INDEX idx_activity_company on activity(company_id)", - "CREATE INDEX idx_activity_company_actor_action ON activity(company_id, actor, action)", - "CREATE INDEX idx_activity_company_created_at on activity(company_id, created_at desc)", - "CREATE INDEX idx_agent_config_rev_agent ON agent_config_revisions(company_id, agent_id, created_at)", - "CREATE UNIQUE INDEX idx_agent_config_rev_num ON agent_config_revisions(agent_id, revision_number)", - "CREATE INDEX idx_agent_message_mentions_agent\n ON agent_message_mentions(company_id, agent_id, created_at)\n ", - "CREATE INDEX idx_agent_message_mentions_message\n ON agent_message_mentions(message_id)\n ", - "CREATE INDEX idx_agent_message_projections_session\n ON agent_message_projections(session_id, projected_at)\n ", - "CREATE INDEX idx_agent_message_reads_agent on agent_message_reads(agent_id)", - "CREATE INDEX idx_agent_messages_channel on agent_messages(channel)", - "CREATE INDEX idx_agent_messages_company on agent_messages(company_id)", - "CREATE INDEX idx_agent_messages_company_created_at on agent_messages(company_id, created_at desc)", - "CREATE INDEX idx_agent_messages_from on agent_messages(from_agent_id)", - "CREATE INDEX idx_agent_messages_to on agent_messages(to_agent_id)", - "CREATE INDEX idx_agent_skill_assignments_skill ON agent_skill_assignments(skill_id)", - "CREATE INDEX idx_agents_company on agents(company_id)", - "CREATE INDEX idx_agents_company_status on agents(company_id, status)", - "CREATE INDEX idx_agents_department on agents(company_id, department)", - "CREATE INDEX idx_agents_reports_to on agents(reports_to)", - "CREATE INDEX idx_agents_session_id ON agents(session_id)", - "CREATE INDEX idx_approval_comments_approval ON approval_comments(approval_id, created_at)", - "CREATE INDEX idx_approvals_company on approvals(company_id)", - "CREATE INDEX idx_approvals_company_created_at ON approvals(company_id, created_at DESC)", - "CREATE INDEX idx_approvals_company_state on approvals(company_id, state)", - "CREATE INDEX idx_approvals_company_state_type ON approvals(company_id, state, type)", - "CREATE INDEX idx_approvals_related_task ON approvals(related_task_id)", - "CREATE INDEX idx_automation_log_company on automation_log(company_id)", - "CREATE INDEX idx_automation_rules_company on automation_rules(company_id)", - "CREATE INDEX idx_automation_rules_company_status on automation_rules(company_id, status)", - "CREATE INDEX idx_automation_rules_trigger on automation_rules(trigger)", - "CREATE INDEX idx_browser_actions_account on browser_actions(social_account_id)", - "CREATE INDEX idx_browser_actions_company on browser_actions(company_id)", - "CREATE INDEX idx_budget_incidents_company_scope ON budget_incidents(company_id, scope_type, scope_id, status)", - "CREATE INDEX idx_budget_incidents_company_status ON budget_incidents(company_id, status)", - "CREATE INDEX idx_budget_incidents_policy ON budget_incidents(policy_id, window_start, threshold_type)", - "CREATE INDEX idx_budget_policies_company_scope ON budget_policies(company_id, scope_type, scope_id, is_active)", - "CREATE UNIQUE INDEX idx_budget_policies_unique ON budget_policies(company_id, scope_type, scope_id, metric, window_kind)", - "CREATE INDEX idx_comments_company on task_comments(company_id)", - "CREATE INDEX idx_comments_task on task_comments(task_id)", - "CREATE UNIQUE INDEX idx_company_skills_company_key ON company_skills(company_id, key)", - "CREATE INDEX idx_company_skills_company_name ON company_skills(company_id, name)", - "CREATE INDEX idx_connector_model_pool_company\n ON connector_model_pool_settings(company_id)", - "CREATE INDEX idx_conv_events_thread ON conversation_events(thread_id, created_at)", - "CREATE INDEX idx_conv_participants_participant ON conversation_participants(participant_id)", - "CREATE INDEX idx_conv_threads_company ON conversation_threads(company_id)", - "CREATE INDEX idx_conv_threads_entity ON conversation_threads(related_entity_type, related_entity_id)", - "CREATE INDEX idx_cost_entries_agent_created_at ON cost_entries(agent_id, created_at DESC)", - "CREATE INDEX idx_cost_entries_company on cost_entries(company_id)", - "CREATE INDEX idx_cost_entries_company_created_at on cost_entries(company_id, created_at desc)", - "CREATE INDEX idx_cost_entries_project ON cost_entries(project_id)", - "CREATE INDEX idx_cost_entries_run on cost_entries(run_id)", - "CREATE INDEX idx_credentials_status ON credentials(status)", - "CREATE INDEX idx_doc_rev_company ON document_revisions(company_id, document_id, created_at)", - "CREATE UNIQUE INDEX idx_doc_rev_doc_num ON document_revisions(document_id, revision_number)", - "CREATE INDEX idx_document_lifecycle_events_company\n ON document_lifecycle_events(company_id, status, updated_at)\n ", - "CREATE INDEX idx_document_lifecycle_events_document\n ON document_lifecycle_events(document_id, hook_type)\n ", - "CREATE INDEX idx_documents_author on documents(author_agent_id)", - "CREATE INDEX idx_documents_company on documents(company_id)", - "CREATE INDEX idx_documents_company_updated_at ON documents(company_id, updated_at DESC)", - "CREATE INDEX idx_documents_project on documents(project_id)", - "CREATE INDEX idx_goals_company on goals(company_id)", - "CREATE INDEX idx_knowledge_category on knowledge_base(category)", - "CREATE INDEX idx_knowledge_company on knowledge_base(company_id)", - "CREATE INDEX idx_meetings_company on meetings(company_id)", - "CREATE INDEX idx_meetings_company_scheduled_at ON meetings(company_id, scheduled_at DESC)", - "CREATE INDEX idx_meetings_organizer on meetings(organizer_agent_id)", - "CREATE INDEX idx_messages_channel on agent_messages(channel, channel_target_id)", - "CREATE INDEX idx_messages_company on agent_messages(company_id)", - "CREATE INDEX idx_model_capabilities_tier ON model_capabilities(tier)", - "CREATE INDEX idx_projects_company on projects(company_id)", - "CREATE INDEX idx_run_events_company ON run_events(company_id, run_id)", - "CREATE INDEX idx_run_events_run ON run_events(run_id, seq)", - "CREATE UNIQUE INDEX idx_run_events_run_seq_unique ON run_events(run_id, seq)", - "CREATE INDEX idx_runs_agent ON runs(agent_id)", - "CREATE INDEX idx_runs_agent_created_at ON runs(agent_id, created_at DESC)", - "CREATE INDEX idx_runs_company ON runs(company_id)", - "CREATE INDEX idx_runs_company_created_at ON runs(company_id, created_at DESC)", - "CREATE INDEX idx_runs_company_status ON runs(company_id, status)", - "CREATE INDEX idx_runs_task ON runs(task_id)", - "CREATE INDEX idx_secrets_company on secrets(company_id)", - "CREATE INDEX idx_session_entries_active ON session_entries(task_session_id, is_superseded, sequence)", - "CREATE INDEX idx_session_entries_session ON session_entries(task_session_id, sequence)", - "CREATE INDEX idx_social_accounts_company on social_accounts(company_id)", - "CREATE INDEX idx_sprints_company on sprints(company_id)", - "CREATE INDEX idx_sprints_company_start_date ON sprints(company_id, start_date DESC)", - "CREATE INDEX idx_task_approval_links_approval ON task_approval_links(approval_id)", - "CREATE INDEX idx_task_approval_links_task ON task_approval_links(task_id)", - "CREATE UNIQUE INDEX idx_task_documents_doc ON task_documents(document_id)", - "CREATE UNIQUE INDEX idx_task_documents_task_key ON task_documents(company_id, task_id, key)", - "CREATE INDEX idx_task_sessions_company_agent\n ON task_sessions(company_id, agent_id, updated_at)", - "CREATE INDEX idx_task_sessions_lookup\n ON task_sessions(company_id, agent_id, adapter_type)", - "CREATE INDEX idx_tasks_assignee ON tasks(assignee_agent_id)", - "CREATE INDEX idx_tasks_company ON tasks(company_id)", - "CREATE INDEX idx_tasks_company_status ON tasks(company_id, status)", - "CREATE INDEX idx_tasks_project ON tasks(project_id)", - "CREATE INDEX idx_thread_subs_subscriber ON thread_subscriptions(subscriber_id)", - "CREATE INDEX idx_thread_wait_company ON thread_wait_states(company_id, resolved_at)", - "CREATE INDEX idx_thread_wait_thread ON thread_wait_states(thread_id)", - "CREATE INDEX idx_wakeup_requests_agent ON wakeup_requests(agent_id, company_id, status)", - "CREATE INDEX idx_wakeup_requests_agent_requested ON wakeup_requests(agent_id, requested_at)", - "CREATE INDEX idx_wakeup_requests_company_agent_status ON wakeup_requests(company_id, agent_id, status)", - "CREATE INDEX idx_wakeup_requests_company_requested ON wakeup_requests(company_id, requested_at)", - "CREATE UNIQUE INDEX idx_work_products_identity\n ON work_products(company_id, workspace_id, provider, external_id)\n WHERE workspace_id IS NOT NULL AND external_id IS NOT NULL\n ", - "CREATE INDEX idx_work_products_last_touched\n ON work_products(company_id, last_touched_by_run_id)\n ", - "CREATE UNIQUE INDEX idx_work_products_primary_active\n ON work_products(company_id, task_id, type)\n WHERE task_id IS NOT NULL\n AND is_primary = 1\n AND status <> 'archived'", - "CREATE INDEX idx_work_products_task\n ON work_products(company_id, task_id, type)", - "CREATE INDEX idx_work_products_updated\n ON work_products(company_id, updated_at)", - "CREATE INDEX idx_workflows_company on workflow_pipelines(company_id)", - "CREATE INDEX idx_workspaces_company on workspaces(company_id)", - "CREATE UNIQUE INDEX secrets_company_name_idx on secrets(company_id, name)", -] as const; - -function quoteIdentifier(name: string): string { - return `"${name.replaceAll("\"", "\"\"")}"`; -} - -function parseSchemaName(sql: string, prefix: RegExp, kind: string): string { - const match = prefix.exec(sql); - if (!match) throw new Error(`Cannot parse baseline ${kind} name from SQL: ${sql}`); - return match[1] ?? match[2]!; -} - -export function parseBaselineTableName(sql: string): string { - return parseSchemaName( - sql, - /^CREATE TABLE(?: IF NOT EXISTS)? (?:"([^"]+)"|([A-Za-z_][A-Za-z0-9_]*))/, - "table", - ); -} - -export function parseBaselineIndexName(sql: string): string { - return parseSchemaName( - sql, - /^CREATE (?:UNIQUE )?INDEX(?: IF NOT EXISTS)? (?:"([^"]+)"|([A-Za-z_][A-Za-z0-9_]*))/, - "index", - ); -} - -export function normalizeSchemaSql(sql: string): string { - return sql - .replace(/\s+/g, " ") - .replace(/\(\s+/g, "(") - .replace(/\s+\)/g, ")") - .replace(/^CREATE TABLE "([^"]+)"/, "CREATE TABLE $1") - .replace(/^CREATE INDEX "([^"]+)"/, "CREATE INDEX $1") - .replace(/^CREATE UNIQUE INDEX "([^"]+)"/, "CREATE UNIQUE INDEX $1") - .trim(); -} - -function ifNotExists(sql: string): string { - return sql - .replace(/^CREATE TABLE /, "CREATE TABLE IF NOT EXISTS ") - .replace(/^CREATE INDEX /, "CREATE INDEX IF NOT EXISTS ") - .replace(/^CREATE UNIQUE INDEX /, "CREATE UNIQUE INDEX IF NOT EXISTS "); -} - -export function installBaselineTables(db: DatabaseSync): void { - db.exec(BASELINE_TABLE_SQL.map(ifNotExists).join(";\n")); -} - -export function installBaselineIndexes(db: DatabaseSync): void { - db.exec(BASELINE_INDEX_SQL.map(ifNotExists).join(";\n")); -} - -export function installCanonicalBaselineIndexes(db: DatabaseSync): void { - for (const sql of BASELINE_INDEX_SQL) { - db.exec(`DROP INDEX IF EXISTS ${quoteIdentifier(parseBaselineIndexName(sql))}`); - } - db.exec(BASELINE_INDEX_SQL.join(";\n")); -} - -export function installBaselineSchema(db: DatabaseSync): void { - installBaselineTables(db); - installBaselineIndexes(db); -} - -export function assertBaselineSchema(db: DatabaseSync): void { - assertSchemaEntries( - db, - "table", - BASELINE_TABLE_SQL.map((sql) => [parseBaselineTableName(sql), normalizeSchemaSql(sql)] as const), - ); - assertSchemaEntries( - db, - "index", - BASELINE_INDEX_SQL.map((sql) => [parseBaselineIndexName(sql), normalizeSchemaSql(sql)] as const), - ); -} - -function assertSchemaEntries( - db: DatabaseSync, - type: "table" | "index", - expectedEntries: ReadonlyArray, -): void { - const selectSql = db.prepare("select sql from sqlite_master where type = ? and name = ?"); - for (const [name, expectedSql] of expectedEntries) { - const row = selectSql.get(type, name) as { sql: string | null } | undefined; - const actualSql = row?.sql ? normalizeSchemaSql(row.sql) : null; - if (actualSql !== expectedSql) { - throw new Error(`Baseline v56 ${type} drift for ${name}: expected ${expectedSql}; actual ${actualSql ?? "missing"}`); - } - } -} diff --git a/src/main/database/migrations/legacy-to-v56.ts b/src/main/database/migrations/legacy-to-v56.ts deleted file mode 100644 index 2b7f8ee1..00000000 --- a/src/main/database/migrations/legacy-to-v56.ts +++ /dev/null @@ -1,433 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import { - BASELINE_SCHEMA_NAME, - BASELINE_SCHEMA_VERSION, - BASELINE_TABLE_SQL, - installCanonicalBaselineIndexes, - installBaselineTables, - normalizeSchemaSql, - parseBaselineTableName, -} from "./baseline-v56"; -import { - columnExists, - nowIso, - tableExists, - type ReadAll, -} from "./types"; - -type ColumnInfo = { - name: string; - type: string; - notnull: number; - dflt_value: string | null; - pk: number; -}; - -type LegacyDeps = { - db: DatabaseSync; - readAll: ReadAll; -}; - -const BASELINE_TABLE_NAMES = BASELINE_TABLE_SQL.map((sql) => parseTableName(sql)); -const EXPECTED_DROPPED_COLUMNS: Readonly>> = { - agent_messages: new Set(["read_at"]), - company_skills: new Set(["markdown"]), - runs: new Set(["context_snapshot_json", "session_display_id"]), - tasks: new Set(["is_heartbeat", "phase", "session_display_id", "session_json"]), - task_sessions: new Set(["session_display_id", "session_params_json", "task_id"]), -}; - -export function markBaselineSchema(db: DatabaseSync): void { - db.prepare("delete from schema_migrations where version <> ?").run(BASELINE_SCHEMA_VERSION); - db - .prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)") - .run(BASELINE_SCHEMA_VERSION, BASELINE_SCHEMA_NAME, nowIso()); -} - -export function upgradeLegacyProfileToBaselineV56({ db, readAll }: LegacyDeps): void { - installBaselineTables(db); - migrateLegacySecrets(db); - migratePendingWakes(db, readAll); - migrateAgentBudgets(db, readAll); - - for (const tableName of BASELINE_TABLE_NAMES) { - if (tableName === "schema_migrations") continue; - if (tableName === "runs") { - backfillRunsUsageStatus(db); - } - if (tableName === "tasks") { - migrateTaskSessions(db, readAll); - backfillRequiresFilesystem(db); - removeSyntheticHeartbeatTasks(db); - } - if (tableName === "work_products") { - detachDanglingWorkProducts(db); - backfillWorkProductProvenance(db); - normalizeWorkProductPrimaries(db); - } - rebuildTableToBaseline(db, tableName); - } - - db.exec("drop table if exists pending_wakes"); - db.exec("drop table if exists task_leases"); - db.exec("drop trigger if exists trg_tasks_phase_from_status_insert"); - db.exec("drop trigger if exists trg_tasks_phase_from_status_update"); - installCanonicalBaselineIndexes(db); - assertNoForeignKeyViolations(db); - markBaselineSchema(db); -} - -function parseTableName(sql: string): string { - return parseBaselineTableName(sql); -} - -function quoteIdentifier(name: string): string { - return `"${name.replaceAll("\"", "\"\"")}"`; -} - -function tableSql(tableName: string): string { - const sql = BASELINE_TABLE_SQL.find((entry) => parseTableName(entry) === tableName); - if (!sql) throw new Error(`Missing baseline SQL for table ${tableName}`); - return sql; -} - -function tableColumns(db: DatabaseSync, tableName: string): ColumnInfo[] { - return db.prepare(`pragma table_info(${quoteIdentifier(tableName)})`).all() as ColumnInfo[]; -} - -function createSqlForTable(sql: string, tableName: string): string { - return sql.replace(/^CREATE TABLE (?:"[^"]+"|[A-Za-z_][A-Za-z0-9_]*)/, `CREATE TABLE ${quoteIdentifier(tableName)}`); -} - -function rebuildTableToBaseline(db: DatabaseSync, tableName: string): void { - if (!tableExists(db, tableName)) return; - if (isBaselineTableDefinition(db, tableName)) return; - - const tempTableName = `__baseline_${tableName}_${process.pid}`; - db.exec(`drop table if exists ${quoteIdentifier(tempTableName)}`); - db.exec(createSqlForTable(tableSql(tableName), tempTableName)); - - const beforeCount = (db.prepare(`select count(*) as count from ${quoteIdentifier(tableName)}`).get() as { count: number }).count; - const sourceColumns = new Set(tableColumns(db, tableName).map((column) => column.name)); - const targetColumns = tableColumns(db, tempTableName); - assertDroppedColumnsAreExpected(tableName, sourceColumns, new Set(targetColumns.map((column) => column.name))); - const insertColumns = targetColumns.map((column) => quoteIdentifier(column.name)); - const selectExpressions = targetColumns.map((column) => { - if (sourceColumns.has(column.name)) return quoteIdentifier(column.name); - if (column.dflt_value !== null) return column.dflt_value; - if (column.notnull === 0) return "NULL"; - if (beforeCount === 0) return "NULL"; - throw new Error(`Cannot rebuild ${tableName}: missing required column ${column.name}`); - }); - - db.exec(`insert into ${quoteIdentifier(tempTableName)} (${insertColumns.join(", ")}) select ${selectExpressions.join(", ")} from ${quoteIdentifier(tableName)}`); - const afterCount = (db.prepare(`select count(*) as count from ${quoteIdentifier(tempTableName)}`).get() as { count: number }).count; - if (afterCount !== beforeCount) { - throw new Error(`Cannot rebuild ${tableName}: copied ${afterCount} of ${beforeCount} rows`); - } - - db.exec(`drop table ${quoteIdentifier(tableName)}`); - db.exec(`alter table ${quoteIdentifier(tempTableName)} rename to ${quoteIdentifier(tableName)}`); -} - -function isBaselineTableDefinition(db: DatabaseSync, tableName: string): boolean { - const row = db - .prepare("select sql from sqlite_master where type = 'table' and name = ?") - .get(tableName) as { sql: string | null } | undefined; - if (!row?.sql) return false; - return normalizeSchemaSql(row.sql) === normalizeSchemaSql(tableSql(tableName)); -} - -function assertDroppedColumnsAreExpected(tableName: string, sourceColumns: Set, targetColumns: Set): void { - const allowed = EXPECTED_DROPPED_COLUMNS[tableName] ?? new Set(); - const unexpected = [...sourceColumns] - .filter((column) => !targetColumns.has(column)) - .filter((column) => !allowed.has(column)); - if (unexpected.length > 0) { - throw new Error(`Cannot rebuild ${tableName}: unexpected legacy columns would be dropped: ${unexpected.join(", ")}`); - } -} - -function migrateLegacySecrets(db: DatabaseSync): void { - if (!tableExists(db, "secrets") || columnExists(db, "secrets", "company_id")) return; - - const currentCompany = db.prepare("select value from settings where key = 'current_company_id'").get() as { value: string } | undefined; - const firstCompany = db.prepare("select id from companies order by created_at asc limit 1").get() as { id: string } | undefined; - const companyId = currentCompany?.value ?? firstCompany?.id; - if (!companyId) { - throw new Error("Cannot migrate legacy secrets table: no company row exists."); - } - - db.exec(` - alter table secrets rename to secrets_legacy; - create table secrets (id text primary key, company_id text not null, name text not null, description text not null, backend text not null, ciphertext blob not null, updated_at text not null, created_at text not null, unique(company_id, name)); - `); - db - .prepare("insert into secrets (id, company_id, name, description, backend, ciphertext, updated_at, created_at) select id, ?, name, description, backend, ciphertext, updated_at, created_at from secrets_legacy") - .run(companyId); - db.exec("drop table secrets_legacy"); -} - -function migratePendingWakes(db: DatabaseSync, readAll: ReadAll): void { - if (!tableExists(db, "pending_wakes")) return; - const rows = readAll<{ id: string; companyId: string; agentId: string; triggerReason: string; createdAt: string }>( - "select id, company_id as companyId, agent_id as agentId, trigger_reason as triggerReason, created_at as createdAt from pending_wakes", - ); - const insert = db.prepare(` - insert or ignore into wakeup_requests (id, company_id, agent_id, source, trigger_detail, status, coalesced_count, requested_at, created_at, updated_at) - values (?, ?, ?, ?, ?, 'queued', 0, ?, ?, ?) - `); - const ts = nowIso(); - for (const row of rows) { - const detail = JSON.stringify([{ trigger: row.triggerReason, at: row.createdAt, detail: row.triggerReason }]); - insert.run(row.id, row.companyId, row.agentId, row.triggerReason, detail, row.createdAt, ts, ts); - } -} - -function migrateAgentBudgets(db: DatabaseSync, readAll: ReadAll): void { - if (!tableExists(db, "agents") || !tableExists(db, "budget_policies")) return; - if (!columnExists(db, "agents", "budget_monthly_usd")) return; - const agents = readAll<{ id: string; companyId: string; budgetMonthlyUsd: number }>( - "select id, company_id as companyId, budget_monthly_usd as budgetMonthlyUsd from agents where budget_monthly_usd > 0", - ); - const existing = db.prepare("select id from budget_policies where company_id = ? and scope_type = 'agent' and scope_id = ? and metric = 'billed_cents' and window_kind = 'calendar_month_utc'"); - const insert = db.prepare(` - insert into budget_policies (id, company_id, scope_type, scope_id, metric, window_kind, amount, warn_percent, hard_stop_enabled, notify_enabled, is_active, created_at, updated_at) - values (?, ?, 'agent', ?, 'billed_cents', 'calendar_month_utc', ?, 80, 1, 1, 1, ?, ?) - `); - const ts = nowIso(); - for (const agent of agents) { - if (existing.get(agent.companyId, agent.id)) continue; - insert.run(randomUUID(), agent.companyId, agent.id, Math.round(agent.budgetMonthlyUsd * 100), ts, ts); - } -} - -function migrateTaskSessions(db: DatabaseSync, readAll: ReadAll): void { - if (!tableExists(db, "tasks") || !columnExists(db, "tasks", "session_json")) return; - if (!columnExists(db, "tasks", "active_session_id")) { - db.exec("alter table tasks add column active_session_id text"); - } - - const rows = readAll<{ - id: string; - companyId: string; - assigneeAgentId: string | null; - sessionJson: string; - sessionDisplayId: string | null; - updatedAt: string; - connectorId: string | null; - }>(` - select t.id, - t.company_id as companyId, - t.assignee_agent_id as assigneeAgentId, - t.session_json as sessionJson, - ${columnExists(db, "tasks", "session_display_id") ? "t.session_display_id" : "NULL"} as sessionDisplayId, - t.updated_at as updatedAt, - a.connector_id as connectorId - from tasks t - left join agents a on a.id = t.assignee_agent_id - where t.session_json is not null - and (t.active_session_id is null or t.active_session_id = '') - `); - const sessionColumns = new Set(tableColumns(db, "task_sessions").map((column) => column.name)); - const updateTask = db.prepare("update tasks set active_session_id = ? where id = ?"); - const existingSessionByTask = sessionColumns.has("task_id") - ? db.prepare("select id from task_sessions where task_id = ? order by updated_at desc limit 1") - : null; - const insertColumns = [ - "id", - "company_id", - "agent_id", - "adapter_type", - "created_at", - "updated_at", - ...(sessionColumns.has("task_id") ? ["task_id"] : []), - ...(sessionColumns.has("session_params_json") ? ["session_params_json"] : []), - ...(sessionColumns.has("session_display_id") ? ["session_display_id"] : []), - ]; - const insert = db.prepare(` - insert into task_sessions (${insertColumns.map(quoteIdentifier).join(", ")}) - values (${insertColumns.map(() => "?").join(", ")}) - `); - for (const row of rows) { - JSON.parse(row.sessionJson); - const existingSession = existingSessionByTask?.get(row.id) as { id: string } | undefined; - if (existingSession) { - updateTask.run(existingSession.id, row.id); - continue; - } - if (!row.assigneeAgentId) { - throw new Error(`Cannot migrate task session for task ${row.id}: assignee_agent_id is missing.`); - } - if (!row.connectorId) { - throw new Error(`Cannot migrate task session for task ${row.id}: assigned agent connector_id is missing.`); - } - const sessionId = randomUUID(); - const values = [ - sessionId, - row.companyId, - row.assigneeAgentId, - row.connectorId, - row.updatedAt, - row.updatedAt, - ...(sessionColumns.has("task_id") ? [row.id] : []), - ...(sessionColumns.has("session_params_json") ? [row.sessionJson] : []), - ...(sessionColumns.has("session_display_id") ? [row.sessionDisplayId] : []), - ]; - insert.run(...values); - updateTask.run(sessionId, row.id); - } -} - -function backfillRequiresFilesystem(db: DatabaseSync): void { - if (!tableExists(db, "tasks")) return; - if (!columnExists(db, "tasks", "requires_filesystem")) { - db.exec("alter table tasks add column requires_filesystem integer not null default 0"); - } - if (columnExists(db, "tasks", "active_run_id")) { - db.exec(` - update tasks - set requires_filesystem = 1 - where status = 'in_progress' - and active_run_id is not null - `); - } - if (columnExists(db, "tasks", "assignee_agent_id")) { - db.exec(` - update tasks - set requires_filesystem = 1 - where status in ('todo', 'backlog') - and assignee_agent_id is not null - and exists ( - select 1 from agents a - where a.id = tasks.assignee_agent_id - and ( - a.role like '%cto%' - or a.role like '%engineer%' - or a.role like '%developer%' - or a.role like '%devops%' - or a.role like '%sre%' - or a.department = 'engineering' - ) - ) - `); - } -} - -function removeSyntheticHeartbeatTasks(db: DatabaseSync): void { - if (!tableExists(db, "tasks") || !columnExists(db, "tasks", "is_heartbeat")) return; - if (tableExists(db, "runs")) { - db.exec("update runs set task_id = null where task_id in (select id from tasks where is_heartbeat = 1)"); - } - db.exec("delete from tasks where is_heartbeat = 1"); -} - -function backfillRunsUsageStatus(db: DatabaseSync): void { - if (!tableExists(db, "runs")) return; - if (!columnExists(db, "runs", "usage_status")) { - db.exec("alter table runs add column usage_status text not null default 'pre_first_message'"); - } - if (!columnExists(db, "runs", "unattributed_cost") || !columnExists(db, "runs", "status")) return; - db.exec(` - update runs - set usage_status = case - when unattributed_cost = 0 then 'ok' - when status in ('cancelled', 'interrupted') then 'aborted_before_usage' - else 'pre_first_message' - end - where usage_status = 'pre_first_message' - `); -} - -function normalizeWorkProductPrimaries(db: DatabaseSync): void { - if (!tableExists(db, "work_products")) return; - db.exec(` - update work_products - set is_primary = 0, - updated_at = datetime('now') - where id in ( - select id from ( - select id, - row_number() over ( - partition by company_id, task_id, type - order by updated_at desc, created_at desc, id desc - ) as rank_in_group - from work_products - where task_id is not null - and is_primary = 1 - and status <> 'archived' - ) - where rank_in_group > 1 - ) - `); -} - -function backfillWorkProductProvenance(db: DatabaseSync): void { - if (!tableExists(db, "work_products")) return; - if (!columnExists(db, "work_products", "workspace_id")) { - db.exec("alter table work_products add column workspace_id text"); - } - if (!columnExists(db, "work_products", "last_touched_by_run_id")) { - db.exec("alter table work_products add column last_touched_by_run_id text"); - } - if (tableExists(db, "tasks") && columnExists(db, "work_products", "task_id") && columnExists(db, "tasks", "workspace_id")) { - db.exec(` - update work_products - set workspace_id = ( - select tasks.workspace_id from tasks - where tasks.id = work_products.task_id - ) - where workspace_id is null - and task_id is not null - `); - } - if (tableExists(db, "runs") && columnExists(db, "work_products", "created_by_run_id") && columnExists(db, "runs", "workspace_id")) { - db.exec(` - update work_products - set workspace_id = ( - select runs.workspace_id from runs - where runs.id = work_products.created_by_run_id - ) - where workspace_id is null - and created_by_run_id is not null - `); - } - if (columnExists(db, "work_products", "created_by_run_id")) { - db.exec(` - update work_products - set last_touched_by_run_id = created_by_run_id - where last_touched_by_run_id is null - and created_by_run_id is not null - `); - } -} - -function detachDanglingWorkProducts(db: DatabaseSync): void { - if (!tableExists(db, "work_products") || !tableExists(db, "tasks") || !columnExists(db, "work_products", "task_id")) return; - db.exec(` - update work_products - set task_id = null - where task_id is not null - and not exists ( - select 1 from tasks - where tasks.id = work_products.task_id - ) - `); -} - -function assertNoForeignKeyViolations(db: DatabaseSync): void { - const violations = db.prepare("pragma foreign_key_check").all() as Array<{ - table: string; - rowid: number | null; - parent: string; - fkid: number; - }>; - if (violations.length === 0) return; - - const sample = violations - .slice(0, 5) - .map((row) => `${row.table}:${row.rowid ?? "unknown"}->${row.parent}#${row.fkid}`) - .join(", "); - throw new Error(`Cannot migrate legacy profile: ${violations.length} foreign key violations after v56 rebuild (${sample}).`); -} diff --git a/src/main/database/migrations/types.ts b/src/main/database/migrations/types.ts deleted file mode 100644 index 42b23bab..00000000 --- a/src/main/database/migrations/types.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; - -export type ReadAll = (sql: string, ...params: SQLInputValue[]) => T[]; -export type Transaction = (operation: () => T) => T; - -export type Migration = { - version: number; - name: string; - sql?: string; - fn?: () => void; -}; - -export type MigrationDeps = { - db: DatabaseSync; - readAll: ReadAll; -}; - -export function nowIso(): string { - return new Date().toISOString(); -} - -export function columnExists( - db: DatabaseSync, - table: string, - column: string, -): boolean { - const rows = db.prepare(`pragma table_info(${table})`).all() as Array<{ - name: string; - }>; - return rows.some((row) => row.name === column); -} - -export function tableExists(db: DatabaseSync, table: string): boolean { - const row = db - .prepare("select name from sqlite_master where type = 'table' and name = ?") - .get(table) as { name: string } | undefined; - return !!row; -} - -export function addColumnIfMissing( - db: DatabaseSync, - table: string, - column: string, - sql: string, -): void { - if (!columnExists(db, table, column)) db.prepare(sql).run(); -} diff --git a/src/main/database/migrations/v57-task-leases.ts b/src/main/database/migrations/v57-task-leases.ts deleted file mode 100644 index 3c60dfd6..00000000 --- a/src/main/database/migrations/v57-task-leases.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { STALE_LOCK_TIMEOUT_MS } from "../../constants"; -import { columnExists, nowIso, tableExists } from "./types"; - -export const TASK_LEASE_SCHEMA_VERSION = 57; -export const TASK_LEASE_SCHEMA_NAME = "task_leases_runtime_ownership"; - -const LEASE_SECONDS = Math.floor(STALE_LOCK_TIMEOUT_MS / 1000); - -export function migrateTaskLeasesV57(db: DatabaseSync): void { - installTaskLeasesTable(db); - backfillTaskLeases(db); - dropTaskOwnershipColumns(db); - db - .prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)") - .run(TASK_LEASE_SCHEMA_VERSION, TASK_LEASE_SCHEMA_NAME, nowIso()); - assertTaskLeasesV57(db); -} - -export function assertTaskLeasesV57(db: DatabaseSync): void { - if (!tableExists(db, "task_leases")) { - throw new Error("Schema v57 drift: task_leases table is missing."); - } - if (!tableExists(db, "tasks")) { - throw new Error("Schema v57 drift: tasks table is missing."); - } - - const leaseColumns = db - .prepare("pragma table_info(task_leases)") - .all() - .map((row) => row as { name: string; type: string; notnull: number; pk: number }); - const expectedLeaseColumns = [ - ["task_id", "TEXT", 0, 1], - ["company_id", "TEXT", 1, 0], - ["run_id", "TEXT", 1, 0], - ["agent_id", "TEXT", 1, 0], - ["acquired_at", "TEXT", 1, 0], - ["renewed_at", "TEXT", 1, 0], - ["expires_at", "TEXT", 1, 0], - ["created_at", "TEXT", 1, 0], - ["updated_at", "TEXT", 1, 0], - ]; - const actualLeaseColumns = leaseColumns.map((column) => [ - column.name, - column.type.toUpperCase(), - column.notnull, - column.pk, - ]); - if (JSON.stringify(actualLeaseColumns) !== JSON.stringify(expectedLeaseColumns)) { - throw new Error("Schema v57 drift: task_leases columns do not match the canonical schema."); - } - - const columns = new Set( - db.prepare("pragma table_info(tasks)").all().map((row) => (row as { name: string }).name), - ); - for (const column of ["active_run_id", "checkout_run_id", "execution_locked_at", "active_session_id"]) { - if (columns.has(column)) { - throw new Error(`Schema v57 drift: tasks.${column} should be stored in task_leases.`); - } - } -} - -function installTaskLeasesTable(db: DatabaseSync): void { - db.exec(` - create table if not exists task_leases ( - task_id text primary key references tasks(id) on delete cascade, - company_id text not null, - run_id text not null unique references runs(id) on delete cascade, - agent_id text not null references agents(id) on delete cascade, - acquired_at text not null, - renewed_at text not null, - expires_at text not null, - created_at text not null, - updated_at text not null - ); - create index if not exists idx_task_leases_company_agent on task_leases(company_id, agent_id); - create index if not exists idx_task_leases_expires_at on task_leases(expires_at); - `); -} - -function backfillTaskLeases(db: DatabaseSync): void { - if (!tableExists(db, "tasks") || !tableExists(db, "runs")) return; - if (!columnExists(db, "tasks", "checkout_run_id") && !columnExists(db, "tasks", "active_run_id")) return; - - const runExpr = [ - columnExists(db, "tasks", "checkout_run_id") ? "t.checkout_run_id" : "NULL", - columnExists(db, "tasks", "active_run_id") ? "t.active_run_id" : "NULL", - ].join(", "); - const lockExpr = columnExists(db, "tasks", "execution_locked_at") - ? "coalesce(t.execution_locked_at, t.updated_at)" - : "t.updated_at"; - const ts = nowIso(); - - db.exec(` - insert or ignore into task_leases ( - task_id, company_id, run_id, agent_id, acquired_at, renewed_at, expires_at, created_at, updated_at - ) - select t.id, - t.company_id, - coalesce(${runExpr}) as run_id, - r.agent_id, - ${lockExpr} as acquired_at, - ${lockExpr} as renewed_at, - strftime('%Y-%m-%dT%H:%M:%fZ', ${lockExpr}, '+${LEASE_SECONDS} seconds') as expires_at, - '${ts}' as created_at, - '${ts}' as updated_at - from tasks t - join runs r on r.id = coalesce(${runExpr}) - where coalesce(${runExpr}) is not null - and r.status in ('queued', 'running') - `); -} - -function dropTaskOwnershipColumns(db: DatabaseSync): void { - if (!tableExists(db, "tasks")) return; - for (const column of ["active_run_id", "checkout_run_id", "execution_locked_at", "active_session_id"]) { - if (columnExists(db, "tasks", column)) { - db.exec(`alter table tasks drop column ${column}`); - } - } -} diff --git a/src/main/database/migrations/v58-approval-policies.ts b/src/main/database/migrations/v58-approval-policies.ts deleted file mode 100644 index 4d008481..00000000 --- a/src/main/database/migrations/v58-approval-policies.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { APPROVAL_POLICY_SEED } from "../../approval-policy-definitions"; -import { nowIso, tableExists } from "./types"; - -export const APPROVAL_POLICY_SCHEMA_VERSION = 58; -export const APPROVAL_POLICY_SCHEMA_NAME = "approval_policy_table"; - -export function migrateApprovalPoliciesV58(db: DatabaseSync): void { - installApprovalPoliciesTable(db); - seedApprovalPolicies(db); - db - .prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)") - .run(APPROVAL_POLICY_SCHEMA_VERSION, APPROVAL_POLICY_SCHEMA_NAME, nowIso()); - assertApprovalPoliciesV58(db); -} - -export function assertApprovalPoliciesV58(db: DatabaseSync): void { - if (!tableExists(db, "approval_policies")) { - throw new Error("Schema v58 drift: approval_policies table is missing."); - } - - const columns = db - .prepare("pragma table_info(approval_policies)") - .all() - .map((row) => row as { name: string; type: string; notnull: number; pk: number }); - const actualColumns = columns.map((column) => [ - column.name, - column.type.toUpperCase(), - column.notnull, - column.pk, - ]); - const expectedColumns = [ - ["approval_type", "TEXT", 0, 1], - ["scope_type", "TEXT", 1, 0], - ["blocks_execution", "INTEGER", 1, 0], - ["required_mode", "TEXT", 1, 0], - ["auto_approvable", "INTEGER", 1, 0], - ["created_at", "TEXT", 1, 0], - ["updated_at", "TEXT", 1, 0], - ]; - if (JSON.stringify(actualColumns) !== JSON.stringify(expectedColumns)) { - throw new Error("Schema v58 drift: approval_policies columns do not match the canonical schema."); - } - - const rows = db - .prepare( - "select approval_type as approvalType, scope_type as scopeType, blocks_execution as blocksExecution, required_mode as requiredMode, auto_approvable as autoApprovable from approval_policies order by approval_type", - ) - .all() as Array<{ - approvalType: string; - scopeType: string; - blocksExecution: number; - requiredMode: string; - autoApprovable: number; - }>; - const actual = rows.map((row) => ({ - approvalType: row.approvalType, - scopeType: row.scopeType, - blocksExecution: row.blocksExecution, - requiredMode: row.requiredMode, - autoApprovable: row.autoApprovable, - })); - const expected = [...APPROVAL_POLICY_SEED] - .sort((a, b) => a.approvalType.localeCompare(b.approvalType)) - .map((policy) => ({ - approvalType: policy.approvalType, - scopeType: policy.scopeType, - blocksExecution: policy.blocksExecution ? 1 : 0, - requiredMode: policy.requiredMode, - autoApprovable: policy.autoApprovable ? 1 : 0, - })); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - throw new Error("Schema v58 drift: approval_policies seed rows do not match the canonical policy."); - } -} - -function installApprovalPoliciesTable(db: DatabaseSync): void { - db.exec(` - create table if not exists approval_policies ( - approval_type text primary key, - scope_type text not null check (scope_type in ('requester_or_task', 'related_agent')), - blocks_execution integer not null check (blocks_execution in (0, 1)), - required_mode text not null check (required_mode in ('any', 'ai_ceo', 'ai_cofounder')), - auto_approvable integer not null check (auto_approvable in (0, 1)), - created_at text not null, - updated_at text not null - ); - `); -} - -function seedApprovalPolicies(db: DatabaseSync): void { - const ts = nowIso(); - const stmt = db.prepare( - `insert or replace into approval_policies ( - approval_type, scope_type, blocks_execution, required_mode, auto_approvable, created_at, updated_at - ) values (?, ?, ?, ?, ?, coalesce((select created_at from approval_policies where approval_type = ?), ?), ?)`, - ); - for (const policy of APPROVAL_POLICY_SEED) { - stmt.run( - policy.approvalType, - policy.scopeType, - policy.blocksExecution ? 1 : 0, - policy.requiredMode, - policy.autoApprovable ? 1 : 0, - policy.approvalType, - ts, - ts, - ); - } -} diff --git a/src/main/database/migrations/v59-social-company-scope.ts b/src/main/database/migrations/v59-social-company-scope.ts deleted file mode 100644 index edcf7e2d..00000000 --- a/src/main/database/migrations/v59-social-company-scope.ts +++ /dev/null @@ -1,163 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { nowIso, tableExists } from "./types"; - -export const SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION = 59; -export const SOCIAL_COMPANY_SCOPE_SCHEMA_NAME = "social_company_scope"; - -const TRIGGER_NAMES = [ - "trg_social_accounts_credential_secret_scope_insert", - "trg_social_accounts_credential_secret_scope_update", - "trg_browser_actions_social_account_scope_insert", - "trg_browser_actions_social_account_scope_update", -] as const; - -export function migrateSocialCompanyScopeV59(db: DatabaseSync): void { - cleanupInvalidSocialAccountSecretRefs(db); - cleanupInvalidBrowserActionRefs(db); - installSocialCompanyScopeTriggers(db); - db - .prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)") - .run(SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION, SOCIAL_COMPANY_SCOPE_SCHEMA_NAME, nowIso()); - assertSocialCompanyScopeV59(db); -} - -export function assertSocialCompanyScopeV59(db: DatabaseSync): void { - if (!tableExists(db, "social_accounts")) { - throw new Error("Schema v59 drift: social_accounts table is missing."); - } - if (!tableExists(db, "secrets")) { - throw new Error("Schema v59 drift: secrets table is missing."); - } - if (!tableExists(db, "browser_actions")) { - throw new Error("Schema v59 drift: browser_actions table is missing."); - } - const invalid = db - .prepare( - `select count(*) as count - from social_accounts sa - where sa.credential_secret_id is not null - and not exists ( - select 1 - from secrets s - where s.id = sa.credential_secret_id - and s.company_id = sa.company_id - )`, - ) - .get() as { count: number } | undefined; - if ((invalid?.count ?? 0) > 0) { - throw new Error("Schema v59 drift: social account credential secrets must belong to the same company."); - } - const invalidActions = db - .prepare( - `select count(*) as count - from browser_actions ba - where not exists ( - select 1 - from social_accounts sa - where sa.id = ba.social_account_id - and sa.company_id = ba.company_id - )`, - ) - .get() as { count: number } | undefined; - if ((invalidActions?.count ?? 0) > 0) { - throw new Error("Schema v59 drift: browser actions must reference social accounts in the same company."); - } - for (const triggerName of TRIGGER_NAMES) { - if (!triggerExists(db, triggerName)) { - throw new Error(`Schema v59 drift: ${triggerName} trigger is missing.`); - } - } -} - -function cleanupInvalidSocialAccountSecretRefs(db: DatabaseSync): void { - if (!tableExists(db, "social_accounts") || !tableExists(db, "secrets")) return; - db - .prepare( - `update social_accounts - set credential_secret_id = null, - updated_at = ? - where credential_secret_id is not null - and not exists ( - select 1 - from secrets s - where s.id = social_accounts.credential_secret_id - and s.company_id = social_accounts.company_id - )`, - ) - .run(nowIso()); -} - -function cleanupInvalidBrowserActionRefs(db: DatabaseSync): void { - if (!tableExists(db, "browser_actions") || !tableExists(db, "social_accounts")) return; - db - .prepare( - `delete from browser_actions - where not exists ( - select 1 - from social_accounts sa - where sa.id = browser_actions.social_account_id - and sa.company_id = browser_actions.company_id - )`, - ) - .run(); -} - -function installSocialCompanyScopeTriggers(db: DatabaseSync): void { - for (const triggerName of TRIGGER_NAMES) { - db.exec(`drop trigger if exists ${triggerName}`); - } - db.exec(` - create trigger trg_social_accounts_credential_secret_scope_insert - before insert on social_accounts - when new.credential_secret_id is not null - and not exists ( - select 1 from secrets - where id = new.credential_secret_id - and company_id = new.company_id - ) - begin - select raise(abort, 'social account credential secret must belong to the same company'); - end; - - create trigger trg_social_accounts_credential_secret_scope_update - before update of credential_secret_id, company_id on social_accounts - when new.credential_secret_id is not null - and not exists ( - select 1 from secrets - where id = new.credential_secret_id - and company_id = new.company_id - ) - begin - select raise(abort, 'social account credential secret must belong to the same company'); - end; - - create trigger trg_browser_actions_social_account_scope_insert - before insert on browser_actions - when not exists ( - select 1 from social_accounts - where id = new.social_account_id - and company_id = new.company_id - ) - begin - select raise(abort, 'browser action social account must belong to the same company'); - end; - - create trigger trg_browser_actions_social_account_scope_update - before update of social_account_id, company_id on browser_actions - when not exists ( - select 1 from social_accounts - where id = new.social_account_id - and company_id = new.company_id - ) - begin - select raise(abort, 'browser action social account must belong to the same company'); - end; - `); -} - -function triggerExists(db: DatabaseSync, name: string): boolean { - const row = db - .prepare("select name from sqlite_master where type = 'trigger' and name = ? limit 1") - .get(name) as { name: string } | undefined; - return Boolean(row); -} diff --git a/src/main/database/migrations/v60-filesystem-task-workspaces.ts b/src/main/database/migrations/v60-filesystem-task-workspaces.ts deleted file mode 100644 index 08d7c25a..00000000 --- a/src/main/database/migrations/v60-filesystem-task-workspaces.ts +++ /dev/null @@ -1,130 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { nowIso, tableExists } from "./types"; - -export const FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION = 60; -export const FILESYSTEM_TASK_WORKSPACES_SCHEMA_NAME = "filesystem_task_workspaces"; - -const ACTIVE_TASK_STATUSES = "'backlog', 'todo', 'in_progress', 'blocked'"; - -export function migrateFilesystemTaskWorkspacesV60(db: DatabaseSync): void { - backfillProjectWorkspaces(db); - backfillAssigneeWorkspaces(db); - backfillSingleCompanyWorkspaces(db); - db - .prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)") - .run(FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION, FILESYSTEM_TASK_WORKSPACES_SCHEMA_NAME, nowIso()); - assertFilesystemTaskWorkspacesV60(db); -} - -export function assertFilesystemTaskWorkspacesV60(db: DatabaseSync): void { - if (!tableExists(db, "tasks") || !tableExists(db, "workspaces")) { - throw new Error("Schema v60 drift: tasks/workspaces tables are missing."); - } - const unresolved = db - .prepare( - `select count(*) as count - from tasks t - where t.requires_filesystem = 1 - and t.workspace_id is null - and t.status in (${ACTIVE_TASK_STATUSES}) - and ( - select count(*) - from workspaces w - where w.company_id = t.company_id - ) = 1`, - ) - .get() as { count: number } | undefined; - if ((unresolved?.count ?? 0) > 0) { - throw new Error("Schema v60 drift: single-workspace companies still have unresolved filesystem tasks."); - } -} - -function backfillProjectWorkspaces(db: DatabaseSync): void { - if (!hasRequiredTables(db)) return; - db - .prepare( - `update tasks - set workspace_id = ( - select w.id - from workspaces w - where w.company_id = tasks.company_id - and w.project_id = tasks.project_id - order by w.is_primary desc, w.created_at asc - limit 1 - ), - updated_at = ? - where requires_filesystem = 1 - and workspace_id is null - and status in (${ACTIVE_TASK_STATUSES}) - and project_id is not null - and exists ( - select 1 - from workspaces w - where w.company_id = tasks.company_id - and w.project_id = tasks.project_id - )`, - ) - .run(nowIso()); -} - -function backfillAssigneeWorkspaces(db: DatabaseSync): void { - if (!hasRequiredTables(db) || !tableExists(db, "agents")) return; - db - .prepare( - `update tasks - set workspace_id = ( - select a.workspace_id - from agents a - join workspaces w - on w.id = a.workspace_id - and w.company_id = a.company_id - where a.id = tasks.assignee_agent_id - and a.company_id = tasks.company_id - limit 1 - ), - updated_at = ? - where requires_filesystem = 1 - and workspace_id is null - and status in (${ACTIVE_TASK_STATUSES}) - and assignee_agent_id is not null - and exists ( - select 1 - from agents a - join workspaces w - on w.id = a.workspace_id - and w.company_id = a.company_id - where a.id = tasks.assignee_agent_id - and a.company_id = tasks.company_id - )`, - ) - .run(nowIso()); -} - -function backfillSingleCompanyWorkspaces(db: DatabaseSync): void { - if (!hasRequiredTables(db)) return; - db - .prepare( - `update tasks - set workspace_id = ( - select w.id - from workspaces w - where w.company_id = tasks.company_id - order by w.is_primary desc, w.created_at asc - limit 1 - ), - updated_at = ? - where requires_filesystem = 1 - and workspace_id is null - and status in (${ACTIVE_TASK_STATUSES}) - and ( - select count(*) - from workspaces w - where w.company_id = tasks.company_id - ) = 1`, - ) - .run(nowIso()); -} - -function hasRequiredTables(db: DatabaseSync): boolean { - return tableExists(db, "tasks") && tableExists(db, "workspaces"); -} diff --git a/src/main/database/model-capabilities-crud.ts b/src/main/database/model-capabilities-crud.ts deleted file mode 100644 index c09584ed..00000000 --- a/src/main/database/model-capabilities-crud.ts +++ /dev/null @@ -1,126 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ModelCapability } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { nowIso } from "./helpers"; - -/** - * CRUD for `model_capabilities`. The table is (provider, model_id) keyed; the - * dispatcher reads it on every run, so every row must have numeric scores — - * we validate inputs at the application layer before touching the DB. - */ -export function buildModelCapabilityMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - type Row = { - provider: string; - model_id: string; - reasoning: number; - coding: number; - writing: number; - tier: "trivial" | "standard" | "hard"; - cost_per_mtok_out: number; - updated_at: string; - }; - - function rowToRecord(row: Row): ModelCapability { - return { - provider: row.provider, - modelId: row.model_id, - reasoning: row.reasoning, - coding: row.coding, - writing: row.writing, - tier: row.tier, - costPerMtokOut: row.cost_per_mtok_out, - updatedAt: row.updated_at, - }; - } - - function listModelCapabilities(): ModelCapability[] { - return readAll( - "SELECT provider, model_id, reasoning, coding, writing, tier, cost_per_mtok_out, updated_at FROM model_capabilities ORDER BY provider, model_id", - ).map(rowToRecord); - } - - function getModelCapability(provider: string, modelId: string): ModelCapability | null { - const row = getDb() - .prepare( - "SELECT provider, model_id, reasoning, coding, writing, tier, cost_per_mtok_out, updated_at FROM model_capabilities WHERE provider = ? AND model_id = ?", - ) - .get(provider, modelId) as Row | undefined; - return row ? rowToRecord(row) : null; - } - - function upsertModelCapability(input: Omit): void { - const now = nowIso(); - getDb() - .prepare( - `INSERT INTO model_capabilities (provider, model_id, reasoning, coding, writing, tier, cost_per_mtok_out, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(provider, model_id) DO UPDATE SET - reasoning = excluded.reasoning, - coding = excluded.coding, - writing = excluded.writing, - tier = excluded.tier, - cost_per_mtok_out = excluded.cost_per_mtok_out, - updated_at = excluded.updated_at`, - ) - .run( - input.provider, - input.modelId, - input.reasoning, - input.coding, - input.writing, - input.tier, - input.costPerMtokOut, - now, - ); - } - - function deleteModelCapability(provider: string, modelId: string): void { - getDb() - .prepare("DELETE FROM model_capabilities WHERE provider = ? AND model_id = ?") - .run(provider, modelId); - } - - /** - * Seed the table from a list of rows. Used at boot when the table is empty - * so a fresh install has something to dispatch against. Runs inside a - * single transaction so either every row is written or none — we don't - * want partial seeding if something goes wrong mid-loop. - */ - function seedModelCapabilities(rows: Array>): number { - return transaction(() => { - let inserted = 0; - const ts = nowIso(); - const stmt = getDb().prepare( - `INSERT OR IGNORE INTO model_capabilities ( - provider, model_id, reasoning, coding, writing, tier, cost_per_mtok_out, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - ); - for (const row of rows) { - const result = stmt.run( - row.provider, - row.modelId, - row.reasoning, - row.coding, - row.writing, - row.tier, - row.costPerMtokOut, - ts, - ); - inserted += Number(result.changes ?? 0); - } - return inserted; - }); - } - - return { - listModelCapabilities, - getModelCapability, - upsertModelCapability, - deleteModelCapability, - seedModelCapabilities, - }; -} diff --git a/src/main/database/run-events.ts b/src/main/database/run-events.ts deleted file mode 100644 index 6e2d6b82..00000000 --- a/src/main/database/run-events.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { type ReadAll, type SqliteRow, type Transaction, nowIso } from "./helpers"; - -/** - * run_events helpers extracted from runs.ts. Every method is spread into - * the final `buildRunMethods` result so AppDatabase call-sites remain - * unchanged. - */ -export function buildRunEventMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - appendRunEvent(input: { - companyId: string; runId: string; agentId: string; - eventType: string; stream?: string | null; level?: string | null; - message?: string | null; payload?: Record | null; - }): void { - const ts = nowIso(); - transaction(() => { - const lastSeq = getDb().prepare( - "SELECT MAX(seq) as maxSeq FROM run_events WHERE run_id = ?" - ).get(input.runId) as { maxSeq: number | null } | undefined; - const seq = (lastSeq?.maxSeq ?? 0) + 1; - getDb().prepare( - "INSERT INTO run_events (company_id, run_id, agent_id, seq, event_type, stream, level, message, payload, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - ).run( - input.companyId, input.runId, input.agentId, seq, - input.eventType, input.stream ?? null, input.level ?? null, - input.message ?? null, input.payload ? JSON.stringify(input.payload) : null, ts - ); - }); - }, - - listRunEvents(runId: string, companyId: string, opts?: { offset?: number; limit?: number }): Array<{ - id: number; runId: string; agentId: string; seq: number; eventType: string; - stream: string | null; level: string | null; message: string | null; - payload: Record | null; createdAt: string; - }> { - const offset = opts?.offset ?? 0; - const limit = opts?.limit ?? 500; - return readAll( - "SELECT id, run_id, agent_id, seq, event_type, stream, level, message, payload, created_at FROM run_events WHERE run_id = ? AND company_id = ? ORDER BY seq ASC LIMIT ? OFFSET ?", - runId, companyId, limit, offset - ).map((row: SqliteRow) => ({ - id: row.id, - runId: row.run_id, - agentId: row.agent_id, - seq: row.seq, - eventType: row.event_type, - stream: row.stream, - level: row.level, - message: row.message, - payload: row.payload ? JSON.parse(row.payload) : null, - createdAt: row.created_at, - })); - }, - - listRunEventsAfter(runId: string, companyId: string, afterSeq: number, limit: number): Array<{ - id: number; runId: string; agentId: string; seq: number; eventType: string; - stream: string | null; level: string | null; message: string | null; - payload: Record | null; createdAt: string; - }> { - return readAll( - "SELECT id, run_id, agent_id, seq, event_type, stream, level, message, payload, created_at FROM run_events WHERE run_id = ? AND company_id = ? AND seq > ? ORDER BY seq ASC LIMIT ?", - runId, companyId, afterSeq, limit - ).map((row: SqliteRow) => ({ - id: row.id, - runId: row.run_id, - agentId: row.agent_id, - seq: row.seq, - eventType: row.event_type, - stream: row.stream, - level: row.level, - message: row.message, - payload: row.payload ? JSON.parse(row.payload) : null, - createdAt: row.created_at, - })); - }, - }; -} diff --git a/src/main/database/run-logs.ts b/src/main/database/run-logs.ts deleted file mode 100644 index f081ece1..00000000 --- a/src/main/database/run-logs.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { writeFileSync, readFileSync, existsSync, statSync, openSync, readSync, closeSync } from "node:fs"; -import { appendFile } from "node:fs/promises"; -import type { DatabaseSync } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { RunLogChunk } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; - -/** - * Find the last complete UTF-8 character boundary in a buffer. - * Returns the number of bytes up to (and including) the last complete character. - * This prevents corrupting multi-byte CJK characters when slicing at chunk edges. - */ -export function findUtf8Boundary(buffer: Buffer, bytesRead: number): number { - if (bytesRead === 0) return 0; - let pos = bytesRead - 1; - while (pos >= 0 && (buffer[pos] & 0xc0) === 0x80) { - pos--; - } - if (pos < 0) return bytesRead; - const lead = buffer[pos]; - let charLen: number; - if ((lead & 0x80) === 0) charLen = 1; - else if ((lead & 0xe0) === 0xc0) charLen = 2; - else if ((lead & 0xf0) === 0xe0) charLen = 3; - else if ((lead & 0xf8) === 0xf0) charLen = 4; - else return bytesRead; - if (pos + charLen <= bytesRead) return bytesRead; - return pos; -} - -/** - * Run log file-IO helpers extracted from runs.ts. Every method is spread - * into the final `buildRunMethods` result so AppDatabase call-sites remain - * unchanged. `writeFileSync` is re-exported indirectly through createRun - * (still in runs.ts) via the shared logs directory. - */ -export function buildRunLogMethods( - getDb: () => DatabaseSync, - _readAll: ReadAll, - _transaction: Transaction, -) { - return { - appendRunLog(runId: string, stream: "stdout" | "stderr", chunk: string) { - const run = getDb().prepare("select log_path as logPath from runs where id = ?").get(runId) as { logPath: string | null } | undefined; - if (!run?.logPath) return; - return appendFile(run.logPath, `[${new Date().toISOString()}][${stream}] ${chunk}`, "utf8"); - }, - - readRunLog(runId: string) { - const run = getDb().prepare("select log_path as logPath from runs where id = ?").get(runId) as { logPath: string | null } | undefined; - if (!run?.logPath) return ""; - try { - return readFileSync(run.logPath, "utf8"); - } catch (err) { - log.warn(`[database/runs] readFileSync failed for run ${runId} log ${run.logPath}:`, err instanceof Error ? err.message : String(err)); - return ""; - } - }, - - readRunLogChunk(runId: string, offset = 0, limit = 65_536): RunLogChunk { - const run = getDb().prepare("select log_path as logPath from runs where id = ?").get(runId) as { logPath: string | null } | undefined; - if (!run?.logPath || !existsSync(run.logPath)) { - return { content: "", offset: 0, nextOffset: 0, totalBytes: 0, eof: true }; - } - - const totalBytes = statSync(run.logPath).size; - const safeOffset = Math.max(0, Math.min(offset, totalBytes)); - const safeLimit = Math.max(1_024, Math.min(limit, 262_144)); - const bytesToRead = Math.max(0, Math.min(safeLimit, totalBytes - safeOffset)); - - if (bytesToRead === 0) { - return { content: "", offset: safeOffset, nextOffset: safeOffset, totalBytes, eof: true }; - } - - const fileDescriptor = openSync(run.logPath, "r"); - try { - const buffer = Buffer.allocUnsafe(bytesToRead); - const bytesRead = readSync(fileDescriptor, buffer, 0, bytesToRead, safeOffset); - const safeBytesRead = findUtf8Boundary(buffer, bytesRead); - const nextOffset = safeOffset + safeBytesRead; - return { - content: buffer.subarray(0, safeBytesRead).toString("utf8"), - offset: safeOffset, - nextOffset, - totalBytes, - eof: nextOffset >= totalBytes, - }; - } finally { - closeSync(fileDescriptor); - } - }, - }; -} - -// Re-exported so runs.ts can still use writeFileSync on run creation. -export { writeFileSync }; diff --git a/src/main/database/runs.ts b/src/main/database/runs.ts deleted file mode 100644 index d84f362c..00000000 --- a/src/main/database/runs.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { rmSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { ConnectorId, RunRecord, RunUsageStatus } from "@shared/types"; -import { type ReadAll, type Transaction, nowIso, toBoolean } from "./helpers"; -import { buildRunLogMethods } from "./run-logs"; -import { buildRunEventMethods } from "./run-events"; -import { buildCostEntryMethods } from "./cost-entries"; -import { checkoutTaskInTransaction } from "./task-checkout"; -import { deriveLegacyRunUsageStatus } from "../run-usage-status"; - -class TaskCheckoutConflict extends Error { - constructor(readonly taskId: string) { - super(`Task checkout conflict: ${taskId}`); - } -} - -export function buildRunMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - logsDir: string; - }, -) { - function createEmptyRunLog(logPath: string): void { - writeFileSync(logPath, "", { encoding: "utf8", flag: "wx" }); - } - - function cleanupEmptyRunLog(logPath: string): void { - rmSync(logPath, { force: true }); - } - - function insertRunRow(input: { - id: string; - companyId: string; - taskId: string | null; - agentId: string; - workspaceId: string | null; - connectorId: ConnectorId; - logPath: string; - ts: string; - }): void { - getDb() - .prepare( - "insert into runs (id, company_id, task_id, agent_id, workspace_id, connector_id, status, summary, unattributed_cost, log_path, created_at, updated_at) values (?, ?, ?, ?, ?, ?, 'queued', '', 0, ?, ?, ?)", - ) - .run( - input.id, - input.companyId, - input.taskId, - input.agentId, - input.workspaceId, - input.connectorId, - input.logPath, - input.ts, - input.ts, - ); - } - - return { - ...buildRunLogMethods(getDb, readAll, transaction), - ...buildRunEventMethods(getDb, readAll, transaction), - ...buildCostEntryMethods(getDb, readAll, transaction), - - getRun(id: string): RunRecord { - const row = getDb() - .prepare( - "select id, company_id as companyId, task_id as taskId, agent_id as agentId, workspace_id as workspaceId, connector_id as connectorId, status, summary, error_message as errorMessage, exit_code as exitCode, signal, model, cost_usd as costUsd, unattributed_cost as unattributedCost, usage_status as usageStatus, started_at as startedAt, finished_at as finishedAt, log_path as logPath, created_at as createdAt, updated_at as updatedAt from runs where id = ?", - ) - .get(id) as RunRecord | undefined; - if (!row) throw new Error(`Run not found: ${id}`); - row.unattributedCost = Boolean(row.unattributedCost); - return row; - }, - - getRunAuthState(runId: string): { id: string; companyId: string; agentId: string; status: RunRecord["status"] } | null { - const row = getDb() - .prepare("select id, company_id as companyId, agent_id as agentId, status from runs where id = ?") - .get(runId) as { id: string; companyId: string; agentId: string; status: RunRecord["status"] } | undefined; - return row ?? null; - }, - - createRun(input: { - id?: string; - companyId: string; - taskId: string | null; - agentId: string; - workspaceId: string | null; - connectorId: ConnectorId; - }) { - const id = input.id ?? randomUUID(); - const ts = nowIso(); - const logPath = join(deps.logsDir, `${id}.log`); - createEmptyRunLog(logPath); - try { - transaction(() => { - insertRunRow({ ...input, id, logPath, ts }); - }); - } catch (error) { - cleanupEmptyRunLog(logPath); - throw error; - } - return { id, logPath }; - }, - - createTaskRun(input: { - id?: string; - companyId: string; - taskId: string; - agentId: string; - workspaceId: string | null; - connectorId: ConnectorId; - }): { id: string; logPath: string } | null { - const id = input.id ?? randomUUID(); - const ts = nowIso(); - const logPath = join(deps.logsDir, `${id}.log`); - createEmptyRunLog(logPath); - try { - transaction(() => { - insertRunRow({ ...input, id, logPath, ts }); - const checkoutOk = checkoutTaskInTransaction(getDb(), input.taskId, id); - if (!checkoutOk) { - throw new TaskCheckoutConflict(input.taskId); - } - }); - } catch (error) { - cleanupEmptyRunLog(logPath); - if (error instanceof TaskCheckoutConflict) { - return null; - } - throw error; - } - return { id, logPath }; - }, - - markRunStatus(runId: string, status: RunRecord["status"], message: string | null) { - const ts = nowIso(); - const startedAt = status === "running" ? ts : null; - transaction(() => { - getDb() - .prepare( - "update runs set status = ?, summary = case when ? is not null then ? else summary end, started_at = coalesce(started_at, ?), updated_at = ? where id = ?", - ) - .run(status, message, message, startedAt, ts, runId); - - if (status === "running") { - const run = getDb().prepare("select agent_id from runs where id = ?").get(runId) as { agent_id: string } | undefined; - if (run) { - getDb() - .prepare("update agents set status = 'running', updated_at = ? where id = ? and status in ('idle', 'active')") - .run(ts, run.agent_id); - } - } - }); - }, - - finishRun(input: { - runId: string; - status: RunRecord["status"]; - summary: string | null; - errorMessage: string | null; - exitCode: number | null; - signal: string | null; - model: string | null; - unattributedCost: boolean; - usageStatus?: RunUsageStatus; - recoverTaskForRetry?: boolean; - }) { - const run = getDb().prepare("select task_id as taskId, agent_id as agentId, company_id as companyId, connector_id as connectorId, started_at as startedAt from runs where id = ?").get(input.runId) as - | { taskId: string | null; agentId: string; companyId: string; connectorId: ConnectorId; startedAt: string | null } - | undefined; - if (!run) return { budgetHardStopped: false }; - // Recoverable terminal paths must roll the task back to 'todo'. - // Otherwise the task is stuck in 'in_progress' with no owner: - // checkoutTask refuses (WHERE status IN todo/backlog), and the - // scheduler loops forever logging "lost checkout race". - const runNeverStarted = - run.startedAt === null && (input.status === "failed" || input.status === "cancelled"); - const shouldReturnTaskToTodo = - run.taskId !== null && (runNeverStarted || input.recoverTaskForRetry === true); - const ts = nowIso(); - const usageStatus = input.usageStatus ?? deriveLegacyRunUsageStatus({ - runStatus: input.status, - unattributedCost: input.unattributedCost, - }); - - // Cost is owned by CostWriter — per-message rows in `cost_entries`. - // finishRun reads the aggregate instead of writing another row, so - // there is exactly one source of truth and `cost_entries.run_id` - // cannot double-count against the previous finishRun INSERT. - const costRow = getDb() - .prepare("select coalesce(sum(amount_usd), 0) as total from cost_entries where run_id = ? and unattributed = 0") - .get(input.runId) as { total: number } | undefined; - const runCostUsd = costRow?.total ?? 0; - - const agent = getDb().prepare( - "select budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, status from agents where id = ?", - ).get(run.agentId) as { budgetMonthlyUsd: number; spentMonthlyUsd: number; status: string } | undefined; - const nextSpend = (agent?.spentMonthlyUsd ?? 0) + runCostUsd; - const budgetHardStopped = Boolean( - agent && - agent.budgetMonthlyUsd > 0 && - nextSpend >= agent.budgetMonthlyUsd && - agent.status !== "paused" && - agent.status !== "terminated", - ); - transaction(() => { - getDb() - .prepare( - "update runs set status = ?, summary = ?, error_message = ?, exit_code = ?, signal = ?, model = ?, cost_usd = ?, unattributed_cost = ?, usage_status = ?, finished_at = ?, updated_at = ? where id = ?", - ) - .run( - input.status, input.summary ?? "", input.errorMessage, input.exitCode, - input.signal, input.model, runCostUsd, - input.unattributedCost ? 1 : 0, usageStatus, ts, ts, input.runId, - ); - if (run.taskId !== null) { - getDb() - .prepare("delete from task_leases where task_id = ? and run_id = ?") - .run(run.taskId, input.runId); - if (shouldReturnTaskToTodo) { - // Roll the task back to `todo` when no *other* live run claims - // it. Invariant: `task.status = 'in_progress'` ⇒ a queued or - // running run owns it through `task_leases`. - getDb() - .prepare( - `UPDATE tasks - SET status = 'todo', - updated_at = ? - WHERE id = ? - AND status = 'in_progress' - AND NOT EXISTS ( - SELECT 1 FROM task_leases l - WHERE l.task_id = tasks.id - AND l.run_id != ? - )`, - ) - .run(ts, run.taskId, input.runId); - } - } - if (runCostUsd > 0) { - if (run.taskId !== null) { - getDb() - .prepare("update tasks set cost_usd = cost_usd + ?, updated_at = ? where id = ?") - .run(runCostUsd, ts, run.taskId); - } - getDb() - .prepare("update agents set spent_monthly_usd = spent_monthly_usd + ?, updated_at = ? where id = ?") - .run(runCostUsd, ts, run.agentId); - } - if (budgetHardStopped) { - getDb() - .prepare("update agents set status = 'paused', updated_at = ? where id = ?") - .run(ts, run.agentId); - } else { - getDb() - .prepare("update agents set status = 'idle', updated_at = ? where id = ? and status = 'running'") - .run(ts, run.agentId); - } - }); - return { budgetHardStopped }; - }, - - markRunCompletionFailure(runId: string, errorMessage: string): void { - const ts = nowIso(); - transaction(() => { - getDb() - .prepare( - "update runs set status = 'failed', summary = ?, error_message = ?, usage_status = 'error_stop', finished_at = coalesce(finished_at, ?), updated_at = ? where id = ?", - ) - .run("Run completion blocked by artifact projection failure.", errorMessage, ts, ts, runId); - }); - }, - - cancelRunForDeletion(runId: string, taskId: string | null, workspaceId: string | null, summary: string) { - const ts = nowIso(); - getDb() - .prepare( - "update runs set status = 'cancelled', summary = ?, error_message = null, exit_code = null, signal = null, model = null, cost_usd = null, unattributed_cost = 1, usage_status = ?, finished_at = ?, updated_at = ? where id = ?", - ) - .run(summary, "aborted_before_usage", ts, ts, runId); - if (taskId !== null) { - getDb() - .prepare("delete from task_leases where task_id = ? and run_id = ?") - .run(taskId, runId); - } - if (workspaceId) { - getDb() - .prepare( - `update workspaces - set lock_holder_run_id = null, lock_acquired_at = null, state = 'ready', updated_at = ? - where id = ? and lock_holder_run_id = ?`, - ) - .run(ts, workspaceId, runId); - } - }, - - hasActiveRun(filter: { companyId: string; taskId?: string; agentId?: string }) { - if (filter.taskId) { - const whereClauses = [ - "l.company_id = ?", - "l.task_id = ?", - "r.status in ('queued', 'running')", - ]; - const params: SQLInputValue[] = [filter.companyId, filter.taskId]; - if (filter.agentId) { - whereClauses.push("r.agent_id = ?"); - params.push(filter.agentId); - } - const row = getDb().prepare( - `select 1 as present - from task_leases l - join runs r on r.id = l.run_id - where ${whereClauses.join(" and ")} - limit 1`, - ).get(...params) as { present: number } | undefined; - return Boolean(row?.present); - } - - const whereClauses = ["company_id = ?", "status in ('queued', 'running')"]; - const params: SQLInputValue[] = [filter.companyId]; - if (filter.agentId) { - whereClauses.push("agent_id = ?"); - params.push(filter.agentId); - } - const row = getDb().prepare( - `select 1 as present from runs where ${whereClauses.join(" and ")} limit 1`, - ).get(...params) as { present: number } | undefined; - return Boolean(row?.present); - }, - - listQueuedRuns() { - return readAll( - `select id, company_id as companyId, task_id as taskId, agent_id as agentId, workspace_id as workspaceId, - connector_id as connectorId, status, summary, error_message as errorMessage, exit_code as exitCode, - signal, model, cost_usd as costUsd, - unattributed_cost as unattributedCost, usage_status as usageStatus, started_at as startedAt, finished_at as finishedAt, - log_path as logPath, created_at as createdAt, updated_at as updatedAt - from runs - where status = 'queued' - order by created_at asc`, - ).map((record) => ({ ...record, unattributedCost: toBoolean(record.unattributedCost) })) as RunRecord[]; - }, - - getInterruptedRunsForRecovery(): Array<{ - runId: string; taskId: string; taskTitle: string; agentId: string; - agentName: string; companyId: string; connectorId: string; interruptedAt: string; - }> { - return readAll<{ - runId: string; taskId: string; taskTitle: string; agentId: string; - agentName: string; companyId: string; connectorId: string; interruptedAt: string; - }>( - `select r.id as runId, r.task_id as taskId, t.title as taskTitle, - r.agent_id as agentId, a.name as agentName, - r.company_id as companyId, - r.connector_id as connectorId, r.finished_at as interruptedAt - from runs r - join tasks t on t.id = r.task_id - join agents a on a.id = r.agent_id - where r.status = 'interrupted' - and t.status = 'blocked' - order by r.finished_at desc` - ); - }, - - updateRunActor(runId: string, actorType: string, actorId: string | null): void { - getDb().prepare( - "UPDATE runs SET actor_type = ?, actor_id = ?, updated_at = ? WHERE id = ?" - ).run(actorType, actorId, nowIso(), runId); - }, - }; -} diff --git a/src/main/database/schema.ts b/src/main/database/schema.ts index db6ca50a..ff507503 100644 --- a/src/main/database/schema.ts +++ b/src/main/database/schema.ts @@ -1,173 +1,149 @@ import type { DatabaseSync } from "node:sqlite"; -import log from "electron-log/main.js"; -import { - BASELINE_SCHEMA_VERSION, - assertBaselineSchema, - installBaselineSchema, -} from "./migrations/baseline-v56"; -import { - markBaselineSchema, - upgradeLegacyProfileToBaselineV56, -} from "./migrations/legacy-to-v56"; -import { - TASK_LEASE_SCHEMA_VERSION, - assertTaskLeasesV57, - migrateTaskLeasesV57, -} from "./migrations/v57-task-leases"; -import { - APPROVAL_POLICY_SCHEMA_VERSION, - assertApprovalPoliciesV58, - migrateApprovalPoliciesV58, -} from "./migrations/v58-approval-policies"; -import { - SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION, - assertSocialCompanyScopeV59, - migrateSocialCompanyScopeV59, -} from "./migrations/v59-social-company-scope"; -import { - FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION, - assertFilesystemTaskWorkspacesV60, - migrateFilesystemTaskWorkspacesV60, -} from "./migrations/v60-filesystem-task-workspaces"; -import { - type ReadAll, - type Transaction, -} from "./migrations/types"; +import { initialEnterpriseSchema } from "./migrations/001-initial"; +import { collaborationProviderPolicySchema } from "./migrations/002-collaboration"; +import { onboardingExecutionSchema } from "./migrations/003-onboarding"; +import { filesPinnedAndScheduledPosts } from "./migrations/004-files-posts"; +import { chatReadState } from "./migrations/005-chat-read-state"; +import { appStateSchema } from "./migrations/006-app-state"; +import { skillHardeningSchema } from "./migrations/007-skill-hardening"; +import { providerHealthSchema } from "./migrations/008-provider-health"; +import { socialGovernanceSchema } from "./migrations/009-social-governance"; +import { fileHandoffSecuritySchema } from "./migrations/010-file-handoff-security"; +import { boardInterventionSchema } from "./migrations/011-board-interventions"; +import { complianceControlsSchema } from "./migrations/012-compliance-controls"; +import { searchDocumentsSchema } from "./migrations/013-search-documents"; +import { providerPolicyUsageSchema } from "./migrations/014-provider-policy-usage"; +import { identityAccessSchema } from "./migrations/015-identity-access"; +import { orgGovernanceSchema } from "./migrations/016-org-governance"; +import { operationsControlsSchema } from "./migrations/017-operations-controls"; +import { sdlcControlsSchema } from "./migrations/018-sdlc-controls"; +import { auditReplaySchema } from "./migrations/019-audit-replay"; +import { rollbackSnapshotsSchema } from "./migrations/020-rollback-snapshots"; +import { providerAuthBrokerSchema } from "./migrations/021-provider-auth-broker"; +import { providerRateLimitObservationSchema } from "./migrations/022-provider-rate-limit-observations"; +import { providerRequestRuntimeSchema } from "./migrations/023-provider-request-runtime"; +import { taskRunProviderRequestSchema } from "./migrations/024-task-run-provider-request"; +import { chatMessageDeliverySchema } from "./migrations/025-chat-message-delivery"; +import { browserPlatformGovernanceSchema } from "./migrations/026-browser-platform-governance"; +import { socialAuditRecordsSchema } from "./migrations/027-social-audit-records"; +import { migrationCutoverJournalSchema } from "./migrations/028-migration-cutover-journal"; +import { fileHandoffRecordsSchema } from "./migrations/029-file-handoff-records"; +import { approvalSourceRefsSchema } from "./migrations/030-approval-source-refs"; +import { providerRequestWorkspaceSchema } from "./migrations/031-provider-request-workspace"; +import { browserActionMetadataSchema } from "./migrations/032-browser-action-metadata"; +import { auditEventImmutabilitySchema } from "./migrations/033-audit-event-immutability"; +import { providerAuthSessionsSchema } from "./migrations/034-provider-auth-sessions"; +import { taskRunIsolationSchema } from "./migrations/035-task-run-isolation"; +import { additionalConnectorsSchema } from "./migrations/036-additional-connectors"; +import { customProvidersSchema } from "./migrations/037-custom-providers"; +import { providerAuthProfileCascadeSchema } from "./migrations/038-provider-auth-profile-cascade"; +import { auditImmutabilityOrgTeardownSchema } from "./migrations/039-audit-immutability-org-teardown"; +import { documentsKnowledgeAutomationSchema } from "./migrations/040-documents-knowledge-automation"; +import { taskSubtasksDeleteSchema } from "./migrations/041-task-subtasks-delete"; +import { approvalNotesMeetingsSprintsSchema } from "./migrations/042-approval-notes-meetings-sprints"; +import { composioIntegrationSchema } from "./migrations/043-composio-integration"; +import { mentionWakeStateSchema } from "./migrations/044-mention-wake-state"; +import { connectorGrantsSchema } from "./migrations/045-connector-grants"; -const LATEST_SCHEMA_VERSION = FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION; - -export function initializeDatabase( - db: DatabaseSync, - ra: ReadAll, - tx: Transaction, - createAutomaticBackup: (reason: string) => string, -): void { - db.exec("create table if not exists schema_migrations (version integer primary key, name text not null, applied_at text not null)"); - - const currentVersion = currentSchemaVersion(db); - if (currentVersion > LATEST_SCHEMA_VERSION) { - throw new Error(`Profile schema version ${currentVersion} is newer than this app schema ${LATEST_SCHEMA_VERSION}.`); - } - - if (currentVersion === LATEST_SCHEMA_VERSION) { - tx(() => { - seedSettings(db); - assertTaskLeasesV57(db); - assertApprovalPoliciesV58(db); - assertSocialCompanyScopeV59(db); - assertFilesystemTaskWorkspacesV60(db); - }); - return; - } - - if (currentVersion === SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION) { - tx(() => { - seedSettings(db); - assertTaskLeasesV57(db); - assertApprovalPoliciesV58(db); - assertSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); - return; - } - - if (currentVersion === APPROVAL_POLICY_SCHEMA_VERSION) { - tx(() => { - seedSettings(db); - assertTaskLeasesV57(db); - assertApprovalPoliciesV58(db); - migrateSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); - return; - } - - if (currentVersion === TASK_LEASE_SCHEMA_VERSION) { - tx(() => { - seedSettings(db); - assertTaskLeasesV57(db); - migrateApprovalPoliciesV58(db); - migrateSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); - return; - } - - if (currentVersion === BASELINE_SCHEMA_VERSION) { - tx(() => { - installBaselineSchema(db); - markBaselineSchema(db); - seedSettings(db); - assertBaselineSchema(db); - migrateTaskLeasesV57(db); - migrateApprovalPoliciesV58(db); - migrateSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); - return; - } - - if (profileHasApplicationTables(db)) { - const backupPath = createAutomaticBackup(`pre-migration-v${BASELINE_SCHEMA_VERSION}`); - log.info(`[schema] pre-migration snapshot for v${BASELINE_SCHEMA_VERSION} at ${backupPath}`); - withForeignKeysPaused(db, tx, () => { - upgradeLegacyProfileToBaselineV56({ db, readAll: ra }); - seedSettings(db); - assertBaselineSchema(db); - migrateTaskLeasesV57(db); - migrateApprovalPoliciesV58(db); - migrateSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); - return; - } - - tx(() => { - installBaselineSchema(db); - markBaselineSchema(db); - seedSettings(db); - assertBaselineSchema(db); - migrateTaskLeasesV57(db); - migrateApprovalPoliciesV58(db); - migrateSocialCompanyScopeV59(db); - migrateFilesystemTaskWorkspacesV60(db); - }); +interface Migration { + version: number; + name: string; + sql: string; } -export function seedSettings(db: DatabaseSync): void { - const getSetting = (key: string): string | null => { - const row = db.prepare("select value from settings where key = ?").get(key) as { value: string } | undefined; - return row?.value ?? null; - }; - const setSetting = (key: string, value: string) => { - db.prepare("insert into settings (key, value) values (?, ?) on conflict(key) do update set value = excluded.value").run(key, value); - }; - if (!getSetting("theme")) setSetting("theme", "system"); - if (!getSetting("updates_enabled")) setSetting("updates_enabled", "false"); - if (!getSetting("log_retention_days")) setSetting("log_retention_days", "90"); +const MIGRATIONS: Migration[] = [ + { version: 1, name: "initial_enterprise_schema", sql: initialEnterpriseSchema }, + { version: 2, name: "collaboration_provider_policy_schema", sql: collaborationProviderPolicySchema }, + { version: 3, name: "onboarding_execution_schema", sql: onboardingExecutionSchema }, + { version: 4, name: "files_pinned_and_scheduled_posts", sql: filesPinnedAndScheduledPosts }, + { version: 5, name: "chat_read_state", sql: chatReadState }, + { version: 6, name: "app_state", sql: appStateSchema }, + { version: 7, name: "skill_hardening", sql: skillHardeningSchema }, + { version: 8, name: "provider_health", sql: providerHealthSchema }, + { version: 9, name: "social_governance", sql: socialGovernanceSchema }, + { version: 10, name: "file_handoff_security", sql: fileHandoffSecuritySchema }, + { version: 11, name: "board_interventions", sql: boardInterventionSchema }, + { version: 12, name: "compliance_controls", sql: complianceControlsSchema }, + { version: 13, name: "search_documents", sql: searchDocumentsSchema }, + { version: 14, name: "provider_policy_usage", sql: providerPolicyUsageSchema }, + { version: 15, name: "identity_access", sql: identityAccessSchema }, + { version: 16, name: "org_governance", sql: orgGovernanceSchema }, + { version: 17, name: "operations_controls", sql: operationsControlsSchema }, + { version: 18, name: "sdlc_controls", sql: sdlcControlsSchema }, + { version: 19, name: "audit_replay", sql: auditReplaySchema }, + { version: 20, name: "rollback_snapshots", sql: rollbackSnapshotsSchema }, + { version: 21, name: "provider_auth_broker", sql: providerAuthBrokerSchema }, + { version: 22, name: "provider_rate_limit_observations", sql: providerRateLimitObservationSchema }, + { version: 23, name: "provider_request_runtime", sql: providerRequestRuntimeSchema }, + { version: 24, name: "task_run_provider_request", sql: taskRunProviderRequestSchema }, + { version: 25, name: "chat_message_delivery", sql: chatMessageDeliverySchema }, + { version: 26, name: "browser_platform_governance", sql: browserPlatformGovernanceSchema }, + { version: 27, name: "social_audit_records", sql: socialAuditRecordsSchema }, + { version: 28, name: "migration_cutover_journal", sql: migrationCutoverJournalSchema }, + { version: 29, name: "file_handoff_records", sql: fileHandoffRecordsSchema }, + { version: 30, name: "approval_source_refs", sql: approvalSourceRefsSchema }, + { version: 31, name: "provider_request_workspace", sql: providerRequestWorkspaceSchema }, + { version: 32, name: "browser_action_metadata", sql: browserActionMetadataSchema }, + { version: 33, name: "audit_event_immutability", sql: auditEventImmutabilitySchema }, + { version: 34, name: "provider_auth_sessions", sql: providerAuthSessionsSchema }, + { version: 35, name: "task_run_isolation", sql: taskRunIsolationSchema }, + { version: 36, name: "additional_connectors", sql: additionalConnectorsSchema }, + { version: 37, name: "custom_providers", sql: customProvidersSchema }, + { version: 38, name: "provider_auth_profile_cascade", sql: providerAuthProfileCascadeSchema }, + { version: 39, name: "audit_immutability_org_teardown", sql: auditImmutabilityOrgTeardownSchema }, + { version: 40, name: "documents_knowledge_automation", sql: documentsKnowledgeAutomationSchema }, + { version: 41, name: "task_subtasks_delete", sql: taskSubtasksDeleteSchema }, + { version: 42, name: "approval_notes_meetings_sprints", sql: approvalNotesMeetingsSprintsSchema }, + { version: 43, name: "composio_integration", sql: composioIntegrationSchema }, + { version: 44, name: "mention_wake_state", sql: mentionWakeStateSchema }, + { version: 45, name: "connector_grants", sql: connectorGrantsSchema }, +]; + +const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version; + +export function installSchema(db: DatabaseSync): void { + db.exec(` + create table if not exists schema_migrations ( + version integer primary key, + name text not null, + applied_at text not null + ); + `); + + const row = db.prepare("select coalesce(max(version), 0) as version from schema_migrations").get() as { version: number }; + let currentVersion = row.version; + if (currentVersion > SCHEMA_VERSION) { + throw new Error(`Database schema ${currentVersion} is newer than supported schema ${SCHEMA_VERSION}.`); + } + backfillMigrationLedger(db, currentVersion); + + for (const migration of MIGRATIONS) { + if (currentVersion >= migration.version) continue; + applyMigration(db, migration); + currentVersion = migration.version; + } } -function currentSchemaVersion(db: DatabaseSync): number { - const row = db - .prepare("select coalesce(max(version), 0) as version from schema_migrations") - .get() as { version: number } | undefined; - return row?.version ?? 0; -} - -function profileHasApplicationTables(db: DatabaseSync): boolean { - const rows = db - .prepare("select name from sqlite_master where type = 'table' and name not like 'sqlite_%'") - .all() as Array<{ name: string }>; - return rows.some((row) => row.name !== "schema_migrations" && row.name !== "settings"); -} - -function withForeignKeysPaused(db: DatabaseSync, tx: Transaction, op: () => T): T { - const row = db.prepare("pragma foreign_keys").get() as { foreign_keys: number } | undefined; - const previous = row?.foreign_keys === 1 ? "ON" : "OFF"; - db.exec("pragma foreign_keys = OFF"); +function applyMigration(db: DatabaseSync, migration: Migration): void { + db.exec("begin immediate"); try { - return tx(op); - } finally { - db.exec(`pragma foreign_keys = ${previous}`); + db.exec(migration.sql); + recordMigration(db, migration); + db.exec("commit"); + } catch (error) { + db.exec("rollback"); + throw error; } } + +function backfillMigrationLedger(db: DatabaseSync, currentVersion: number): void { + for (const migration of MIGRATIONS) { + if (migration.version > currentVersion) return; + recordMigration(db, migration); + } +} + +function recordMigration(db: DatabaseSync, migration: Migration): void { + db.prepare("insert or ignore into schema_migrations(version, name, applied_at) values (?, ?, datetime('now'))") + .run(migration.version, migration.name); +} diff --git a/src/main/database/session-entries.ts b/src/main/database/session-entries.ts deleted file mode 100644 index c3b64c0d..00000000 --- a/src/main/database/session-entries.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { ReadAll, Transaction } from "./helpers"; -import { nowIso } from "./helpers"; - -/** - * The `session_entries` table only ever stores one kind — full pi - * `AgentMessage` envelopes emitted by `message_end`. Earlier builds - * reserved `"compaction"` and `"summary"` variants for a supersede - * pipeline that never shipped; their writers are gone and the column - * holds `"message"` for every live row. Narrowing the type prevents - * new code from writing a dead kind by accident. - */ -export type SessionEntryKind = "message"; - -export interface SessionEntryRow { - id: string; - taskSessionId: string; - sequence: number; - kind: SessionEntryKind; - role: string | null; - payloadJson: string; - createdAt: string; -} - -export interface AppendInput { - taskSessionId: string; - kind: SessionEntryKind; - role?: string | null; - payloadJson: string; -} - -export function buildSessionEntryMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - function nextSequence(taskSessionId: string): number { - const rows = readAll<{ maxSeq: number | null }>( - "select max(sequence) as maxSeq from session_entries where task_session_id = ?", - taskSessionId, - ); - const max = rows[0]?.maxSeq; - return (max ?? 0) + 1; - } - - function append(input: AppendInput): SessionEntryRow { - const id = randomUUID(); - const sequence = nextSequence(input.taskSessionId); - const created = nowIso(); - getDb() - .prepare( - "insert into session_entries (id, task_session_id, sequence, kind, role, payload_json, is_superseded, created_at) values (?, ?, ?, ?, ?, ?, 0, ?)", - ) - .run( - id, - input.taskSessionId, - sequence, - input.kind, - input.role ?? null, - input.payloadJson, - created, - ); - return { - id, - taskSessionId: input.taskSessionId, - sequence, - kind: input.kind, - role: input.role ?? null, - payloadJson: input.payloadJson, - createdAt: created, - }; - } - - function listActive(taskSessionId: string): SessionEntryRow[] { - const rows = readAll<{ - id: string; - task_session_id: string; - sequence: number; - kind: SessionEntryKind; - role: string | null; - payload_json: string; - created_at: string; - }>( - "select id, task_session_id, sequence, kind, role, payload_json, created_at from session_entries where task_session_id = ? and is_superseded = 0 order by sequence asc, created_at asc", - taskSessionId, - ); - return rows.map((row) => ({ - id: row.id, - taskSessionId: row.task_session_id, - sequence: row.sequence, - kind: row.kind, - role: row.role, - payloadJson: row.payload_json, - createdAt: row.created_at, - })); - } - - function compactWithSummary(input: { - taskSessionId: string; - supersedeEntryIds: string[]; - summaryRole: string | null; - summaryPayloadJson: string; - }): SessionEntryRow { - return transaction(() => { - const uniqueIds = [...new Set(input.supersedeEntryIds)]; - if (uniqueIds.length === 0) { - throw new Error("session_entries compaction requires at least one entry to supersede."); - } - const placeholders = uniqueIds.map(() => "?").join(", "); - const rows = readAll<{ id: string; sequence: number }>( - `select id, sequence from session_entries where task_session_id = ? and is_superseded = 0 and id in (${placeholders}) order by sequence asc`, - input.taskSessionId, - ...(uniqueIds as SQLInputValue[]), - ); - if (rows.length !== uniqueIds.length) { - throw new Error(`session_entries compaction expected ${uniqueIds.length} active row(s), found ${rows.length}.`); - } - const summarySequence = rows[0]?.sequence; - if (summarySequence === undefined) { - throw new Error("session_entries compaction could not resolve summary sequence."); - } - getDb() - .prepare(`update session_entries set is_superseded = 1 where task_session_id = ? and id in (${placeholders})`) - .run(input.taskSessionId, ...(uniqueIds as SQLInputValue[])); - - const id = randomUUID(); - const created = nowIso(); - getDb() - .prepare( - "insert into session_entries (id, task_session_id, sequence, kind, role, payload_json, is_superseded, created_at) values (?, ?, ?, 'message', ?, ?, 0, ?)", - ) - .run(id, input.taskSessionId, summarySequence, input.summaryRole, input.summaryPayloadJson, created); - return { - id, - taskSessionId: input.taskSessionId, - sequence: summarySequence, - kind: "message", - role: input.summaryRole, - payloadJson: input.summaryPayloadJson, - createdAt: created, - }; - }); - } - - return { append, listActive, compactWithSummary }; -} diff --git a/src/main/database/settings.ts b/src/main/database/settings.ts deleted file mode 100644 index fa9278d5..00000000 --- a/src/main/database/settings.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { existsSync, lstatSync, realpathSync, unlinkSync } from "node:fs"; -import { extname, resolve, sep } from "node:path"; -import type { DatabaseSync } from "node:sqlite"; -import log from "electron-log/main.js"; -import type { ReadAll } from "./helpers"; -import { nowIso } from "./helpers"; - - -function isWithinOrEqual(targetPath: string, rootPath: string) { - const resolvedTarget = resolve(targetPath); - const resolvedRoot = resolve(rootPath); - return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(`${resolvedRoot}${sep}`); -} - -function safeRealpath(targetPath: string) { - try { - return realpathSync(targetPath); - } catch (error) { - log.debug( - `[db/settings] realpathSync fallback for ${targetPath}: ${error instanceof Error ? error.message : String(error)}`, - ); - return resolve(targetPath); - } -} - -export function buildSettingsMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - deps: { - profileDir: string; - logsDir: string; - artifactsDir: string; - backupsDir: string; - }, -) { - function getSetting(key: string): string | null { - const row = getDb().prepare("select value from settings where key = ?").get(key) as { value: string } | undefined; - return row?.value ?? null; - } - - function setSetting(key: string, value: string) { - getDb() - .prepare("insert into settings (key, value) values (?, ?) on conflict(key) do update set value = excluded.value") - .run(key, value); - } - - return { - getSetting, - setSetting, - - getCurrentCompanyId() { - return getSetting("current_company_id"); - }, - - setCurrentCompany(companyId: string) { - setSetting("current_company_id", companyId); - }, - - updateSettings(input: { theme?: "system" | "light" | "dark"; locale?: "en" | "zh"; updatesEnabled?: boolean; logRetentionDays?: number }) { - if (input.theme) { - setSetting("theme", input.theme); - } - if (input.locale) { - setSetting("locale", input.locale); - } - if (typeof input.updatesEnabled === "boolean") { - setSetting("updates_enabled", input.updatesEnabled ? "true" : "false"); - } - if (typeof input.logRetentionDays === "number") { - setSetting("log_retention_days", String(input.logRetentionDays)); - } - }, - - getLogRetentionDays(): number { - const raw = getSetting("log_retention_days"); - const parsed = raw ? parseInt(raw, 10) : NaN; - return Number.isFinite(parsed) && parsed >= 1 ? parsed : 90; - }, - - /** - * Per-(company, connector) disabled model list. - * - * Pre-v42 the key-value `settings` table stored one global entry - * per connector (`disabled_models:${connectorId}`). That let the - * setting leak across companies — deleting a company did not - * clear the pool config, and new companies inherited the old - * selections. v42 moved the data to `connector_model_pool_settings` - * with `company_id` in the primary key and `ON DELETE CASCADE` - * from companies, so company removal wipes pool config by - * construction. - */ - getDisabledModels(companyId: string, connectorId: string): Array<{ id: string; label: string }> { - const row = getDb() - .prepare( - "SELECT disabled_models_json AS json FROM connector_model_pool_settings WHERE company_id = ? AND connector_id = ?", - ) - .get(companyId, connectorId) as { json: string } | undefined; - if (!row) return []; - try { - return JSON.parse(row.json); - } catch { - return []; - } - }, - - setDisabledModels( - companyId: string, - connectorId: string, - models: Array<{ id: string; label: string }>, - ) { - const ts = new Date().toISOString(); - getDb() - .prepare( - `INSERT INTO connector_model_pool_settings (company_id, connector_id, disabled_models_json, updated_at) - VALUES (?, ?, ?, ?) - ON CONFLICT(company_id, connector_id) DO UPDATE SET - disabled_models_json = excluded.disabled_models_json, - updated_at = excluded.updated_at`, - ) - .run(companyId, connectorId, JSON.stringify(models), ts); - }, - - hasModelPoolSettings(companyId: string, connectorId: string): boolean { - const row = getDb() - .prepare( - "SELECT 1 AS found FROM connector_model_pool_settings WHERE company_id = ? AND connector_id = ? LIMIT 1", - ) - .get(companyId, connectorId) as { found: number } | undefined; - return !!row; - }, - - getLastBudgetResetMonth(companyId: string): string | null { - return getSetting(`budget_reset_month_${companyId}`); - }, - - setLastBudgetResetMonth(companyId: string, month: string) { - setSetting(`budget_reset_month_${companyId}`, month); - }, - - purgeExpiredRunLogs(): number { - const raw = getSetting("log_retention_days"); - const parsed = raw ? parseInt(raw, 10) : NaN; - const retentionDays = Number.isFinite(parsed) && parsed >= 1 ? parsed : 90; - const cutoff = new Date(Date.now() - retentionDays * 86_400_000).toISOString(); - const expiredRuns = readAll<{ id: string; logPath: string | null }>( - "select id, log_path as logPath from runs where finished_at is not null and finished_at < ? and log_path is not null", - cutoff, - ); - let purged = 0; - for (const run of expiredRuns) { - if (run.logPath) { - try { - unlinkSync(run.logPath); - } catch (error) { - log.warn( - `[db/settings] purgeExpiredRunLogs: unlink failed for run ${run.id} (${run.logPath}): ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - getDb() - .prepare("update runs set log_path = null, updated_at = ? where id = ?") - .run(nowIso(), run.id); - purged++; - } - return purged; - }, - - canOpenPath(targetPath: string, companyId: string) { - if (!targetPath || !existsSync(targetPath)) { - return false; - } - const managedRoots = [deps.profileDir, deps.logsDir, deps.artifactsDir, deps.backupsDir]; - const sensitiveProfileExtensions = new Set([".sqlite", ".db", ".key"]); - const forbiddenExecutableExtensions = new Set([".app", ".exe", ".bat", ".cmd", ".sh", ".command", ".desktop", ".msi", ".com", ".scr"]); - const resolvedTarget = safeRealpath(targetPath); - const targetStats = lstatSync(targetPath); - const targetExtension = extname(resolvedTarget).toLowerCase(); - if ( - managedRoots.some((rootPath) => isWithinOrEqual(resolvedTarget, rootPath)) && - sensitiveProfileExtensions.has(targetExtension) - ) { - return false; - } - if (!targetStats.isDirectory() && forbiddenExecutableExtensions.has(targetExtension)) { - return false; - } - const workspaces = readAll<{ localPath: string }>( - "select local_path as localPath from workspaces where company_id = ?", - companyId, - ); - if (workspaces.some((workspace) => isWithinOrEqual(resolvedTarget, safeRealpath(workspace.localPath)))) { - return true; - } - const runLogs = readAll<{ logPath: string | null }>( - "select log_path as logPath from runs where company_id = ? and log_path is not null", - companyId, - ); - if (runLogs.some((run) => run.logPath ? safeRealpath(run.logPath) === resolvedTarget : false)) { - return true; - } - const browserScreenshots = readAll<{ screenshotPath: string | null }>( - "select screenshot_path as screenshotPath from browser_actions where company_id = ? and screenshot_path is not null", - companyId, - ); - return browserScreenshots.some((action) => action.screenshotPath ? safeRealpath(action.screenshotPath) === resolvedTarget : false); - }, - - hasCompany(companyId: string) { - const row = getDb().prepare("select id from companies where id = ?").get(companyId) as { id: string } | undefined; - return Boolean(row); - }, - - belongsToCompany(table: "workspaces" | "agents" | "goals" | "projects" | "tasks" | "approvals" | "runs" | "secrets" | "meetings" | "documents" | "knowledge_base" | "sprints" | "automation_rules" | "workflow_pipelines", id: string, companyId: string) { - const queries: Record = { - workspaces: "select 1 as present from workspaces where id = ? and company_id = ?", - agents: "select 1 as present from agents where id = ? and company_id = ?", - goals: "select 1 as present from goals where id = ? and company_id = ?", - projects: "select 1 as present from projects where id = ? and company_id = ?", - tasks: "select 1 as present from tasks where id = ? and company_id = ?", - approvals: "select 1 as present from approvals where id = ? and company_id = ?", - runs: "select 1 as present from runs where id = ? and company_id = ?", - secrets: "select 1 as present from secrets where id = ? and company_id = ?", - meetings: "select 1 as present from meetings where id = ? and company_id = ?", - documents: "select 1 as present from documents where id = ? and company_id = ?", - knowledge_base: "select 1 as present from knowledge_base where id = ? and company_id = ?", - sprints: "select 1 as present from sprints where id = ? and company_id = ?", - automation_rules: "select 1 as present from automation_rules where id = ? and company_id = ?", - workflow_pipelines: "select 1 as present from workflow_pipelines where id = ? and company_id = ?", - }; - const sql = queries[table]; - if (!sql) throw new Error(`Unknown table: ${table}`); - const row = getDb().prepare(sql).get(id, companyId) as { present: number } | undefined; - return Boolean(row?.present); - }, - }; -} diff --git a/src/main/database/skills.ts b/src/main/database/skills.ts deleted file mode 100644 index 02710955..00000000 --- a/src/main/database/skills.ts +++ /dev/null @@ -1,165 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { SkillRecord, FileInventoryEntry, SkillSourceType, TrustLevel } from "../skill-types.js"; -import type { ReadAll, SqliteRow } from "./helpers"; -import { nowIso, parseJson } from "./helpers"; - -export function buildSkillMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, -) { - function assignmentTargetsBelongToCompany(companyId: string, agentId: string, skillId: string): boolean { - const row = getDb() - .prepare(` - SELECT 1 AS present - FROM agents a - JOIN company_skills cs ON cs.id = ? - WHERE a.id = ? - AND a.company_id = ? - AND cs.company_id = ? - LIMIT 1 - `) - .get(skillId, agentId, companyId, companyId) as { present: number } | undefined; - return Boolean(row?.present); - } - - function mapSkillRow(row: SqliteRow): SkillRecord { - return { - id: row.id, - companyId: row.company_id, - key: row.key, - slug: row.slug, - name: row.name, - description: row.description ?? null, - sourceType: (row.source_type ?? "local_path") as SkillSourceType, - sourceLocator: row.source_locator ?? null, - sourceRef: row.source_ref ?? null, - trustLevel: (row.trust_level ?? "markdown_only") as TrustLevel, - compatibility: row.compatibility ?? "compatible", - fileInventory: parseJson(row.file_inventory, []), - metadata: parseJson | null>(row.metadata, null), - createdAt: row.created_at, - updatedAt: row.updated_at, - }; - } - - return { - upsertCompanySkill(skill: { - id: string; companyId: string; key: string; slug: string; name: string; - description: string | null; sourceType: string; - sourceLocator: string | null; sourceRef: string | null; trustLevel: string; - compatibility: string; fileInventory: string; metadata: string | null; - createdAt: string; updatedAt: string; - }): { isUpdate: boolean } { - const existing = getDb() - .prepare("SELECT 1 FROM company_skills WHERE company_id = ? AND key = ?") - .get(skill.companyId, skill.key); - const isUpdate = existing != null; - - getDb().prepare(` - INSERT INTO company_skills ( - id, company_id, key, slug, name, description, - source_type, source_locator, source_ref, trust_level, - compatibility, file_inventory, metadata, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(company_id, key) DO UPDATE SET - slug = excluded.slug, - name = excluded.name, - description = excluded.description, - source_ref = excluded.source_ref, - trust_level = excluded.trust_level, - file_inventory = excluded.file_inventory, - metadata = excluded.metadata, - updated_at = excluded.updated_at - `).run( - skill.id, skill.companyId, skill.key, skill.slug, - skill.name, skill.description, - skill.sourceType, skill.sourceLocator, skill.sourceRef, - skill.trustLevel, skill.compatibility, skill.fileInventory, - skill.metadata, skill.createdAt, skill.updatedAt, - ); - - return { isUpdate }; - }, - - listCompanySkills(companyId: string): SkillRecord[] { - const rows = readAll( - "SELECT * FROM company_skills WHERE company_id = ? ORDER BY created_at ASC", - companyId, - ); - return rows.map((row) => mapSkillRow(row)); - }, - - getCompanySkill(companyId: string, skillId: string): SkillRecord | null { - const row = getDb() - .prepare("SELECT * FROM company_skills WHERE id = ? AND company_id = ?") - .get(skillId, companyId) as SqliteRow | undefined; - return row ? mapSkillRow(row) : null; - }, - - deleteCompanySkill(companyId: string, skillId: string): boolean { - const result = getDb() - .prepare("DELETE FROM company_skills WHERE id = ? AND company_id = ?") - .run(skillId, companyId); - return result.changes > 0; - }, - - assignSkillToAgent(companyId: string, agentId: string, skillId: string): boolean { - if (!assignmentTargetsBelongToCompany(companyId, agentId, skillId)) { - return false; - } - getDb() - .prepare("INSERT OR IGNORE INTO agent_skill_assignments (agent_id, skill_id, created_at) VALUES (?, ?, ?)") - .run(agentId, skillId, nowIso()); - return true; - }, - - removeSkillFromAgent(companyId: string, agentId: string, skillId: string): boolean { - if (!assignmentTargetsBelongToCompany(companyId, agentId, skillId)) { - return false; - } - const result = getDb() - .prepare("DELETE FROM agent_skill_assignments WHERE agent_id = ? AND skill_id = ?") - .run(agentId, skillId); - return result.changes > 0; - }, - - listAgentSkillAssignments(companyId: string, agentId: string): string[] { - return readAll<{ skill_id: string }>( - `SELECT asa.skill_id - FROM agent_skill_assignments asa - JOIN agents a ON a.id = asa.agent_id - JOIN company_skills cs ON cs.id = asa.skill_id - WHERE asa.agent_id = ? - AND a.company_id = ? - AND cs.company_id = ? - ORDER BY cs.created_at ASC`, - agentId, - companyId, - companyId, - ).map((row) => row.skill_id); - }, - - listSkillAgentAssignments(companyId: string, skillId: string): string[] { - return readAll<{ agent_id: string }>( - `SELECT asa.agent_id - FROM agent_skill_assignments asa - JOIN agents a ON a.id = asa.agent_id - JOIN company_skills cs ON cs.id = asa.skill_id - WHERE asa.skill_id = ? - AND a.company_id = ? - AND cs.company_id = ? - ORDER BY a.created_at ASC`, - skillId, - companyId, - companyId, - ).map((row) => row.agent_id); - }, - - updateCompanySkillMetadata(companyId: string, skillId: string, metadataJson: string): void { - const ts = nowIso(); - getDb().prepare( - "UPDATE company_skills SET metadata = ?, updated_at = ? WHERE id = ? AND company_id = ?" - ).run(metadataJson, ts, skillId, companyId); - }, - }; -} diff --git a/src/main/database/snapshot.ts b/src/main/database/snapshot.ts deleted file mode 100644 index 6dccf599..00000000 --- a/src/main/database/snapshot.ts +++ /dev/null @@ -1,223 +0,0 @@ -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { - ActivityRecord, - AgentRecord, - ApprovalRecord, - CompanyRecord, - CommentRecord, - ConnectorRecord, - CostRecord, - GoalRecord, - ProfileSnapshot, - ProjectRecord, - RunRecord, - SecretRecord, - TaskRecord, - WorkspaceRecord, -} from "@shared/types"; -import { activeRunIdSql, BOARD_READER_ID, type ReadAll, type SqliteRow, toBoolean } from "./helpers"; - -export function buildSnapshotMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - deps: { - getCurrentCompanyId: () => string | null; - getSetting: (key: string) => string | null; - readConnectors: () => ConnectorRecord[]; - profileDir: string; - vaultBackendLabel: () => string; - }, -) { - function listSnapshot(options: { companyId?: string | null } = {}): ProfileSnapshot { - const companyId = options.companyId ?? null; - const companyWhere = companyId ? " where company_id = ?" : ""; - const companyArgs: SQLInputValue[] = companyId ? [companyId] : []; - const boardReadReceiptParams: SQLInputValue[] = companyId ? [BOARD_READER_ID, companyId] : [BOARD_READER_ID]; - const connectors = deps.readConnectors(); - const theme = (deps.getSetting("theme") as "system" | "light" | "dark" | null) ?? "system"; - const locale = (deps.getSetting("locale") as "en" | "zh" | null) ?? "en"; - // AgentMessageRecord.readAt is a per-viewer field — its meaning is - // "has the current viewer acknowledged this message?". The renderer - // view has exactly one human viewer (the Board operator), so the - // renderer snapshot fills it from that reader's agent_message_reads - // rows. Agent-side queries (listAgentMessages) resolve it against - // the current agent's receipts. The old `agent_messages.read_at` - // column was dropped in migration v49 — the join table is the - // sole source of truth. - const boardReadReceiptMap = new Map( - readAll<{ messageId: string; readAt: string }>( - `select reads.message_id as messageId, reads.read_at as readAt - from agent_message_reads reads - join agent_messages messages on messages.id = reads.message_id - where reads.agent_id = ?${companyId ? " and messages.company_id = ?" : ""}`, - ...boardReadReceiptParams, - ).map((row) => [row.messageId, row.readAt]), - ); - return { - currentCompanyId: deps.getCurrentCompanyId(), - profilePath: deps.profileDir, - updatesEnabled: deps.getSetting("updates_enabled") !== "false", - theme, - locale, - backend: { - secretBackend: deps.vaultBackendLabel(), - }, - companies: readAll( - "select id, name, description, status, auto_approve_hires as autoApproveHires, review_deliverables as reviewDeliverables, execution_mode as executionMode, created_at as createdAt, updated_at as updatedAt from companies order by created_at asc", - ).map((record) => ({ ...record, autoApproveHires: toBoolean(record.autoApproveHires), reviewDeliverables: toBoolean(record.reviewDeliverables) })) as CompanyRecord[], - connectors, - workspaces: readAll( - `select id, company_id as companyId, name, local_path as localPath, repo_url as repoUrl, repo_ref as repoRef, project_id as projectId, state, is_primary as isPrimary, created_at as createdAt, updated_at as updatedAt from workspaces${companyWhere} order by created_at desc`, - ...companyArgs, - ).map((record) => ({ ...record, isPrimary: toBoolean(record.isPrimary) })) as WorkspaceRecord[], - agents: readAll( - `select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, role_level as roleLevel, model_strategy as modelStrategy, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, session_id as sessionId, created_at as createdAt, updated_at as updatedAt from agents${companyWhere} order by created_at asc`, - ...companyArgs, - ).map((record: SqliteRow) => ({ ...record, heartbeatEnabled: toBoolean(record.heartbeatEnabled) })) as AgentRecord[], - goals: readAll( - `select id, company_id as companyId, title, description, parent_id as parentId, owner_agent_id as ownerAgentId, status, created_at as createdAt, updated_at as updatedAt from goals${companyWhere} order by created_at asc`, - ...companyArgs, - ), - projects: readAll( - `select id, company_id as companyId, goal_id as goalId, name, description, lead_agent_id as leadAgentId, status, target_date as targetDate, created_at as createdAt, updated_at as updatedAt from projects${companyWhere} order by created_at desc`, - ...companyArgs, - ), - tasks: 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, ${activeRunIdSql("tasks")} as activeRunId, cost_usd as costUsd, task_type as taskType, requires_user_review as requiresUserReview, requires_filesystem as requiresFilesystem, 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 limit 2000`, - ...companyArgs, - ).map((record) => ({ ...record, requiresUserReview: toBoolean(record.requiresUserReview), requiresFilesystem: toBoolean(record.requiresFilesystem), startedAt: record.startedAt ?? null, completedAt: record.completedAt ?? null, cancelledAt: record.cancelledAt ?? null })) as TaskRecord[], - approvals: 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 limit 1000`, - ...companyArgs, - ), - runs: readAll( - `select id, company_id as companyId, task_id as taskId, agent_id as agentId, workspace_id as workspaceId, connector_id as connectorId, status, summary, error_message as errorMessage, exit_code as exitCode, signal, model, cost_usd as costUsd, unattributed_cost as unattributedCost, usage_status as usageStatus, started_at as startedAt, finished_at as finishedAt, log_path as logPath, created_at as createdAt, updated_at as updatedAt from runs${companyWhere} order by created_at desc limit ${companyId ? 2000 : 2000}`, - ...companyArgs, - ).map((record) => ({ ...record, unattributedCost: Boolean(record.unattributedCost) })) as RunRecord[], - costs: readAll( - `select id, company_id as companyId, run_id as runId, task_id as taskId, agent_id as agentId, connector_id as connectorId, amount_usd as amountUsd, unattributed, created_at as createdAt from cost_entries${companyWhere} order by created_at desc limit ${companyId ? 2000 : 2000}`, - ...companyArgs, - ).map((entry) => ({ ...entry, unattributed: Boolean(entry.unattributed) })) as CostRecord[], - activity: readAll( - `select id, company_id as companyId, actor, action, entity_type as entityType, entity_id as entityId, detail, created_at as createdAt from activity${companyWhere} order by created_at desc limit ${companyId ? 1000 : 1000}`, - ...companyArgs, - ), - secrets: readAll( - `select id, company_id as companyId, name, description, backend, updated_at as updatedAt from secrets${companyWhere} order by updated_at desc`, - ...companyArgs, - ), - comments: readAll( - `select id, company_id as companyId, task_id as taskId, author_agent_id as authorAgentId, author_name as authorName, body, created_at as createdAt from task_comments${companyWhere} order by created_at asc`, - ...companyArgs, - ), - socialAccounts: readAll( - `select id, company_id, platform, account_name, display_name, profile_url, credential_secret_id, status, require_approval, metadata_json, last_used_at, created_at, updated_at from social_accounts${companyWhere} order by created_at desc`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, platform: r.platform, accountName: r.account_name, - displayName: r.display_name, profileUrl: r.profile_url, credentialSecretId: r.credential_secret_id, - status: r.status, requireApproval: toBoolean(r.require_approval), metadataJson: r.metadata_json, - lastUsedAt: r.last_used_at, createdAt: r.created_at, updatedAt: r.updated_at, - })), - meetings: readAll( - `select id, company_id, type, title, organizer_agent_id, participant_agent_ids, scheduled_at, duration_minutes, agenda_json, notes_json, decisions_json, action_items_json, status, created_at, updated_at from meetings${companyWhere} order by scheduled_at desc`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, type: r.type, title: r.title, organizerAgentId: r.organizer_agent_id, - participantAgentIds: r.participant_agent_ids, scheduledAt: r.scheduled_at, durationMinutes: r.duration_minutes, - agendaJson: r.agenda_json, notesJson: r.notes_json, decisionsJson: r.decisions_json, - actionItemsJson: r.action_items_json, status: r.status, createdAt: r.created_at, updatedAt: r.updated_at, - })), - documents: 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, 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, latestRevisionId: r.latest_revision_id ?? null, createdAt: r.created_at, updatedAt: r.updated_at, - })), - // Archived rows stay in the table as tombstones for audit but - // never surface as deliverables — the DocumentCenter and every - // downstream consumer read this snapshot, so the filter is - // pinned here as the canonical visibility gate. - workProducts: readAll( - `select id, company_id, project_id, task_id, workspace_id, type, provider, external_id, title, url, status, review_state, is_primary, summary, metadata_json, created_by_run_id, last_touched_by_run_id, created_at, updated_at from work_products${companyWhere}${companyWhere ? " and" : " where"} status <> 'archived' order by updated_at desc limit 500`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, projectId: r.project_id, taskId: r.task_id, - workspaceId: r.workspace_id ?? null, - 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, - lastTouchedByRunId: r.last_touched_by_run_id ?? null, - createdAt: r.created_at, updatedAt: r.updated_at, - })), - knowledgeBase: 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`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, category: r.category, topic: r.topic, content: r.content, - authorAgentId: r.author_agent_id, importance: r.importance, tagsJson: r.tags_json, - referencedEntityType: r.referenced_entity_type, referencedEntityId: r.referenced_entity_id, - createdAt: r.created_at, updatedAt: r.updated_at, - })), - sprints: readAll( - `select id, company_id, name, goal, start_date, end_date, status, retrospective_notes, velocity_points, completed_points, created_at, updated_at from sprints${companyWhere} order by start_date desc limit 500`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, name: r.name, goal: r.goal, - startDate: r.start_date, endDate: r.end_date, status: r.status, - retrospectiveNotes: r.retrospective_notes, velocityPoints: r.velocity_points, - completedPoints: r.completed_points, createdAt: r.created_at, updatedAt: r.updated_at, - })), - automationRules: readAll( - `select id, company_id, name, description, trigger, conditions_json, action, action_config_json, source_department, target_department, priority, status, execution_count, last_executed_at, created_at, updated_at from automation_rules${companyWhere} order by priority desc, created_at desc`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, name: r.name, description: r.description, - trigger: r.trigger, conditionsJson: r.conditions_json, action: r.action, - actionConfigJson: r.action_config_json, sourceDepartment: r.source_department, - targetDepartment: r.target_department, priority: r.priority, status: r.status, - executionCount: r.execution_count, lastExecutedAt: r.last_executed_at, - createdAt: r.created_at, updatedAt: r.updated_at, - })), - agentMessages: readAll( - // readAt semantics live in the agent_message_reads receipts - // table, resolved against the current viewer above. The old - // `agent_messages.read_at` column was dropped in v49. - `select id, company_id, from_agent_id, to_agent_id, sender_kind, channel, channel_target_id, subject, body, priority, parent_message_id, attachments_json, created_at from agent_messages${companyWhere} order by created_at desc limit 1000`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, fromAgentId: r.from_agent_id, - toAgentId: r.to_agent_id, senderKind: r.sender_kind ?? "agent", - channel: r.channel, channelTargetId: r.channel_target_id, - subject: r.subject, body: r.body, priority: r.priority, - readAt: boardReadReceiptMap.get(r.id) ?? null, - parentMessageId: r.parent_message_id, attachmentsJson: r.attachments_json, - createdAt: r.created_at, - })), - workflows: readAll( - `select id, company_id, name, description, steps_json, trigger_type, trigger_config_json, status, current_step_index, run_count, last_run_at, created_at, updated_at from workflow_pipelines${companyWhere} order by created_at desc`, - ...companyArgs, - ).map((r) => ({ - id: r.id, companyId: r.company_id, name: r.name, description: r.description, - stepsJson: r.steps_json, triggerType: r.trigger_type, triggerConfigJson: r.trigger_config_json, - status: r.status, currentStepIndex: r.current_step_index, runCount: r.run_count, - lastRunAt: r.last_run_at, createdAt: r.created_at, updatedAt: r.updated_at, - })), - }; - } - - return { - listSnapshot, - - listRendererSnapshot(): ProfileSnapshot { - const currentCompanyId = deps.getCurrentCompanyId(); - return currentCompanyId - ? listSnapshot({ companyId: currentCompanyId }) - : listSnapshot(); - }, - }; -} diff --git a/src/main/database/social.ts b/src/main/database/social.ts deleted file mode 100644 index 90915274..00000000 --- a/src/main/database/social.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { BrowserActionRecord, SocialAccountRecord } from "@shared/types"; -import type { ReadAll, SqliteRow, Transaction } from "./helpers"; -import { ensureId, normalizeOptionalId, nowIso, toBoolean } from "./helpers"; - -export class SocialAccountScopeError extends Error { - constructor( - public readonly reference: "social_account" | "credential_secret", - message: string, - ) { - super(message); - this.name = "SocialAccountScopeError"; - } -} - -export function buildSocialMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - saveSocialAccount(input: { - id?: string | null; - companyId: string; - platform: string; - accountName: string; - displayName?: string; - profileUrl?: string; - credentialSecretId?: string | null; - status?: string; - requireApproval?: boolean; - metadataJson?: string; - }): string { - return transaction(() => { - const id = ensureId(input.id); - const now = nowIso(); - const credentialSecretId = normalizeOptionalId(input.credentialSecretId); - const existing = getDb() - .prepare("SELECT id, company_id AS companyId FROM social_accounts WHERE id = ? LIMIT 1") - .get(id) as { id: string; companyId: string } | undefined; - if (existing && existing.companyId !== input.companyId) { - throw new SocialAccountScopeError("social_account", "Social account does not belong to the current company"); - } - if (credentialSecretId) { - const secret = getDb() - .prepare("SELECT id FROM secrets WHERE id = ? AND company_id = ? LIMIT 1") - .get(credentialSecretId, input.companyId) as { id: string } | undefined; - if (!secret) { - throw new SocialAccountScopeError("credential_secret", "Credential secret does not belong to the current company"); - } - } - if (existing) { - getDb().prepare(`UPDATE social_accounts - SET platform = ?, - account_name = ?, - display_name = ?, - profile_url = ?, - credential_secret_id = ?, - status = ?, - require_approval = ?, - metadata_json = ?, - updated_at = ? - WHERE id = ? AND company_id = ?`).run( - input.platform, input.accountName, - input.displayName ?? "", input.profileUrl ?? "", - credentialSecretId, input.status ?? "login_required", - input.requireApproval !== false ? 1 : 0, - input.metadataJson ?? "{}", now, - id, input.companyId, - ); - } else { - getDb().prepare(`INSERT INTO social_accounts (id, company_id, platform, account_name, display_name, profile_url, credential_secret_id, status, require_approval, metadata_json, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run( - id, input.companyId, input.platform, input.accountName, - input.displayName ?? "", input.profileUrl ?? "", - credentialSecretId, input.status ?? "login_required", - input.requireApproval !== false ? 1 : 0, - input.metadataJson ?? "{}", now, now, - ); - } - return id; - }); - }, - - deleteSocialAccount(id: string, companyId: string) { - transaction(() => { - getDb().prepare("DELETE FROM browser_actions WHERE social_account_id = ? AND company_id = ?").run(id, companyId); - getDb().prepare("DELETE FROM social_accounts WHERE id = ? AND company_id = ?").run(id, companyId); - }); - }, - - listSocialAccounts(companyId: string): SocialAccountRecord[] { - const rows = getDb().prepare("SELECT * FROM social_accounts WHERE company_id = ? ORDER BY created_at DESC").all(companyId) as SqliteRow[]; - return rows.map((r) => ({ - id: r.id, companyId: r.company_id, platform: r.platform, - accountName: r.account_name, displayName: r.display_name, - profileUrl: r.profile_url, credentialSecretId: r.credential_secret_id, - status: r.status, requireApproval: toBoolean(r.require_approval), - metadataJson: r.metadata_json, lastUsedAt: r.last_used_at, - createdAt: r.created_at, updatedAt: r.updated_at, - })); - }, - - getSocialAccount(id: string, companyId: string): SocialAccountRecord | null { - const row = getDb() - .prepare("SELECT * FROM social_accounts WHERE id = ? AND company_id = ?") - .get(id, companyId) as SqliteRow | undefined; - if (!row) return null; - return { - id: row.id, companyId: row.company_id, platform: row.platform, - accountName: row.account_name, displayName: row.display_name, - profileUrl: row.profile_url, credentialSecretId: row.credential_secret_id, - status: row.status, requireApproval: toBoolean(row.require_approval), - metadataJson: row.metadata_json, lastUsedAt: row.last_used_at, - createdAt: row.created_at, updatedAt: row.updated_at, - }; - }, - - saveBrowserAction(input: { - companyId: string; - socialAccountId: string; - agentId: string; - taskId?: string | null; - actionType: string; - payloadJson: string; - status?: string; - approvalId?: string | null; - }): string { - const id = randomUUID(); - const now = nowIso(); - const socialAccount = getDb() - .prepare("SELECT id FROM social_accounts WHERE id = ? AND company_id = ? LIMIT 1") - .get(input.socialAccountId, input.companyId) as { id: string } | undefined; - if (!socialAccount) { - throw new SocialAccountScopeError("social_account", "Browser action social account does not belong to the current company"); - } - getDb().prepare(`INSERT INTO browser_actions (id, company_id, social_account_id, agent_id, task_id, action_type, payload_json, status, approval_id, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run( - id, input.companyId, input.socialAccountId, input.agentId, - input.taskId ?? null, input.actionType, input.payloadJson, - input.status ?? "queued", input.approvalId ?? null, now, now, - ); - return id; - }, - - updateBrowserAction(id: string, updates: { status?: string; resultSummary?: string; screenshotPath?: string | null; errorMessage?: string | null; startedAt?: string; finishedAt?: string }) { - const now = nowIso(); - const sets: string[] = ["updated_at = ?"]; - const values: SQLInputValue[] = [now]; - if (updates.status) { sets.push("status = ?"); values.push(updates.status); } - if (updates.resultSummary !== undefined) { sets.push("result_summary = ?"); values.push(updates.resultSummary); } - if (updates.screenshotPath !== undefined) { sets.push("screenshot_path = ?"); values.push(updates.screenshotPath); } - if (updates.errorMessage !== undefined) { sets.push("error_message = ?"); values.push(updates.errorMessage); } - if (updates.startedAt) { sets.push("started_at = ?"); values.push(updates.startedAt); } - if (updates.finishedAt) { sets.push("finished_at = ?"); values.push(updates.finishedAt); } - values.push(id); - getDb().prepare(`UPDATE browser_actions SET ${sets.join(", ")} WHERE id = ?`).run(...values); - }, - - listBrowserActions(companyId: string, filters?: { socialAccountId?: string; status?: string; limit?: number }): BrowserActionRecord[] { - let sql = "SELECT * FROM browser_actions WHERE company_id = ?"; - const params: SQLInputValue[] = [companyId]; - if (filters?.socialAccountId) { sql += " AND social_account_id = ?"; params.push(filters.socialAccountId); } - if (filters?.status) { - const statuses = filters.status.split(",").filter(Boolean); - if (statuses.length > 0) { - sql += ` AND status IN (${statuses.map(() => "?").join(",")})`; - params.push(...statuses); - } - } - sql += " ORDER BY created_at DESC"; - if (filters?.limit) { sql += " LIMIT ?"; params.push(filters.limit); } - - const rows = getDb().prepare(sql).all(...params) as SqliteRow[]; - return rows.map((r) => ({ - id: r.id, companyId: r.company_id, socialAccountId: r.social_account_id, - agentId: r.agent_id, taskId: r.task_id, status: r.status, - actionType: r.action_type, payloadJson: r.payload_json, - resultSummary: r.result_summary, screenshotPath: r.screenshot_path, - approvalId: r.approval_id, errorMessage: r.error_message, - startedAt: r.started_at, finishedAt: r.finished_at, - createdAt: r.created_at, updatedAt: r.updated_at, - })); - }, - - getBrowserAction(id: string, companyId: string): BrowserActionRecord | null { - const row = getDb() - .prepare("SELECT * FROM browser_actions WHERE id = ? AND company_id = ?") - .get(id, companyId) as SqliteRow | undefined; - if (!row) return null; - return { - id: row.id, companyId: row.company_id, socialAccountId: row.social_account_id, - agentId: row.agent_id, taskId: row.task_id, status: row.status, - actionType: row.action_type, payloadJson: row.payload_json, - resultSummary: row.result_summary, screenshotPath: row.screenshot_path, - approvalId: row.approval_id, errorMessage: row.error_message, - startedAt: row.started_at, finishedAt: row.finished_at, - createdAt: row.created_at, updatedAt: row.updated_at, - }; - }, - - getBrowserActionByApprovalId(approvalId: string, companyId: string): BrowserActionRecord | null { - const row = getDb() - .prepare("SELECT * FROM browser_actions WHERE approval_id = ? AND company_id = ? ORDER BY created_at DESC LIMIT 1") - .get(approvalId, companyId) as SqliteRow | undefined; - if (!row) return null; - return { - id: row.id, companyId: row.company_id, socialAccountId: row.social_account_id, - agentId: row.agent_id, taskId: row.task_id, status: row.status, - actionType: row.action_type, payloadJson: row.payload_json, - resultSummary: row.result_summary, screenshotPath: row.screenshot_path, - approvalId: row.approval_id, errorMessage: row.error_message, - startedAt: row.started_at, finishedAt: row.finished_at, - createdAt: row.created_at, updatedAt: row.updated_at, - }; - }, - }; -} diff --git a/src/main/database/task-assignment.ts b/src/main/database/task-assignment.ts deleted file mode 100644 index 88b09f63..00000000 --- a/src/main/database/task-assignment.ts +++ /dev/null @@ -1,138 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ReadAll } from "./helpers"; - -interface AssignmentTask { - id: string; - title: string; - description: string; - projectId: string | null; -} - -interface AssignmentCandidate { - id: string; - name: string; - department: string | null; - capabilities: string; - taskCount: number; - budgetMonthlyUsd: number; - spentMonthlyUsd: number; -} - -function tokenize(text: string): string[] { - return text.toLowerCase().split(/\W+/).filter((word) => word.length > 3); -} - -function getProjectDepartment( - db: DatabaseSync, - companyId: string, - projectId: string | null, -): string | null { - if (!projectId) return null; - const project = db - .prepare("select lead_agent_id from projects where id = ? and company_id = ?") - .get(projectId, companyId) as { lead_agent_id: string | null } | undefined; - if (!project?.lead_agent_id) return null; - const lead = db - .prepare("select department from agents where id = ? and company_id = ?") - .get(project.lead_agent_id, companyId) as { department: string | null } | undefined; - return lead?.department ?? null; -} - -function loadSkillWordsForAgents( - readAll: ReadAll, - companyId: string, - agentIds: string[], -): Map { - const result = new Map(); - if (agentIds.length === 0) return result; - const placeholders = agentIds.map(() => "?").join(","); - const rows = readAll<{ agentId: string; name: string; description: string | null; slug: string }>( - `select asa.agent_id as agentId, cs.name, cs.description, cs.slug - from company_skills cs - join agent_skill_assignments asa on asa.skill_id = cs.id - where cs.company_id = ? and asa.agent_id in (${placeholders})`, - companyId, - ...agentIds, - ); - const grouped = new Map(); - for (const row of rows) { - const blob = `${row.name} ${row.description ?? ""} ${row.slug}`; - const existing = grouped.get(row.agentId); - if (existing) existing.push(blob); - else grouped.set(row.agentId, [blob]); - } - for (const agentId of agentIds) { - result.set(agentId, tokenize((grouped.get(agentId) ?? []).join(" "))); - } - return result; -} - -function loadAgentsWithReports( - readAll: ReadAll, - companyId: string, - agentIds: string[], -): Set { - const result = new Set(); - if (agentIds.length === 0) return result; - const placeholders = agentIds.map(() => "?").join(","); - const rows = readAll<{ reportsTo: string }>( - `select distinct reports_to as reportsTo from agents where company_id = ? and reports_to in (${placeholders})`, - companyId, - ...agentIds, - ); - for (const row of rows) result.add(row.reportsTo); - return result; -} - -export function chooseBestTaskAssignee( - getDb: () => DatabaseSync, - readAll: ReadAll, - companyId: string, - task: AssignmentTask, - candidates: AssignmentCandidate[], -): string | null { - const eligibleCandidates = candidates.filter((candidate) => { - if (candidate.budgetMonthlyUsd > 0 && candidate.spentMonthlyUsd >= candidate.budgetMonthlyUsd) { - return false; - } - return true; - }); - - if (eligibleCandidates.length === 0) { - return null; - } - - const taskWords = tokenize(`${task.title} ${task.description}`); - const projectDept = getProjectDepartment(getDb(), companyId, task.projectId); - const eligibleIds = eligibleCandidates.map((candidate) => candidate.id); - const skillWordsByAgent = loadSkillWordsForAgents(readAll, companyId, eligibleIds); - const agentsWithReports = loadAgentsWithReports(readAll, companyId, eligibleIds); - - let bestAgentId: string | null = null; - let bestScore = -Infinity; - - for (const candidate of eligibleCandidates) { - const capabilityWords = tokenize(candidate.capabilities); - const skillWords = skillWordsByAgent.get(candidate.id) ?? []; - const capabilityOverlap = taskWords.filter((word) => capabilityWords.includes(word)).length; - const skillOverlap = taskWords.filter((word) => skillWords.includes(word)).length; - let score = capabilityOverlap * 10 + skillOverlap * 12 - candidate.taskCount * 5; - if (projectDept && candidate.department === projectDept) { - score += 15; - } - if (!agentsWithReports.has(candidate.id)) { - score += 5; - } - if ( - score > bestScore || - (score === bestScore && - candidate.taskCount < - (eligibleCandidates.find((entry) => entry.id === bestAgentId)?.taskCount ?? Number.POSITIVE_INFINITY)) - ) { - bestScore = score; - bestAgentId = candidate.id; - } - } - - return bestAgentId ?? eligibleCandidates[0]?.id ?? null; -} diff --git a/src/main/database/task-checkout.ts b/src/main/database/task-checkout.ts deleted file mode 100644 index 6003a161..00000000 --- a/src/main/database/task-checkout.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { STALE_LOCK_TIMEOUT_MS } from "../constants"; - -function isoFromMs(ms: number): string { - return new Date(ms).toISOString(); -} - -function loadRunForCheckout( - db: DatabaseSync, - taskId: string, - runId: string, -): { companyId: string; agentId: string; taskId: string | null } { - const row = db - .prepare("SELECT company_id as companyId, agent_id as agentId, task_id as taskId FROM runs WHERE id = ?") - .get(runId) as { companyId: string; agentId: string; taskId: string | null } | undefined; - if (!row) { - throw new Error(`Run not found for task checkout: ${runId}`); - } - if (row.taskId !== null && row.taskId !== taskId) { - throw new Error(`Run ${runId} is bound to task ${row.taskId}, not ${taskId}.`); - } - return row; -} - -export function checkoutTaskInTransaction( - db: DatabaseSync, - taskId: string, - runId: string, -): boolean { - const run = loadRunForCheckout(db, taskId, runId); - const nowMs = Date.now(); - const ts = isoFromMs(nowMs); - const result = db - .prepare( - `UPDATE tasks - SET status = 'in_progress', - started_at = coalesce(started_at, ?), - updated_at = ? - WHERE id = ? - AND company_id = ? - AND status IN ('todo', 'backlog') - AND NOT EXISTS ( - SELECT 1 FROM task_leases - WHERE task_leases.task_id = tasks.id - )`, - ) - .run(ts, ts, taskId, run.companyId); - - if (result.changes === 0) { - return false; - } - - if (run.taskId === null) { - db.prepare("update runs set task_id = ?, updated_at = ? where id = ? and task_id is null").run(taskId, ts, runId); - } - - db - .prepare( - `insert into task_leases ( - task_id, company_id, run_id, agent_id, acquired_at, renewed_at, expires_at, created_at, updated_at - ) values (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - ) - .run( - taskId, - run.companyId, - runId, - run.agentId, - ts, - ts, - isoFromMs(nowMs + STALE_LOCK_TIMEOUT_MS), - ts, - ts, - ); - - return true; -} diff --git a/src/main/database/task-queries.ts b/src/main/database/task-queries.ts deleted file mode 100644 index a1a6838c..00000000 --- a/src/main/database/task-queries.ts +++ /dev/null @@ -1,177 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { TaskRecord } from "@shared/types"; -import { activeRunIdSql, type ReadAll, type Transaction, taskPriorityOrderSql } from "./helpers"; -import type { TaskListByStatusesRow } from "./tasks-crud"; - -/** - * Task list/aggregate read queries extracted from tasks-crud.ts. - * - * Every method is spread into the final `buildTaskMethods` result so - * AppDatabase call-sites remain unchanged. - */ -export function buildTaskQueryMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - _transaction: Transaction, -) { - return { - /** - * Returns actionable real work for an agent. - */ - listAgentTasks( - agentId: string, - companyId: string, - statuses: string[], - ): TaskRecord[] { - const placeholders = statuses.map(() => "?").join(","); - return 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, ${activeRunIdSql("tasks")} as activeRunId, cost_usd as costUsd, task_type as taskType, created_at as createdAt, updated_at as updatedAt - from tasks - where company_id = ? and assignee_agent_id = ? and status in (${placeholders}) - order by - case status - when 'in_progress' then 0 - when 'todo' then 1 - when 'blocked' then 2 - when 'backlog' then 3 - else 4 - end asc, - ${taskPriorityOrderSql("priority")} desc, - created_at asc`, - companyId, - agentId, - ...statuses, - ); - }, - - /** - * Returns the slim task projection (id, title, status, priority) for a - * single assignee, ordered by created_at desc. - */ - listAssigneeTasksForStandup( - companyId: string, - agentId: string, - ): Array<{ id: string; title: string; status: string; priority: string }> { - return readAll( - "select id, title, status, priority from tasks where company_id = ? and assignee_agent_id = ? order by created_at desc", - companyId, - agentId, - ); - }, - - /** - * Returns the slim task projection for a set of assignees. Safe on - * an empty assignee list (returns []). - */ - listTasksForAssignees( - companyId: string, - assigneeIds: string[], - ): Array<{ - id: string; - title: string; - status: string; - priority: string; - assigneeAgentId: string; - }> { - if (assigneeIds.length === 0) return []; - const placeholders = assigneeIds.map(() => "?").join(","); - return readAll( - `select id, title, status, priority, assignee_agent_id as assigneeAgentId from tasks where company_id = ? and assignee_agent_id in (${placeholders}) order by created_at desc`, - companyId, - ...assigneeIds, - ); - }, - - /** - * Returns tasks filtered by status. - */ - listTasksByStatuses( - companyId: string, - statuses: string[], - ): TaskListByStatusesRow[] { - const placeholders = statuses.map(() => "?").join(", "); - return 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, ${activeRunIdSql("tasks")} as activeRunId, 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 company_id = ? and status in (${placeholders}) order by created_at desc`, - companyId, - ...statuses, - ).map((t) => ({ - ...t, - requiresUserReview: Boolean(t.requiresUserReview), - startedAt: t.startedAt ?? null, - completedAt: t.completedAt ?? null, - cancelledAt: t.cancelledAt ?? null, - })) as TaskListByStatusesRow[]; - }, - - countActiveTasksForCompany(companyId: string): number { - const row = getDb() - .prepare( - "select count(*) as cnt from tasks where company_id = ? and status not in ('done', 'cancelled')", - ) - .get(companyId) as { cnt: number }; - return row.cnt; - }, - - /** - * Count tasks that are actively producing progress this cycle — - * todo (waiting to be checked out) and in_progress (currently being - * worked). Excludes in_review (waiting on a human or manager) and - * blocked (waiting on a resolution). Used by the bootstrap - * scheduler to decide whether the CEO needs to be pinged: a company - * where every task is stuck in review or blocked is functionally - * idle even though countActiveTasksForCompany reports > 0. - */ - countAdvancingTasksForCompany(companyId: string): number { - const row = getDb() - .prepare( - "select count(*) as cnt from tasks where company_id = ? and status in ('todo','in_progress')", - ) - .get(companyId) as { cnt: number }; - return row.cnt; - }, - - listChildTasks( - parentId: string, - companyId: string, - ): Array<{ id: string; status: string; assigneeAgentId: string | null }> { - return readAll<{ id: string; status: string; assigneeAgentId: string | null }>( - `select id, status, assignee_agent_id as assigneeAgentId from tasks where parent_id = ? and company_id = ?`, - parentId, - companyId, - ); - }, - - /** - * Returns the set of distinct assignee agent ids on tasks in a project, - * excluding unassigned tasks. Used by message-dispatch to fan out wake - * targets for a project channel. - */ - listProjectTaskAssigneeIds(projectId: string, companyId: string): string[] { - const rows = readAll<{ assigneeAgentId: string | null }>( - "select distinct assignee_agent_id as assigneeAgentId from tasks where project_id = ? and company_id = ? and assignee_agent_id is not null", - projectId, - companyId, - ); - return rows.map((r) => r.assigneeAgentId).filter((id): id is string => id !== null); - }, - - /** - * Returns assignee agent ids for a set of task ids scoped to a company. - * Used by task-quality-gates sweep to find reviewers of in-review tasks - * that have exceeded the review timeout. - */ - listReviewTasksForSweep(companyId: string): Array<{ - id: string; - assigneeAgentId: string | null; - updatedAt: string; - title: string; - }> { - return readAll( - `SELECT id, assignee_agent_id as assigneeAgentId, updated_at as updatedAt, title - FROM tasks - WHERE company_id = ? AND status = 'in_review'`, - companyId, - ); - }, - }; -} diff --git a/src/main/database/task-review-guard.ts b/src/main/database/task-review-guard.ts deleted file mode 100644 index ab27ab04..00000000 --- a/src/main/database/task-review-guard.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ReadAll } from "./helpers"; - -export function guardInReviewHasReviewer(readAll: ReadAll, taskId: string): void { - const row = readAll<{ requiresUserReview: number; reportsTo: string | null }>( - `select t.requires_user_review as requiresUserReview, - a.reports_to as reportsTo - from tasks t - left join agents a on a.id = t.assignee_agent_id - where t.id = ?`, - taskId, - )[0]; - if (!row) return; - if (row.requiresUserReview === 1) return; - if (row.reportsTo !== null) return; - throw new Error( - `Task ${taskId} has a top-level assignee and no reviewer: cannot enter in_review without requires_user_review=1.`, - ); -} diff --git a/src/main/database/task-sessions-crud.ts b/src/main/database/task-sessions-crud.ts deleted file mode 100644 index 0331ff27..00000000 --- a/src/main/database/task-sessions-crud.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync } from "node:sqlite"; -import type { TaskSessionRecord } from "@shared/types"; -import { type ReadAll, type Transaction, nowIso } from "./helpers"; - -/** - * Agent-scoped session lifecycle. Sessions belong to agents, not - * tasks — `agents.session_id` is the canonical pointer, and - * `task_sessions` rows are looked up by their own primary key only. - * Legacy task/session pointer columns were dropped by v41; any read - * that still needs a session given a task id resolves it through the - * task's assignee agent. - */ -export function buildTaskSessionMethods( - getDb: () => DatabaseSync, - _readAll: ReadAll, - transaction: Transaction, -) { - return { - /** - * Fetch a session by its primary key. This is the single lookup - * path — the rotation evaluator, the worker's finalizer, and the - * turn-context builder all know which session id they want because - * they either receive it from the agent record or from the worker - * event envelope. - */ - getSessionById(sessionId: string): TaskSessionRecord | null { - return ( - (getDb() - .prepare( - `SELECT id, company_id as companyId, agent_id as agentId, - adapter_type as adapterType, last_run_id as lastRunId, - last_error as lastError, run_count as runCount, - total_input_tokens as totalInputTokens, total_output_tokens as totalOutputTokens, - rotated_at as rotatedAt, rotation_reason as rotationReason, - handoff_markdown as handoffMarkdown, created_at as createdAt, updated_at as updatedAt - FROM task_sessions WHERE id = ?`, - ) - .get(sessionId) as TaskSessionRecord | undefined) ?? null - ); - }, - - incrementSessionUsage( - sessionId: string, - inputTokens: number, - outputTokens: number, - runId: string, - ): void { - const ts = nowIso(); - getDb() - .prepare( - `UPDATE task_sessions - SET run_count = run_count + 1, - total_input_tokens = total_input_tokens + ?, - total_output_tokens = total_output_tokens + ?, - last_run_id = ?, - updated_at = ? - WHERE id = ?`, - ) - .run(inputTokens, outputTokens, runId, ts, sessionId); - }, - - archiveSession(sessionId: string, reason: string, handoffMarkdown: string): void { - const ts = nowIso(); - getDb() - .prepare( - `UPDATE task_sessions SET rotated_at = ?, rotation_reason = ?, handoff_markdown = ?, updated_at = ? WHERE id = ?`, - ) - .run(ts, reason, handoffMarkdown, ts, sessionId); - }, - - /** - * Return the agent's active session id, creating one lazily on - * first call. One session per agent — switching tasks emits a - * "now work on X" user turn on the ongoing transcript rather than - * spawning a new session. - */ - ensureAgentSession(input: { - agentId: string; - companyId: string; - adapterType: string; - }): string { - const agentRow = getDb() - .prepare("SELECT session_id FROM agents WHERE id = ?") - .get(input.agentId) as { session_id: string | null } | undefined; - if (agentRow?.session_id) return agentRow.session_id; - - const sessionId = randomUUID(); - const ts = nowIso(); - transaction(() => { - getDb() - .prepare( - `INSERT INTO task_sessions (id, company_id, agent_id, adapter_type, - run_count, total_input_tokens, total_output_tokens, created_at, updated_at) - VALUES (?, ?, ?, ?, 0, 0, 0, ?, ?)`, - ) - .run(sessionId, input.companyId, input.agentId, input.adapterType, ts, ts); - getDb() - .prepare("UPDATE agents SET session_id = ?, updated_at = ? WHERE id = ?") - .run(sessionId, ts, input.agentId); - }); - return sessionId; - }, - - setAgentSessionId(agentId: string, sessionId: string): void { - const ts = nowIso(); - getDb() - .prepare("UPDATE agents SET session_id = ?, updated_at = ? WHERE id = ?") - .run(sessionId, ts, agentId); - }, - - /** - * Create a replacement session row after rotation. Inherits the - * agent / company / adapter type from the caller. Counters start - * at zero — Pi Mono has no per-turn provider state to carry forward. - */ - createNewSession(input: { - companyId: string; - agentId: string; - adapterType: string; - }): string { - const sessionId = randomUUID(); - const ts = nowIso(); - getDb() - .prepare( - `INSERT INTO task_sessions (id, company_id, agent_id, adapter_type, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?)`, - ) - .run(sessionId, input.companyId, input.agentId, input.adapterType, ts, ts); - return sessionId; - }, - }; -} diff --git a/src/main/database/task-status-rules.ts b/src/main/database/task-status-rules.ts deleted file mode 100644 index 788a086a..00000000 --- a/src/main/database/task-status-rules.ts +++ /dev/null @@ -1,41 +0,0 @@ -export const VALID_TASK_STATUSES = new Set([ - "backlog", - "todo", - "in_progress", - "in_review", - "done", - "blocked", - "cancelled", -]); - -export function assertValidTaskStatus(status: string): void { - if (!VALID_TASK_STATUSES.has(status)) { - throw new Error(`Invalid task status: ${status}`); - } -} - -export function buildTaskStatusTransition( - newStatus: string, - timestamp: string, -): { sets: string[]; values: (string | null)[] } { - const sets: string[] = ["status = ?", "updated_at = ?"]; - const values: (string | null)[] = [newStatus, timestamp]; - - if (newStatus === "in_progress") { - sets.push("started_at = COALESCE(started_at, ?)"); - values.push(timestamp); - } - if (newStatus === "done") { - sets.push("completed_at = ?"); - values.push(timestamp); - } else { - sets.push("completed_at = NULL"); - } - if (newStatus === "cancelled") { - sets.push("cancelled_at = ?"); - values.push(timestamp); - } else { - sets.push("cancelled_at = NULL"); - } - return { sets, values }; -} diff --git a/src/main/database/tasks-crud.ts b/src/main/database/tasks-crud.ts deleted file mode 100644 index accd8de0..00000000 --- a/src/main/database/tasks-crud.ts +++ /dev/null @@ -1,272 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import { - type ReadAll, - type Transaction, - ensureId, - normalizeOptionalId, - nowIso, -} from "./helpers"; - -/** - * Row shape returned by listTasksByStatuses — used by the - * GET /api/companies/:companyId/issues route. Mirrors the historical - * inline-SQL projection (no taskType column) so the HTTP response shape - * stays stable for agent CLI clients. - */ -export type TaskListByStatusesRow = { - id: string; - companyId: string; - projectId: string | null; - goalId: string | null; - parentId: string | null; - title: string; - description: string; - assigneeAgentId: string | null; - workspaceId: string | null; - status: string; - priority: string; - activeRunId: string | null; - costUsd: number | null; - requiresUserReview: boolean; - startedAt: string | null; - completedAt: string | null; - cancelledAt: string | null; - createdAt: string; - updatedAt: string; -}; - -export function buildTaskCrudMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - _deps: { - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - }, -) { - return { - saveTask(input: { - id?: string | null; - companyId: string; - projectId?: string | null; - goalId?: string | null; - parentId?: string | null; - title: string; - description: string; - assigneeAgentId?: string | null; - workspaceId?: string | null; - priority: string; - status: string; - /** - * Per-task filesystem lock policy (v52+). Production callers - * pass this explicitly. Direct DB fixtures may omit it: inserts - * use the SQL default 0 and updates preserve the stored value. - */ - requiresFilesystem?: boolean; - }): string { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - const assigneeAgentId = normalizeOptionalId(input.assigneeAgentId); - if (input.status === "in_progress" && !assigneeAgentId) { - throw new Error("Tasks in progress require an assignee."); - } - const existing = getDb() - .prepare("select id from tasks where id = ? and company_id = ?") - .get(id, input.companyId) as { id: string } | undefined; - if (existing) { - if (input.requiresFilesystem === undefined) { - getDb() - .prepare( - "update tasks set project_id = ?, goal_id = ?, parent_id = ?, title = ?, description = ?, assignee_agent_id = ?, workspace_id = ?, priority = ?, status = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run( - normalizeOptionalId(input.projectId), - normalizeOptionalId(input.goalId), - normalizeOptionalId(input.parentId), - input.title, - input.description, - assigneeAgentId, - normalizeOptionalId(input.workspaceId), - input.priority, - input.status, - ts, - id, - input.companyId, - ); - } else { - getDb() - .prepare( - "update tasks set project_id = ?, goal_id = ?, parent_id = ?, title = ?, description = ?, assignee_agent_id = ?, workspace_id = ?, priority = ?, status = ?, requires_filesystem = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run( - normalizeOptionalId(input.projectId), - normalizeOptionalId(input.goalId), - normalizeOptionalId(input.parentId), - input.title, - input.description, - assigneeAgentId, - normalizeOptionalId(input.workspaceId), - input.priority, - input.status, - input.requiresFilesystem ? 1 : 0, - ts, - id, - input.companyId, - ); - } - } else { - getDb() - .prepare( - "insert into tasks (id, company_id, project_id, goal_id, parent_id, title, description, assignee_agent_id, workspace_id, status, priority, requires_filesystem, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - ) - .run( - id, - input.companyId, - normalizeOptionalId(input.projectId), - normalizeOptionalId(input.goalId), - normalizeOptionalId(input.parentId), - input.title, - input.description, - assigneeAgentId, - normalizeOptionalId(input.workspaceId), - input.status, - input.priority, - input.requiresFilesystem ? 1 : 0, - ts, - ts, - ); - } - return id; - }, - - deleteTask(id: string, companyId: string): void { - transaction(() => { - const activeTaskRuns = getDb() - .prepare( - "select id, task_id as taskId, workspace_id as workspaceId from runs where task_id = ? and company_id = ? and status in ('queued', 'running')", - ) - .all(id, companyId) as Array<{ - id: string; - taskId: string; - workspaceId: string | null; - }>; - for (const run of activeTaskRuns) { - const ts = nowIso(); - getDb() - .prepare( - "update runs set status = 'cancelled', summary = ?, error_message = null, exit_code = null, signal = null, model = null, session_display_id = null, cost_usd = null, unattributed_cost = 1, usage_status = ?, finished_at = ?, updated_at = ? where id = ?", - ) - .run("Task deleted.", "aborted_before_usage", ts, ts, run.id); - getDb() - .prepare("delete from task_leases where task_id = ? and run_id = ?") - .run(run.taskId, run.id); - if (run.workspaceId) { - getDb() - .prepare( - `update workspaces - set lock_holder_run_id = null, lock_acquired_at = null, state = 'ready', updated_at = ? - where id = ? and lock_holder_run_id = ?`, - ) - .run(ts, run.workspaceId, run.id); - } - } - getDb() - .prepare( - "update tasks set parent_id = null where parent_id = ? and company_id = ?", - ) - .run(id, companyId); - getDb() - .prepare("delete from approvals where related_task_id = ? and company_id = ?") - .run(id, companyId); - getDb() - .prepare("delete from task_comments where task_id = ? and company_id = ?") - .run(id, companyId); - getDb() - .prepare("delete from tasks where id = ? and company_id = ?") - .run(id, companyId); - }); - }, - - getRecentRunsForTask( - taskId: string, - limit: number, - ): Array<{ - id: string; - status: string; - summary: string | null; - errorMessage: string | null; - finishedAt: string | null; - connectorId: string; - }> { - return readAll( - `SELECT id, status, summary, error_message as errorMessage, - finished_at as finishedAt, connector_id as connectorId - FROM runs WHERE task_id = ? ORDER BY finished_at DESC, rowid DESC LIMIT ?`, - taskId, - limit, - ); - }, - - getRecentActivityForTask( - taskId: string, - limit: number, - ): Array<{ - action: string; - detail: string; - createdAt: string; - }> { - return readAll( - `SELECT action, detail, created_at as createdAt - FROM activity WHERE entity_type = 'task' AND entity_id = ? - ORDER BY created_at DESC LIMIT ?`, - taskId, - limit, - ); - }, - - setTaskType(taskId: string, taskType: string): void { - const ts = nowIso(); - getDb() - .prepare("update tasks set task_type = ?, updated_at = ? where id = ?") - .run(taskType, ts, taskId); - }, - - getTaskRetryCount(taskId: string): number { - const row = getDb() - .prepare("select retry_count from tasks where id = ?") - .get(taskId) as { retry_count: number } | undefined; - return row?.retry_count ?? 0; - }, - - incrementTaskRetryCount(taskId: string): void { - const ts = nowIso(); - getDb() - .prepare( - "update tasks set retry_count = retry_count + 1, last_failure_at = ?, updated_at = ? where id = ?", - ) - .run(ts, ts, taskId); - }, - - resetTaskRetryCount(taskId: string): void { - const ts = nowIso(); - getDb() - .prepare( - "update tasks set retry_count = 0, last_failure_at = null, updated_at = ? where id = ?", - ) - .run(ts, taskId); - }, - - /** - * Returns `task_type` for a single task id, or null when the task is - * missing. Used by checkpoint-engine to branch on task type without - * loading the full row. - */ - getTaskType(taskId: string): string | null { - const row = getDb() - .prepare("SELECT task_type as taskType FROM tasks WHERE id = ? LIMIT 1") - .get(taskId) as { taskType: string | null } | undefined; - return row?.taskType ?? null; - }, - - }; -} diff --git a/src/main/database/tasks-status.ts b/src/main/database/tasks-status.ts deleted file mode 100644 index 66855d21..00000000 --- a/src/main/database/tasks-status.ts +++ /dev/null @@ -1,256 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { TaskRecord } from "@shared/types"; -import { - type ReadAll, - type Transaction, - activeRunIdSql, - nowIso, - taskPriorityOrderSql, -} from "./helpers"; -import { chooseBestTaskAssignee } from "./task-assignment"; -import { checkoutTaskInTransaction } from "./task-checkout"; -import { guardInReviewHasReviewer } from "./task-review-guard"; -import { assertValidTaskStatus, buildTaskStatusTransition } from "./task-status-rules"; -import { STALE_LOCK_TIMEOUT_MS } from "../constants"; - -export function buildTaskStatusMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - }, -) { - function incrementActiveSprintVelocity(companyId: string, delta: number): void { - const ts = nowIso(); - const today = ts.slice(0, 10); - getDb() - .prepare( - "update sprints set completed_points = max(0, completed_points + ?), updated_at = ? where company_id = ? and status = 'active' and start_date <= ? and end_date >= ?", - ) - .run(delta, ts, companyId, today, today); - } - - return { - advanceTaskStatus( - taskId: string, - newStatus: string, - comment?: string, - ): { previousStatus: string } { - assertValidTaskStatus(newStatus); - const task = getDb() - .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 }; - if (newStatus === "in_review") guardInReviewHasReviewer(readAll, taskId); - const ts = nowIso(); - const transition = buildTaskStatusTransition(newStatus, ts); - transaction(() => { - getDb() - .prepare( - `UPDATE tasks SET ${transition.sets.join(", ")} WHERE id = ?`, - ) - .run(...transition.values, taskId); - if (newStatus !== "in_progress") { - getDb().prepare("delete from task_leases where task_id = ?").run(taskId); - } - }); - - if (comment) { - deps.addComment({ - companyId: task.company_id, - taskId, - authorAgentId: null, - authorName: "System", - body: comment, - }); - } - if (newStatus === "done" && previousStatus !== "done") { - incrementActiveSprintVelocity(task.company_id, 1); - } - if (previousStatus === "done" && newStatus !== "done") { - incrementActiveSprintVelocity(task.company_id, -1); - } - return { previousStatus }; - }, - - listReviewTasksForManager(managerId: string, companyId: string): TaskRecord[] { - return readAll( - `select t.id, t.company_id as companyId, t.project_id as projectId, t.goal_id as goalId, - t.parent_id as parentId, t.title, t.description, - t.assignee_agent_id as assigneeAgentId, t.workspace_id as workspaceId, - t.status, t.priority, - ${activeRunIdSql("t")} as activeRunId, - t.cost_usd as costUsd, - t.created_at as createdAt, t.updated_at as updatedAt - from tasks t - inner join agents a on t.assignee_agent_id = a.id - where t.company_id = ? and t.status = 'in_review' and a.reports_to = ? - order by ${taskPriorityOrderSql("t.priority")} desc, t.created_at asc`, - companyId, - managerId, - ); - }, - - checkoutTask(taskId: string, runId: string): boolean { - return transaction(() => checkoutTaskInTransaction(getDb(), taskId, runId)); - }, - - releaseTaskLock(taskId: string, runId: string): void { - getDb() - .prepare("delete from task_leases where task_id = ? and run_id = ?") - .run(taskId, runId); - }, - - renewTaskLease(taskId: string, runId: string): boolean { - const ts = nowIso(); - const expiresAt = new Date(Date.now() + STALE_LOCK_TIMEOUT_MS).toISOString(); - const result = getDb() - .prepare( - "update task_leases set renewed_at = ?, expires_at = ?, updated_at = ? where task_id = ? and run_id = ?", - ) - .run(ts, expiresAt, ts, taskId, runId); - return result.changes > 0; - }, - - setTaskRequiresUserReview(taskId: string, value: boolean): void { - const ts = nowIso(); - getDb() - .prepare("update tasks set requires_user_review = ?, updated_at = ? where id = ?") - .run(value ? 1 : 0, ts, taskId); - }, - - hasPendingDeliverableReviews(companyId: string): boolean { - const approval = getDb() - .prepare( - "select 1 from approvals where company_id = ? and type = 'deliverable_review' and state = 'pending' limit 1", - ) - .get(companyId); - if (approval) return true; - const flaggedTask = getDb() - .prepare( - "select 1 from tasks where company_id = ? and requires_user_review = 1 limit 1", - ) - .get(companyId); - return !!flaggedTask; - }, - - hasAgentPendingDeliverableReview(agentId: string, companyId: string): boolean { - const row = getDb() - .prepare( - `select 1 from approvals a - join tasks t on a.related_task_id = t.id - where a.company_id = ? and a.type = 'deliverable_review' and a.state = 'pending' - and t.assignee_agent_id = ? - limit 1`, - ) - .get(companyId, agentId); - return !!row; - }, - - hasAgentTaskAwaitingReview(agentId: string, companyId: string): boolean { - const row = getDb() - .prepare( - "select 1 from tasks where assignee_agent_id = ? and company_id = ? and requires_user_review = 1 limit 1", - ) - .get(agentId, companyId); - return !!row; - }, - - autoAssignTask(taskId: string, companyId: string): string | null { - const task = getDb() - .prepare( - "select id, title, description, project_id as projectId, assignee_agent_id as assigneeAgentId from tasks where id = ? and company_id = ?", - ) - .get(taskId, companyId) as - | { - id: string; - title: string; - description: string; - projectId: string | null; - assigneeAgentId: string | null; - } - | undefined; - if (!task) return null; - - // If task already has an assignee, return them (don't reassign) - if (task.assigneeAgentId) return task.assigneeAgentId; - - // Get eligible agents: active/idle with remaining budget - const candidates = readAll<{ - id: string; - name: string; - department: string | null; - capabilities: string; - taskCount: number; - budgetMonthlyUsd: number; - spentMonthlyUsd: number; - }>( - `select a.id, a.name, a.department, a.capabilities, - a.budget_monthly_usd as budgetMonthlyUsd, a.spent_monthly_usd as spentMonthlyUsd, - (select count(*) from tasks t where t.assignee_agent_id = a.id and t.status in ('todo', 'in_progress')) as taskCount - from agents a - where a.company_id = ? and a.status in ('idle', 'active') - order by taskCount asc`, - companyId, - ); - - const bestAgent = chooseBestTaskAssignee(getDb, readAll, companyId, task, candidates); - if (!bestAgent) return null; - - getDb() - .prepare( - "update tasks set assignee_agent_id = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run(bestAgent, nowIso(), taskId, companyId); - deps.addActivity({ - companyId, - actor: "system", - action: "task.auto_assigned", - entityType: "task", - entityId: taskId, - detail: `Auto-assigned to ${candidates.find((c) => c.id === bestAgent)?.name ?? bestAgent}`, - }); - return bestAgent; - }, - - retryInterruptedTask( - taskId: string, - _agentId: string, - _companyId: string, - ): void { - const ts = nowIso(); - getDb() - .prepare("update tasks set status = 'todo', updated_at = ? where id = ?") - .run(ts, taskId); - getDb() - .prepare( - "update tasks set retry_count = 0, last_failure_at = null, updated_at = ? where id = ?", - ) - .run(ts, taskId); - }, - - dismissInterruptedTask(taskId: string): void { - const taskRow = getDb() - .prepare("select company_id from tasks where id = ?") - .get(taskId) as { company_id: string } | undefined; - deps.addComment({ - companyId: taskRow?.company_id ?? "", - taskId, - authorAgentId: null, - authorName: "System", - body: "Interrupted run dismissed by user. Task remains blocked for manual handling.", - }); - }, - - markInterruptedTaskFailed(taskId: string): void { - const ts = nowIso(); - getDb() - .prepare("update tasks set status = 'cancelled', updated_at = ? where id = ?") - .run(ts, taskId); - }, - }; -} diff --git a/src/main/database/tasks-update.ts b/src/main/database/tasks-update.ts deleted file mode 100644 index cef32d39..00000000 --- a/src/main/database/tasks-update.ts +++ /dev/null @@ -1,255 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ReadAll, Transaction } from "./helpers"; -import { normalizeOptionalId, nowIso } from "./helpers"; -import { guardInReviewHasReviewer } from "./task-review-guard"; -import { assertValidTaskStatus, buildTaskStatusTransition } from "./task-status-rules"; - -type TaskUpdatePatch = { - title: string; - description: string; - status: string; - priority: string; - projectId?: string | null; - goalId?: string | null; - parentId?: string | null; - assigneeAgentId?: string | null; - workspaceId?: string | null; - requiresFilesystem: boolean; -}; - -type ReviewDocument = { id: string; title: string } & Record; - -type TaskReviewRequest = { - reviewerAgentName: string; - documents: ReviewDocument[]; -}; - -type TaskUpdateActivity = { - action: string; - detail: string; -}; - -type ApprovalRequestInput = { - companyId: string; - relatedTaskId?: string | null; - requestedByAgentId?: string | null; - relatedAgentId?: string | null; - type: string; - payloadSummary: string; - impactSummary: string; - payloadJson?: string | null; -}; - -type TaskUpdateResult = { - previousStatus: string; - newStatus: string; - previousAssigneeAgentId: string | null; - newAssigneeAgentId: string | null; - parentId: string | null; - reviewRequested: boolean; - statusChanged: boolean; -}; - -export function buildTaskUpdateMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - requestApproval: (input: ApprovalRequestInput) => string; - setHeartbeat: (agentId: string, enabled: boolean, intervalSec: number) => void; - }, -) { - function incrementActiveSprintVelocity(companyId: string, delta: number): void { - const ts = nowIso(); - const today = ts.slice(0, 10); - getDb() - .prepare( - "update sprints set completed_points = max(0, completed_points + ?), updated_at = ? where company_id = ? and status = 'active' and start_date <= ? and end_date >= ?", - ) - .run(delta, ts, companyId, today, today); - } - - function pauseAssigneeHeartbeat(agentId: string | null): void { - if (!agentId) return; - const agent = getDb() - .prepare("select heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec from agents where id = ?") - .get(agentId) as { heartbeatEnabled: number; heartbeatIntervalSec: number | null } | undefined; - if (!agent?.heartbeatEnabled) return; - deps.setHeartbeat(agentId, false, agent.heartbeatIntervalSec || 120); - } - - function requestDeliverableReview(input: { - companyId: string; - taskId: string; - actorAgentId: string; - taskTitle: string; - currentAssigneeAgentId: string | null; - reviewRequest: TaskReviewRequest; - }): void { - const docTitles = input.reviewRequest.documents.map((document) => document.title).join(", "); - deps.requestApproval({ - companyId: input.companyId, - relatedTaskId: input.taskId, - requestedByAgentId: input.actorAgentId, - type: "deliverable_review", - payloadSummary: `Review deliverable: ${docTitles || input.taskTitle}`.slice(0, 280), - impactSummary: `${input.reviewRequest.reviewerAgentName} reviewed and approved. Awaiting your final review.`.slice(0, 400), - payloadJson: JSON.stringify({ - documentIds: input.reviewRequest.documents.map((document) => document.id), - documents: input.reviewRequest.documents, - }), - }); - getDb() - .prepare("update tasks set requires_user_review = 0, updated_at = ? where id = ? and company_id = ?") - .run(nowIso(), input.taskId, input.companyId); - pauseAssigneeHeartbeat(input.currentAssigneeAgentId); - deps.addComment({ - companyId: input.companyId, - taskId: input.taskId, - authorAgentId: null, - authorName: "System", - body: "Deliverable submitted for board review.", - }); - } - - return { - updateTaskWithReviewSideEffects(input: { - taskId: string; - companyId: string; - actorAgentId: string; - actorName: string; - task: TaskUpdatePatch; - comment?: string; - reviewRequest?: TaskReviewRequest | null; - activity: TaskUpdateActivity; - }): TaskUpdateResult { - assertValidTaskStatus(input.task.status); - const assigneeAgentId = normalizeOptionalId(input.task.assigneeAgentId); - if (input.task.status === "in_progress" && !assigneeAgentId) { - throw new Error("Tasks in progress require an assignee."); - } - - return transaction(() => { - const current = getDb() - .prepare( - "select id, company_id as companyId, status, title, assignee_agent_id as assigneeAgentId, parent_id as parentId, requires_user_review as requiresUserReview from tasks where id = ? and company_id = ?", - ) - .get(input.taskId, input.companyId) as - | { - id: string; - companyId: string; - status: string; - title: string; - assigneeAgentId: string | null; - parentId: string | null; - requiresUserReview: number; - } - | undefined; - if (!current) { - throw new Error(`Task not found: ${input.taskId}`); - } - - const reviewRequested = - input.task.status === "done" && - current.requiresUserReview === 1 && - input.reviewRequest !== null && - input.reviewRequest !== undefined; - if (input.task.status === "done" && current.requiresUserReview === 1 && !input.reviewRequest) { - throw new Error(`Task ${input.taskId} requires a deliverable review request before it can be marked done.`); - } - const newStatus = reviewRequested ? "in_review" : input.task.status; - assertValidTaskStatus(newStatus); - - if (reviewRequested) { - requestDeliverableReview({ - companyId: input.companyId, - taskId: input.taskId, - actorAgentId: input.actorAgentId, - taskTitle: current.title, - currentAssigneeAgentId: current.assigneeAgentId, - reviewRequest: input.reviewRequest!, - }); - } - - const statusChanged = current.status !== newStatus; - if (statusChanged && newStatus === "in_review") { - guardInReviewHasReviewer(readAll, input.taskId); - } - - const ts = nowIso(); - const sets = [ - "project_id = ?", - "goal_id = ?", - "parent_id = ?", - "title = ?", - "description = ?", - "assignee_agent_id = ?", - "workspace_id = ?", - "priority = ?", - "requires_filesystem = ?", - ]; - const values: Array = [ - normalizeOptionalId(input.task.projectId), - normalizeOptionalId(input.task.goalId), - normalizeOptionalId(input.task.parentId), - input.task.title, - input.task.description, - assigneeAgentId, - normalizeOptionalId(input.task.workspaceId), - input.task.priority, - input.task.requiresFilesystem ? 1 : 0, - ]; - const transition = statusChanged ? buildTaskStatusTransition(newStatus, ts) : null; - if (transition) { - sets.push(...transition.sets); - values.push(...transition.values); - } else { - sets.push("status = ?", "updated_at = ?"); - values.push(newStatus, ts); - } - - const updateResult = getDb() - .prepare(`update tasks set ${sets.join(", ")} where id = ? and company_id = ?`) - .run(...values, input.taskId, input.companyId); - if (updateResult.changes === 0) { - throw new Error(`Task not found: ${input.taskId}`); - } - if (newStatus === "done" && current.status !== "done") { - incrementActiveSprintVelocity(input.companyId, 1); - } - if (current.status === "done" && newStatus !== "done") { - incrementActiveSprintVelocity(input.companyId, -1); - } - if (input.comment) { - deps.addComment({ - companyId: input.companyId, - taskId: input.taskId, - authorAgentId: input.actorAgentId, - authorName: input.actorName, - body: input.comment, - }); - } - deps.addActivity({ - companyId: input.companyId, - actor: input.actorAgentId, - action: input.activity.action, - entityType: "task", - entityId: input.taskId, - detail: input.activity.detail, - }); - - return { - previousStatus: current.status, - newStatus, - previousAssigneeAgentId: current.assigneeAgentId, - newAssigneeAgentId: assigneeAgentId, - parentId: normalizeOptionalId(input.task.parentId), - reviewRequested, - statusChanged, - }; - }); - }, - }; -} diff --git a/src/main/database/tasks.ts b/src/main/database/tasks.ts deleted file mode 100644 index 3a936066..00000000 --- a/src/main/database/tasks.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { ReadAll, Transaction } from "./helpers"; -import { buildTaskCrudMethods } from "./tasks-crud"; -import { buildTaskQueryMethods } from "./task-queries"; -import { buildTaskSessionMethods } from "./task-sessions-crud"; -import { buildTaskStatusMethods } from "./tasks-status"; -import { buildTaskUpdateMethods } from "./tasks-update"; - -export function buildTaskMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, - deps: { - addComment: (input: { companyId: string; taskId: string; authorAgentId: string | null; authorName: string; body: string }) => void; - addActivity: (input: { companyId: string; actor: string; action: string; entityType: string; entityId: string; detail: string }) => void; - requestApproval: (input: { - companyId: string; - relatedTaskId?: string | null; - requestedByAgentId?: string | null; - relatedAgentId?: string | null; - type: string; - payloadSummary: string; - impactSummary: string; - payloadJson?: string | null; - }) => string; - setHeartbeat: (agentId: string, enabled: boolean, intervalSec: number) => void; - }, -) { - return { - ...buildTaskCrudMethods(getDb, readAll, transaction, deps), - ...buildTaskQueryMethods(getDb, readAll, transaction), - ...buildTaskSessionMethods(getDb, readAll, transaction), - ...buildTaskStatusMethods(getDb, readAll, transaction, deps), - ...buildTaskUpdateMethods(getDb, readAll, transaction, deps), - }; -} diff --git a/src/main/database/threads.ts b/src/main/database/threads.ts deleted file mode 100644 index f5516fc2..00000000 --- a/src/main/database/threads.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { - ConversationEventRecord, - ConversationParticipantRecord, - ConversationThreadRecord, - ThreadActorType, - ThreadEventType, - ThreadNotifyOn, - ThreadParticipantRole, - ThreadSubscriptionRecord, - ThreadType, - ThreadWaitingFor, - ThreadWaitStateRecord, -} from "@shared/types"; -import { type ReadAll, type SqliteRow, nowIso } from "./helpers"; - -export function buildThreadMethods(getDb: () => DatabaseSync, readAll: ReadAll) { - function getThread(threadId: string, companyId: string): ConversationThreadRecord | null { - const row = getDb() - .prepare( - `SELECT id, company_id, title, type, related_entity_type, related_entity_id, created_at, updated_at - FROM conversation_threads WHERE id = ? AND company_id = ?`, - ) - .get(threadId, companyId) as SqliteRow | undefined; - if (!row) return null; - return { - id: row.id as string, - companyId: row.company_id as string, - title: row.title as string, - type: row.type as ThreadType, - relatedEntityType: (row.related_entity_type as string | null) ?? null, - relatedEntityId: (row.related_entity_id as string | null) ?? null, - createdAt: row.created_at as string, - updatedAt: row.updated_at as string, - }; - } - - return { - createThread(input: { - companyId: string; - title: string; - type: ThreadType; - relatedEntityType: string | null; - relatedEntityId: string | null; - }): ConversationThreadRecord { - const id = randomUUID(); - const ts = nowIso(); - getDb() - .prepare( - `INSERT INTO conversation_threads (id, company_id, title, type, related_entity_type, related_entity_id, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - ) - .run(id, input.companyId, input.title, input.type, input.relatedEntityType, input.relatedEntityId, ts, ts); - return { - id, - companyId: input.companyId, - title: input.title, - type: input.type, - relatedEntityType: input.relatedEntityType, - relatedEntityId: input.relatedEntityId, - createdAt: ts, - updatedAt: ts, - }; - }, - - listThreads(options: { - companyId: string; - type?: ThreadType; - relatedEntityType?: string; - relatedEntityId?: string; - limit?: number; - offset?: number; - }): ConversationThreadRecord[] { - const conditions: string[] = ["company_id = ?"]; - const params: SQLInputValue[] = [options.companyId]; - if (options.type) { conditions.push("type = ?"); params.push(options.type); } - if (options.relatedEntityType) { conditions.push("related_entity_type = ?"); params.push(options.relatedEntityType); } - if (options.relatedEntityId) { conditions.push("related_entity_id = ?"); params.push(options.relatedEntityId); } - const where = conditions.join(" AND "); - const limit = options.limit ?? 50; - const offset = options.offset ?? 0; - const rows = readAll( - `SELECT id, company_id, title, type, related_entity_type, related_entity_id, created_at, updated_at - FROM conversation_threads WHERE ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`, - ...params, limit, offset, - ); - return rows.map((r) => ({ - id: r.id as string, - companyId: r.company_id as string, - title: r.title as string, - type: r.type as ThreadType, - relatedEntityType: (r.related_entity_type as string | null) ?? null, - relatedEntityId: (r.related_entity_id as string | null) ?? null, - createdAt: r.created_at as string, - updatedAt: r.updated_at as string, - })); - }, - - getThread, - - addThreadEvent(input: { - threadId: string; - actorId: string; - actorType: ThreadActorType; - eventType: ThreadEventType; - body: string; - metadataJson: string; - }): ConversationEventRecord { - const id = randomUUID(); - const ts = nowIso(); - const db = getDb(); - db.prepare( - `INSERT INTO conversation_events (id, thread_id, actor_id, actor_type, event_type, body, metadata_json, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, - ).run(id, input.threadId, input.actorId, input.actorType, input.eventType, input.body, input.metadataJson, ts); - db.prepare("UPDATE conversation_threads SET updated_at = ? WHERE id = ?").run(ts, input.threadId); - return { - id, - threadId: input.threadId, - actorId: input.actorId, - actorType: input.actorType, - eventType: input.eventType, - body: input.body, - metadataJson: input.metadataJson, - createdAt: ts, - }; - }, - - listThreadEvents( - threadId: string, - companyId: string, - options: { limit?: number; offset?: number } = {}, - ): ConversationEventRecord[] { - const limit = options.limit ?? 50; - const offset = options.offset ?? 0; - const rows = readAll( - `SELECT id, thread_id, actor_id, actor_type, event_type, body, metadata_json, created_at - FROM conversation_events - WHERE thread_id = ? - AND thread_id IN (SELECT id FROM conversation_threads WHERE id = ? AND company_id = ?) - ORDER BY created_at ASC LIMIT ? OFFSET ?`, - threadId, threadId, companyId, limit, offset, - ); - return rows.map((r) => ({ - id: r.id as string, - threadId: r.thread_id as string, - actorId: r.actor_id as string, - actorType: r.actor_type as ThreadActorType, - eventType: r.event_type as ThreadEventType, - body: r.body as string, - metadataJson: r.metadata_json as string, - createdAt: r.created_at as string, - })); - }, - - setThreadWaitState(input: { - threadId: string; - companyId: string; - waitingFor: ThreadWaitingFor; - relatedApprovalId: string | null; - reason: string; - }): ThreadWaitStateRecord { - const id = randomUUID(); - const ts = nowIso(); - getDb() - .prepare( - `INSERT INTO thread_wait_states (id, thread_id, company_id, waiting_for, related_approval_id, reason, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?)`, - ) - .run(id, input.threadId, input.companyId, input.waitingFor, input.relatedApprovalId, input.reason, ts); - return { - id, - threadId: input.threadId, - companyId: input.companyId, - waitingFor: input.waitingFor, - relatedApprovalId: input.relatedApprovalId, - reason: input.reason, - createdAt: ts, - resolvedAt: null, - }; - }, - - resolveThreadWaitState(waitStateId: string, companyId: string): void { - const ts = nowIso(); - getDb() - .prepare( - `UPDATE thread_wait_states SET resolved_at = ? WHERE id = ? AND company_id = ? AND resolved_at IS NULL`, - ) - .run(ts, waitStateId, companyId); - }, - - listThreadWaitStates( - companyId: string, - options: { resolvedOnly?: boolean } = {}, - ): ThreadWaitStateRecord[] { - const where = options.resolvedOnly - ? "company_id = ? AND resolved_at IS NOT NULL" - : "company_id = ? AND resolved_at IS NULL"; - const rows = readAll( - `SELECT id, thread_id, company_id, waiting_for, related_approval_id, reason, created_at, resolved_at - FROM thread_wait_states WHERE ${where} ORDER BY created_at DESC`, - companyId, - ); - return rows.map((r) => ({ - id: r.id as string, - threadId: r.thread_id as string, - companyId: r.company_id as string, - waitingFor: r.waiting_for as ThreadWaitingFor, - relatedApprovalId: (r.related_approval_id as string | null) ?? null, - reason: r.reason as string, - createdAt: r.created_at as string, - resolvedAt: (r.resolved_at as string | null) ?? null, - })); - }, - - /** - * Returns true when the agent owns an unresolved wait state on any - * thread type — task, approval, or freeform. Ownership is the union - * of three predicates so approval-only threads and ad-hoc threads - * are no longer invisible to the heartbeat scheduler and the - * `beforeToolCall` gate: - * - * 1. Task thread whose task is assigned to the agent. - * 2. Approval thread whose approval was requested by the agent. - * 3. Any thread on which the agent is a recorded participant. - * - * Each branch uses an EXISTS subquery so the query short-circuits - * as soon as one wait state matches. - */ - hasUnresolvedWaitStateForAgent(companyId: string, agentId: string): boolean { - const rows = readAll<{ id: string }>( - `SELECT tws.id FROM thread_wait_states tws - JOIN conversation_threads ct ON ct.id = tws.thread_id - WHERE tws.company_id = ? - AND tws.resolved_at IS NULL - AND ( - (ct.related_entity_type = 'task' AND EXISTS ( - SELECT 1 FROM tasks t - WHERE t.id = ct.related_entity_id AND t.assignee_agent_id = ? - )) - OR (ct.related_entity_type = 'approval' AND EXISTS ( - SELECT 1 FROM approvals a - WHERE a.id = ct.related_entity_id AND a.requested_by_agent_id = ? - )) - OR EXISTS ( - SELECT 1 FROM conversation_participants cp - WHERE cp.thread_id = tws.thread_id AND cp.participant_id = ? - ) - ) - LIMIT 1`, - companyId, agentId, agentId, agentId, - ); - return rows.length > 0; - }, - - // ── Participants ────────────────────────────────────────────────────── - - addParticipant(input: { - threadId: string; - participantId: string; - participantType: ThreadActorType; - role?: ThreadParticipantRole; - }): ConversationParticipantRecord { - const ts = nowIso(); - const role = input.role ?? "member"; - getDb() - .prepare( - `INSERT OR IGNORE INTO conversation_participants (thread_id, participant_id, participant_type, role, joined_at) - VALUES (?, ?, ?, ?, ?)`, - ) - .run(input.threadId, input.participantId, input.participantType, role, ts); - return { - threadId: input.threadId, - participantId: input.participantId, - participantType: input.participantType, - role, - joinedAt: ts, - }; - }, - - listParticipants(threadId: string): ConversationParticipantRecord[] { - const rows = readAll( - `SELECT thread_id, participant_id, participant_type, role, joined_at - FROM conversation_participants WHERE thread_id = ? ORDER BY joined_at ASC`, - threadId, - ); - return rows.map((r) => ({ - threadId: r.thread_id as string, - participantId: r.participant_id as string, - participantType: r.participant_type as ThreadActorType, - role: r.role as ThreadParticipantRole, - joinedAt: r.joined_at as string, - })); - }, - - removeParticipant(threadId: string, participantId: string): void { - getDb() - .prepare("DELETE FROM conversation_participants WHERE thread_id = ? AND participant_id = ?") - .run(threadId, participantId); - }, - - // ── Subscriptions ──────────────────────────────────────────────────── - - subscribe(input: { - threadId: string; - subscriberId: string; - subscriberType: ThreadActorType; - notifyOn?: ThreadNotifyOn; - }): ThreadSubscriptionRecord { - const ts = nowIso(); - const notifyOn = input.notifyOn ?? "all"; - getDb() - .prepare( - `INSERT OR REPLACE INTO thread_subscriptions (thread_id, subscriber_id, subscriber_type, notify_on, subscribed_at) - VALUES (?, ?, ?, ?, ?)`, - ) - .run(input.threadId, input.subscriberId, input.subscriberType, notifyOn, ts); - return { - threadId: input.threadId, - subscriberId: input.subscriberId, - subscriberType: input.subscriberType, - notifyOn, - subscribedAt: ts, - }; - }, - - unsubscribe(threadId: string, subscriberId: string): void { - getDb() - .prepare("DELETE FROM thread_subscriptions WHERE thread_id = ? AND subscriber_id = ?") - .run(threadId, subscriberId); - }, - - listSubscriptions(threadId: string): ThreadSubscriptionRecord[] { - const rows = readAll( - `SELECT thread_id, subscriber_id, subscriber_type, notify_on, subscribed_at - FROM thread_subscriptions WHERE thread_id = ? ORDER BY subscribed_at ASC`, - threadId, - ); - return rows.map((r) => ({ - threadId: r.thread_id as string, - subscriberId: r.subscriber_id as string, - subscriberType: r.subscriber_type as ThreadActorType, - notifyOn: r.notify_on as ThreadNotifyOn, - subscribedAt: r.subscribed_at as string, - })); - }, - - listSubscribedThreads(subscriberId: string, companyId: string): ConversationThreadRecord[] { - const rows = readAll( - `SELECT ct.id, ct.company_id, ct.title, ct.type, ct.related_entity_type, ct.related_entity_id, ct.created_at, ct.updated_at - FROM conversation_threads ct - JOIN thread_subscriptions ts ON ct.id = ts.thread_id - WHERE ts.subscriber_id = ? AND ct.company_id = ? - ORDER BY ct.updated_at DESC`, - subscriberId, companyId, - ); - return rows.map((r) => ({ - id: r.id as string, - companyId: r.company_id as string, - title: r.title as string, - type: r.type as ThreadType, - relatedEntityType: (r.related_entity_type as string | null) ?? null, - relatedEntityId: (r.related_entity_id as string | null) ?? null, - createdAt: r.created_at as string, - updatedAt: r.updated_at as string, - })); - }, - }; -} diff --git a/src/main/database/wakeup.ts b/src/main/database/wakeup.ts deleted file mode 100644 index 2e83f592..00000000 --- a/src/main/database/wakeup.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { DatabaseSync, SQLInputValue } from "node:sqlite"; -import type { ReadAll, Transaction } from "./helpers"; -import { nowIso } from "./helpers"; - -export function buildWakeupMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - function parseTriggerDetail(raw: string | null): Array<{ trigger?: string; at?: string; detail?: string }> { - if (!raw) return []; - try { - const parsed = JSON.parse(raw); - return Array.isArray(parsed) ? parsed.filter((entry) => entry && typeof entry === "object") as Array<{ trigger?: string; at?: string; detail?: string }> : []; - } catch { - return []; - } - } - - function choosePreferredTrigger(triggers: string[]): string | null { - const unique = new Set(triggers.filter(Boolean)); - const preferredOrder = [ - "message", - "peer_request", - "comment_mentioned", - "approval_resolved", - "subtask_completed", - "report_blocked", - "report_failed", - "comment", - "assignment", - "manual", - "timer", - ]; - for (const trigger of preferredOrder) { - if (unique.has(trigger)) return trigger; - } - return triggers[0] ?? null; - } - - function 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 }); - } - - return { - enqueueWakeupRequest(companyId: string, agentId: string, trigger: string, detail: string, context?: Record): void { - const ts = nowIso(); - transaction(() => { - const existing = getDb() - .prepare( - `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; context_snapshot: string | null } - | undefined; - - if (existing) { - const triggers: Array<{ trigger: string; at: string; detail: string }> = existing.trigger_detail - ? JSON.parse(existing.trigger_detail) - : []; - triggers.push({ trigger, at: ts, detail }); - 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); - } - getDb() - .prepare( - `UPDATE wakeup_requests - SET trigger_detail = ?, - coalesced_count = coalesced_count + 1, - context_snapshot = ?, - updated_at = ? - WHERE id = ?`, - ) - .run(JSON.stringify(triggers), mergedContext, ts, existing.id); - } else { - const triggerDetail = JSON.stringify([{ trigger, at: ts, detail }]); - const contextJson = context ? JSON.stringify(context) : null; - getDb() - .prepare( - `INSERT INTO wakeup_requests - (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, contextJson, ts, ts, ts); - } - }); - }, - - promoteWakeupRequests(agentId: string, companyId: string): number { - let promoted = 0; - transaction(() => { - const queued = getDb() - .prepare( - `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; context_snapshot: string | null } | undefined; - const deferred = 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) { - 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 = mergeContextSnapshots(mergedCtx, d.context_snapshot); - } - getDb().prepare( - `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) { - getDb().prepare("DELETE FROM wakeup_requests WHERE id = ?").run(d.id); - } - promoted = deferred.length; - } else { - const [first, ...rest] = deferred; - if (!first) return 0; - getDb().prepare( - `UPDATE wakeup_requests SET status = 'queued', updated_at = ? WHERE id = ?`, - ).run(ts, first.id); - 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 = mergeContextSnapshots(mergedCtx, d.context_snapshot); - } - getDb().prepare( - `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) { - getDb().prepare("DELETE FROM wakeup_requests WHERE id = ?").run(d.id); - } - } - promoted = deferred.length; - } - }); - return promoted; - }, - - listPendingWakeupAgents(companyId: string): Array<{ agentId: string }> { - return readAll( - `SELECT agent_id AS agentId - FROM wakeup_requests - WHERE company_id = ? AND status IN ('queued', 'deferred') - GROUP BY agent_id - ORDER BY MIN(requested_at) ASC`, - companyId, - ); - }, - - listWakeupRequests(companyId: string, filters?: { status?: string; agentId?: string; limit?: number }): Array<{ - id: string; companyId: string; agentId: string; source: string; triggerDetail: string | null; - status: string; coalescedCount: number; runId: string | null; requestedAt: string; - claimedAt: string | null; finishedAt: string | null; createdAt: string; updatedAt: string; - }> { - const conditions = ["company_id = ?"]; - const params: SQLInputValue[] = [companyId]; - if (filters?.status) { conditions.push("status = ?"); params.push(filters.status); } - if (filters?.agentId) { conditions.push("agent_id = ?"); params.push(filters.agentId); } - const limit = filters?.limit ?? 50; - return readAll( - `SELECT id, company_id AS companyId, agent_id AS agentId, source, trigger_detail AS triggerDetail, - status, coalesced_count AS coalescedCount, run_id AS runId, requested_at AS requestedAt, - claimed_at AS claimedAt, finished_at AS finishedAt, created_at AS createdAt, updated_at AS updatedAt - FROM wakeup_requests - WHERE ${conditions.join(" AND ")} - ORDER BY requested_at DESC - LIMIT ?`, - ...params, limit, - ); - }, - - getPreferredWakeTrigger(agentId: string, companyId: string): string | null { - const rows = readAll<{ source: string; trigger_detail: string | null }>( - `SELECT source, trigger_detail - FROM wakeup_requests - WHERE agent_id = ? AND company_id = ? AND status IN ('queued', 'deferred') - ORDER BY requested_at ASC`, - agentId, - companyId, - ); - if (rows.length === 0) return null; - - const triggers: string[] = []; - for (const row of rows) { - if (row.source) triggers.push(row.source); - for (const entry of parseTriggerDetail(row.trigger_detail)) { - if (typeof entry.trigger === "string" && entry.trigger.length > 0) { - triggers.push(entry.trigger); - } - } - } - - return choosePreferredTrigger(triggers); - }, - - completePendingWakeupRequests(agentId: string, companyId: string, runId: string): number { - const ts = nowIso(); - const result = getDb().prepare( - `UPDATE wakeup_requests - SET status = 'completed', - run_id = ?, - claimed_at = COALESCE(claimed_at, ?), - finished_at = ?, - updated_at = ? - WHERE agent_id = ? AND company_id = ? AND status IN ('queued', 'deferred')`, - ).run(runId, ts, ts, ts, agentId, companyId); - return Number(result.changes); - }, - - purgeExpiredWakeupRequests() { - const cutoff = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(); - const result = getDb().prepare("DELETE FROM wakeup_requests WHERE created_at < ? AND status IN ('completed')").run(cutoff); - return Number(result.changes); - }, - }; -} diff --git a/src/main/database/workspaces.ts b/src/main/database/workspaces.ts deleted file mode 100644 index d106ead9..00000000 --- a/src/main/database/workspaces.ts +++ /dev/null @@ -1,208 +0,0 @@ -import type { DatabaseSync } from "node:sqlite"; -import type { RunStatus, WorkspaceRecord } from "@shared/types"; -import type { ReadAll, Transaction } from "./helpers"; -import { ensureId, normalizeOptionalId, nowIso, toBoolean } from "./helpers"; - -export function buildWorkspaceMethods( - getDb: () => DatabaseSync, - readAll: ReadAll, - transaction: Transaction, -) { - return { - saveWorkspace(input: { - id?: string | null; - companyId: string; - name: string; - localPath: string; - repoUrl: string; - repoRef: string; - projectId?: string | null; - isPrimary: boolean; - }) { - const id = ensureId(input.id ?? null); - const ts = nowIso(); - if (input.isPrimary) { - getDb().prepare("update workspaces set is_primary = 0 where company_id = ?").run(input.companyId); - } - const existing = getDb().prepare("select id from workspaces where id = ? and company_id = ?").get(id, input.companyId) as { id: string } | undefined; - if (existing) { - getDb() - .prepare( - "update workspaces set name = ?, local_path = ?, repo_url = ?, repo_ref = ?, project_id = ?, is_primary = ?, updated_at = ? where id = ? and company_id = ?", - ) - .run(input.name, input.localPath, input.repoUrl, input.repoRef, normalizeOptionalId(input.projectId), input.isPrimary ? 1 : 0, ts, id, input.companyId); - } else { - getDb() - .prepare( - "insert into workspaces (id, company_id, name, local_path, repo_url, repo_ref, project_id, state, is_primary, created_at, updated_at) values (?, ?, ?, ?, ?, ?, ?, 'ready', ?, ?, ?)", - ) - .run(id, input.companyId, input.name, input.localPath, input.repoUrl, input.repoRef, normalizeOptionalId(input.projectId), input.isPrimary ? 1 : 0, ts, ts); - } - return id; - }, - - getWorkspace(id: string | null | undefined): WorkspaceRecord | null { - if (!id) return null; - const row = getDb() - .prepare( - "select id, company_id as companyId, name, local_path as localPath, repo_url as repoUrl, repo_ref as repoRef, project_id as projectId, state, is_primary as isPrimary, created_at as createdAt, updated_at as updatedAt from workspaces where id = ?", - ) - .get(id) as WorkspaceRecord | undefined; - return row ? { ...row, isPrimary: toBoolean(row.isPrimary) } : null; - }, - - /** - * Reverse-lookup a workspace's id by its local_path within a - * company. Used by the artifact projector to heal a run context - * whose workspaceId was never bound but whose workspacePath is - * still known — we look up the row that owns that path so the - * resulting work_product carries a real foreign key instead of - * another null that downstream readers would have to heal again. - * Returns null when the path does not match any workspace (the - * caller proceeds without a workspace_id, which is then handled - * defensively by updateWorkProduct). - */ - findWorkspaceIdByLocalPath(companyId: string, localPath: string): string | null { - const row = getDb() - .prepare("select id from workspaces where company_id = ? and local_path = ? limit 1") - .get(companyId, localPath) as { id: string } | undefined; - return row?.id ?? null; - }, - - getProjectPrimaryWorkspace(projectId: string | null | undefined, companyId: string): WorkspaceRecord | null { - if (!projectId) return null; - const row = getDb() - .prepare( - "select id, company_id as companyId, name, local_path as localPath, repo_url as repoUrl, repo_ref as repoRef, project_id as projectId, state, is_primary as isPrimary, created_at as createdAt, updated_at as updatedAt from workspaces where company_id = ? and project_id = ? order by is_primary desc, created_at asc limit 1", - ) - .get(companyId, projectId) as WorkspaceRecord | undefined; - return row ? { ...row, isPrimary: toBoolean(row.isPrimary) } : null; - }, - - /** - * Pick a single workspace per company for *observation only* (no - * lock claim). Used by the artifact projector to know where on - * disk a `lockMode='none'` cognitive run might write files. The - * tie-break order is `is_primary` first, then earliest `created_at` - * — i.e. the workspace the operator marked as canonical wins, and - * if no one is marked, the oldest row wins (which historically is - * the company's default scratch directory). - * - * Returns `null` when the company has no workspace at all; the - * caller treats that as "agent has no observation surface", which - * is correct — there is genuinely nowhere to look for files. - */ - getCompanyObservationWorkspace(companyId: string): WorkspaceRecord | null { - const row = getDb() - .prepare( - "select id, company_id as companyId, name, local_path as localPath, repo_url as repoUrl, repo_ref as repoRef, project_id as projectId, state, is_primary as isPrimary, created_at as createdAt, updated_at as updatedAt from workspaces where company_id = ? order by is_primary desc, created_at asc limit 1", - ) - .get(companyId) as WorkspaceRecord | undefined; - return row ? { ...row, isPrimary: toBoolean(row.isPrimary) } : null; - }, - - listWorkspaceLocalPaths(companyId: string): string[] { - const rows = getDb() - .prepare("select local_path as localPath from workspaces where company_id = ? and local_path is not null") - .all(companyId) as Array<{ localPath: string }>; - return rows.map((r) => r.localPath).filter(Boolean); - }, - - deleteWorkspace(id: string, companyId: string) { - transaction(() => { - getDb().prepare("update agents set workspace_id = null where workspace_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("update tasks set workspace_id = null where workspace_id = ? and company_id = ?").run(id, companyId); - getDb().prepare("delete from workspaces where id = ? and company_id = ?").run(id, companyId); - }); - }, - - acquireWorkspaceLock(workspaceId: string, runId: string): boolean { - const ts = nowIso(); - const result = getDb() - .prepare( - `update workspaces - set lock_holder_run_id = ?, lock_acquired_at = ?, state = 'busy', updated_at = ? - where id = ? - and (lock_holder_run_id is null or lock_holder_run_id = ?)`, - ) - .run(runId, ts, ts, workspaceId, runId); - return result.changes > 0; - }, - - claimWorkspaceLock(workspaceId: string, runId: string): boolean { - const holder = getDb() - .prepare("select lock_holder_run_id as lockHolderRunId from workspaces where id = ?") - .get(workspaceId) as { lockHolderRunId: string | null } | undefined; - if (!holder) return false; - if (!holder.lockHolderRunId || holder.lockHolderRunId === runId) { - const ts = nowIso(); - const result = getDb() - .prepare( - `update workspaces - set lock_holder_run_id = ?, lock_acquired_at = ?, state = 'busy', updated_at = ? - where id = ? - and (lock_holder_run_id is null or lock_holder_run_id = ?)`, - ) - .run(runId, ts, ts, workspaceId, runId); - return result.changes > 0; - } - const blockingRun = getDb() - .prepare("select status from runs where id = ?") - .get(holder.lockHolderRunId) as { status: RunStatus } | undefined; - if (blockingRun && (blockingRun.status === "queued" || blockingRun.status === "running")) { - return false; - } - const ts = nowIso(); - const result = getDb() - .prepare( - `update workspaces - set lock_holder_run_id = ?, lock_acquired_at = ?, state = 'busy', updated_at = ? - where id = ? and lock_holder_run_id = ?`, - ) - .run(runId, ts, ts, workspaceId, holder.lockHolderRunId); - return result.changes > 0; - }, - - releaseWorkspaceLock(workspaceId: string, runId: string) { - getDb() - .prepare( - `update workspaces - set lock_holder_run_id = null, lock_acquired_at = null, state = 'ready', updated_at = ? - where id = ? and lock_holder_run_id = ?`, - ) - .run(nowIso(), workspaceId, runId); - }, - - releaseAllWorkspaceLocks() { - getDb() - .prepare( - "update workspaces set lock_holder_run_id = null, lock_acquired_at = null, state = 'ready', updated_at = ? where lock_holder_run_id is not null", - ) - .run(nowIso()); - }, - - releaseStaleWorkspaceLocks(): number { - const result = getDb() - .prepare( - `update workspaces - set lock_holder_run_id = null, lock_acquired_at = null, state = 'ready', updated_at = ? - where lock_holder_run_id is not null - and not exists ( - select 1 - from runs - where runs.id = workspaces.lock_holder_run_id - and runs.status in ('queued', 'running') - )`, - ) - .run(nowIso()); - return Number(result.changes); - }, - - isWorkspaceLocked(workspaceId: string): boolean { - const row = getDb() - .prepare("select lock_holder_run_id from workspaces where id = ?") - .get(workspaceId) as { lock_holder_run_id: string | null } | undefined; - return Boolean(row?.lock_holder_run_id); - }, - }; -} diff --git a/src/main/default-automation-rules.ts b/src/main/default-automation-rules.ts deleted file mode 100644 index d0bf131b..00000000 --- a/src/main/default-automation-rules.ts +++ /dev/null @@ -1,170 +0,0 @@ -interface DefaultAutomationRule { - name: string; - description: string; - trigger: string; - action: string; - /** Typed condition config. Stringified once at seed time. */ - conditions?: Record; - /** Typed action config. Stringified once at seed time. */ - actionConfig?: Record; - priority?: number; -} - -export const DEFAULT_AUTOMATION_RULES: ReadonlyArray = [ - { - name: "Auto-assign new tasks", - description: "Automatically assign new unassigned tasks to the best-fit agent based on capabilities and workload.", - trigger: "task_created", - action: "assign_task", - priority: 90, - }, - { - name: "Escalate blocked tasks", - description: "When a task is blocked, escalate to the assignee's manager.", - trigger: "task_blocked", - action: "escalate_to_manager", - actionConfig: { body: "A task assigned to your report is blocked and needs your attention." }, - priority: 85, - }, - { - name: "Escalate completed work to manager", - description: "When a run completes successfully, escalate to the assignee's manager so they can review the completed work.", - trigger: "run_completed", - action: "escalate_to_manager", - actionConfig: { body: "A task run has completed successfully. The task has moved to review status. Please review and either approve (mark as done) or send back with feedback." }, - priority: 80, - }, - { - name: "Reassign on run failure", - description: "When a run fails after exhausting retries, attempt to reassign the task to another capable agent.", - trigger: "run_failed", - action: "reassign_task", - conditions: { afterRetryExhaustion: true }, - priority: 75, - }, - { - name: "Budget alert at 80%", - description: "Send an alert when an agent reaches 80% of their monthly budget.", - trigger: "budget_threshold", - action: "send_message", - actionConfig: { subject: "Budget warning", body: "Agent is approaching budget limit (80% utilized).", priority: "urgent" }, - priority: 70, - }, - { - name: "Notify department on task completion", - description: "When a run completes successfully, send a status update to the agent's department channel.", - trigger: "run_completed", - action: "send_message", - actionConfig: { channel: "department", subject: "Task completed", body: "A task has been completed successfully. Check the task details for more information.", priority: "low" }, - priority: 40, - }, - { - name: "Wake new hire on approval", - description: "When a new agent hire is approved, immediately wake the new agent to start onboarding.", - trigger: "hire_approved", - action: "trigger_heartbeat", - actionConfig: {}, - priority: 90, - }, - { - name: "Auto-run assigned tasks", - description: "When a task transitions to 'todo' status, automatically wake the assigned agent to start working on it.", - trigger: "task_status_changed", - conditions: { status: "todo" }, - action: "run_task", - actionConfig: {}, - priority: 65, - }, - { - name: "Notify company on sprint start", - description: "When a sprint starts, notify the entire company.", - trigger: "sprint_started", - action: "send_message", - actionConfig: { channel: "company", subject: "Sprint started", body: "A new sprint has begun. Check your assigned tasks and start execution.", priority: "normal" }, - priority: 50, - }, - { - name: "Schedule retrospective on sprint end", - description: "When a sprint ends, schedule a retrospective meeting.", - trigger: "sprint_ended", - action: "schedule_meeting", - actionConfig: { meetingType: "retrospective", title: "Sprint Retrospective", durationMinutes: 45 }, - priority: 55, - }, - { - name: "Auto-assign work to idle agents", - description: "When an agent has been idle for 10+ minutes, automatically assign available unassigned tasks from the backlog.", - trigger: "agent_idle", - action: "assign_task", - priority: 60, - }, - { - name: "Wake idle agents to check for work", - description: "When an agent has no tasks and is idle, wake them so they can check for available work and coordinate with their team.", - trigger: "agent_idle", - action: "trigger_heartbeat", - priority: 45, - }, - { - name: "Wake manager when task moves to review", - description: "When a task status changes to in_review, wake the assignee's manager to review the work.", - trigger: "task_status_changed", - conditions: { status: "in_review" }, - action: "escalate_to_manager", - actionConfig: { body: "A task from your report has been submitted for review. Please review the work and either approve (mark as done) or send back with feedback." }, - priority: 82, - }, - { - name: "Wake assigned agent on task feedback", - description: "When a reviewed task is sent back to in_progress with feedback, wake the assigned agent to address the feedback.", - trigger: "task_status_changed", - conditions: { status: "in_progress", previousStatus: "in_review" }, - action: "trigger_heartbeat", - actionConfig: {}, - priority: 78, - }, - { - name: "Wake approvers on new approval", - description: "When a new approval request is created and not auto-approved, escalate to the requesting agent's manager for review.", - trigger: "approval_created", - action: "escalate_to_manager", - actionConfig: { body: "A new approval request needs your review. Please check the Approvals section." }, - priority: 88, - }, -]; - -export function seedDefaultAutomationRules( - companyId: string, - deps: { - listAutomationRuleNames: (companyId: string) => Set; - saveAutomationRule: (input: { - companyId: string; - name: string; - description?: string; - trigger: string; - conditionsJson?: string; - action: string; - actionConfigJson?: string; - priority?: number; - status?: string; - }) => string; - }, -) { - const existingRuleNames = deps.listAutomationRuleNames(companyId); - for (const rule of DEFAULT_AUTOMATION_RULES) { - if (existingRuleNames.has(rule.name)) { - continue; - } - deps.saveAutomationRule({ - companyId, - name: rule.name, - description: rule.description, - trigger: rule.trigger, - conditionsJson: JSON.stringify(rule.conditions ?? {}), - action: rule.action, - actionConfigJson: JSON.stringify(rule.actionConfig ?? {}), - priority: rule.priority ?? 50, - status: "active", - }); - } -} diff --git a/src/main/desktop-shell-menu.ts b/src/main/desktop-shell-menu.ts deleted file mode 100644 index 85f8aa64..00000000 --- a/src/main/desktop-shell-menu.ts +++ /dev/null @@ -1,272 +0,0 @@ -import { dirname, join } from "node:path"; -import { - app, - BrowserWindow, - dialog, - Menu, - nativeImage, - shell, - Tray, -} from "electron"; -import type { IpcMainInvokeEvent } from "electron"; -import { IPC_CHANNELS } from "@shared/contracts"; -import type { DesktopResult } from "@shared/contracts"; -import { ok } from "./ipc-core-common"; - -export interface DesktopShellMenuDependencies { - iconPath: string; - isDev: boolean; - onCheckForUpdates: () => Promise; - onBackupProfile: () => Promise; - onShortcut: (action: "toggle-command-palette" | "refresh") => void; - getMainWindow: () => BrowserWindow | null; - ensureWindow: () => Promise; - requestQuitWithConfirmation: () => Promise; - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; -} - -export function createDesktopShellMenu(deps: DesktopShellMenuDependencies) { - const { - iconPath, - isDev, - onCheckForUpdates, - onBackupProfile, - onShortcut, - getMainWindow, - ensureWindow, - requestQuitWithConfirmation, - registerHandle, - } = deps; - - let appTray: Tray | null = null; - - function buildMenu() { - const macAppMenu: Electron.MenuItemConstructorOptions = { - label: app.name, - submenu: [ - { role: "about" }, - { type: "separator" }, - { role: "services" }, - { type: "separator" }, - { role: "hide" }, - { role: "hideOthers" }, - { role: "unhide" }, - { type: "separator" }, - { - label: `Quit ${app.name}`, - accelerator: "CmdOrCtrl+Q", - click: () => void requestQuitWithConfirmation(), - }, - ], - }; - const template: Electron.MenuItemConstructorOptions[] = [ - ...(process.platform === "darwin" ? [macAppMenu] : []), - { - label: "File", - submenu: [ - { - label: "Open Workspace Folder", - accelerator: "CmdOrCtrl+O", - click: async () => { - const result = await dialog.showOpenDialog({ - properties: ["openDirectory"], - }); - const targetPath = result.filePaths[0]; - if (result.canceled || !targetPath) return; - shell.openPath(targetPath); - }, - }, - { type: "separator" }, - { - label: "Backup Profile", - accelerator: "CmdOrCtrl+Shift+B", - click: async () => { - await onBackupProfile(); - }, - }, - ...(process.platform === "darwin" ? [] : [ - { type: "separator" as const }, - { - label: "Quit", - accelerator: "Alt+F4", - click: () => void requestQuitWithConfirmation(), - }, - ]), - ], - }, - { - label: "Edit", - submenu: [ - { role: "undo" }, - { role: "redo" }, - { type: "separator" }, - { role: "cut" }, - { role: "copy" }, - { role: "paste" }, - { role: "selectAll" }, - ], - }, - { - label: "View", - submenu: [ - { - label: "Command Palette", - accelerator: "CmdOrCtrl+K", - click: () => onShortcut("toggle-command-palette"), - }, - { - label: "Refresh Data", - accelerator: "CmdOrCtrl+R", - click: () => onShortcut("refresh"), - }, - { type: "separator" }, - { - role: "toggleDevTools", - // Hidden in packaged builds unless opted in via env var so power - // users can still inspect rendered state without a dev build. - visible: isDev || process.env.AGENTCOMPANY_ENABLE_DEVTOOLS === "true", - }, - ], - }, - { - label: "Run", - submenu: [ - { - label: "Check For Updates", - click: async () => { - await onCheckForUpdates(); - }, - }, - ], - }, - ]; - const menu = Menu.buildFromTemplate(template); - const mainWindow = getMainWindow(); - 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() { - if (appTray) { - return; - } - - const assetsDir = dirname(iconPath); - let trayIcon: Electron.NativeImage; - - if (process.platform === "darwin") { - // macOS menu bar: use Template images (monochrome black + alpha). - // Electron auto-detects the @2x variant when the base name includes "Template". - const templatePath = join(assetsDir, "tray-iconTemplate.png"); - trayIcon = nativeImage.createFromPath(templatePath); - if (!trayIcon.isEmpty()) { - trayIcon.setTemplateImage(true); - } - } else { - // Windows / Linux: use the color tray icon - const trayPath = join(assetsDir, "tray-icon.png"); - trayIcon = nativeImage.createFromPath(trayPath); - } - - // Fallback: resize the full app icon - if (trayIcon.isEmpty()) { - const fallback = nativeImage.createFromPath(iconPath); - if (!fallback.isEmpty()) { - trayIcon = fallback.resize({ width: 32, height: 32 }); - if (process.platform === "darwin") { - trayIcon.setTemplateImage(true); - } - } - } - - appTray = new Tray(trayIcon.isEmpty() ? nativeImage.createEmpty() : trayIcon); - appTray.setToolTip("AgentCompany"); - appTray.setContextMenu( - Menu.buildFromTemplate([ - { - label: "Show AgentCompany", - click: () => { - void ensureWindow().then((win) => { - if (win) { - win.show(); - win.focus(); - } - }); - }, - }, - { - label: "Hide AgentCompany", - click: () => { - const mainWindow = getMainWindow(); - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.hide(); - } - }, - }, - { type: "separator" }, - { - label: "Quit", - click: () => void requestQuitWithConfirmation(), - }, - ]), - ); - appTray.on("click", () => { - void ensureWindow().then((win) => { - if (!win) return; - if (win.isVisible()) { - win.hide(); - return; - } - win.show(); - win.focus(); - }); - }); - } - - function registerWindowControlIpc() { - // Window control IPC for custom title bar (Windows/Linux frameless windows). - // Routed through registerHandle so the trusted-sender check blocks - // embedded webContents from closing/minimizing the app. - registerHandle(IPC_CHANNELS.windowMinimize, () => { - getMainWindow()?.minimize(); - return ok(null); - }); - registerHandle(IPC_CHANNELS.windowMaximize, () => { - const mainWindow = getMainWindow(); - if (mainWindow?.isMaximized()) { - mainWindow.unmaximize(); - } else { - mainWindow?.maximize(); - } - return ok(null); - }); - registerHandle(IPC_CHANNELS.windowClose, () => { - getMainWindow()?.close(); - return ok(null); - }); - registerHandle(IPC_CHANNELS.windowIsMaximized, () => { - return ok(getMainWindow()?.isMaximized() ?? false); - }); - } - - function destroy() { - appTray?.destroy(); - appTray = null; - } - - return { - buildMenu, - createTray, - registerWindowControlIpc, - destroy, - }; -} diff --git a/src/main/desktop-shell-service.ts b/src/main/desktop-shell-service.ts deleted file mode 100644 index d492a62b..00000000 --- a/src/main/desktop-shell-service.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createDesktopShellWindow, type DesktopShellWindowDependencies } from "./desktop-shell-window"; -import { createDesktopShellMenu, type DesktopShellMenuDependencies } from "./desktop-shell-menu"; - -export type DesktopShellServiceDependencies = DesktopShellWindowDependencies & { - registerHandle: DesktopShellMenuDependencies["registerHandle"]; -}; - -export function createDesktopShellService(deps: DesktopShellServiceDependencies) { - const window = createDesktopShellWindow(deps); - const menu = createDesktopShellMenu({ - iconPath: deps.iconPath, - isDev: deps.isDev, - onCheckForUpdates: deps.onCheckForUpdates, - onBackupProfile: deps.onBackupProfile, - onShortcut: deps.onShortcut, - getMainWindow: window.getMainWindow, - ensureWindow: window.ensureWindow, - requestQuitWithConfirmation: window.requestQuitWithConfirmation, - registerHandle: deps.registerHandle, - }); - - function initialize() { - window.installSecurityGuards(); - window.registerProtocol(); - menu.buildMenu(); - menu.createTray(); - menu.registerWindowControlIpc(); - } - - function destroy() { - menu.destroy(); - } - - return { - initialize, - installSecurityGuards: window.installSecurityGuards, - registerProtocol: window.registerProtocol, - buildMenu: menu.buildMenu, - createTray: menu.createTray, - createWindow: window.createWindow, - ensureWindow: window.ensureWindow, - getMainWindow: window.getMainWindow, - destroy, - }; -} diff --git a/src/main/desktop-shell-window.ts b/src/main/desktop-shell-window.ts deleted file mode 100644 index 666720be..00000000 --- a/src/main/desktop-shell-window.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { existsSync } from "node:fs"; -import { extname } from "node:path"; -import { pathToFileURL } from "node:url"; -import { resolve, sep } from "node:path"; -import { - app, - BrowserWindow, - dialog, - nativeImage, - nativeTheme, - net, - protocol, - session, - shell, -} from "electron"; -import log from "electron-log/main.js"; -import { attachWindowStatePersistence, loadWindowState } from "./window-state"; -import type { NotificationOptions } from "./notification-service"; -import { classifyExternalUrl } from "./external-url-policy"; - -export interface DesktopShellWindowDependencies { - preloadPath: string; - rendererDist: string; - iconPath: string; - isDev: boolean; - devServerUrl?: string; - windowStatePath: string; - shouldQuit: () => boolean; - onRequestQuit: () => void; - onCheckForUpdates: () => Promise; - onBackupProfile: () => Promise; - onShortcut: (action: "toggle-command-palette" | "refresh") => void; - notify: (options: NotificationOptions) => void; - getActiveRunCount: () => number; -} - -function isSocialBrowserSession(contents: Electron.WebContents) { - return contents.session !== session.defaultSession; -} - -function isWithinDirectory(rootPath: string, targetPath: string) { - const normalizedRoot = resolve(rootPath); - const normalizedTarget = resolve(targetPath); - return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(`${normalizedRoot}${sep}`); -} - -export function createDesktopShellWindow(deps: DesktopShellWindowDependencies) { - const { - preloadPath, - rendererDist, - iconPath, - isDev, - devServerUrl, - windowStatePath, - shouldQuit, - onRequestQuit, - notify, - getActiveRunCount, - } = deps; - - let mainWindow: BrowserWindow | null = null; - let backgroundCloseNoticeShown = false; - let windowCreationPromise: Promise | null = null; - let quitDialogShowing = false; - - /** - * Quit confirmation gate — shown when agents are actively running. - * Gives the user three choices: - * 0 = "Stop All & Quit" → terminate all agents and exit - * 1 = "Minimize to Background" → hide window, agents keep running - * 2 = "Cancel" → do nothing - * - * When no agents are active the app quits immediately without a dialog. - */ - async function requestQuitWithConfirmation() { - if (quitDialogShowing) return; - - let activeRunCount = 0; - try { - activeRunCount = getActiveRunCount(); - } catch (err) { - log.warn(`[desktop-shell-window] getActiveRunCount failed; quitting as fail-safe:`, err instanceof Error ? err.message : String(err)); - onRequestQuit(); - app.quit(); - return; - } - - if (activeRunCount === 0) { - onRequestQuit(); - app.quit(); - return; - } - - quitDialogShowing = true; - try { - const message = activeRunCount === 1 - ? "1 agent run is currently active." - : `${activeRunCount} agent runs are currently active.`; - - const options: Electron.MessageBoxOptions = { - type: "question", - buttons: ["Stop All & Quit", "Minimize to Background", "Cancel"], - defaultId: 2, - cancelId: 2, - title: "AgentCompany", - message, - detail: "Quitting will stop all running agents and their tasks. You can also minimize to keep agents running in the background.", - }; - - const parentWindow = mainWindow && !mainWindow.isDestroyed() ? mainWindow : null; - const result = parentWindow - ? await dialog.showMessageBox(parentWindow, options) - : await dialog.showMessageBox(options); - - if (result.response === 0) { - // Stop All & Quit - onRequestQuit(); - app.quit(); - } else if (result.response === 1) { - // Minimize to Background - if (parentWindow) { - parentWindow.hide(); - } - if (!backgroundCloseNoticeShown) { - backgroundCloseNoticeShown = true; - notify({ - title: "Running in Background", - body: "AgentCompany is still running in the system tray", - urgency: "informational", - navigation: { section: "overview" }, - }); - } - } - // Cancel: do nothing - } catch (err) { - log.warn(`[desktop-shell-window] Quit confirmation dialog failed; quitting as fail-safe:`, err instanceof Error ? err.message : String(err)); - onRequestQuit(); - app.quit(); - } finally { - quitDialogShowing = false; - } - } - - function getMainWindow() { - return mainWindow; - } - - function installSecurityGuards() { - session.defaultSession.setPermissionCheckHandler(() => false); - session.defaultSession.setPermissionRequestHandler((_webContents, _permission, callback) => { - callback(false); - }); - app.on("web-contents-created", (_event, contents) => { - contents.setWindowOpenHandler(({ url }) => { - const decision = classifyExternalUrl(url); - if (decision.kind === "trusted") { - void shell.openExternal(decision.url); - return { action: "deny" }; - } - if (decision.kind === "confirm") { - // Dialog is dispatched asynchronously so the main-process event loop - // is not blocked while the user decides. setWindowOpenHandler must - // return synchronously, so the window is always denied here; if the - // user approves, shell.openExternal runs in the async continuation. - void (async () => { - const parentWindow = mainWindow && !mainWindow.isDestroyed() ? mainWindow : null; - const options: Electron.MessageBoxOptions = { - type: "question", - buttons: ["Open Link", "Cancel"], - defaultId: 1, - cancelId: 1, - title: "Open External Link?", - message: "AgentCompany blocked an untrusted external link.", - detail: `${decision.url}\n\nOnly trusted product and documentation domains open automatically. Review this destination before continuing.`, - }; - const result = parentWindow - ? await dialog.showMessageBox(parentWindow, options) - : await dialog.showMessageBox(options); - if (result.response === 0) { - void shell.openExternal(decision.url); - } - })(); - } - return { action: "deny" }; - }); - contents.on("will-attach-webview", (event) => { - event.preventDefault(); - }); - contents.on("will-navigate", (event) => { - if (isSocialBrowserSession(contents)) return; - event.preventDefault(); - }); - }); - } - - function registerProtocol() { - const textMimeTypes: Record = { - ".html": "text/html; charset=utf-8", - ".js": "text/javascript; charset=utf-8", - ".mjs": "text/javascript; charset=utf-8", - ".css": "text/css; charset=utf-8", - ".json": "application/json; charset=utf-8", - ".svg": "image/svg+xml; charset=utf-8", - }; - protocol.handle("app", async (request) => { - const url = new URL(request.url); - const relativePath = decodeURIComponent(url.pathname === "/" ? "index.html" : url.pathname.replace(/^\/+/, "")); - const targetPath = resolve(rendererDist, relativePath); - if (!isWithinDirectory(rendererDist, targetPath) || !existsSync(targetPath)) { - return new Response("Not found", { status: 404 }); - } - const response = await net.fetch(pathToFileURL(targetPath).toString()); - const mime = textMimeTypes[extname(targetPath).toLowerCase()]; - if (mime) { - const headers = new Headers(response.headers); - headers.set("Content-Type", mime); - return new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers, - }); - } - return response; - }); - } - - async function createWindow() { - const windowIcon = nativeImage.createFromPath(iconPath); - const savedWindowState = loadWindowState(windowStatePath); - const isWindows = process.platform === "win32"; - const isLinux = process.platform === "linux"; - const webPreferences: Electron.WebPreferences = { - preload: preloadPath, - contextIsolation: true, - nodeIntegration: false, - sandbox: true, - webviewTag: false, - devTools: isDev, - webSecurity: true, - allowRunningInsecureContent: false, - }; - mainWindow = new BrowserWindow({ - title: "AgentCompany", - icon: windowIcon.isEmpty() ? undefined : windowIcon, - width: savedWindowState.bounds.width, - height: savedWindowState.bounds.height, - x: savedWindowState.bounds.x, - y: savedWindowState.bounds.y, - minWidth: 1180, - minHeight: 760, - backgroundColor: nativeTheme.shouldUseDarkColors ? "#141413" : "#F5F4ED", - frame: process.platform === "darwin", - titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "default", - ...(isWindows || isLinux ? { titleBarOverlay: false } : {}), - webPreferences, - }); - - if (isDev && devServerUrl) { - await mainWindow.loadURL(devServerUrl); - } else { - await mainWindow.loadURL("app://-/index.html"); - } - attachWindowStatePersistence(mainWindow, windowStatePath); - if (savedWindowState.maximized) { - mainWindow.maximize(); - } - mainWindow.on("close", (event) => { - if (process.platform === "darwin" || shouldQuit()) { - return; - } - event.preventDefault(); - mainWindow?.hide(); - if (!backgroundCloseNoticeShown) { - backgroundCloseNoticeShown = true; - notify({ - title: "Running in Background", - body: "AgentCompany is still running in the system tray", - urgency: "informational", - navigation: { section: "overview" }, - }); - } - }); - mainWindow.on("closed", () => { - mainWindow = null; - }); - } - - async function ensureWindow() { - if (!mainWindow || mainWindow.isDestroyed()) { - if (!windowCreationPromise) { - windowCreationPromise = createWindow() - .then(() => mainWindow) - .finally(() => { - windowCreationPromise = null; - }); - } - return windowCreationPromise; - } - return mainWindow; - } - - return { - getMainWindow, - installSecurityGuards, - registerProtocol, - createWindow, - ensureWindow, - requestQuitWithConfirmation, - }; -} diff --git a/src/main/document-lifecycle-handlers.ts b/src/main/document-lifecycle-handlers.ts deleted file mode 100644 index e9e60607..00000000 --- a/src/main/document-lifecycle-handlers.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Registers the concrete lifecycle hook handlers against the processor. - * Handler side is kept thin — read the payload, call into the service - * graph, translate throws into a `retryable` outcome so the processor's - * attempt cap decides when a transient failure becomes permanent. - */ - -import type { AutomationEventContext } from "./automation/types"; -import type { - DocumentLifecycleProcessor, - LifecycleHookContext, - LifecycleHookOutcome, -} from "./document-lifecycle-processor"; - -export interface LifecycleHandlerDeps { - dispatchAutomation: (trigger: string, ctx: AutomationEventContext) => void; - wakeAgentIfPossible: ( - agentId: string | null | undefined, - companyId: string, - trigger: string, - ) => string | null; -} - -export function registerLifecycleHandlers( - processor: DocumentLifecycleProcessor, - deps: LifecycleHandlerDeps, -): void { - processor.register("automation_dispatch", automationDispatchHandler(deps)); - processor.register("reviewer_wake", reviewerWakeHandler(deps)); -} - -function automationDispatchHandler(deps: LifecycleHandlerDeps) { - return (payload: Record, context: LifecycleHookContext): LifecycleHookOutcome => { - const trigger = typeof payload.trigger === "string" ? payload.trigger : "document_created"; - const automationContext: AutomationEventContext = { - companyId: context.companyId, - agentId: stringOrUndefined(payload.agentId), - projectId: stringOrUndefined(payload.projectId), - }; - try { - deps.dispatchAutomation(trigger, automationContext); - return { kind: "succeeded" }; - } catch (error) { - return { kind: "retryable", reason: describeError(error) }; - } - }; -} - -function reviewerWakeHandler(deps: LifecycleHandlerDeps) { - return (payload: Record, context: LifecycleHookContext): LifecycleHookOutcome => { - const reviewerAgentId = stringOrNull(payload.reviewerAgentId); - if (!reviewerAgentId) { - return { kind: "failed", reason: "payload missing reviewerAgentId" }; - } - try { - deps.wakeAgentIfPossible(reviewerAgentId, context.companyId, "assignment"); - return { kind: "succeeded" }; - } catch (error) { - return { kind: "retryable", reason: describeError(error) }; - } - }; -} - -function stringOrUndefined(value: unknown): string | undefined { - return typeof value === "string" && value.length > 0 ? value : undefined; -} - -function stringOrNull(value: unknown): string | null { - return typeof value === "string" && value.length > 0 ? value : null; -} - -function describeError(error: unknown): string { - if (error instanceof Error) return error.message; - return String(error); -} diff --git a/src/main/document-lifecycle-processor.ts b/src/main/document-lifecycle-processor.ts deleted file mode 100644 index b48e1f56..00000000 --- a/src/main/document-lifecycle-processor.ts +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Durable processor for `document_lifecycle_events`. - * - * `createDocumentWithLifecycle` enqueues hook rows inside the same - * transaction as `saveDocument`, so the ledger commit is the new - * durability boundary for cross-process side effects. This processor - * is what moves rows from `pending` to `succeeded` / `failed`: - * - * - `drainForDocument(documentId)` runs synchronously right after - * the save commits so the happy-path latency is unchanged. - * - `processBatch(limit)` runs on a periodic sweep so a crash - * between commit and the immediate drain is self-healing. - * - `reclaimStale()` rescues rows stuck in `running` past the - * configured cutoff — typically because the process died - * mid-handler — and puts them back on the pending queue so the - * next claim picks them up. - * - * Claim semantics are atomic: `claimPendingBatch` flips rows to - * `running` and increments `attempts` in a single UPDATE so two - * processors cannot race onto the same id. `maxAttempts` caps the - * retry budget; rows that exhaust it stay `pending` with their - * attempt count at the cap and surface to the operator through - * `listExhausted`. - */ - -import type { AppDatabase } from "./database"; -import { DOCUMENT_LIFECYCLE_PROCESSOR_DEFAULTS } from "./constants"; -import type { DocumentLifecycleEventRow } from "./database/document-lifecycle-events"; - -export interface LifecycleHookContext { - companyId: string; - documentId: string; - eventId: string; -} - -export type LifecycleHookOutcome = - | { kind: "succeeded" } - | { kind: "retryable"; reason: string } - | { kind: "failed"; reason: string }; - -export type LifecycleHookHandler = ( - payload: Record, - context: LifecycleHookContext, -) => LifecycleHookOutcome; - -export interface LifecycleProcessorOptions { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - /** Maximum `attempts` value allowed before a row becomes dead-letter. */ - maxAttempts: number; - /** Cutoff for reclaiming rows stuck in `running`. */ - staleRunningMs: number; - /** Batch size for a single sweep. */ - batchSize: number; - /** Interval for the background sweep. 0 disables periodic work. */ - sweepIntervalMs: number; -} - -export function makeLifecycleProcessorOptions( - overrides: Partial & Pick, -): LifecycleProcessorOptions { - return { - ...DOCUMENT_LIFECYCLE_PROCESSOR_DEFAULTS, - ...overrides, - }; -} - -export class DocumentLifecycleProcessor { - private readonly handlers = new Map(); - private sweepTimer: ReturnType | null = null; - private stopped = false; - - constructor(private readonly options: LifecycleProcessorOptions) {} - - register(hookType: string, handler: LifecycleHookHandler): void { - this.handlers.set(hookType, handler); - } - - /** Immediate drain scoped to one document, used right after commit. */ - drainForDocument(documentId: string): void { - const batch = this.options.db.projection.documentLifecycleEvents.claimPendingBatch({ - limit: this.options.batchSize, - maxAttempts: this.options.maxAttempts, - documentId, - }); - for (const row of batch) this.dispatch(row); - } - - /** Periodic sweep: rescues stragglers across all documents. */ - processBatch(): number { - const batch = this.options.db.projection.documentLifecycleEvents.claimPendingBatch({ - limit: this.options.batchSize, - maxAttempts: this.options.maxAttempts, - }); - for (const row of batch) this.dispatch(row); - return batch.length; - } - - /** Move rows stuck in `running` back to `pending`. */ - reclaimStale(): number { - const cutoff = new Date(Date.now() - this.options.staleRunningMs).toISOString(); - const reclaimed = this.options.db.projection.documentLifecycleEvents.reclaimStaleRunning(cutoff); - if (reclaimed > 0) { - this.options.logger.info( - `[document-lifecycle] reclaimed ${reclaimed} stale running row(s) past ${this.options.staleRunningMs}ms cutoff`, - ); - } - return reclaimed; - } - - /** - * Start the periodic sweeper. Idempotent: calling twice is a no-op. - * `stop()` tears it down so the process can exit cleanly. - */ - start(): void { - if (this.sweepTimer || this.stopped) return; - if (this.options.sweepIntervalMs <= 0) return; - // Run a reclaim + sweep on startup so a crashed process's leftover - // `running` rows are rescued before the first new claim arrives. - this.tick(); - this.sweepTimer = setInterval(() => this.tick(), this.options.sweepIntervalMs); - if (typeof this.sweepTimer.unref === "function") this.sweepTimer.unref(); - } - - stop(): void { - this.stopped = true; - if (this.sweepTimer) { - clearInterval(this.sweepTimer); - this.sweepTimer = null; - } - } - - private tick(): void { - try { - this.reclaimStale(); - } catch (error) { - this.options.logger.warn( - `[document-lifecycle] reclaimStale failed: ${describeError(error)}`, - ); - } - try { - this.processBatch(); - } catch (error) { - this.options.logger.warn( - `[document-lifecycle] processBatch failed: ${describeError(error)}`, - ); - } - } - - private dispatch(row: DocumentLifecycleEventRow): void { - const handler = this.handlers.get(row.hookType); - if (!handler) { - const reason = `No handler registered for hook type "${row.hookType}"`; - this.options.db.projection.documentLifecycleEvents.markFailed(row.id, reason); - this.options.logger.error(`[document-lifecycle] ${reason} (event ${row.id})`); - return; - } - - let payload: Record; - try { - payload = row.payloadJson ? (JSON.parse(row.payloadJson) as Record) : {}; - } catch (error) { - const reason = `payload_json parse failed: ${describeError(error)}`; - this.options.db.projection.documentLifecycleEvents.markFailed(row.id, reason); - this.options.logger.error(`[document-lifecycle] ${reason} (event ${row.id})`); - return; - } - - let outcome: LifecycleHookOutcome; - try { - outcome = handler(payload, { - companyId: row.companyId, - documentId: row.documentId, - eventId: row.id, - }); - } catch (error) { - const message = describeError(error); - this.options.logger.error( - `[document-lifecycle] handler "${row.hookType}" threw for event ${row.id}: ${message}`, - ); - this.recordOutcome(row, { kind: "retryable", reason: message }); - return; - } - this.recordOutcome(row, outcome); - } - - private recordOutcome(row: DocumentLifecycleEventRow, outcome: LifecycleHookOutcome): void { - try { - if (outcome.kind === "succeeded") { - this.options.db.projection.documentLifecycleEvents.markSucceeded(row.id); - return; - } - if (outcome.kind === "failed") { - this.options.db.projection.documentLifecycleEvents.markFailed(row.id, outcome.reason); - return; - } - if (row.attempts >= this.options.maxAttempts) { - this.options.db.projection.documentLifecycleEvents.markFailed( - row.id, - `Retry budget exhausted (${row.attempts}/${this.options.maxAttempts}): ${outcome.reason}`, - ); - return; - } - this.options.db.projection.documentLifecycleEvents.markRetryable(row.id, outcome.reason); - } catch (error) { - this.options.logger.warn( - `[document-lifecycle] recordOutcome failed for ${row.id}: ${describeError(error)}`, - ); - } - } -} - -function describeError(error: unknown): string { - if (error instanceof Error) return error.message; - return String(error); -} diff --git a/src/main/document-lifecycle.ts b/src/main/document-lifecycle.ts deleted file mode 100644 index c60b1639..00000000 --- a/src/main/document-lifecycle.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Unified document-creation lifecycle. - * - * Two invariants: - * - * 1. DB-writing hooks (thread events, checkpoint approval, - * deliverable-review approval) commit atomically with the - * document row. A failure in any of them rolls back the save so - * the operator never sees a live document with a missing thread - * or a skipped approval. - * - * 2. Cross-process side effects (automation dispatch, reviewer wake) - * are durable via the `document_lifecycle_events` ledger. Every - * hook attempt lands a row and the processor stamps its outcome; - * a crash between "document saved" and "reviewer woken" is - * observable as a `failed` ledger row instead of a silent gap. - * - * The HTTP API route and the desktop IPC handler both call - * `createDocumentWithLifecycle`, so both surfaces end up in the same - * state after a save — no more divergence between the two entry points. - */ - -import log from "electron-log/main.js"; -import { IMPORTANT_DOC_TYPE_SET } from "@shared/document-categories"; -import type { AppDatabase } from "./database"; -import type { ThreadIntegrationService } from "./thread-integration"; -import type { createCheckpointEngine } from "./checkpoint-engine"; -import type { DocumentLifecycleProcessor } from "./document-lifecycle-processor"; -import { classifyUnknownError } from "./errors/index.js"; - -export type CheckpointEngineLike = Pick< - ReturnType, - "onDocumentDrafted" ->; - -export interface DocumentLifecycleDeps { - db: AppDatabase; - threadIntegration: ThreadIntegrationService; - checkpointEngine: CheckpointEngineLike; - /** - * Drains the ledger rows this save enqueued. The processor reads from - * `document_lifecycle_events` (not from an in-memory closure) so a - * crash between commit and dispatch is self-healing — the next sweep - * picks up anything left as `pending`. Callers still see the immediate - * happy-path outcome because `drainForDocument` is synchronous. - */ - lifecycleProcessor: Pick; - publishDomainChanged: () => void; - logger: { - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export interface DocumentLifecycleInput { - id?: string | null; - companyId: string; - type: string; - title: string; - content: string; - authorAgentId: string | null; - reviewerAgentId: string | null; - projectId: string | null; - goalId: string | null; - parentDocId: string | null; - version: number; - status: string; - tagsJson: string; - sourceRunId: string | null; -} - -export interface DocumentLifecycleOutcome { - id: string; - isNew: boolean; - taskId: string | null; - deliverableReviewApprovalId: string | null; -} - -export type SideEffectHook = "automation_dispatch" | "reviewer_wake"; - -export function createDocumentWithLifecycle( - deps: DocumentLifecycleDeps, - input: DocumentLifecycleInput, -): DocumentLifecycleOutcome { - const outcome = deps.db.withTransaction(() => { - const isNew = !input.id; - const id = deps.db.core.documents.saveDocument(input); - const taskId = deriveTaskIdFromRun(deps.db, input.sourceRunId, input.companyId, deps.logger); - - let deliverableReviewApprovalId: string | null = null; - if (isNew) { - // DB-writing hooks run inside the transaction. Any throw rolls - // back `saveDocument` along with the thread event / approvals. - deps.threadIntegration.onDocumentCreated( - input.companyId, - input.authorAgentId, - taskId, - input.title, - ); - deps.checkpointEngine.onDocumentDrafted( - input.companyId, - id, - input.title, - input.type, - input.authorAgentId, - taskId, - ); - if (IMPORTANT_DOC_TYPE_SET.has(input.type)) { - deliverableReviewApprovalId = maybeRaiseDeliverableReviewApproval(deps, input, id, taskId); - } - - // Side effects (cross-process / advisory) land in the ledger as - // `pending` rows. The processor drains them post-commit — not a - // memoised closure — so a crash between this commit and the first - // handler attempt is self-healing: the periodic sweeper picks the - // row up on its next tick. - deps.db.projection.documentLifecycleEvents.enqueue({ - companyId: input.companyId, - documentId: id, - hookType: "automation_dispatch", - payloadJson: JSON.stringify({ - trigger: "document_created", - agentId: input.authorAgentId, - projectId: input.projectId, - }), - }); - - if (input.reviewerAgentId && input.reviewerAgentId !== input.authorAgentId) { - deps.db.projection.documentLifecycleEvents.enqueue({ - companyId: input.companyId, - documentId: id, - hookType: "reviewer_wake", - payloadJson: JSON.stringify({ reviewerAgentId: input.reviewerAgentId }), - }); - } - } - - return { id, isNew, taskId, deliverableReviewApprovalId }; - }); - - if (outcome.isNew) { - // Immediate synchronous drain so the happy path behaves identically - // to the pre-processor layout. A failure inside the processor is - // recorded on the ledger row — the ledger, not an in-memory list, - // is what the periodic sweeper retries against. - try { - deps.lifecycleProcessor.drainForDocument(outcome.id); - } catch (error) { - deps.logger.warn( - `[document-lifecycle] drainForDocument(${outcome.id}) threw: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - deps.publishDomainChanged(); - return outcome; -} - -function deriveTaskIdFromRun( - db: AppDatabase, - runId: string | null, - companyId: string, - logger: DocumentLifecycleDeps["logger"], -): string | null { - if (!runId) return null; - try { - const run = db.core.runs.getRun(runId); - if (run.companyId !== companyId) return null; - return run.taskId ?? null; - } catch (error) { - const classified = classifyUnknownError(error, { - kind: "recoverable", - code: "document_lifecycle.get_run.failed", - message: `getRun(${runId}) failed while deriving taskId`, - context: { runId, companyId }, - }); - logger.warn( - `[${classified.code}] ${classified.message}: ${error instanceof Error ? error.message : String(error)}`, - ); - return null; - } -} - -function maybeRaiseDeliverableReviewApproval( - deps: DocumentLifecycleDeps, - input: DocumentLifecycleInput, - documentId: string, - taskId: string | null, -): string | null { - const companySettings = deps.db.core.company.getCompanyApprovalSettings(input.companyId); - if (!companySettings?.reviewDeliverables) return null; - if (deps.db.core.company.getCompanyExecutionMode(input.companyId) === "ai_cofounder") return null; - if (deps.db.core.tasks.hasPendingDeliverableReviews(input.companyId)) return null; - - const approvalId = deps.db.core.approvals.requestApproval({ - companyId: input.companyId, - relatedTaskId: taskId, - requestedByAgentId: input.authorAgentId ?? "", - type: "deliverable_review", - payloadSummary: `Review deliverable: ${input.title}`.slice(0, 280), - impactSummary: `New ${input.type.replaceAll("_", " ")} created. Awaiting your review before workflow continues.`.slice(0, 400), - payloadJson: JSON.stringify({ - documentIds: [documentId], - documents: [{ id: documentId, type: input.type, title: input.title }], - }), - }); - - if (input.authorAgentId) { - try { - const agent = deps.db.core.entity.getAgent(input.authorAgentId); - if (agent.heartbeatEnabled) { - deps.db.core.agents.setHeartbeat(input.authorAgentId, false, agent.heartbeatIntervalSec || 120); - } - } catch (error) { - deps.logger.warn( - `[document-lifecycle] heartbeat pause failed for agent ${input.authorAgentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - return approvalId; -} - -export const defaultLogger: DocumentLifecycleDeps["logger"] = log; diff --git a/src/main/errors/handlers.ts b/src/main/errors/handlers.ts deleted file mode 100644 index 763deefb..00000000 --- a/src/main/errors/handlers.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Handler helpers that sit on top of the AppError taxonomy (C6.1 part 1/2). - * - * These are thin conveniences, not a framework. Every helper here reduces - * two lines of boilerplate at the call site; it does NOT swap in default - * values or change observable behaviour. - */ - -import { classifyUnknownError, type AppError, type AppErrorMeta } from "./taxonomy.js"; - -export interface Logger { - error?: (...args: unknown[]) => void; - warn?: (...args: unknown[]) => void; -} - -type FatalErrorRoute = (error: AppError) => never; - -const defaultFatalErrorRoute: FatalErrorRoute = (error) => { - if (process.env.VITEST === "true" || process.env.NODE_ENV === "test") { - throw error; - } - process.stderr.write(`[fatal:${error.code}] ${error.message}\n`); - process.abort(); -}; - -let fatalErrorRoute: FatalErrorRoute = defaultFatalErrorRoute; - -export function setFatalErrorRouteForTesting(route: FatalErrorRoute | null): void { - fatalErrorRoute = route ?? defaultFatalErrorRoute; -} - -/** - * Classify an unknown thrown value and emit a single structured log line. - * Returns the `AppError` so the caller can still branch on `err.kind` - * (e.g. throw for `fatal`, return default for `recoverable`). - * - * No fallback data is invented: this helper only formats a log line; the - * caller is still responsible for what to do next. - */ -export function logAppError( - logger: Logger, - raw: unknown, - fallback: AppErrorMeta, - level: "error" | "warn" = "error", -): AppError { - const err = classifyUnknownError(raw, fallback); - const line = `[${err.code}] ${err.message}`; - const detail = err.context ?? {}; - const causeDetail = - err.appCause instanceof Error - ? err.appCause.message - : err.appCause !== undefined - ? String(err.appCause) - : undefined; - const parts: unknown[] = [line]; - if (Object.keys(detail).length > 0) parts.push(detail); - if (causeDetail) parts.push(`cause=${causeDetail}`); - if (level === "warn" && typeof logger.warn === "function") { - logger.warn(...parts); - } else if (typeof logger.error === "function") { - logger.error(...parts); - } else if (typeof logger.warn === "function") { - logger.warn(...parts); - } - if (err.kind === "fatal") { - fatalErrorRoute(err); - } - return err; -} diff --git a/src/main/errors/index.ts b/src/main/errors/index.ts deleted file mode 100644 index 048e2a5d..00000000 --- a/src/main/errors/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Error taxonomy entry point (C6.1). - * - * Re-exports the AppError hierarchy and helpers. Import from this path - * everywhere inside src/main/ so the rest of the tree never reaches - * directly into `./taxonomy.ts` or `./handlers.ts`. - */ - -export { - AppError, - RecoverableError, - UserInputError, - UpstreamError, - FatalError, - classifyUnknownError, - isAppError, - type AppErrorMeta, - type ErrorKind, -} from "./taxonomy.js"; - -export { logAppError, setFatalErrorRouteForTesting, type Logger } from "./handlers.js"; diff --git a/src/main/errors/taxonomy.ts b/src/main/errors/taxonomy.ts deleted file mode 100644 index ca6f73b9..00000000 --- a/src/main/errors/taxonomy.ts +++ /dev/null @@ -1,230 +0,0 @@ -/** - * AppError taxonomy (C6.1 part 1/2). - * - * Purpose: give every catch site in src/main/ a stable, auditable - * classification. Today's 248 catch blocks in main/ are overwhelmingly - * untyped `} catch {}` or `} catch (e) { log.warn(...); return default }` - * — behaviour is correct case-by-case but the codebase has no machine - * readable signal for "is this recoverable vs fatal", so: - * - * - graceful-shutdown logic cannot tell a user-input 400 apart from - * an upstream 502 apart from a corrupted SQLite file; - * - telemetry cannot bucket errors by kind; - * - audits of "which catches silently swallow fatal conditions" have - * to be by-hand grep. - * - * Design invariants (Karpathy "let it crash" + Linus "no silent defaults"): - * - * 1. `classifyUnknownError` never invents classification. The caller - * MUST pass a fallback meta describing the *expected* worst case; - * the helper only honours it when the raw error doesn't already - * carry an AppError classification. - * 2. No fallback defaults on construction. `kind` and `code` are - * required; there is no "unknown" catch-all kind because that - * would reintroduce the exact silent-fallthrough pattern this - * module exists to replace. - * 3. The taxonomy is intentionally narrow: 4 kinds. Adding a 5th is - * a conscious proposal, not a one-off at a call site. - * - * Kinds: - * - * - `recoverable`: expected transient failure the caller can work - * around without human involvement. Example: JSON parse of a stale - * cache entry; re-read or skip. - * - `user_input`: caller-supplied input is invalid. Example: user - * pasted a malformed URL; surface to UI, do not retry. - * - `upstream`: downstream service/dependency failed (HTTP 5xx, - * tool provider down, disk IO). Retriable at a higher level or - * must be propagated to the user with context. - * - `fatal`: process-level invariant broken (DB corruption, missing - * required config at runtime). Should abort the current operation - * and ideally the process. - */ - -import log from "electron-log/main.js"; - -export type ErrorKind = "recoverable" | "user_input" | "upstream" | "fatal"; - -export interface AppErrorMeta { - kind: ErrorKind; - /** - * Machine-readable stable identifier for this error site. - * Convention: `module.subdomain.condition`, e.g. `db.lock.busy`, - * `ipc.payload.invalid`, `skills.yaml.parse_failed`. - */ - code: string; - /** Human-readable summary suitable for logs. */ - message: string; - /** Original thrown value, preserved for cause-chain inspection. */ - cause?: unknown; - /** Arbitrary structured context captured at the catch site. */ - context?: Record; -} - -/** - * Canonical error carrier for the AgentCompany main process. - * - * Subclasses below exist only so `instanceof RecoverableError` etc. work - * ergonomically at call sites; the behavioural difference lives entirely - * in `kind`. - */ -export class AppError extends Error { - readonly kind: ErrorKind; - readonly code: string; - readonly context?: Record; - // Error has `cause` as optional since ES2022; we mirror it explicitly to - // give a stable accessor regardless of lib version. - readonly appCause: unknown; - - constructor(meta: AppErrorMeta) { - super(meta.message); - this.name = "AppError"; - this.kind = meta.kind; - this.code = meta.code; - this.context = meta.context; - this.appCause = meta.cause; - } - - /** - * Structured envelope suitable for log lines or IPC payloads. - */ - toJSON(): { - name: string; - kind: ErrorKind; - code: string; - message: string; - context?: Record; - cause?: string; - } { - const payload: { - name: string; - kind: ErrorKind; - code: string; - message: string; - context?: Record; - cause?: string; - } = { - name: this.name, - kind: this.kind, - code: this.code, - message: this.message, - }; - if (this.context) payload.context = this.context; - if (this.appCause !== undefined) { - payload.cause = - this.appCause instanceof Error - ? this.appCause.message - : String(this.appCause); - } - return payload; - } -} - -export class RecoverableError extends AppError { - constructor(meta: Omit) { - super({ ...meta, kind: "recoverable" }); - this.name = "RecoverableError"; - } -} - -export class UserInputError extends AppError { - constructor(meta: Omit) { - super({ ...meta, kind: "user_input" }); - this.name = "UserInputError"; - } -} - -export class UpstreamError extends AppError { - constructor(meta: Omit) { - super({ ...meta, kind: "upstream" }); - this.name = "UpstreamError"; - } -} - -export class FatalError extends AppError { - constructor(meta: Omit) { - super({ ...meta, kind: "fatal" }); - this.name = "FatalError"; - } -} - -let rawStringifyFallbackWarned = false; - -/** - * Wrap an unknown thrown value into an AppError. - * - * Three cases, resolved in order: - * - * 1. `e` is already an AppError → return it unchanged. The original - * classification (often narrower than the caller's guess) wins. - * 2. `e instanceof Error` → construct an AppError with the caller's - * fallback meta and attach `e` as `cause`. The original - * `Error.message` is preserved in the cause chain; `meta.message` - * wins at the AppError level because it's the site-specific - * description. - * 3. anything else (string, number, plain object, undefined) → - * construct with fallback meta and stash the raw value in - * `context.raw` for debugging. - * - * The `fallback` argument is required on purpose: the call site is the - * only place that knows the semantic intent of the surrounding code, so - * it must commit to a kind/code/message. A silent default here would - * reintroduce the exact "mystery-shaped error" problem this helper is - * designed to eliminate. - */ -export function classifyUnknownError( - e: unknown, - fallback: AppErrorMeta, -): AppError { - if (e instanceof AppError) { - return e; - } - if (e instanceof Error) { - return new AppError({ - ...fallback, - cause: e, - }); - } - return new AppError({ - ...fallback, - context: { - ...(fallback.context ?? {}), - raw: stringifyRaw(e), - }, - }); -} - -function stringifyRaw(value: unknown): string { - if (value === undefined) return "undefined"; - if (value === null) return "null"; - if (typeof value === "string") return value; - if (typeof value === "number" || typeof value === "boolean") { - return String(value); - } - try { - return JSON.stringify(value); - } catch (error) { - // The raw value is a cyclic / un-serialisable object. `String(value)` - // falls back to "[object Object]" which is still better than losing - // the fact that something was thrown. - warnRawStringifyFallback(error); - return String(value); - } -} - -function warnRawStringifyFallback(error: unknown): void { - if (rawStringifyFallbackWarned) return; - rawStringifyFallbackWarned = true; - log.warn( - "[errors] stringifyRaw failed; using String(value) for raw thrown value.", - error instanceof Error ? error.message : String(error), - ); -} - -/** - * Convenience narrowing predicate. Intentional: avoids forcing every - * consumer to re-import `AppError` just to write an `instanceof` guard. - */ -export function isAppError(value: unknown): value is AppError { - return value instanceof AppError; -} diff --git a/src/main/execution-mode-reconciler.ts b/src/main/execution-mode-reconciler.ts deleted file mode 100644 index 35c1a944..00000000 --- a/src/main/execution-mode-reconciler.ts +++ /dev/null @@ -1,154 +0,0 @@ -import log from "electron-log/main.js"; -import { resolveApprovalDecision } from "./approval-policy"; -import type { AppDatabase } from "./database"; - -type ReconcileExecutionModeChangeInput = { - db: AppDatabase; - companyId: string; - previousExecutionMode: string; - nextExecutionMode: string; - previousReviewDeliverables: boolean; - nextReviewDeliverables: boolean; - handleApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; -}; - -const REVIEW_WAIT_STATE_TYPES = new Set(["user_reply", "user_review", "user_approval"]); - -function collectImpactedAgentIdsFromWaitStates(db: AppDatabase, companyId: string): Set { - const agentIds = new Set(); - const waitStates = db.core.threads.listThreadWaitStates(companyId); - for (const waitState of waitStates) { - const thread = db.core.threads.getThread(waitState.threadId, companyId); - if (!thread || thread.relatedEntityType !== "task" || !thread.relatedEntityId) continue; - try { - const task = db.core.entity.getTask(thread.relatedEntityId); - if (task.assigneeAgentId) { - agentIds.add(task.assigneeAgentId); - } - } catch (err) { - log.warn(`[execution-mode-reconciler] getTask failed for ${thread.relatedEntityId}:`, err instanceof Error ? err.message : String(err)); - continue; - } - } - return agentIds; -} - -function collectImpactedAgentIdsFromReviewState(db: AppDatabase, companyId: string): Set { - const agentIds = new Set(); - const flaggedTasks = db.queryAll<{ assigneeAgentId: string | null }>( - "select assignee_agent_id as assigneeAgentId from tasks where company_id = ? and requires_user_review = 1", - companyId, - ); - for (const task of flaggedTasks) { - if (task.assigneeAgentId) { - agentIds.add(task.assigneeAgentId); - } - } - const pendingApprovals = db.queryAll<{ requestedByAgentId: string | null; relatedTaskId: string | null }>( - `select requested_by_agent_id as requestedByAgentId, related_task_id as relatedTaskId - from approvals - where company_id = ? - and state = 'pending' - and type = 'deliverable_review'`, - companyId, - ); - for (const approval of pendingApprovals) { - if (approval.requestedByAgentId) { - agentIds.add(approval.requestedByAgentId); - } - if (!approval.relatedTaskId) continue; - try { - const task = db.core.entity.getTask(approval.relatedTaskId); - if (task.assigneeAgentId) { - agentIds.add(task.assigneeAgentId); - } - } catch (err) { - log.warn(`[execution-mode-reconciler] getTask failed for approval ${approval.relatedTaskId}:`, err instanceof Error ? err.message : String(err)); - continue; - } - } - return agentIds; -} - -function resumeAgents(db: AppDatabase, companyId: string, agentIds: Iterable): void { - for (const agentId of agentIds) { - try { - const agent = db.core.entity.getAgent(agentId); - if (agent.companyId !== companyId) continue; - if (["terminated", "pending_approval"].includes(agent.status)) continue; - if (!agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(agent.id, true, agent.heartbeatIntervalSec || 120); - } - } catch (err) { - log.warn(`[execution-mode-reconciler] resumeAgents failed for ${agentId}:`, err instanceof Error ? err.message : String(err)); - continue; - } - } -} - -export function reconcileExecutionModeChange({ - db, - companyId, - previousExecutionMode, - nextExecutionMode, - previousReviewDeliverables, - nextReviewDeliverables, - handleApprovalResolved, -}: ReconcileExecutionModeChangeInput): void { - const leavingCofounderMode = - previousExecutionMode === "ai_cofounder" && nextExecutionMode === "ai_ceo"; - const disablingDeliverableReviews = - previousReviewDeliverables && !nextReviewDeliverables; - - if (!leavingCofounderMode && !disablingDeliverableReviews) { - return; - } - - const impactedAgents = new Set([ - ...collectImpactedAgentIdsFromWaitStates(db, companyId), - ...collectImpactedAgentIdsFromReviewState(db, companyId), - ]); - - if (leavingCofounderMode) { - const pendingApprovals = db.queryAll<{ id: string; type: string }>( - `select a.id, a.type - from approvals a - inner join approval_policies p on p.approval_type = a.type - where a.company_id = ? - and a.state = 'pending' - and p.blocks_execution = 1 - and p.required_mode = 'ai_cofounder'`, - companyId, - ); - for (const approval of pendingApprovals) { - resolveApprovalDecision({ - db, - handleApprovalResolved, - companyId, - approvalId: approval.id, - state: "approved", - decisionNote: "Auto-approved because the company switched to AI CEO mode.", - detail: `Mode transition auto-approved ${approval.type}.`, - actor: "system", - }); - } - - const waitStates = db.core.threads.listThreadWaitStates(companyId); - for (const waitState of waitStates) { - if (!REVIEW_WAIT_STATE_TYPES.has(waitState.waitingFor)) continue; - db.core.threads.resolveThreadWaitState(waitState.id, companyId); - } - } - - if (disablingDeliverableReviews || leavingCofounderMode) { - const tasks = db.queryAll<{ id: string }>( - "select id from tasks where company_id = ? and requires_user_review = 1", - companyId, - ); - for (const task of tasks) { - db.core.tasks.setTaskRequiresUserReview(task.id, false); - } - } - - resumeAgents(db, companyId, impactedAgents); -} diff --git a/src/main/execution-policy.ts b/src/main/execution-policy.ts deleted file mode 100644 index 6594bdd4..00000000 --- a/src/main/execution-policy.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Execution Policy - * - * Runtime decisions read the seeded approval_policies table. The exported - * constants below exist for prompt/docs contracts that need the same seed - * vocabulary without opening SQLite. - */ - -import type { AppDatabase } from "./database"; -import type { ApprovalType, ExecutionMode } from "@shared/types"; -export { - APPROVAL_POLICY_SEED, - COFOUNDER_MANDATORY_APPROVAL_TYPES, - OPERATIONAL_APPROVAL_TYPES, -} from "./approval-policy-definitions"; -import { - COFOUNDER_MANDATORY_APPROVAL_TYPES, - OPERATIONAL_APPROVAL_TYPES, -} from "./approval-policy-definitions"; - -function assertExecutionMode(value: string): asserts value is ExecutionMode { - if (value !== "ai_ceo" && value !== "ai_cofounder") { - throw new Error(`Invalid execution mode returned from database: ${value}`); - } -} - -const COFOUNDER_MANDATORY_APPROVALS = new Set(COFOUNDER_MANDATORY_APPROVAL_TYPES); - -export function isCofounderMandatoryApproval(approvalType: string): approvalType is ApprovalType { - return COFOUNDER_MANDATORY_APPROVALS.has(approvalType as ApprovalType); -} - -const OPERATIONAL_APPROVALS = new Set(OPERATIONAL_APPROVAL_TYPES); - -export function isOperationalApproval(approvalType: string): approvalType is ApprovalType { - return OPERATIONAL_APPROVALS.has(approvalType as ApprovalType); -} - -/** Task types that get plan_review checkpoints in co-founder mode. */ -export const CHECKPOINT_TASK_TYPES = new Set(["research", "content", "management"]); - -/** Document types that get strategy_review instead of draft_review. */ -export const STRATEGY_DOCUMENT_TYPES = new Set(["project_brief", "proposal", "budget_proposal"]); - -/** - * Determines whether an approval should be auto-approved. - * This is the single decision function — no other module should - * independently decide auto-approval policy. - */ -export function shouldAutoApprove( - db: AppDatabase, - companyId: string, - approvalType: string, -): boolean { - const rawMode = db.core.company.getCompanyExecutionMode(companyId); - assertExecutionMode(rawMode); - const mode = rawMode; - const policy = db.core.approvals.getApprovalPolicy(approvalType); - if (!policy?.autoApprovable) { - return false; - } - - if (mode === "ai_cofounder" && policy.requiredMode === "ai_cofounder") { - return false; - } - - const settings = db.core.company.getCompanyApprovalSettings(companyId); - if (!settings?.autoApproveHires) return false; - - // When reviewDeliverables is ON, CEO strategy needs human review - if (approvalType === "approve_ceo_strategy" && settings.reviewDeliverables) { - return false; - } - - return true; -} diff --git a/src/main/external-url-policy.ts b/src/main/external-url-policy.ts deleted file mode 100644 index 4f85ac7f..00000000 --- a/src/main/external-url-policy.ts +++ /dev/null @@ -1,54 +0,0 @@ -const TRUSTED_EXTERNAL_HOSTS = new Set([ - "github.com", - "www.github.com", - "agentcompany.pages.dev", - "claude.ai", - "www.electronjs.org", - "www.electron.build", -]); - -export type ExternalUrlDecision = - | { kind: "trusted"; url: string; host: string } - | { kind: "confirm"; url: string; host: string } - | { kind: "blocked"; reason: string }; - -export function normalizeExternalHttpUrl(rawUrl: string): string { - const trimmed = rawUrl.trim(); - if (!trimmed) { - throw new Error("External URL is required."); - } - let parsed: URL; - try { - parsed = new URL(trimmed); - } catch { - throw new Error("External URL must be absolute."); - } - if (parsed.protocol !== "https:" && parsed.protocol !== "http:") { - throw new Error("External URL protocol must be http or https."); - } - if (!parsed.hostname) { - throw new Error("External URL host is required."); - } - if (parsed.username || parsed.password) { - throw new Error("External URL credentials are not allowed."); - } - return parsed.toString(); -} - -export function classifyExternalUrl(rawUrl: string): ExternalUrlDecision { - let normalized: string; - try { - normalized = normalizeExternalHttpUrl(rawUrl); - } catch (error) { - return { - kind: "blocked", - reason: error instanceof Error ? error.message : String(error), - }; - } - const parsed = new URL(normalized); - const host = parsed.hostname.toLowerCase(); - if (parsed.protocol === "https:" && TRUSTED_EXTERNAL_HOSTS.has(host)) { - return { kind: "trusted", url: normalized, host }; - } - return { kind: "confirm", url: normalized, host }; -} diff --git a/src/main/hire-hook.ts b/src/main/hire-hook.ts deleted file mode 100644 index 7bb15547..00000000 --- a/src/main/hire-hook.ts +++ /dev/null @@ -1,112 +0,0 @@ -import log from "electron-log/main.js"; -import { getConnectorDefinition } from "./connectors"; -import type { AppDatabase } from "./database"; -import { classifyUnknownError } from "./errors/index.js"; - -/** - * Payload captured when an agent hire is approved. Kept for call-sites that - * want to surface the approval in activity feeds or future integrations. - */ -export interface HireApprovedPayload { - companyId: string; - agentId: string; - agentName: string; - connectorId: string; - source: "join_request" | "approval"; - sourceId: string; - approvedAt: string; - message: string; -} - -/** - * Record that an agent hire was approved. Pi-mono does not expose an adapter - * hook, so this records an activity row for the company timeline. - * Non-fatal: failures are logged but never thrown. - */ -export async function notifyHireApproved( - db: AppDatabase, - input: { - companyId: string; - agentId: string; - source: "join_request" | "approval"; - sourceId: string; - approvedAt?: string; - }, -): Promise { - try { - let agent; - try { - agent = db.core.entity.getAgent(input.agentId); - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "hire_hook.agent.not_found", - message: `Agent ${input.agentId} not found, skipping hire notification`, - context: { agentId: input.agentId, companyId: input.companyId }, - }); - log.warn(`[${classified.code}] ${classified.message}`); - return; - } - - let connectorDef; - try { - connectorDef = getConnectorDefinition(agent.connectorId); - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "hire_hook.connector.not_found", - message: `No connector definition for ${agent.connectorId}, skipping hire notification`, - context: { connectorId: agent.connectorId, agentId: input.agentId }, - }); - log.warn(`[${classified.code}] ${classified.message}`); - return; - } - - const locale = (db.queryAll<{ value: string }>("select value from settings where key = 'locale' limit 1")[0]?.value ?? "en"); - const payload: HireApprovedPayload = { - companyId: input.companyId, - agentId: input.agentId, - agentName: agent.name, - connectorId: connectorDef.id, - source: input.source, - sourceId: input.sourceId, - approvedAt: input.approvedAt ?? new Date().toISOString(), - message: locale === "zh" - ? `你已被批准为"${agent.title}"。你现在已激活,可以接收任务。` - : `Your hire as "${agent.title}" in the company has been approved. You are now active and ready to receive tasks.`, - }; - - log.info(`[hire-hook] Hire approved for agent ${agent.name} (${input.agentId}) on connector ${connectorDef.id}`); - db.core.activity.addActivity({ - companyId: input.companyId, - actor: "system", - action: "hire_hook.success", - entityType: "agent", - entityId: input.agentId, - detail: `Hire approved: ${payload.agentName} via ${connectorDef.id}`, - }); - } catch (error) { - const classified = classifyUnknownError(error, { - kind: "upstream", - code: "hire_hook.notify.exception", - message: `Exception notifying hire for agent ${input.agentId}`, - context: { agentId: input.agentId, companyId: input.companyId }, - }); - const message = error instanceof Error ? error.message : String(error); - log.error(`[${classified.code}] ${classified.message}: ${message}`); - try { - db.core.activity.addActivity({ - companyId: input.companyId, - actor: "system", - action: "hire_hook.exception", - entityType: "agent", - entityId: input.agentId, - detail: message, - }); - } catch (activityError) { - log.error( - `[hire-hook] Activity logging also failed for agent ${input.agentId}: ${activityError instanceof Error ? activityError.message : String(activityError)}`, - ); - } - } -} diff --git a/src/main/host-environment-service.ts b/src/main/host-environment-service.ts deleted file mode 100644 index 3bd2ed31..00000000 --- a/src/main/host-environment-service.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { spawn } from "node:child_process"; -import { existsSync, readdirSync } from "node:fs"; -import { homedir } from "node:os"; -import { delimiter as pathDelimiter, join } from "node:path"; -import { app } from "electron"; - -interface HostEnvironmentDependencies { - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - }; -} - -/** - * On Windows, Electron apps launched from installer shortcuts inherit a minimal PATH - * that often lacks user-installed CLI tool directories. This function enriches - * process.env.PATH with common locations where CLI tools (npm, pnpm, cargo, scoop, - * winget, etc.) are typically installed. - */ -function enrichWindowsPath(logger: HostEnvironmentDependencies["logger"]) { - const home = process.env.USERPROFILE ?? homedir(); - const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming"); - const localAppData = process.env.LOCALAPPDATA ?? join(home, "AppData", "Local"); - - const pythonBase = join(localAppData, "Programs", "Python"); - // Enumerate installed Python versions so new releases (Python313, ...) - // are picked up automatically without code changes. - const pythonScriptDirs: string[] = (() => { - try { - return readdirSync(pythonBase) - .filter((name) => /^Python\d+$/.test(name)) - .map((name) => join(pythonBase, name, "Scripts")); - } catch (err) { - logger.warn(`[path] readdirSync failed for ${pythonBase}:`, err instanceof Error ? err.message : String(err)); - return []; - } - })(); - - const candidateDirs = [ - join(appData, "npm"), - join(localAppData, "pnpm"), - join(home, ".local", "bin"), - join(home, ".cargo", "bin"), - ...pythonScriptDirs, - join(home, "scoop", "shims"), - join(home, ".bun", "bin"), - join(home, ".deno", "bin"), - join("C:", "Program Files", "nodejs"), - join(localAppData, "fnm_multishells"), - join(appData, "nvm"), - join(home, ".claude"), - join(localAppData, "Claude"), - ]; - - const current = new Set( - (process.env.PATH ?? "").split(pathDelimiter).map((entry) => entry.toLowerCase()), - ); - const toAdd = candidateDirs.filter( - (dir) => !current.has(dir.toLowerCase()) && existsSync(dir), - ); - - if (toAdd.length > 0) { - process.env.PATH = [process.env.PATH, ...toAdd].filter(Boolean).join(pathDelimiter); - logger.info(`[path] Windows: added ${toAdd.length} PATH entries: ${toAdd.join(", ")}`); - } -} - -export async function prepareHostEnvironment({ - logger, -}: HostEnvironmentDependencies) { - if (process.platform === "win32") { - enrichWindowsPath(logger); - app.setAppUserModelId("com.agentcompany.desktop"); - } else if (process.env.AGENTCOMPANY_ENABLE_SHELL_PATH_PROBE === "true") { - try { - const userShell = process.env.SHELL || "/bin/zsh"; - const shellPath = await new Promise((resolve) => { - const child = spawn(userShell, ["-ilc", "echo -n $PATH"], { - env: { ...process.env }, - stdio: ["ignore", "pipe", "ignore"], - timeout: 5000, - }); - let output = ""; - child.stdout?.on("data", (chunk: Buffer) => { - output += chunk.toString(); - }); - child.on("close", () => resolve(output.trim())); - child.on("error", () => resolve("")); - }); - if (shellPath && shellPath.length > 0) { - const current = new Set((process.env.PATH ?? "").split(pathDelimiter).filter(Boolean)); - const shellParts = shellPath.split(pathDelimiter).filter(Boolean); - const toAdd = shellParts.filter((entry) => !current.has(entry)); - if (toAdd.length > 0) { - process.env.PATH = [process.env.PATH, ...toAdd].join(pathDelimiter); - logger.info(`[path] Added ${toAdd.length} shell PATH entries.`); - } - } - } catch (err) { - logger.warn(`[path] Shell PATH probe failed:`, err instanceof Error ? err.message : String(err)); - } - } else { - logger.info("[path] Skipping interactive shell PATH probe; using deterministic PATH setup only."); - } - - // Dock icon: macOS uses the .icns from the app bundle with the system squircle - // mask applied automatically. Do not call dock.setIcon() — it bypasses the mask - // and renders the raw PNG oversized and square. -} diff --git a/src/main/index.ts b/src/main/index.ts index fe4688e2..40a97167 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,37 +1,57 @@ -import "./install-main-warning-suppressions"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; import { app } from "electron"; -import { configureMainProcess } from "./main-process-setup"; -import { createMainRuntime } from "./main-runtime"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { DatabaseConnection } from "./database/connection"; +import { createMainWindow } from "./app/create-window"; +import { registerIpcHandlers } from "./app/ipc-handlers"; +import { startProviderBackgroundWorker } from "./app/provider-background-worker"; +import { recoverInterruptedWork } from "./app/startup-recovery"; +import { startTaskQueueWorker } from "./app/task-queue-worker"; const __dirname = dirname(fileURLToPath(import.meta.url)); -configureMainProcess("AgentCompany"); - -const profileDir = process.env.AGENTCOMPANY_PROFILE_DIR ?? join(app.getPath("userData"), "profile"); -const isDev = Boolean(process.env.ELECTRON_RENDERER_URL); -const devServerOrigin = process.env.ELECTRON_RENDERER_URL ? new URL(process.env.ELECTRON_RENDERER_URL).origin : null; -const hasSingleInstanceLock = - process.env.AGENTCOMPANY_DISABLE_SINGLE_INSTANCE === "true" - ? true - : app.requestSingleInstanceLock(); - -const runtime = createMainRuntime({ - hasSingleInstanceLock, - isDev, - devServerOrigin, - profileDir, - windowStatePath: join(profileDir, "window-state.json"), - preloadPath: join(__dirname, "../preload/index.js"), - rendererDist: join(__dirname, "../renderer"), - iconPath: resolve(__dirname, "../../assets/icon.png"), - workerPath: join(__dirname, "worker.js"), - devServerUrl: process.env.ELECTRON_RENDERER_URL, -}); - -if (hasSingleInstanceLock) { - void runtime.bootstrap(); -} else { +// A losing second instance must never touch the database: quit is +// asynchronous, so all startup work stays behind the lock check. +if (!app.requestSingleInstanceLock()) { app.quit(); +} else { + app.whenReady().then(() => { + const profileDir = process.env.AGENTCOMPANY_NEW_PROFILE_DIR ?? join(app.getPath("userData"), "profile"); + const connection = new DatabaseConnection(join(profileDir, "agentcompany.db")); + connection.transaction(() => recoverInterruptedWork(connection.db)); + const win = createMainWindow({ + preloadPath: join(__dirname, "../preload/index.js"), + rendererDist: join(__dirname, "../renderer"), + devServerUrl: process.env.ELECTRON_RENDERER_URL, + }); + + registerIpcHandlers({ + connection, + mainWindow: win, + artifactRoot: join(profileDir, "artifacts"), + }); + const stopProviderBackgroundWorker = startProviderBackgroundWorker({ + db: connection.db, + mainWindow: win, + }); + const autonomousExecution = process.env.AGENTCOMPANY_NEW_AUTORUN !== "0"; + const stopTaskQueueWorker = autonomousExecution + ? startTaskQueueWorker({ connection, mainWindow: win }) + : () => {}; + + app.on("second-instance", () => { + if (win.isMinimized()) win.restore(); + win.focus(); + }); + + app.on("before-quit", () => { + stopProviderBackgroundWorker(); + stopTaskQueueWorker(); + connection.close(); + }); + }); + + app.on("window-all-closed", () => { + if (process.platform !== "darwin") app.quit(); + }); } diff --git a/src/main/install-main-warning-suppressions.ts b/src/main/install-main-warning-suppressions.ts deleted file mode 100644 index dc874683..00000000 --- a/src/main/install-main-warning-suppressions.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - classifyConsoleErrorSuppression, - classifyWarningSuppression, -} from "./main-warning-suppression-rules"; - -const originalEmitWarning = process.emitWarning.bind(process); - -process.emitWarning = ((warning: unknown, ...rest: unknown[]) => { - if (classifyWarningSuppression(warning)) return; - return (originalEmitWarning as (...args: unknown[]) => void)(warning, ...rest); -}) as typeof process.emitWarning; - -const originalConsoleError = console.error.bind(console); - -console.error = ((...args: unknown[]) => { - if (classifyConsoleErrorSuppression(args)) return; - return originalConsoleError(...args); -}) as typeof console.error; diff --git a/src/main/ipc-agent-coordination-handlers.ts b/src/main/ipc-agent-coordination-handlers.ts deleted file mode 100644 index 64cc58b6..00000000 --- a/src/main/ipc-agent-coordination-handlers.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - IPC_CHANNELS, - agentMessageInputSchema, - markMessageReadSchema, - searchMessagesSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; -import { dispatchAgentMessage } from "./messaging/dispatch"; - -export function registerAgentCoordinationHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - emitEvent, - notify, - wakeAgentIfPossible, - injectRuntimeMessage, - onHumanMessage, -}: Pick< - RegisterDomainHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "publishDomainChanged" - | "emitEvent" - | "notify" - | "wakeAgentIfPossible" - | "injectRuntimeMessage" - | "onHumanMessage" ->) { - registerHandle(IPC_CHANNELS.sendAgentMessage, async (_event, payload) => { - const parsed = agentMessageInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const dispatchResult = dispatchAgentMessage( - { - db, - emitEvent, - notify, - publishDomainChanged, - wakeAgentIfPossible, - injectRuntimeMessage, - onHumanMessage, - }, - parsed, - "message", - ); - if (!dispatchResult.ok) { - return fail(dispatchResult.error.code, dispatchResult.error.message); - } - return ok({ - id: dispatchResult.data.id, - mentionResults: dispatchResult.data.mentionResults, - }); - }); - - registerHandle(IPC_CHANNELS.markMessageRead, async (_event, payload) => { - const parsed = markMessageReadSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const message = db.core.messages.getAgentMessage(parsed.messageId, parsed.companyId); - if (!message) { - return fail("MESSAGE_NOT_FOUND", "Message not found in the current company."); - } - if (parsed.readerAgentId && !db.core.settings.belongsToCompany("agents", parsed.readerAgentId, parsed.companyId)) { - return fail("INVALID_COMPANY_REFERENCE", "The selected message reader does not belong to the current company."); - } - if (parsed.readerAgentId) { - const visibleToReader = db.core.messages - .listAgentMessages(parsed.companyId, { - agentId: parsed.readerAgentId, - messageId: parsed.messageId, - limit: 1, - }) - .some((entry) => entry.id === parsed.messageId); - if (!visibleToReader) { - return fail("MESSAGE_NOT_VISIBLE", "This message is not visible to the selected reader."); - } - } - db.core.messages.markMessageReadForReader(parsed.messageId, parsed.companyId, parsed.readerAgentId ?? null); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.searchMessages, async (_event, payload) => { - const parsed = searchMessagesSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - return ok(db.core.messages.searchMessages(parsed.companyId, parsed.query, { - channel: parsed.channel, - channelTargetId: parsed.channelTargetId, - limit: parsed.limit, - })); - }); - -} diff --git a/src/main/ipc-automation-operations-handlers.ts b/src/main/ipc-automation-operations-handlers.ts deleted file mode 100644 index b76277d6..00000000 --- a/src/main/ipc-automation-operations-handlers.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { z } from "zod"; -import { - IPC_CHANNELS, - automationRuleInputSchema, - deleteEntitySchema, - runWorkflowSchema, - toggleAutomationRuleSchema, - workflowInputSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; - -export function registerAutomationOperationsHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - runWorkflowPipeline, -}: Pick< - RegisterDomainHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "publishDomainChanged" - | "runWorkflowPipeline" ->) { - const companyIdSchema = z.string().uuid(); - - registerHandle(IPC_CHANNELS.saveAutomationRule, async (_event, payload) => { - const parsed = automationRuleInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("automation_rules", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Automation rule not found in the current company."); - } - const id = db.automation.rules.saveAutomationRule(parsed); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteAutomationRule, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("automation_rules", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Automation rule not found in the current company."); - } - db.automation.rules.deleteAutomationRule(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.toggleAutomationRule, async (_event, payload) => { - const parsed = toggleAutomationRuleSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("automation_rules", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Automation rule not found in the current company."); - } - db.automation.rules.toggleAutomationRule(parsed.id, parsed.companyId, parsed.status); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.getAutomationLog, async (_event, companyId) => { - const parsed = companyIdSchema.parse(companyId); - const companyError = ensureCompanyExists(parsed); - if (companyError) return companyError; - return ok(db.automation.rules.getAutomationLog(parsed)); - }); - - registerHandle(IPC_CHANNELS.saveWorkflow, async (_event, payload) => { - const parsed = workflowInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("workflow_pipelines", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Workflow not found in the current company."); - } - const id = db.automation.rules.saveWorkflow(parsed); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteWorkflow, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("workflow_pipelines", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Workflow not found in the current company."); - } - db.automation.rules.deleteWorkflow(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.runWorkflow, async (_event, payload) => { - const parsed = runWorkflowSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("workflow_pipelines", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Workflow not found in the current company."); - } - await runWorkflowPipeline(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-browser-handlers.ts b/src/main/ipc-browser-handlers.ts deleted file mode 100644 index cac802fe..00000000 --- a/src/main/ipc-browser-handlers.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - IPC_CHANNELS, - browserActionQuerySchema, - cancelBrowserActionSchema, - deleteEntitySchema, - socialAccountInputSchema, - triggerBrowserLoginSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; -import { SocialAccountScopeError } from "./database/social"; - -const inflightBrowserLogins = new Set(); - -export function registerBrowserHandlers({ - registerHandle, - db, - logger, - ensureCompanyExists, - publishDomainChanged, - getBrowserActions, -}: Pick< - RegisterDomainHandlersDependencies, - | "registerHandle" - | "db" - | "logger" - | "ensureCompanyExists" - | "publishDomainChanged" - | "getBrowserActions" ->) { - registerHandle(IPC_CHANNELS.saveSocialAccount, (_event, payload) => { - const input = socialAccountInputSchema.parse(payload); - const err = ensureCompanyExists(input.companyId); - if (err) return err; - let id: string; - try { - id = db.core.social.saveSocialAccount(input); - } catch (error) { - if (error instanceof SocialAccountScopeError) { - return fail("INVALID_COMPANY_REFERENCE", error.message); - } - throw error; - } - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteSocialAccount, async (_event, payload) => { - const input = deleteEntitySchema.parse(payload); - const err = ensureCompanyExists(input.companyId); - if (err) return err; - const browserActions = db.core.social.listBrowserActions(input.companyId, { socialAccountId: input.id, limit: 500 }); - await getBrowserActions()?.clearSocialAccountData( - input.id, - browserActions.flatMap((action: { screenshotPath: string | null }) => (action.screenshotPath ? [action.screenshotPath] : [])), - ); - db.core.social.deleteSocialAccount(input.id, input.companyId); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.listBrowserActions, (_event, payload) => { - const input = browserActionQuerySchema.parse(payload); - const err = ensureCompanyExists(input.companyId); - if (err) return err; - return ok(db.core.social.listBrowserActions(input.companyId, { - socialAccountId: input.socialAccountId, - status: input.status, - limit: input.limit, - })); - }); - - registerHandle(IPC_CHANNELS.cancelBrowserAction, (_event, payload) => { - const input = cancelBrowserActionSchema.parse(payload); - const action = db.core.social.getBrowserAction(input.actionId, input.companyId); - if (!action) { - return fail("BROWSER_ACTION_NOT_FOUND", "Browser action not found."); - } - getBrowserActions()?.cancelAction(input.actionId); - db.core.social.updateBrowserAction(input.actionId, { - status: "cancelled", - resultSummary: "Browser action cancelled from the desktop control surface.", - errorMessage: "Action cancelled.", - finishedAt: new Date().toISOString(), - }); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.triggerBrowserLogin, async (_event, payload) => { - const input = triggerBrowserLoginSchema.parse(payload); - const err = ensureCompanyExists(input.companyId); - if (err) return err; - const browserActions = getBrowserActions(); - if (!browserActions) { - return fail("BROWSER_NOT_READY", "Browser manager not initialized"); - } - - const account = db.core.social.getSocialAccount(input.socialAccountId, input.companyId); - if (!account) { - return fail("ACCOUNT_NOT_FOUND", "Social account not found"); - } - - if (inflightBrowserLogins.has(input.socialAccountId)) { - return fail("LOGIN_IN_PROGRESS", "A login for this account is already in progress."); - } - inflightBrowserLogins.add(input.socialAccountId); - browserActions.launchLoginBrowser(input.socialAccountId, account.platform).then(async (result) => { - if (result.success) { - const latestAccount = db.core.social.getSocialAccount(input.socialAccountId, account.companyId); - if (!latestAccount) { - return; - } - let detectedName = ""; - let detectedDisplay = ""; - try { - const profile = await browserActions.extractProfileFromSession(input.socialAccountId, account.platform); - detectedName = profile.accountName; - detectedDisplay = profile.displayName; - } catch (err) { - logger.warn(`[ipc/browser] extractProfileFromSession failed for social account ${input.socialAccountId}:`, err instanceof Error ? err.message : String(err)); - } - db.core.social.saveSocialAccount({ - id: latestAccount.id, - companyId: latestAccount.companyId, - platform: latestAccount.platform, - accountName: detectedName || latestAccount.accountName, - displayName: detectedDisplay || latestAccount.displayName, - profileUrl: latestAccount.profileUrl, - credentialSecretId: latestAccount.credentialSecretId, - status: "logged_in", - requireApproval: latestAccount.requireApproval, - }); - publishDomainChanged(); - } - }).catch((error) => { - logger.error(`[browser] Login failed: ${error}`); - }).finally(() => { - inflightBrowserLogins.delete(input.socialAccountId); - }); - - return ok(true); - }); -} diff --git a/src/main/ipc-budget-handlers.ts b/src/main/ipc-budget-handlers.ts deleted file mode 100644 index 2af66d6e..00000000 --- a/src/main/ipc-budget-handlers.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - IPC_CHANNELS, - budgetPolicyInputSchema, - listBudgetPoliciesSchema, - deleteBudgetPolicySchema, - listBudgetIncidentsSchema, - resolveBudgetIncidentSchema, - getBudgetStatusSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; -import type { createBudgetEnforcementService } from "./budget-enforcement-service"; -import type { AppDatabase } from "./database"; - -interface BudgetHandlerDependencies extends Pick< - RegisterDomainHandlersDependencies, - "registerHandle" | "ensureCompanyExists" | "publishDomainChanged" | "logger" -> { - budgetService: ReturnType | null; - db: AppDatabase; -} - -export function registerBudgetHandlers({ - registerHandle, - ensureCompanyExists, - publishDomainChanged, - budgetService, - db, - logger, -}: BudgetHandlerDependencies) { - // ---- Save (create/update) a budget policy ---- - registerHandle(IPC_CHANNELS.saveBudgetPolicy, async (_event, payload) => { - const parsed = budgetPolicyInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const id = db.core.budget.saveBudgetPolicy(parsed); - // D-06: Auto-resolve incidents if limit was increased above current spend - if (budgetService) { - try { - budgetService.checkAutoResolve(parsed.companyId, id); - } catch (err) { - logger.warn(`[ipc/budget] checkAutoResolve failed for policy ${id} in company ${parsed.companyId}:`, err instanceof Error ? err.message : String(err)); - } - } - publishDomainChanged(); - return ok(id); - }); - - // ---- Delete a budget policy ---- - registerHandle(IPC_CHANNELS.deleteBudgetPolicy, async (_event, payload) => { - const parsed = deleteBudgetPolicySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - db.core.budget.deleteBudgetPolicy(parsed.companyId, parsed.policyId); - publishDomainChanged(); - return ok(true); - }); - - // ---- List all budget policies for a company ---- - registerHandle(IPC_CHANNELS.listBudgetPolicies, async (_event, payload) => { - const parsed = listBudgetPoliciesSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - return ok(db.core.budget.listBudgetPolicies(parsed.companyId)); - }); - - // ---- List budget incidents ---- - registerHandle(IPC_CHANNELS.listBudgetIncidents, async (_event, payload) => { - const parsed = listBudgetIncidentsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - return ok(db.core.budget.listBudgetIncidents(parsed.companyId, parsed.status)); - }); - - // ---- Resolve a budget incident manually ---- - registerHandle(IPC_CHANNELS.resolveBudgetIncident, async (_event, payload) => { - const parsed = resolveBudgetIncidentSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - db.core.budget.resolveBudgetIncident(parsed.incidentId, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); - - // ---- Get budget status summary ---- - registerHandle(IPC_CHANNELS.getBudgetStatus, async (_event, payload) => { - const parsed = getBudgetStatusSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!budgetService) { - return fail("SERVICE_NOT_READY", "Budget enforcement service is not initialized."); - } - return ok(budgetService.getBudgetStatus(parsed.companyId)); - }); -} diff --git a/src/main/ipc-company-operations/document-handlers.ts b/src/main/ipc-company-operations/document-handlers.ts deleted file mode 100644 index 1fdad9f0..00000000 --- a/src/main/ipc-company-operations/document-handlers.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { IPC_CHANNELS, deleteEntitySchema, documentInputSchema } from "@shared/contracts"; -import { createDocumentWithLifecycle } from "../document-lifecycle"; -import { fail, ok } from "../ipc-domain-common"; -import type { CompanyOperationHandlerDependencies } from "./types"; - -export function registerDocumentHandlers({ - registerHandle, - db, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - threadIntegration, - checkpointEngine, - lifecycleProcessor, - logger, -}: CompanyOperationHandlerDependencies) { - registerHandle(IPC_CHANNELS.saveDocument, async (_event, payload) => { - const parsed = documentInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("documents", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Document not found in the current company."); - } - - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.authorAgentId, table: "agents", label: "document author" }, - { id: parsed.reviewerAgentId, table: "agents", label: "document reviewer" }, - { id: parsed.projectId, table: "projects", label: "document project" }, - { id: parsed.goalId, table: "goals", label: "document goal" }, - { id: parsed.parentDocId, table: "documents", label: "parent document" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - - const outcome = createDocumentWithLifecycle( - { - db, - threadIntegration, - checkpointEngine, - lifecycleProcessor, - publishDomainChanged, - logger, - }, - { - id: parsed.id ?? null, - companyId: parsed.companyId, - type: parsed.type, - title: parsed.title, - content: parsed.content ?? "", - authorAgentId: parsed.authorAgentId ?? null, - reviewerAgentId: parsed.reviewerAgentId ?? null, - projectId: parsed.projectId ?? null, - goalId: parsed.goalId ?? null, - parentDocId: parsed.parentDocId ?? null, - version: parsed.version ?? 1, - status: parsed.status ?? "draft", - tagsJson: parsed.tagsJson ?? "[]", - sourceRunId: null, - }, - ); - return ok(outcome.id); - }); - - registerHandle(IPC_CHANNELS.deleteDocument, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("documents", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Document not found in the current company."); - } - db.core.documents.deleteDocument(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-company-operations/index.ts b/src/main/ipc-company-operations/index.ts deleted file mode 100644 index d850c465..00000000 --- a/src/main/ipc-company-operations/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { registerDocumentHandlers } from "./document-handlers"; -import { registerKnowledgeEntryHandlers } from "./knowledge-entry-handlers"; -import { registerMeetingHandlers } from "./meeting-handlers"; -import { registerSprintHandlers } from "./sprint-handlers"; -import type { CompanyOperationHandlerDependencies } from "./types"; - -export function registerCompanyOperationsHandlers(dependencies: CompanyOperationHandlerDependencies) { - registerMeetingHandlers(dependencies); - registerDocumentHandlers(dependencies); - registerKnowledgeEntryHandlers(dependencies); - registerSprintHandlers(dependencies); -} diff --git a/src/main/ipc-company-operations/knowledge-entry-handlers.ts b/src/main/ipc-company-operations/knowledge-entry-handlers.ts deleted file mode 100644 index e7b3a39f..00000000 --- a/src/main/ipc-company-operations/knowledge-entry-handlers.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { IPC_CHANNELS, deleteEntitySchema, knowledgeEntryInputSchema } from "@shared/contracts"; -import { fail, ok } from "../ipc-domain-common"; -import { COMPANY_SCOPED_REFERENCE_TABLES } from "./reference-tables"; -import type { CompanyOperationHandlerDependencies } from "./types"; - -export function registerKnowledgeEntryHandlers({ - registerHandle, - db, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, -}: CompanyOperationHandlerDependencies) { - registerHandle(IPC_CHANNELS.saveKnowledgeEntry, async (_event, payload) => { - const parsed = knowledgeEntryInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("knowledge_base", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Knowledge entry not found in the current company."); - } - - const knowledgeReferences = [ - { id: parsed.authorAgentId, table: "agents", label: "knowledge author" }, - ...(parsed.referencedEntityId && parsed.referencedEntityType && COMPANY_SCOPED_REFERENCE_TABLES.has(parsed.referencedEntityType) - ? [{ id: parsed.referencedEntityId, table: parsed.referencedEntityType, label: "referenced entity" }] - : []), - ]; - const invalidReference = findInvalidReference(parsed.companyId, [ - ...knowledgeReferences, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - - const id = db.core.knowledge.saveKnowledgeEntry(parsed); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteKnowledgeEntry, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("knowledge_base", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Knowledge entry not found in the current company."); - } - db.core.knowledge.deleteKnowledgeEntry(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-company-operations/meeting-handlers.ts b/src/main/ipc-company-operations/meeting-handlers.ts deleted file mode 100644 index 457566e5..00000000 --- a/src/main/ipc-company-operations/meeting-handlers.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { IPC_CHANNELS, deleteEntitySchema, meetingInputSchema } from "@shared/contracts"; -import { fail, ok } from "../ipc-domain-common"; -import type { CompanyOperationHandlerDependencies } from "./types"; - -export function registerMeetingHandlers({ - registerHandle, - db, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - logger, -}: CompanyOperationHandlerDependencies) { - registerHandle(IPC_CHANNELS.saveMeeting, async (_event, payload) => { - const parsed = meetingInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("meetings", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Meeting not found in the current company."); - } - - let participantAgentIds: string[] = []; - try { - const parsedParticipantIds = JSON.parse(parsed.participantAgentIds); - participantAgentIds = Array.isArray(parsedParticipantIds) - ? parsedParticipantIds.filter((value): value is string => typeof value === "string") - : []; - } catch (err) { - logger.warn(`[ipc/meetings] Meeting participants JSON parse failed:`, err instanceof Error ? err.message : String(err)); - return fail("INVALID_PARTICIPANTS", "Meeting participants must be valid JSON."); - } - - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.organizerAgentId, table: "agents", label: "meeting organizer" }, - ...participantAgentIds.map((agentId) => ({ id: agentId, table: "agents", label: "meeting participant" })), - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - - const id = db.core.knowledge.saveMeeting(parsed); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteMeeting, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("meetings", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Meeting not found in the current company."); - } - db.core.knowledge.deleteMeeting(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-company-operations/reference-tables.ts b/src/main/ipc-company-operations/reference-tables.ts deleted file mode 100644 index 330ef2ed..00000000 --- a/src/main/ipc-company-operations/reference-tables.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const COMPANY_SCOPED_REFERENCE_TABLES = new Set([ - "agents", - "goals", - "projects", - "tasks", - "approvals", - "runs", - "secrets", - "meetings", - "documents", - "knowledge_base", - "sprints", - "automation_rules", - "workflow_pipelines", -]); diff --git a/src/main/ipc-company-operations/sprint-handlers.ts b/src/main/ipc-company-operations/sprint-handlers.ts deleted file mode 100644 index c237a418..00000000 --- a/src/main/ipc-company-operations/sprint-handlers.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { IPC_CHANNELS, deleteEntitySchema, sprintInputSchema } from "@shared/contracts"; -import { fail, ok } from "../ipc-domain-common"; -import type { CompanyOperationHandlerDependencies } from "./types"; - -export function registerSprintHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - dispatchAutomation, - logger, -}: CompanyOperationHandlerDependencies) { - registerHandle(IPC_CHANNELS.saveSprint, async (_event, payload) => { - const parsed = sprintInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (parsed.id && !db.core.settings.belongsToCompany("sprints", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Sprint not found in the current company."); - } - - let previousSprintStatus: string | null = null; - if (parsed.id) { - try { - previousSprintStatus = db.projection.snapshot.listSnapshot().sprints.find((s: { id: string }) => s.id === parsed.id)?.status ?? null; - } catch (err) { - logger.warn(`[ipc/sprints] listSnapshot failed while resolving sprint ${parsed.id} previous status:`, err instanceof Error ? err.message : String(err)); - previousSprintStatus = null; - } - } - - const id = db.core.knowledge.saveSprint(parsed); - if (parsed.status === "active" && previousSprintStatus !== "active") { - dispatchAutomation("sprint_started", { companyId: parsed.companyId }); - } - if (parsed.status === "completed" && previousSprintStatus !== "completed") { - dispatchAutomation("sprint_ended", { companyId: parsed.companyId }); - } - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.deleteSprint, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("sprints", parsed.id, parsed.companyId)) { - return fail("ENTITY_NOT_FOUND", "Sprint not found in the current company."); - } - db.core.knowledge.deleteSprint(parsed.id, parsed.companyId); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-company-operations/types.ts b/src/main/ipc-company-operations/types.ts deleted file mode 100644 index b1172daf..00000000 --- a/src/main/ipc-company-operations/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { RegisterDomainHandlersDependencies } from "../ipc-domain-common"; - -export type CompanyOperationHandlerDependencies = Pick< - RegisterDomainHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "findInvalidReference" - | "publishDomainChanged" - | "dispatchAutomation" - | "threadIntegration" - | "checkpointEngine" - | "lifecycleProcessor" - | "logger" ->; diff --git a/src/main/ipc-core-admin-handlers.ts b/src/main/ipc-core-admin-handlers.ts deleted file mode 100644 index e2ea3e85..00000000 --- a/src/main/ipc-core-admin-handlers.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { execFile } from "node:child_process"; -import { - IPC_CHANNELS, - companyIdSchema, - companyInputSchema, - connectorDisabledModelsSchema, - connectorInputSchema, - deleteEntitySchema, - openTerminalCommandSchema, -} from "@shared/contracts"; -import { validateConnectorConfigurationModel } from "./connector-model-policy"; -import { reconcileExecutionModeChange } from "./execution-mode-reconciler"; -import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; - -/** - * Probe the user's shell PATH for a `node` binary. The onboarding Node - * check uses this to decide whether agents will be able to run the - * "Node.js fetch()" snippets the API prompt-builder emits. Returns the - * shell `node --version` output on success; never surfaces the raw - * `process.version` (that is Electron's bundled Node, not what the - * agent's bash tool will actually invoke). - */ -function probeShellNode(timeoutMs = 3000): Promise<{ installed: boolean; version: string | null }> { - return new Promise((resolve) => { - execFile("node", ["--version"], { timeout: timeoutMs }, (error, stdout) => { - if (error) { - resolve({ installed: false, version: null }); - return; - } - const version = stdout.trim(); - resolve({ installed: version.length > 0, version: version.length > 0 ? version : null }); - }); - }); -} - -export function registerCoreAdminHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - handleApprovalResolved, - checkConnector, - openGenericTerminal, -}: Pick< - RegisterCoreHandlersDependencies, - "registerHandle" | "db" | "ensureCompanyExists" | "publishDomainChanged" | "handleApprovalResolved" | "checkConnector" | "openGenericTerminal" ->) { - registerHandle(IPC_CHANNELS.saveCompany, async (_event, payload) => { - const parsed = companyInputSchema.parse(payload); - const previousMode = parsed.id ? db.core.company.getCompanyExecutionMode(parsed.id) : parsed.executionMode; - const previousApprovalSettings = parsed.id - ? db.core.company.getCompanyApprovalSettings(parsed.id) - : { autoApproveHires: parsed.autoApproveHires, reviewDeliverables: parsed.reviewDeliverables }; - const id = db.core.company.saveCompany(parsed); - reconcileExecutionModeChange({ - db, - companyId: id, - previousExecutionMode: previousMode, - nextExecutionMode: parsed.executionMode, - previousReviewDeliverables: previousApprovalSettings?.reviewDeliverables ?? false, - nextReviewDeliverables: parsed.reviewDeliverables, - handleApprovalResolved, - }); - db.core.activity.addActivity({ - companyId: id, - actor: "board", - action: parsed.id ? "company.updated" : "company.created", - entityType: "company", - entityId: id, - detail: parsed.name, - }); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.setCurrentCompany, async (_event, companyId) => { - const parsed = companyIdSchema.parse(companyId); - if (!db.core.settings.hasCompany(parsed)) { - return fail("COMPANY_NOT_FOUND", "The selected company does not exist."); - } - db.core.settings.setCurrentCompany(parsed); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.saveConnector, async (_event, payload) => { - const parsed = connectorInputSchema.parse(payload); - const connectorConfigValidation = validateConnectorConfigurationModel(parsed.id, parsed.model ?? null); - if (!connectorConfigValidation.ok) { - return fail("CONNECTOR_MODEL_NOT_ALLOWED", connectorConfigValidation.error); - } - // The per-company disabled-models pool is not consulted here — - // connector config is a global hint, and pool enforcement - // happens at run dispatch time where the company is known. - db.core.connectors.saveConnector({ - ...parsed, - model: parsed.model ?? null, - }); - db.core.activity.addActivity({ - companyId: db.core.settings.getCurrentCompanyId() ?? "00000000-0000-0000-0000-000000000000", - actor: "board", - action: "connector.updated", - entityType: "connector", - entityId: parsed.id, - detail: parsed.id, - }); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.testConnector, async (_event, id) => { - const parsed = connectorInputSchema.shape.id.parse(id); - await checkConnector(parsed); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.checkNodeInstalled, async () => { - return ok(await probeShellNode()); - }); - - registerHandle(IPC_CHANNELS.openTerminalCommand, async (_event, payload) => { - const parsed = openTerminalCommandSchema.parse(payload); - await openGenericTerminal(parsed); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.setConnectorDisabledModels, async (_event, payload) => { - const parsed = connectorDisabledModelsSchema.parse(payload); - db.core.settings.setDisabledModels(parsed.companyId, parsed.connectorId, parsed.disabledModels); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.deleteSecret, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("secrets", parsed.id, parsed.companyId)) { - return fail("SECRET_NOT_FOUND", "Secret not found in the current company."); - } - db.core.entity.deleteSecret(parsed.id, parsed.companyId); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: "secret.deleted", - entityType: "secret", - entityId: parsed.id, - detail: "", - }); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.deleteCompany, async (_event, companyId) => { - const parsed = companyIdSchema.parse(companyId); - if (!db.core.settings.hasCompany(parsed)) { - return fail("COMPANY_NOT_FOUND", "Company not found."); - } - db.core.company.deleteCompany(parsed); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-core-agent-graph-handlers.ts b/src/main/ipc-core-agent-graph-handlers.ts deleted file mode 100644 index cd811822..00000000 --- a/src/main/ipc-core-agent-graph-handlers.ts +++ /dev/null @@ -1,325 +0,0 @@ -import { - IPC_CHANNELS, - agentInputSchema, - deleteEntitySchema, - hireRequestSchema, - workspaceInputSchema, -} from "@shared/contracts"; -import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy"; -import { resolveApprovalDecision } from "./approval-policy"; -import { shouldAutoApprove } from "./execution-policy"; -import { getHireNameValidationError, getHireRoutingValidationError, resolveHireReportsTo } from "./agent-permissions"; -import { validateConnectorModelSelection, connectorPolicyDepsFromDb } from "./connector-model-policy"; -import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; - -export function registerCoreAgentGraphHandlers({ - registerHandle, - db, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - handleApprovalResolved, - logger, -}: Pick< - RegisterCoreHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "findInvalidReference" - | "publishDomainChanged" - | "handleApprovalResolved" - | "logger" ->) { - registerHandle(IPC_CHANNELS.saveWorkspace, async (_event, payload) => { - const parsed = workspaceInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.projectId, table: "projects", label: "project" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const id = db.core.workspaces.saveWorkspace(parsed); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.id ? "workspace.updated" : "workspace.created", - entityType: "workspace", - entityId: id, - detail: parsed.localPath, - }); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.saveAgent, async (_event, payload) => { - const parsed = agentInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const isNew = !parsed.id; - if (isNew) { - return fail( - "AGENT_CREATION_REQUIRES_HIRE_REQUEST", - "Create new agents through the hiring workflow so approval, onboarding, and org state stay synchronized.", - ); - } - const existingAgent = parsed.id ? db.core.entity.findAgent(parsed.id) : null; - if (!existingAgent || existingAgent.companyId !== parsed.companyId) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - if (existingAgent.status === "pending_approval") { - return fail( - "AGENT_APPROVAL_REQUIRED", - "Pending hires must be resolved from Hiring or Approvals. Direct edits, deletes, and activation changes are blocked here.", - ); - } - if (parsed.status === "pending_approval") { - return fail( - "AGENT_STATUS_LOCKED", - "Active agents cannot be moved back to pending approval by editing status directly.", - ); - } - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.reportsTo, table: "agents", label: "manager" }, - { id: parsed.workspaceId, table: "workspaces", label: "workspace" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const connectorRecord = db.core.connectors.findConnector(parsed.connectorId); - if (!connectorRecord) { - return fail("CONNECTOR_NOT_FOUND", "The selected connector does not exist."); - } - const connectorIssue = getConnectorExecutionReadinessIssue(connectorRecord); - if (connectorIssue) { - return fail("CONNECTOR_NOT_READY", connectorIssue); - } - const modelSelection = validateConnectorModelSelection(connectorPolicyDepsFromDb(db), parsed.companyId, parsed.connectorId, parsed.model ?? null); - if (!modelSelection.ok) { - return fail("CONNECTOR_MODEL_NOT_ALLOWED", modelSelection.error); - } - let resolvedStatus = parsed.status; - if (resolvedStatus === "paused" && existingAgent.status === "paused" && parsed.budgetMonthlyUsd > 0) { - const spent = existingAgent.spentMonthlyUsd ?? 0; - if (parsed.budgetMonthlyUsd > spent) { - resolvedStatus = "idle"; - } - } - - let id: string; - try { - id = db.core.agents.saveAgent({ - id: parsed.id ?? null, - companyId: parsed.companyId, - name: parsed.name, - role: parsed.role, - title: parsed.title, - department: parsed.department ?? null, - status: resolvedStatus, - reportsTo: parsed.reportsTo ?? null, - connectorId: parsed.connectorId, - workspaceId: parsed.workspaceId ?? null, - model: parsed.model ?? null, - metadataJson: parsed.metadataJson, - capabilities: parsed.capabilities, - budgetMonthlyUsd: parsed.budgetMonthlyUsd, - modelStrategy: "explicit", - }); - } catch (error) { - return fail("INVALID_AGENT_HIERARCHY", error instanceof Error ? error.message : "Agent could not be saved."); - } - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.id ? "agent.updated" : "agent.created", - entityType: "agent", - entityId: id, - detail: parsed.name, - }); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.requestHire, async (_event, payload) => { - const parsed = hireRequestSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const resolvedReportsTo = resolveHireReportsTo( - db, - parsed.companyId, - parsed.requestedByAgentId ?? null, - parsed.reportsTo, - parsed.department ?? null, - ); - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.requestedByAgentId, table: "agents", label: "requesting agent" }, - { id: resolvedReportsTo, table: "agents", label: "manager" }, - { id: parsed.workspaceId, table: "workspaces", label: "workspace" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const connectorRecord = db.core.connectors.findConnector(parsed.connectorId); - if (!connectorRecord) { - return fail("CONNECTOR_NOT_FOUND", "The selected connector does not exist."); - } - const connectorIssue = getConnectorExecutionReadinessIssue(connectorRecord); - if (connectorIssue) { - return fail("CONNECTOR_NOT_READY", connectorIssue); - } - const nameError = getHireNameValidationError({ - name: parsed.name, - role: parsed.role, - title: parsed.title, - }); - if (nameError) { - return fail("INVALID_HIRE_NAME", nameError); - } - const routingError = getHireRoutingValidationError( - db, - parsed.companyId, - parsed.requestedByAgentId ?? null, - parsed.reportsTo, - parsed.department ?? null, - ); - if (routingError) { - return fail("INVALID_HIRE_ROUTING", routingError); - } - const modelSelection = validateConnectorModelSelection(connectorPolicyDepsFromDb(db), parsed.companyId, parsed.connectorId, parsed.model ?? null); - if (!modelSelection.ok) { - return fail("CONNECTOR_MODEL_NOT_ALLOWED", modelSelection.error); - } - const managerLabel = resolvedReportsTo - ? (() => { - try { - return db.core.entity.getAgent(resolvedReportsTo).name; - } catch (err) { - logger.warn(`[ipc/agent-graph] getAgent failed for manager ${resolvedReportsTo}:`, err instanceof Error ? err.message : String(err)); - return resolvedReportsTo; - } - })() - : "the company board"; - const payloadSummary = `Hire ${parsed.name} as ${parsed.role}`; - const impactSummary = parsed.capabilities || `${parsed.name} will report to ${managerLabel}.`; - let result: { agentId: string; approvalId: string }; - try { - result = db.createHireRequest({ - companyId: parsed.companyId, - requestedByAgentId: parsed.requestedByAgentId ?? null, - name: parsed.name, - role: parsed.role, - title: parsed.title, - department: parsed.department ?? null, - reportsTo: resolvedReportsTo, - connectorId: parsed.connectorId, - workspaceId: parsed.workspaceId ?? null, - model: parsed.model ?? null, - metadataJson: parsed.metadataJson, - capabilities: parsed.capabilities, - budgetMonthlyUsd: parsed.budgetMonthlyUsd, - payloadSummary, - impactSummary, - payloadJson: JSON.stringify({ - name: parsed.name, - role: parsed.role, - title: parsed.title, - requestedByAgentId: parsed.requestedByAgentId ?? null, - requestedConfigurationSnapshot: { - connectorId: parsed.connectorId, - workspaceId: parsed.workspaceId ?? null, - model: parsed.model ?? null, - metadataJson: parsed.metadataJson ?? "{}", - capabilities: parsed.capabilities, - budgetMonthlyUsd: parsed.budgetMonthlyUsd, - reportsTo: resolvedReportsTo, - department: parsed.department ?? null, - title: parsed.title, - }, - }), - }); - } catch (error) { - return fail("HIRE_REQUEST_FAILED", error instanceof Error ? error.message : "Hire request could not be created."); - } - - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: parsed.requestedByAgentId ?? "board", - action: "agent.hire_requested", - entityType: "agent", - entityId: result.agentId, - detail: parsed.name, - }); - - let autoApproved = false; - if (shouldAutoApprove(db, parsed.companyId, "hire_agent")) { - resolveApprovalDecision({ - db, - handleApprovalResolved, - companyId: parsed.companyId, - approvalId: result.approvalId, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: "Auto-approved by company policy", - }); - autoApproved = true; - } - - publishDomainChanged(); - return ok({ ...result, autoApproved }); - }); - - registerHandle(IPC_CHANNELS.deleteAgent, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("agents", parsed.id, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - const agent = db.core.entity.getAgent(parsed.id); - if (agent.status === "pending_approval") { - return fail( - "AGENT_APPROVAL_REQUIRED", - "Pending hires cannot be deleted from the agent editor. Reject the hire request from Hiring or Approvals instead.", - ); - } - db.core.agents.deleteAgent(parsed.id, parsed.companyId); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: "agent.deleted", - entityType: "agent", - entityId: parsed.id, - detail: "", - }); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.deleteApproval, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("approvals", parsed.id, parsed.companyId)) { - return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company."); - } - const approval = db.core.approvals.getApprovalRecord(parsed.id); - if (approval.state === "pending" && approval.type === "hire_agent") { - return fail( - "APPROVAL_DELETE_BLOCKED", - "Pending hire approvals cannot be deleted. Reject the hire request instead so the linked agent record stays consistent.", - ); - } - db.core.approvals.deleteApproval(parsed.id, parsed.companyId); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: "approval.deleted", - entityType: "approval", - entityId: parsed.id, - detail: "", - }); - publishDomainChanged(); - return ok(true); - }); -} diff --git a/src/main/ipc-core-common.ts b/src/main/ipc-core-common.ts deleted file mode 100644 index 879ed798..00000000 --- a/src/main/ipc-core-common.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { IpcMainInvokeEvent } from "electron"; -import type { DesktopResult } from "@shared/contracts"; -import type { ConnectorId, DesktopEvent, SectionId } from "@shared/types"; -import type { AppDatabase } from "./database"; - -type CompanyScopedTable = "workspaces" | "agents" | "goals" | "projects" | "tasks" | "approvals" | "runs" | "secrets"; - -export interface RegisterCoreHandlersDependencies { - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; - db: AppDatabase; - ensureCompanyExists: (companyId: string) => DesktopResult | null; - findInvalidReference: ( - companyId: string, - refs: Array<{ id: string | null | undefined; table: CompanyScopedTable; label: string }>, - ) => { id: string | null | undefined; table: CompanyScopedTable; label: string } | null; - publishDomainChanged: () => 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; - handleApprovalCreated: (approvalId: string, companyId: string, taskId: string | null, approvalType: string, summary: string) => void; - handleApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - dispatchAutomation: (trigger: string, ctx: { companyId: string; [key: string]: unknown }) => void; - queueTaskRun: (taskId: string, trigger: string, actor: string) => DesktopResult; - checkConnector: (id: ConnectorId) => Promise; - openGenericTerminal: (input: { commandKey: string }) => Promise; - checkForUpdates: (options?: { manual?: boolean }) => Promise; - getWorkerProcess: () => { postMessage: (message: unknown) => void } | null; - resetAfterRestore: () => void; - listConnectorModels: (connectorId: string) => Promise>; - notify: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string }; batchKey?: string }) => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export function ok(data: T): DesktopResult { - return { ok: true, data }; -} - -export function fail(code: string, message: string): DesktopResult { - return { ok: false, error: { code, message } }; -} diff --git a/src/main/ipc-core-handlers.ts b/src/main/ipc-core-handlers.ts deleted file mode 100644 index ff7fe3cb..00000000 --- a/src/main/ipc-core-handlers.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { RegisterCoreHandlersDependencies } from "./ipc-core-common"; -import { registerCoreAdminHandlers } from "./ipc-core-admin-handlers"; -import { registerCoreOperationHandlers } from "./ipc-core-operations-handlers"; -import { registerCoreReadHandlers } from "./ipc-core-read-handlers"; -import { registerCoreWorkGraphHandlers } from "./ipc-core-work-graph-handlers"; -import { registerThreadHandlers } from "./ipc-thread-handlers"; - -export function registerCoreHandlers(dependencies: RegisterCoreHandlersDependencies) { - registerCoreReadHandlers(dependencies); - registerCoreAdminHandlers(dependencies); - registerCoreWorkGraphHandlers(dependencies); - registerCoreOperationHandlers(dependencies); - registerThreadHandlers(dependencies); -} diff --git a/src/main/ipc-core-operations-handlers.ts b/src/main/ipc-core-operations-handlers.ts deleted file mode 100644 index b52290a5..00000000 --- a/src/main/ipc-core-operations-handlers.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { - IPC_CHANNELS, - approvalDecisionSchema, - approvalInputSchema, - cancelRunSchema, - commentInputSchema, - heartbeatSettingsSchema, - runLogChunkSchema, - runLogSchema, - startRunSchema, - triggerHeartbeatSchema, -} from "@shared/contracts"; -import { resolveApprovalDecision } from "./approval-policy"; -import { shouldAutoApprove } from "./execution-policy"; -import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; - -export function registerCoreOperationHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - emitEvent, - wakeAgentIfPossible, - handleApprovalCreated, - handleApprovalResolved, - dispatchAutomation, - queueTaskRun, - getWorkerProcess, - notify, - logger, -}: Pick< - RegisterCoreHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "publishDomainChanged" - | "emitEvent" - | "wakeAgentIfPossible" - | "handleApprovalCreated" - | "handleApprovalResolved" - | "dispatchAutomation" - | "queueTaskRun" - | "getWorkerProcess" - | "notify" - | "logger" ->) { - registerHandle(IPC_CHANNELS.requestApproval, async (_event, payload) => { - const parsed = approvalInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidTask = parsed.relatedTaskId && !db.core.settings.belongsToCompany("tasks", parsed.relatedTaskId, parsed.companyId); - const invalidAgent = parsed.requestedByAgentId && !db.core.settings.belongsToCompany("agents", parsed.requestedByAgentId, parsed.companyId); - const invalidRelatedAgent = parsed.relatedAgentId && !db.core.settings.belongsToCompany("agents", parsed.relatedAgentId, parsed.companyId); - if (invalidTask || invalidAgent || invalidRelatedAgent) { - return fail("INVALID_COMPANY_REFERENCE", "The approval references data outside the current company."); - } - let id: string; - try { - id = db.core.approvals.requestApproval(parsed); - } catch (error) { - return fail("APPROVAL_INVALID", error instanceof Error ? error.message : "Approval could not be created."); - } - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: parsed.requestedByAgentId ?? "board", - action: "approval.created", - entityType: "approval", - entityId: id, - detail: parsed.payloadSummary, - }); - - // Notify thread integration about the new approval - handleApprovalCreated(id, parsed.companyId, parsed.relatedTaskId ?? null, parsed.type, parsed.payloadSummary ?? ""); - - if (shouldAutoApprove(db, parsed.companyId, parsed.type)) { - resolveApprovalDecision({ - db, - handleApprovalResolved, - companyId: parsed.companyId, - approvalId: id, - state: "approved", - decisionNote: "Auto-approved by company policy", - detail: "Auto-approved by company policy", - }); - publishDomainChanged(); - return ok(id); - } - // Approval was NOT auto-approved — wake decision-makers to review it - dispatchAutomation("approval_created", { - companyId: parsed.companyId, - agentId: parsed.requestedByAgentId ?? undefined, - taskId: parsed.relatedTaskId ?? undefined, - }); - notify({ - title: "Approval Required", - body: parsed.payloadSummary ?? `${parsed.type} approval pending`, - urgency: "critical", - navigation: { section: "approvals", entityId: id }, - batchKey: "pending_approval", - }); - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.decideApproval, async (_event, payload) => { - const parsed = approvalDecisionSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("approvals", parsed.approvalId, parsed.companyId)) { - return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company."); - } - const approval = db.core.approvals.getApprovalRecord(parsed.approvalId); - if (!approval || approval.companyId !== parsed.companyId) { - return fail("APPROVAL_NOT_FOUND", "Approval not found in the current company."); - } - resolveApprovalDecision({ - db, - handleApprovalResolved, - companyId: approval.companyId, - approvalId: approval.id, - state: parsed.state, - decisionNote: parsed.decisionNote, - detail: parsed.decisionNote, - }); - emitEvent({ type: "approval-updated", approvalId: approval.id, action: "decided" }); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.startTaskRun, async (_event, payload) => { - const parsed = startRunSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("tasks", parsed.taskId, parsed.companyId)) { - return fail("TASK_NOT_FOUND", "Task not found in the current company."); - } - return queueTaskRun(parsed.taskId, "manual", "board"); - }); - - registerHandle(IPC_CHANNELS.cancelRun, (_event, payload) => { - const parsed = cancelRunSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("runs", parsed.runId, parsed.companyId)) { - return fail("RUN_NOT_FOUND", "Run not found in the current company."); - } - getWorkerProcess()?.postMessage({ type: "cancel-run", runId: parsed.runId }); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.getRunLog, (_event, payload) => { - const parsed = runLogSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("runs", parsed.runId, parsed.companyId)) { - return fail("RUN_NOT_FOUND", "Run not found in the current company."); - } - return ok(db.core.runs.readRunLog(parsed.runId)); - }); - - registerHandle(IPC_CHANNELS.getRunLogChunk, (_event, payload) => { - const parsed = runLogChunkSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("runs", parsed.runId, parsed.companyId)) { - return fail("RUN_NOT_FOUND", "Run not found in the current company."); - } - return ok(db.core.runs.readRunLogChunk(parsed.runId, parsed.offset, parsed.limit)); - }); - - registerHandle(IPC_CHANNELS.addComment, async (_event, payload) => { - const parsed = commentInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const comment = db.core.activity.addComment({ - companyId: parsed.companyId, - taskId: parsed.taskId, - authorAgentId: parsed.authorAgentId ?? null, - authorName: parsed.authorName, - body: parsed.body, - }); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: parsed.authorAgentId ?? "board", - action: "comment.created", - entityType: "task", - entityId: parsed.taskId, - detail: parsed.body.slice(0, 100), - }); - emitEvent({ type: "agent-message", taskId: parsed.taskId, comment }); - emitEvent({ type: "task-updated", taskId: parsed.taskId, action: "updated" }); - try { - const task = db.core.entity.getTask(parsed.taskId); - if (task.assigneeAgentId) { - wakeAgentIfPossible(task.assigneeAgentId, task.companyId, "comment"); - } - dispatchAutomation("comment_posted", { - companyId: parsed.companyId, - taskId: parsed.taskId, - agentId: parsed.authorAgentId ?? undefined, - }); - } catch (err) { - logger.warn(`[ipc/core-operations] Post-comment wake/dispatch failed for task ${parsed.taskId}:`, err instanceof Error ? err.message : String(err)); - } - return ok(comment.id); - }); - - registerHandle(IPC_CHANNELS.setHeartbeat, async (_event, payload) => { - const parsed = heartbeatSettingsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - db.core.agents.setHeartbeat(parsed.agentId, parsed.enabled, parsed.intervalSec); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.enabled ? "heartbeat.enabled" : "heartbeat.disabled", - entityType: "agent", - entityId: parsed.agentId, - detail: `Interval: ${parsed.intervalSec}s`, - }); - emitEvent({ type: "heartbeat-status", agentId: parsed.agentId, enabled: parsed.enabled, nextWakeAt: null }); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.triggerHeartbeat, async (_event, payload) => { - const parsed = triggerHeartbeatSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("AGENT_NOT_FOUND", "Agent not found in the current company."); - } - const runId = wakeAgentIfPossible(parsed.agentId, parsed.companyId, parsed.trigger); - if (!runId) { - return fail("HEARTBEAT_SKIPPED", "Agent cannot be woken right now (check connector status, budget, or active runs)."); - } - return ok(runId); - }); - -} diff --git a/src/main/ipc-core-read-handlers.ts b/src/main/ipc-core-read-handlers.ts deleted file mode 100644 index 098c38a9..00000000 --- a/src/main/ipc-core-read-handlers.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { dialog, nativeTheme, shell } from "electron"; -import { join } from "node:path"; -import { z } from "zod"; -import { - IPC_CHANNELS, - connectorInputSchema, - connectorModelPoolQuerySchema, - entityGetterSchema, - managedPathInputSchema, - metricsQuerySchema, - settingsSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; -import { logAppError } from "./errors/index.js"; -import { classifyExternalUrl } from "./external-url-policy"; - -async function openExternalUrlWithTrustPolicy(rawUrl: string) { - const decision = classifyExternalUrl(rawUrl); - if (decision.kind === "blocked") { - return fail("OPEN_EXTERNAL_URL_FORBIDDEN", decision.reason); - } - if (decision.kind === "confirm") { - const result = await dialog.showMessageBox({ - type: "question", - buttons: ["Open Link", "Cancel"], - defaultId: 1, - cancelId: 1, - title: "Open External Link?", - message: "AgentCompany blocked an untrusted external link.", - detail: `${decision.url}\n\nOnly trusted product and documentation domains open automatically. Review this destination before continuing.`, - }); - if (result.response !== 0) { - return ok(false); - } - } - const url = decision.url; - const error = await shell.openExternal(url).then(() => "").catch((err: unknown) => err instanceof Error ? err.message : String(err)); - return error ? fail("OPEN_EXTERNAL_URL_FAILED", error) : ok(true); -} - -export function registerCoreReadHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - checkForUpdates, - resetAfterRestore, - listConnectorModels, - logger, -}: Pick< - RegisterCoreHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "publishDomainChanged" - | "checkForUpdates" - | "resetAfterRestore" - | "listConnectorModels" - | "logger" ->) { - function requireCurrentCompanyScope(requestedCompanyId: string) { - const currentCompanyId = db.core.settings.getCurrentCompanyId(); - if (!currentCompanyId) { - return { ok: false as const, error: fail("COMPANY_NOT_SELECTED", "Select a company before opening a managed path.") }; - } - const companyError = ensureCompanyExists(currentCompanyId); - if (companyError) { - return { ok: false as const, error: companyError }; - } - if (requestedCompanyId !== currentCompanyId) { - return { ok: false as const, error: fail("INVALID_COMPANY_REFERENCE", "The requested company must match the current company.") }; - } - return { ok: true as const, companyId: currentCompanyId }; - } - - registerHandle(IPC_CHANNELS.loadSnapshot, () => ok(db.projection.snapshot.listRendererSnapshot())); - - registerHandle(IPC_CHANNELS.pickDirectory, async () => { - const result = await dialog.showOpenDialog({ - properties: ["openDirectory", "createDirectory"], - }); - return ok(result.canceled ? null : (result.filePaths[0] ?? null)); - }); - - registerHandle(IPC_CHANNELS.openPath, async (_event, payload) => { - const parsed = managedPathInputSchema.safeParse(payload); - if (!parsed.success) { - return fail("INVALID_PAYLOAD", "openPath requires { companyId, path }."); - } - const currentScope = requireCurrentCompanyScope(parsed.data.companyId); - if (!currentScope.ok) return currentScope.error; - if (!db.core.settings.canOpenPath(parsed.data.path, currentScope.companyId)) { - return fail("OPEN_PATH_FORBIDDEN", "The requested path is outside the managed desktop workspace."); - } - const error = await shell.openPath(parsed.data.path); - return error ? fail("OPEN_PATH_FAILED", error) : ok(true); - }); - - /** - * openWorkProduct resolves a work_product row to a concrete absolute - * path (or URL) before handing off to the OS shell. The DocumentCenter - * can no longer forward `externalId` straight into `openPath`: that - * column stores a workspace-relative path so artifacts survive a - * workspace-root move, but `shell.openPath` wants an absolute managed - * path. The DB resolver joins the work_product back to its originating - * task → workspace (or run → workspace for taskless runs) so the path - * we hand to the shell is always inside the currently-mounted managed - * tree and passes `canOpenPath` validation. - */ - registerHandle(IPC_CHANNELS.openWorkProduct, async (_event, payload) => { - const parsed = entityGetterSchema.safeParse(payload); - if (!parsed.success) return fail("INVALID_PAYLOAD", "openWorkProduct requires { companyId, id }."); - const currentScope = requireCurrentCompanyScope(parsed.data.companyId); - if (!currentScope.ok) return currentScope.error; - const target = db.core.documents.resolveWorkProductTarget(parsed.data.id, currentScope.companyId); - if (target.kind === "error") { - const codeByReason = { - not_found: "WORK_PRODUCT_NOT_FOUND", - archived: "WORK_PRODUCT_ARCHIVED", - no_target: "WORK_PRODUCT_NO_TARGET", - workspace_unresolved: "WORK_PRODUCT_WORKSPACE_UNRESOLVED", - path_escape: "WORK_PRODUCT_PATH_ESCAPE", - path_missing: "WORK_PRODUCT_PATH_MISSING", - } as const; - if (target.reason === "path_missing") { - db.core.documents.updateWorkProduct(parsed.data.id, currentScope.companyId, { status: "archived" }); - publishDomainChanged(); - } - return fail(codeByReason[target.reason], target.detail); - } - if (target.kind === "url") { - return openExternalUrlWithTrustPolicy(target.value); - } - if (!db.core.settings.canOpenPath(target.value, currentScope.companyId)) { - return fail("OPEN_PATH_FORBIDDEN", "The requested path is outside the managed desktop workspace."); - } - const error = await shell.openPath(target.value); - return error ? fail("OPEN_PATH_FAILED", error) : ok(true); - }); - - registerHandle(IPC_CHANNELS.backupProfile, async () => { - const result = await dialog.showOpenDialog({ - properties: ["openDirectory", "createDirectory"], - }); - if (result.canceled || result.filePaths.length === 0) { - return ok(null); - } - const backupPath = join(result.filePaths[0]!, `agentcompany-backup-${Date.now()}`); - await db.core.backup.exportBackup(backupPath); - return ok(backupPath); - }); - - registerHandle(IPC_CHANNELS.restoreProfile, async () => { - const hasActiveRuns = db.projection.snapshot.listSnapshot().runs.some((run: { status: string }) => run.status === "queued" || run.status === "running"); - if (hasActiveRuns) { - return fail("RESTORE_BLOCKED", "Stop all active runs before restoring a profile backup."); - } - const result = await dialog.showOpenDialog({ - properties: ["openDirectory"], - }); - if (result.canceled || result.filePaths.length === 0) { - return ok(false); - } - await db.core.backup.restoreFromBackup(result.filePaths[0]!); - resetAfterRestore(); - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.updateSettings, async (_event, payload) => { - const parsed = settingsSchema.parse(payload); - db.core.settings.updateSettings(parsed); - if (parsed.theme) { - nativeTheme.themeSource = parsed.theme; - } - publishDomainChanged(); - return ok(true); - }); - - registerHandle(IPC_CHANNELS.checkForUpdates, async () => { - // Invocation via IPC only happens when the user opens Settings and clicks - // "Check for updates". Pass manual:true so the Up-to-Date toast fires. - return ok(await checkForUpdates({ manual: true })); - }); - - registerHandle(IPC_CHANNELS.listConnectorModels, async (_event, connectorId) => { - try { - const parsed = connectorInputSchema.shape.id.parse(connectorId); - return ok(await listConnectorModels(parsed)); - } catch (err) { - logAppError(logger, err, { - kind: "upstream", - code: "ipc.list_connector_models.failed", - message: `listConnectorModels failed for connector ${String(connectorId)}`, - context: { connectorId }, - }, "warn"); - return ok([]); - } - }); - - registerHandle(IPC_CHANNELS.getConnectorDisabledModels, (_event, payload) => { - let parsed: z.infer; - try { - parsed = connectorModelPoolQuerySchema.parse(payload); - } catch (err) { - logAppError(logger, err, { - kind: "user_input", - code: "ipc.get_connector_disabled_models.invalid_payload", - message: "getConnectorDisabledModels rejected payload (schema parse failed)", - }, "warn"); - return ok([]); - } - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - return ok(db.core.settings.getDisabledModels(parsed.companyId, parsed.connectorId)); - }); - - registerHandle(IPC_CHANNELS.getCompanyMetrics, (_event, payload) => { - const input = metricsQuerySchema.parse(payload); - const err = ensureCompanyExists(input.companyId); - if (err) return err; - return ok(db.core.company.getCompanyMetrics(input.companyId, input.days)); - }); - - registerHandle(IPC_CHANNELS.getStandupReport, (_event, payload) => { - const companyId = z.string().uuid().parse(payload); - const err = ensureCompanyExists(companyId); - if (err) return err; - return ok(db.core.company.getStandupReport(companyId)); - }); - - // --- Entity getters for granular IPC updates --- - - registerHandle(IPC_CHANNELS.getTask, (_event, payload) => { - const parsed = entityGetterSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - try { - const task = db.core.entity.getTask(parsed.id); - if (task.companyId !== parsed.companyId) return fail("TASK_NOT_FOUND", "Task not found in current company."); - return ok(task); - } catch (err) { - logAppError(logger, err, { - kind: "recoverable", - code: "ipc.get_task.lookup_failed", - message: `getTask failed for id ${parsed.id}`, - context: { taskId: parsed.id, companyId: parsed.companyId }, - }, "warn"); - return fail("TASK_NOT_FOUND", "Task not found."); - } - }); - - registerHandle(IPC_CHANNELS.getAgent, (_event, payload) => { - const parsed = entityGetterSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - try { - const agent = db.core.entity.getAgent(parsed.id); - if (agent.companyId !== parsed.companyId) return fail("AGENT_NOT_FOUND", "Agent not found in current company."); - return ok(agent); - } catch (err) { - logAppError(logger, err, { - kind: "recoverable", - code: "ipc.get_agent.lookup_failed", - message: `getAgent failed for id ${parsed.id}`, - context: { agentId: parsed.id, companyId: parsed.companyId }, - }, "warn"); - return fail("AGENT_NOT_FOUND", "Agent not found."); - } - }); - - registerHandle(IPC_CHANNELS.getRun, (_event, payload) => { - const parsed = entityGetterSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - try { - const run = db.core.runs.getRun(parsed.id); - if (run.companyId !== parsed.companyId) return fail("RUN_NOT_FOUND", "Run not found in current company."); - return ok(run); - } catch (err) { - logAppError(logger, err, { - kind: "recoverable", - code: "ipc.get_run.lookup_failed", - message: `getRun failed for id ${parsed.id}`, - context: { runId: parsed.id, companyId: parsed.companyId }, - }, "warn"); - return fail("RUN_NOT_FOUND", "Run not found."); - } - }); - - registerHandle(IPC_CHANNELS.getApproval, (_event, payload) => { - const parsed = entityGetterSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - try { - const approval = db.core.approvals.getApprovalRecord(parsed.id); - if (approval.companyId !== parsed.companyId) return fail("APPROVAL_NOT_FOUND", "Approval not found in current company."); - return ok(approval); - } catch (err) { - logAppError(logger, err, { - kind: "recoverable", - code: "ipc.get_approval.lookup_failed", - message: `getApprovalRecord failed for id ${parsed.id}`, - context: { approvalId: parsed.id, companyId: parsed.companyId }, - }, "warn"); - return fail("APPROVAL_NOT_FOUND", "Approval not found."); - } - }); -} diff --git a/src/main/ipc-core-task-graph-handlers.ts b/src/main/ipc-core-task-graph-handlers.ts deleted file mode 100644 index b60826b0..00000000 --- a/src/main/ipc-core-task-graph-handlers.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { - IPC_CHANNELS, - deleteEntitySchema, - goalInputSchema, - projectInputSchema, - taskInputSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; -import { validateTaskCreation, checkCapabilityMatch } from "./task-quality-gates"; -import { resolveTaskWorkspaceBinding } from "./task-workspace-binding"; - -export function registerCoreTaskGraphHandlers({ - registerHandle, - db, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - emitEvent, - wakeAgentIfPossible, - handleTaskCreated, - handleTaskStatusChange, - logger, -}: Pick< - RegisterCoreHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "findInvalidReference" - | "publishDomainChanged" - | "emitEvent" - | "wakeAgentIfPossible" - | "handleTaskCreated" - | "handleTaskStatusChange" - | "logger" ->) { - registerHandle(IPC_CHANNELS.saveGoal, async (_event, payload) => { - const parsed = goalInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.parentId, table: "goals", label: "parent goal" }, - { id: parsed.ownerAgentId, table: "agents", label: "owner agent" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const id = db.core.entity.saveGoal(parsed); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.id ? "goal.updated" : "goal.created", - entityType: "goal", - entityId: id, - detail: parsed.title, - }); - publishDomainChanged(); - if (parsed.status === "active" && parsed.ownerAgentId) { - wakeAgentIfPossible(parsed.ownerAgentId, parsed.companyId, "goal_activated"); - } - return ok(id); - }); - - registerHandle(IPC_CHANNELS.saveProject, async (_event, payload) => { - const parsed = projectInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.goalId, table: "goals", label: "goal" }, - { id: parsed.leadAgentId, table: "agents", label: "lead agent" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const id = db.core.entity.saveProject(parsed); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: parsed.id ? "project.updated" : "project.created", - entityType: "project", - entityId: id, - detail: parsed.name, - }); - if (parsed.leadAgentId) { - wakeAgentIfPossible(parsed.leadAgentId, parsed.companyId, "assignment"); - } - publishDomainChanged(); - return ok(id); - }); - - registerHandle(IPC_CHANNELS.saveTask, async (_event, payload) => { - const parsed = taskInputSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const invalidReference = findInvalidReference(parsed.companyId, [ - { id: parsed.projectId, table: "projects", label: "project" }, - { id: parsed.goalId, table: "goals", label: "goal" }, - { id: parsed.parentId, table: "tasks", label: "parent task" }, - { id: parsed.assigneeAgentId, table: "agents", label: "assignee agent" }, - { id: parsed.workspaceId, table: "workspaces", label: "workspace" }, - ]); - if (invalidReference) { - return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`); - } - const isNew = !parsed.id; - if (isNew) { - const validation = validateTaskCreation(parsed); - if (!validation.valid) { - return fail("TASK_VALIDATION_FAILED", validation.errors.join("; ")); - } - } - let previousStatus: string | null = null; - let previousAssigneeAgentId: string | null = null; - let existingWorkspaceId: string | null = null; - if (!isNew) { - const taskId = parsed.id; - if (!taskId) return fail("INVALID_TASK_STATE", "Task ID required for updates."); - try { - const existingTask = db.core.entity.getTask(taskId); - previousStatus = existingTask.status; - previousAssigneeAgentId = existingTask.assigneeAgentId; - existingWorkspaceId = existingTask.workspaceId; - } catch (err) { - logger.warn(`[ipc/task-graph] getTask failed for ${taskId}; treating as new task:`, err instanceof Error ? err.message : String(err)); - previousStatus = null; - previousAssigneeAgentId = null; - existingWorkspaceId = null; - } - } - let id: string; - try { - const workspaceBinding = resolveTaskWorkspaceBinding(db, { - companyId: parsed.companyId, - requiresFilesystem: parsed.requiresFilesystem, - explicitWorkspaceId: parsed.workspaceId ?? (parsed.requiresFilesystem ? existingWorkspaceId : null), - projectId: parsed.projectId ?? null, - assigneeAgentId: parsed.assigneeAgentId ?? null, - }); - if (!workspaceBinding.ok) { - return fail("INVALID_TASK_STATE", workspaceBinding.error); - } - id = db.core.tasks.saveTask({ - ...parsed, - workspaceId: workspaceBinding.workspaceId, - }); - } catch (error) { - return fail("INVALID_TASK_STATE", error instanceof Error ? error.message : "Task could not be saved."); - } - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: isNew ? "task.created" : "task.updated", - entityType: "task", - entityId: id, - detail: parsed.title, - }); - if (isNew) { - handleTaskCreated(id, parsed.companyId); - } else { - if (previousStatus && previousStatus !== parsed.status) { - handleTaskStatusChange(id, parsed.companyId, previousStatus, parsed.status); - } - // User (board) manually advancing a flagged task to done: clear the review flag - if (parsed.status === "done") { - try { - db.core.tasks.setTaskRequiresUserReview(id, false); - } catch (error) { - logger.warn( - `[ipc-task] setTaskRequiresUserReview(false) failed for task ${id}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - // Wake new assignee when task is reassigned (matches api-server.ts behavior) - if (parsed.assigneeAgentId && parsed.assigneeAgentId !== previousAssigneeAgentId) { - wakeAgentIfPossible(parsed.assigneeAgentId, parsed.companyId, "assignment"); - } - } - let capabilityWarning: string | undefined; - if (isNew && parsed.assigneeAgentId) { - try { - const match = checkCapabilityMatch(db, parsed.assigneeAgentId, parsed.description, parsed.companyId); - if (!match.matched) { - capabilityWarning = match.warning; - } - } catch (error) { - logger.warn( - `[ipc-task] capability check failed for new task ${id} (advisory, not blocking): ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - emitEvent({ type: "task-updated", taskId: id, action: isNew ? "created" : "updated" }); - return ok({ id, capabilityWarning }); - }); - - const deleteHandlers = [ - { channel: IPC_CHANNELS.deleteTask, table: "tasks", entity: "task", deleteFn: (id: string, companyId: string) => db.core.tasks.deleteTask(id, companyId) }, - { channel: IPC_CHANNELS.deleteGoal, table: "goals", entity: "goal", deleteFn: (id: string, companyId: string) => db.core.entity.deleteGoal(id, companyId) }, - { channel: IPC_CHANNELS.deleteProject, table: "projects", entity: "project", deleteFn: (id: string, companyId: string) => db.core.entity.deleteProject(id, companyId) }, - { channel: IPC_CHANNELS.deleteWorkspace, table: "workspaces", entity: "workspace", deleteFn: (id: string, companyId: string) => db.core.workspaces.deleteWorkspace(id, companyId) }, - ] as const; - - for (const { channel, table, entity, deleteFn } of deleteHandlers) { - registerHandle(channel, async (_event, payload) => { - const parsed = deleteEntitySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany(table, parsed.id, parsed.companyId)) { - return fail(`${entity.toUpperCase()}_NOT_FOUND`, `${entity.charAt(0).toUpperCase() + entity.slice(1)} not found in the current company.`); - } - deleteFn(parsed.id, parsed.companyId); - db.core.activity.addActivity({ - companyId: parsed.companyId, - actor: "board", - action: `${entity}.deleted`, - entityType: entity, - entityId: parsed.id, - detail: "", - }); - if (entity === "task") { - emitEvent({ type: "task-updated", taskId: parsed.id, action: "deleted" }); - } else { - publishDomainChanged(); - } - return ok(true); - }); - } -} diff --git a/src/main/ipc-core-work-graph-handlers.ts b/src/main/ipc-core-work-graph-handlers.ts deleted file mode 100644 index 54613fd0..00000000 --- a/src/main/ipc-core-work-graph-handlers.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { RegisterCoreHandlersDependencies } from "./ipc-core-common"; -import { registerCoreAgentGraphHandlers } from "./ipc-core-agent-graph-handlers"; -import { registerCoreTaskGraphHandlers } from "./ipc-core-task-graph-handlers"; - -export function registerCoreWorkGraphHandlers( - deps: Pick< - RegisterCoreHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "findInvalidReference" - | "publishDomainChanged" - | "emitEvent" - | "wakeAgentIfPossible" - | "handleApprovalResolved" - | "handleTaskCreated" - | "handleTaskStatusChange" - | "logger" - >, -) { - registerCoreAgentGraphHandlers({ - registerHandle: deps.registerHandle, - db: deps.db, - ensureCompanyExists: deps.ensureCompanyExists, - findInvalidReference: deps.findInvalidReference, - publishDomainChanged: deps.publishDomainChanged, - handleApprovalResolved: deps.handleApprovalResolved, - logger: deps.logger, - }); - registerCoreTaskGraphHandlers({ - registerHandle: deps.registerHandle, - db: deps.db, - ensureCompanyExists: deps.ensureCompanyExists, - findInvalidReference: deps.findInvalidReference, - publishDomainChanged: deps.publishDomainChanged, - emitEvent: deps.emitEvent, - wakeAgentIfPossible: deps.wakeAgentIfPossible, - handleTaskCreated: deps.handleTaskCreated, - handleTaskStatusChange: deps.handleTaskStatusChange, - logger: deps.logger, - }); -} diff --git a/src/main/ipc-credentials-handlers.ts b/src/main/ipc-credentials-handlers.ts deleted file mode 100644 index 239de0f1..00000000 --- a/src/main/ipc-credentials-handlers.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { ipcMain, type IpcMainInvokeEvent } from "electron"; -import type { SimpleStreamOptions } from "@mariozechner/pi-ai"; -import type { DesktopResult } from "@shared/contracts"; -import { IPC_CHANNELS } from "@shared/contracts"; -import { - removeCredentialInputSchema, - saveCredentialInputSchema, - testCredentialInputSchema, - type CredentialSummary, -} from "@shared/contracts/schemas-credentials"; -import type { DesktopEvent } from "@shared/types"; -import { getConnectorDefinition } from "./connectors"; -import { resolveModel, resolveExtraStreamHeaders } from "./model-resolver"; -import type { CredentialResolver } from "./credentials/credential-resolver"; -import type { CredentialStore } from "./credentials/credential-store"; -import type { StoredCredentialPayload } from "./credentials/types"; -import { ok } from "./ipc-core-common"; -import { classifyUnknownError } from "./errors/index.js"; -import { safeStreamSimpleWithEnv } from "./worker/runtime/pi-safe-stream"; - -/** Strip credential-shaped substrings from an error message before sending it - * back to the renderer. Matches are anchored to issuer-specific prefixes so - * we do not shred diagnostic signals — git SHAs, UUIDs, model identifiers - * like `accounts/fireworks/models/...`, and other high-entropy-but-not-secret - * strings pass through unchanged. */ -function redactSecrets(message: string): string { - return message - .replace(/Bearer\s+[A-Za-z0-9\-_.~+/=]+/gi, "Bearer [REDACTED]") - .replace(/sk-(ant|proj)-[A-Za-z0-9\-_]+/g, "sk-$1-[REDACTED]") - .replace(/sk-[A-Za-z0-9]{20,}/g, "sk-[REDACTED]") - .replace(/AKIA[0-9A-Z]{16}/g, "AKIA[REDACTED]") - .replace(/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[REDACTED-JWT]"); -} - -function describeError(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} - -function isSafeLogToken(value: unknown): value is string { - return typeof value === "string" && /^[A-Za-z0-9._:-]{1,160}$/.test(value); -} - -function safeLogToken(value: unknown, fallback: string): string { - return isSafeLogToken(value) ? value : fallback; -} - -function extractHeader(headers: unknown, name: string): unknown { - if (!headers) return undefined; - if (typeof (headers as { get?: unknown }).get === "function") { - return (headers as { get: (key: string) => unknown }).get(name); - } - if (typeof headers === "object") { - const record = headers as Record; - return record[name] ?? record[name.toLowerCase()] ?? record[name.toUpperCase()]; - } - return undefined; -} - -function readObjectField(source: unknown, field: string): unknown { - if (!source || typeof source !== "object") return undefined; - return (source as Record)[field]; -} - -function extractCredentialErrorCode(error: unknown, fallback: string): string { - const candidates = [ - readObjectField(error, "code"), - readObjectField(error, "errorCode"), - readObjectField(error, "status"), - readObjectField(error, "statusCode"), - error instanceof Error ? error.name : undefined, - ]; - for (const value of candidates) { - if (isSafeLogToken(value)) return value; - if (typeof value === "number" && Number.isInteger(value)) return String(value); - } - return fallback; -} - -function extractCredentialRequestId(error: unknown): string | null { - const response = readObjectField(error, "response"); - const metadata = readObjectField(error, "$metadata"); - const candidates = [ - readObjectField(error, "requestId"), - readObjectField(error, "request_id"), - readObjectField(error, "x-request-id"), - readObjectField(metadata, "requestId"), - extractHeader(readObjectField(error, "headers"), "x-request-id"), - extractHeader(readObjectField(response, "headers"), "x-request-id"), - extractHeader(readObjectField(response, "headers"), "x-amzn-requestid"), - ]; - for (const value of candidates) { - if (isSafeLogToken(value)) return value; - } - return null; -} - -function credentialLogLine(action: string, input: { - connectorId: string; - provider: string | undefined; - code: string; - requestId: string | null; -}): string { - const fields = [ - `connector=${safeLogToken(input.connectorId, "invalid")}`, - `provider=${safeLogToken(input.provider, "unknown")}`, - `code=${safeLogToken(input.code, "unknown")}`, - ]; - if (input.requestId) fields.push(`requestId=${safeLogToken(input.requestId, "invalid")}`); - return `[credentials] ${action}: ${fields.join(" ")}`; -} - -function getConnectorProviderForLog(connectorId: string): string | undefined { - try { - return getConnectorDefinition(connectorId).provider; - } catch { - return undefined; - } -} - -interface CredentialHandlerDeps { - store: CredentialStore; - resolver: CredentialResolver; - emitEvent: (event: DesktopEvent) => void; - /** Refresh the connector's health row after a save/remove so its `status` - * flips between `auth_required` and `ready` immediately, instead of waiting - * for the next bootstrap pass. */ - refreshConnectorHealth: (connectorId: string) => Promise; - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; - fail: (code: string, message: string) => DesktopResult; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; -} - -export function registerCredentialIpcHandlers(deps: CredentialHandlerDeps): () => void { - const channels: string[] = [ - IPC_CHANNELS.credentialsList, - IPC_CHANNELS.credentialsSave, - IPC_CHANNELS.credentialsRemove, - IPC_CHANNELS.credentialsTest, - ]; - - deps.registerHandle(IPC_CHANNELS.credentialsList, async () => { - return ok(deps.store.list()); - }); - - deps.registerHandle(IPC_CHANNELS.credentialsSave, async (_event, raw) => { - const parsed = saveCredentialInputSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - const definition = (() => { - try { return getConnectorDefinition(parsed.data.connectorId); } - catch (e) { return e instanceof Error ? e.message : String(e); } - })(); - if (typeof definition === "string") return deps.fail("UNKNOWN_CONNECTOR", definition); - - const payload = parsed.data.payload; - if (!definition.auth) { - return deps.fail("UNSUPPORTED_PAYLOAD", `Connector ${parsed.data.connectorId} has no auth schema.`); - } - if (definition.auth.type === "oauth") { - return deps.fail("UNSUPPORTED_PAYLOAD", "Use OAuth login flow for OAuth connectors."); - } - if (definition.auth.type !== payload.kind) { - return deps.fail("MISMATCHED_KIND", `Connector ${parsed.data.connectorId} expects ${definition.auth.type} credential.`); - } - try { - const stored = deps.store.save(parsed.data.connectorId, payload as StoredCredentialPayload, null); - await deps.refreshConnectorHealth(parsed.data.connectorId); - deps.emitEvent({ type: "credentials-changed", connectorId: parsed.data.connectorId }); - return ok(stored); - } catch (error) { - const err = classifyUnknownError(error, { - kind: "upstream", - code: "credentials.save.failed", - message: `save failed for ${parsed.data.connectorId}`, - context: { connectorId: parsed.data.connectorId }, - }); - deps.logger.error(credentialLogLine("save failed", { - connectorId: parsed.data.connectorId, - provider: definition.provider, - code: err.code, - requestId: extractCredentialRequestId(error), - })); - return deps.fail("SAVE_FAILED", "Could not save credential. Check application logs for details."); - } - }); - - deps.registerHandle(IPC_CHANNELS.credentialsRemove, async (_event, raw) => { - const parsed = removeCredentialInputSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - try { - deps.store.remove(parsed.data.connectorId); - await deps.refreshConnectorHealth(parsed.data.connectorId); - deps.emitEvent({ type: "credentials-changed", connectorId: parsed.data.connectorId }); - return ok(true); - } catch (error) { - const err = classifyUnknownError(error, { - kind: "upstream", - code: "credentials.remove.failed", - message: `remove failed for ${parsed.data.connectorId}`, - context: { connectorId: parsed.data.connectorId }, - }); - deps.logger.error(credentialLogLine("remove failed", { - connectorId: parsed.data.connectorId, - provider: getConnectorProviderForLog(parsed.data.connectorId), - code: err.code, - requestId: extractCredentialRequestId(error), - })); - return deps.fail("REMOVE_FAILED", "Could not remove credential. Check application logs for details."); - } - }); - - deps.registerHandle(IPC_CHANNELS.credentialsTest, async (_event, raw) => { - const parsed = testCredentialInputSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - let definition; - try { - definition = getConnectorDefinition(parsed.data.connectorId); - } catch (error) { - const err = classifyUnknownError(error, { - kind: "user_input", - code: "credentials.test.unknown_connector", - message: `test failed lookup for ${parsed.data.connectorId}`, - context: { connectorId: parsed.data.connectorId }, - }); - deps.logger.error(credentialLogLine("test failed", { - connectorId: parsed.data.connectorId, - provider: undefined, - code: err.code, - requestId: extractCredentialRequestId(error), - })); - return deps.fail("UNKNOWN_CONNECTOR", "Unknown connector."); - } - let resolved; - try { - resolved = await deps.resolver.resolve(parsed.data.connectorId); - } catch (error) { - const err = classifyUnknownError(error, { - kind: "upstream", - code: "credentials.test.resolve_failed", - message: `test resolve failed for ${parsed.data.connectorId}`, - context: { connectorId: parsed.data.connectorId }, - }); - const message = describeError(error); - deps.logger.error(credentialLogLine("test failed", { - connectorId: parsed.data.connectorId, - provider: definition.provider, - code: extractCredentialErrorCode(error, err.code), - requestId: extractCredentialRequestId(error), - })); - return ok({ ok: false, message: redactSecrets(message) }); - } - - const runTest = async (): Promise> => { - try { - if (!definition.provider) { - return ok({ ok: false, message: `Connector ${parsed.data.connectorId} has no pi-ai provider id configured.` }); - } - if (!definition.defaultModel) { - return ok({ ok: false, message: `Connector ${parsed.data.connectorId} has no default model configured.` }); - } - const provider = definition.provider; - const defaultModel = definition.defaultModel; - const model = resolveModel(provider, defaultModel, { baseUrl: resolved.baseUrl }); - if (!model) return ok({ ok: false, message: `Unknown model ${defaultModel} for provider ${provider}` }); - const extraHeaders = resolveExtraStreamHeaders(provider, resolved.apiKey); - const options: SimpleStreamOptions = { - apiKey: resolved.apiKey, - maxTokens: 1, - ...(extraHeaders ? { headers: extraHeaders } : {}), - }; - const stream = safeStreamSimpleWithEnv( - model, - { - systemPrompt: "Reply with the single character 'k'.", - messages: [{ role: "user", content: "ping", timestamp: Date.now() }], - }, - options, - resolved.extraEnv, - ); - const final = await stream.result(); - if (final.stopReason === "error" || final.stopReason === "aborted") { - const message = final.errorMessage ?? `Provider returned ${final.stopReason}.`; - deps.logger.warn(credentialLogLine("test failed", { - connectorId: parsed.data.connectorId, - provider, - code: final.stopReason === "error" ? "stream_error" : "stream_aborted", - requestId: null, - })); - return ok({ ok: false, message: redactSecrets(message) }); - } - return ok({ ok: true, message: `OK (${model.id})` }); - } catch (error) { - const message = describeError(error); - deps.logger.error(credentialLogLine("test failed", { - connectorId: parsed.data.connectorId, - provider: definition.provider, - code: extractCredentialErrorCode(error, "stream_exception"), - requestId: extractCredentialRequestId(error), - })); - return ok({ ok: false, message: redactSecrets(message) }); - } - }; - - return runTest(); - }); - - return () => { - for (const channel of channels) ipcMain.removeHandler(channel); - }; -} diff --git a/src/main/ipc-domain-common.ts b/src/main/ipc-domain-common.ts deleted file mode 100644 index db8a8c9d..00000000 --- a/src/main/ipc-domain-common.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { IpcMainInvokeEvent } from "electron"; -import { z } from "zod"; -import type { DesktopResult } from "@shared/contracts"; -import type { bootstrapOnboardingSchema } from "@shared/contracts"; -import type { AgentMessageRecord, DesktopEvent, SectionId } from "@shared/types"; -import type { AppDatabase } from "./database"; -import type { createSkillService } from "./skill-service"; -import type { createBudgetEnforcementService } from "./budget-enforcement-service"; -import type { CheckpointEngineLike } from "./document-lifecycle"; -import type { DocumentLifecycleProcessor } from "./document-lifecycle-processor"; -import type { ThreadIntegrationService } from "./thread-integration"; - -interface BrowserActionControl { - clearSocialAccountData: (socialAccountId: string, screenshotPaths?: string[]) => Promise; - cancelAction: (actionId: string) => boolean; - launchLoginBrowser: (socialAccountId: string, platform: string, loginUrl?: string) => Promise<{ - success: boolean; - cancelled: boolean; - summary: string; - screenshotPath: string | null; - error: string | null; - }>; - extractProfileFromSession: (socialAccountId: string, platform: string) => Promise<{ - accountName: string; - displayName: string; - }>; -} - -export interface RegisterDomainHandlersDependencies { - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; - db: AppDatabase; - logger: { - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - ensureCompanyExists: (companyId: string) => DesktopResult | null; - findInvalidReference: ( - companyId: string, - refs: Array<{ id: string | null | undefined; table: string; label: string }>, - ) => { id: string | null | undefined; table: string; label: string } | null; - publishDomainChanged: () => void; - emitEvent: (event: DesktopEvent) => void; - notify: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string }; batchKey?: string }) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - injectRuntimeMessage: (recipientAgentId: string, companyId: string, message: AgentMessageRecord) => boolean; - dispatchAutomation: (trigger: string, ctx: { companyId: string; [key: string]: unknown }) => void; - runWorkflowPipeline: (workflowId: string, companyId: string) => Promise; - bootstrapOnboarding: (input: z.infer) => unknown; - getBrowserActions: () => BrowserActionControl | null; - randomFallbackCompanyId: () => string; - skillService: ReturnType | null; - budgetService: ReturnType | null; - /** Called when a human sends a message to resolve thread wait states. */ - onHumanMessage?: (companyId: string, toAgentId?: string | null, threadId?: string | null, waitStateId?: string | null) => void; - /** - * Shared document-creation lifecycle collaborators. Routed through the - * dependency bag so both the IPC save path and the HTTP save path call - * the same `createDocumentWithLifecycle` fan-out. - */ - threadIntegration: ThreadIntegrationService; - checkpointEngine: CheckpointEngineLike; - lifecycleProcessor: Pick; -} - -export { ok, fail } from "./ipc-core-common"; diff --git a/src/main/ipc-domain-handlers.ts b/src/main/ipc-domain-handlers.ts deleted file mode 100644 index 9cd8e7fb..00000000 --- a/src/main/ipc-domain-handlers.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { RegisterDomainHandlersDependencies } from "./ipc-domain-common"; -import { registerAgentCoordinationHandlers } from "./ipc-agent-coordination-handlers"; -import { registerAutomationOperationsHandlers } from "./ipc-automation-operations-handlers"; -import { registerBrowserHandlers } from "./ipc-browser-handlers"; -import { registerCompanyOperationsHandlers } from "./ipc-company-operations/index"; -import { registerOnboardingHandlers } from "./ipc-onboarding-handlers"; -import { registerRecoveryHandlers } from "./ipc-recovery-handlers"; -import { registerSkillHandlers } from "./ipc-skill-handlers"; -import { registerBudgetHandlers } from "./ipc-budget-handlers"; - -export function registerDomainHandlers(dependencies: RegisterDomainHandlersDependencies) { - registerOnboardingHandlers(dependencies); - registerBrowserHandlers(dependencies); - registerCompanyOperationsHandlers(dependencies); - registerAutomationOperationsHandlers(dependencies); - registerAgentCoordinationHandlers(dependencies); - registerRecoveryHandlers(dependencies); - registerSkillHandlers({ - registerHandle: dependencies.registerHandle, - ensureCompanyExists: dependencies.ensureCompanyExists, - publishDomainChanged: dependencies.publishDomainChanged, - skillService: dependencies.skillService, - db: dependencies.db, - logger: dependencies.logger, - }); - registerBudgetHandlers({ - registerHandle: dependencies.registerHandle, - ensureCompanyExists: dependencies.ensureCompanyExists, - publishDomainChanged: dependencies.publishDomainChanged, - budgetService: dependencies.budgetService, - db: dependencies.db, - logger: dependencies.logger, - }); -} diff --git a/src/main/ipc-oauth-handlers.ts b/src/main/ipc-oauth-handlers.ts deleted file mode 100644 index 465b9780..00000000 --- a/src/main/ipc-oauth-handlers.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { ipcMain, type IpcMainInvokeEvent } from "electron"; -import type { DesktopResult } from "@shared/contracts"; -import { IPC_CHANNELS } from "@shared/contracts"; -import { - oauthCancelInputSchema, - oauthManualCodeResponseSchema, - oauthPromptResponseSchema, - oauthStartInputSchema, -} from "@shared/contracts/schemas-oauth"; -import type { OAuthLoginService } from "./credentials/oauth-login-service"; -import { ok } from "./ipc-core-common"; - -interface OAuthHandlerDeps { - service: OAuthLoginService; - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; - fail: (code: string, message: string) => DesktopResult; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; -} - -export function registerOAuthIpcHandlers(deps: OAuthHandlerDeps): () => void { - const channels: string[] = [ - IPC_CHANNELS.oauthStart, - IPC_CHANNELS.oauthCancel, - IPC_CHANNELS.oauthPromptResponse, - IPC_CHANNELS.oauthManualCodeResponse, - ]; - - deps.registerHandle(IPC_CHANNELS.oauthStart, async (_event, raw) => { - const parsed = oauthStartInputSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - deps.service.start(parsed.data.connectorId).catch((error) => { - deps.logger.warn(`[oauth] login flow ended: ${error instanceof Error ? error.message : String(error)}`); - }); - return ok(true); - }); - - deps.registerHandle(IPC_CHANNELS.oauthCancel, async (_event, raw) => { - const parsed = oauthCancelInputSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - deps.service.cancel(parsed.data.connectorId); - return ok(true); - }); - - deps.registerHandle(IPC_CHANNELS.oauthPromptResponse, async (_event, raw) => { - const parsed = oauthPromptResponseSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - const accepted = deps.service.submitPromptResponse(parsed.data.requestId, parsed.data.value); - return ok(accepted); - }); - - deps.registerHandle(IPC_CHANNELS.oauthManualCodeResponse, async (_event, raw) => { - const parsed = oauthManualCodeResponseSchema.safeParse(raw); - if (!parsed.success) return deps.fail("INVALID_INPUT", parsed.error.message); - const accepted = deps.service.submitManualCode(parsed.data.requestId, parsed.data.code); - return ok(accepted); - }); - - return () => { - for (const channel of channels) ipcMain.removeHandler(channel); - }; -} diff --git a/src/main/ipc-onboarding-handlers.ts b/src/main/ipc-onboarding-handlers.ts deleted file mode 100644 index 4615e5b7..00000000 --- a/src/main/ipc-onboarding-handlers.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - IPC_CHANNELS, - bootstrapOnboardingSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; - -export function registerOnboardingHandlers({ - registerHandle, - bootstrapOnboarding, -}: Pick< - RegisterDomainHandlersDependencies, - "registerHandle" | "bootstrapOnboarding" ->) { - registerHandle(IPC_CHANNELS.bootstrapOnboarding, (_event, payload) => { - const input = bootstrapOnboardingSchema.parse(payload); - try { - return ok(bootstrapOnboarding(input)); - } catch (error) { - return fail("ONBOARDING_BOOTSTRAP_FAILED", error instanceof Error ? error.message : "Unable to bootstrap onboarding."); - } - }); -} diff --git a/src/main/ipc-recovery-handlers.ts b/src/main/ipc-recovery-handlers.ts deleted file mode 100644 index 0a6c9281..00000000 --- a/src/main/ipc-recovery-handlers.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IPC_CHANNELS, recoveryRetrySchema, recoveryTaskSchema } from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; - -export function registerRecoveryHandlers({ - registerHandle, - db, - ensureCompanyExists, - publishDomainChanged, - wakeAgentIfPossible, - logger, -}: Pick< - RegisterDomainHandlersDependencies, - | "registerHandle" - | "db" - | "ensureCompanyExists" - | "publishDomainChanged" - | "wakeAgentIfPossible" - | "logger" ->) { - registerHandle(IPC_CHANNELS.recoveryRetry, async (_event, payload) => { - const parsed = recoveryRetrySchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("tasks", parsed.taskId, parsed.companyId)) { - return fail("TASK_NOT_FOUND", "Task not found in the current company."); - } - db.core.tasks.retryInterruptedTask(parsed.taskId, parsed.agentId, parsed.companyId); - try { - wakeAgentIfPossible(parsed.agentId, parsed.companyId, "retry_interrupted"); - } catch (err) { - logger.warn(`[ipc/recovery] wakeAgentIfPossible failed for agent ${parsed.agentId}:`, err instanceof Error ? err.message : String(err)); - } - publishDomainChanged(); - return ok(null); - }); - - registerHandle(IPC_CHANNELS.recoveryFail, async (_event, payload) => { - const parsed = recoveryTaskSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("tasks", parsed.taskId, parsed.companyId)) { - return fail("TASK_NOT_FOUND", "Task not found in the current company."); - } - db.core.tasks.markInterruptedTaskFailed(parsed.taskId); - publishDomainChanged(); - return ok(null); - }); -} diff --git a/src/main/ipc-skill-handlers.ts b/src/main/ipc-skill-handlers.ts deleted file mode 100644 index 061c93cf..00000000 --- a/src/main/ipc-skill-handlers.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { join } from "node:path"; -import { readFile } from "node:fs/promises"; -import { - IPC_CHANNELS, - importSkillSchema, - listSkillsSchema, - getSkillDetailSchema, - getSkillMarkdownSchema, - deleteSkillSchema, - assignSkillToAgentSchema, - removeSkillFromAgentSchema, - checkSkillUpdateSchema, - listSkillAgentsSchema, - listAgentSkillsSchema, -} from "@shared/contracts"; -import { fail, ok, type RegisterDomainHandlersDependencies } from "./ipc-domain-common"; -import type { createSkillService } from "./skill-service"; -import type { AppDatabase } from "./database"; - -interface SkillHandlerDependencies extends Pick< - RegisterDomainHandlersDependencies, - "registerHandle" | "ensureCompanyExists" | "publishDomainChanged" | "logger" -> { - skillService: ReturnType | null; - db: AppDatabase; -} - -export function registerSkillHandlers({ - registerHandle, - ensureCompanyExists, - publishDomainChanged, - skillService, - db, - logger, -}: SkillHandlerDependencies) { - function requireSkillService(): - | { service: NonNullable; error?: undefined } - | { service?: undefined; error: ReturnType } { - if (!skillService) { - return { error: fail("SERVICE_NOT_READY", "Skill service is not initialized.") }; - } - return { service: skillService }; - } - - // ---- Import skill from source (GitHub URL, local path, raw URL, skills.sh) ---- - registerHandle(IPC_CHANNELS.importSkill, async (_event, payload) => { - const parsed = importSkillSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - const result = await svc.importFromSource(parsed.companyId, parsed.source); - if (result.ok) { - publishDomainChanged(); - } - return result; - }); - - // ---- List all skills for a company (also scans workspace .agents/skills/) ---- - registerHandle(IPC_CHANNELS.listSkills, async (_event, payload) => { - const parsed = listSkillsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - // Scan workspace .agents/skills/ directories for new skills before listing - try { - await svc.scanWorkspaceSkills(parsed.companyId); - } catch (err) { - logger.warn(`[ipc/skills] scanWorkspaceSkills failed for company ${parsed.companyId}:`, err instanceof Error ? err.message : String(err)); - } - return ok(svc.listForCompany(parsed.companyId)); - }); - - // ---- Get skill detail ---- - registerHandle(IPC_CHANNELS.getSkillDetail, async (_event, payload) => { - const parsed = getSkillDetailSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - return svc.getDetail(parsed.companyId, parsed.skillId); - }); - - // ---- Read SKILL.md body live from disk ---- - registerHandle(IPC_CHANNELS.getSkillMarkdown, async (_event, payload) => { - const parsed = getSkillMarkdownSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - const dir = svc.skillFilesDir(parsed.companyId, parsed.slug); - const path = join(dir, "SKILL.md"); - try { - const content = await readFile(path, "utf-8"); - return ok(content); - } catch (err) { - const e = err as NodeJS.ErrnoException; - if (e.code === "ENOENT") { - return fail("SKILL_NOT_FOUND", `SKILL.md not found at ${path}`); - } - return fail("SKILL_READ_FAILED", e.message ?? String(err)); - } - }); - - // ---- Delete a skill ---- - registerHandle(IPC_CHANNELS.deleteSkill, async (_event, payload) => { - const parsed = deleteSkillSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - const result = await svc.deleteSkill(parsed.companyId, parsed.skillId); - if (result.ok) { - publishDomainChanged(); - } - return result; - }); - - // ---- Assign skill to agent ---- - registerHandle(IPC_CHANNELS.assignSkillToAgent, async (_event, payload) => { - const parsed = assignSkillToAgentSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - const result = svc.assignToAgent(parsed.companyId, parsed.agentId, parsed.skillId); - if (result.ok) { - publishDomainChanged(); - } - return result; - }); - - // ---- Remove skill from agent ---- - registerHandle(IPC_CHANNELS.removeSkillFromAgent, async (_event, payload) => { - const parsed = removeSkillFromAgentSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - const result = svc.removeFromAgent(parsed.companyId, parsed.agentId, parsed.skillId); - if (result.ok) { - publishDomainChanged(); - } - return result; - }); - - // ---- Check if skill has update available ---- - registerHandle(IPC_CHANNELS.checkSkillUpdate, async (_event, payload) => { - const parsed = checkSkillUpdateSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - const svcResult = requireSkillService(); - if (svcResult.error) return svcResult.error; - const svc = svcResult.service; - return svc.checkUpdateStatus(parsed.companyId, parsed.skillId); - }); - - // ---- List agent IDs assigned to a skill ---- - registerHandle(IPC_CHANNELS.listSkillAgents, async (_event, payload) => { - const parsed = listSkillAgentsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.skills.getCompanySkill(parsed.companyId, parsed.skillId)) { - return fail("not_found", `Skill ${parsed.skillId} not found`); - } - return ok(db.core.skills.listSkillAgentAssignments(parsed.companyId, parsed.skillId)); - }); - - // ---- List skill IDs assigned to an agent ---- - registerHandle(IPC_CHANNELS.listAgentSkills, async (_event, payload) => { - const parsed = listAgentSkillsSchema.parse(payload); - const companyError = ensureCompanyExists(parsed.companyId); - if (companyError) return companyError; - if (!db.core.settings.belongsToCompany("agents", parsed.agentId, parsed.companyId)) { - return fail("not_found", `Agent ${parsed.agentId} not found`); - } - return ok(db.core.skills.listAgentSkillAssignments(parsed.companyId, parsed.agentId)); - }); -} diff --git a/src/main/ipc-support.ts b/src/main/ipc-support.ts deleted file mode 100644 index 9edef637..00000000 --- a/src/main/ipc-support.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { IpcMainInvokeEvent, BrowserWindow } from "electron"; -import { ipcMain, Notification } from "electron"; -import { ZodError } from "zod"; -import type { DesktopEvent } from "@shared/types"; -import type { DesktopResult } from "@shared/contracts"; -import type { NotificationOptions } from "./notification-service"; -import { classifyUnknownError } from "./errors/index.js"; - -interface IpcSupportDependencies { - isDev: boolean; - devServerOrigin: string | null; - logger: { - error: (...args: unknown[]) => void; - }; - getMainWindow: () => BrowserWindow | null; - getDb: () => { - hasCompany: (companyId: string) => boolean; - belongsToCompany: (table: string, id: string, companyId: string) => boolean; - }; - notificationService?: { notify: (options: NotificationOptions) => void }; -} - -function isTrustedRendererUrl(url: string, isDev: boolean, devServerOrigin: string | null) { - if (!url) { - return false; - } - let parsed: URL; - try { - parsed = new URL(url); - } catch { - return false; - } - if (isDev) { - return devServerOrigin ? parsed.origin === devServerOrigin : false; - } - return parsed.protocol === "app:" && parsed.hostname === "-"; -} - -export function createIpcSupport({ - isDev, - devServerOrigin, - logger, - getMainWindow, - getDb, - notificationService, -}: IpcSupportDependencies) { - function sanitizeHandlerError(classified: { code: string }) { - if (classified.code === "ipc.payload.invalid") { - return { - code: classified.code, - message: "The desktop request payload is invalid.", - }; - } - return { - code: classified.code, - message: "The desktop operation failed. Use the error code when reporting this issue.", - }; - } - - function fail(code: string, message: string): DesktopResult { - return { ok: false, error: { code, message } }; - } - - function registerHandle( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) { - ipcMain.handle(channel, async (event, ...args) => { - const senderUrl = event.senderFrame?.url ?? event.sender.getURL(); - if (!isTrustedRendererUrl(senderUrl, isDev, devServerOrigin)) { - logger.error(`[ipc:${channel}] blocked untrusted sender ${senderUrl || ""}`); - return fail("IPC_FORBIDDEN", "IPC sender is not allowed."); - } - try { - return await handler(event, ...args); - } catch (error) { - const classified = classifyUnknownError(error, { - kind: error instanceof ZodError ? "user_input" : "upstream", - code: error instanceof ZodError ? "ipc.payload.invalid" : "ipc.handler.failed", - message: `IPC handler ${channel} threw`, - context: { channel }, - }); - const rawMessage = error instanceof Error ? error.message : String(error); - const sanitized = sanitizeHandlerError(classified); - logger.error(`[${classified.code}] [ipc:${channel}] ${rawMessage}`); - return fail(sanitized.code, sanitized.message); - } - }); - } - - // Transport-layer failures when the renderer is mid-reload or already - // disposed throw "Render frame was disposed before WebFrameMain could - // be accessed" out of Electron's IPC core. Those exceptions are a - // lifecycle signal, never a logic bug — but if they bubble, they - // abort every downstream event in the same tick (RuntimeBridge fans - // two emits per agent-event, the second one never runs when the first - // throws). Treat emitEvent as a fire-and-forget sink: renderer - // disappearances are silent, real serialisation errors are warned - // once per event type. - const renderFrameDisposedMessage = "Render frame was disposed"; - const emitWarnedChannels = new Set(); - - function emitEvent(event: DesktopEvent) { - const mainWindow = getMainWindow(); - if (!mainWindow || mainWindow.isDestroyed()) return; - const webContents = mainWindow.webContents; - if (webContents.isDestroyed() || webContents.isCrashed()) return; - // `mainFrame.detached` flips true while the frame is being torn down - // or swapped during a navigation. Sending into a detached frame is - // what makes Electron's native layer throw "Render frame was - // disposed" and also what makes its own WebFrameMain.prototype.send - // spam `console.error('Error sending from webFrameMain: ', …)` to - // stderr on every call. Short-circuiting here closes the window - // between our `isDestroyed` check and the native send. - const mainFrame = webContents.mainFrame; - if (!mainFrame || mainFrame.detached) return; - try { - webContents.send("agent-company:event", event); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - if (message.includes(renderFrameDisposedMessage)) { - // Renderer is reloading or gone — expected; skip. - return; - } - const key = event.type ?? ""; - const classified = classifyUnknownError(error, { - kind: "recoverable", - code: "ipc.emit_event.send_failed", - message: `emitEvent(${key}) failed`, - context: { eventType: key }, - }); - if (!emitWarnedChannels.has(key)) { - emitWarnedChannels.add(key); - logger.error(`[${classified.code}] ${classified.message}: ${message}`); - } - } - } - - function ensureCompanyExists(companyId: string) { - return getDb().hasCompany(companyId) - ? null - : fail("COMPANY_NOT_FOUND", "The selected company no longer exists."); - } - - function findInvalidReference( - companyId: string, - refs: Array<{ id: string | null | undefined; table: string; label: string }>, - ) { - return refs.find((ref) => ref.id && !getDb().belongsToCompany(ref.table, ref.id, companyId)) ?? null; - } - - function publishDomainChanged() { - emitEvent({ type: "domain-changed" }); - } - - function notify(options: NotificationOptions) { - if (notificationService) { - notificationService.notify(options); - } else if (Notification.isSupported()) { - // Fallback for early bootstrap before notification service is wired - new Notification({ title: options.title, body: options.body }).show(); - } - } - - return { - fail, - registerHandle, - emitEvent, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - notify, - }; -} diff --git a/src/main/ipc-thread-handlers.ts b/src/main/ipc-thread-handlers.ts deleted file mode 100644 index 2359af3e..00000000 --- a/src/main/ipc-thread-handlers.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - IPC_CHANNELS, - listThreadEventsSchema, - listThreadParticipantsSchema, - listThreadWaitStatesSchema, - threadGetterSchema, -} from "@shared/contracts"; -import type { RegisterCoreHandlersDependencies } from "./ipc-core-common"; -import { fail, ok } from "./ipc-core-common"; - -export function registerThreadHandlers({ registerHandle, db, ensureCompanyExists }: RegisterCoreHandlersDependencies) { - registerHandle(IPC_CHANNELS.getThread, async (_event, payload) => { - const input = threadGetterSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const thread = db.core.threads.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found"); - return ok(thread); - }); - - registerHandle(IPC_CHANNELS.listThreadEvents, async (_event, payload) => { - const input = listThreadEventsSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const events = db.core.threads.listThreadEvents(input.threadId, input.companyId, { - limit: input.limit, - offset: input.offset, - }); - return ok(events); - }); - - registerHandle(IPC_CHANNELS.listThreadWaitStates, async (_event, payload) => { - const input = listThreadWaitStatesSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const waitStates = db.core.threads.listThreadWaitStates(input.companyId, { resolvedOnly: input.resolvedOnly }); - return ok(waitStates); - }); - - registerHandle(IPC_CHANNELS.listThreadParticipants, async (_event, payload) => { - const input = listThreadParticipantsSchema.parse(payload); - const companyError = ensureCompanyExists(input.companyId); - if (companyError) return companyError; - const thread = db.core.threads.getThread(input.threadId, input.companyId); - if (!thread) return fail("THREAD_NOT_FOUND", "Thread not found"); - const participants = db.core.threads.listParticipants(input.threadId); - return ok(participants); - }); -} diff --git a/src/main/main-process-setup.ts b/src/main/main-process-setup.ts deleted file mode 100644 index ad1603eb..00000000 --- a/src/main/main-process-setup.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { delimiter as PATH_DELIMITER } from "node:path"; -import { app, protocol } from "electron"; - -function listExtraPathEntries() { - return ( - process.platform === "win32" - ? [ - `${process.env.LOCALAPPDATA ?? ""}\\Programs`, - `${process.env.APPDATA ?? ""}\\npm`, - `${process.env.USERPROFILE ?? ""}\\.cargo\\bin`, - `${process.env.USERPROFILE ?? ""}\\.local\\bin`, - `${process.env.USERPROFILE ?? ""}\\.bun\\bin`, - ] - : [ - "/usr/local/bin", - "/opt/homebrew/bin", - "/opt/homebrew/sbin", - `${process.env.HOME}/.local/bin`, - `${process.env.HOME}/.cargo/bin`, - `${process.env.HOME}/.nvm/current/bin`, - `${process.env.HOME}/.volta/bin`, - `${process.env.HOME}/.bun/bin`, - "/usr/local/sbin", - "/snap/bin", - ] - ).filter((entry) => entry && !entry.includes("undefined")); -} - -function prependCommonCliPaths() { - const currentPath = process.env.PATH ?? ""; - const existing = new Set(currentPath.split(PATH_DELIMITER).filter(Boolean)); - const toAdd = listExtraPathEntries().filter((entry) => !existing.has(entry)); - if (toAdd.length === 0) { - return; - } - process.env.PATH = [...toAdd, currentPath].join(PATH_DELIMITER); -} - -function registerPrivilegedSchemes() { - protocol.registerSchemesAsPrivileged([ - { - scheme: "app", - privileges: { - secure: true, - standard: true, - supportFetchAPI: true, - stream: true, - }, - }, - ]); -} - -export function configureMainProcess(appName: string) { - app.name = appName; - app.enableSandbox(); - prependCommonCliPaths(); - registerPrivilegedSchemes(); -} diff --git a/src/main/main-runtime-support.ts b/src/main/main-runtime-support.ts deleted file mode 100644 index f1862dab..00000000 --- a/src/main/main-runtime-support.ts +++ /dev/null @@ -1,276 +0,0 @@ -import log from "electron-log/main.js"; -import type { AgentApiServer } from "./api-server"; -import { initializeAgentTokenSigningKey } from "./agent-auth"; -import { bootstrapApplication } from "./bootstrap-application"; -import { openGenericTerminal as openGenericTerminalImpl } from "./connector-auth-service"; -import type { ConnectorId } from "@shared/types"; -import type { AppDatabase } from "./database"; -import { seedDefaultAutomationRules as seedDefaultAutomationRulesImpl } from "./default-automation-rules"; -import { registerCoreHandlers } from "./ipc-core-handlers"; -import { registerDomainHandlers } from "./ipc-domain-handlers"; -import { registerCredentialIpcHandlers } from "./ipc-credentials-handlers"; -import { registerOAuthIpcHandlers } from "./ipc-oauth-handlers"; -import { fail } from "./ipc-core-common"; -import type { ThreadIntegrationService } from "./thread-integration"; -import type { createCheckpointEngine } from "./checkpoint-engine"; -import type { DocumentLifecycleProcessor } from "./document-lifecycle-processor"; - -type BootstrapResult = Awaited>; - -interface MainRuntimeState { - db: AppDatabase | null; - apiServer: AgentApiServer | null; - serviceGraph: BootstrapResult["serviceGraph"] | null; - ipcSupport: BootstrapResult["ipcSupport"] | null; - threadIntegration: ThreadIntegrationService | null; - checkpointEngine: ReturnType | null; - lifecycleProcessor: DocumentLifecycleProcessor | null; -} - -export function createMainRuntimeSupport(state: MainRuntimeState) { - function requireDb() { - if (!state.db) { - throw new Error("Database is not initialized."); - } - return state.db; - } - - function requireServiceGraph() { - if (!state.serviceGraph) { - throw new Error("Service graph is not initialized."); - } - return state.serviceGraph; - } - - function requireIpcSupport() { - if (!state.ipcSupport) { - throw new Error("IPC support is not initialized."); - } - return state.ipcSupport; - } - - function requireAutomationService() { - const service = requireServiceGraph().getAutomationService(); - if (!service) { - throw new Error("Automation service is not initialized."); - } - return service; - } - - function requireBrowserActionService() { - const service = requireServiceGraph().getBrowserActionService(); - if (!service) { - throw new Error("Browser action service is not initialized."); - } - return service; - } - - function requireConnectorHealthService() { - const service = requireServiceGraph().getConnectorHealthService(); - if (!service) { - throw new Error("Connector health service is not initialized."); - } - return service; - } - - function requireOnboardingService() { - const service = requireServiceGraph().getOnboardingService(); - if (!service) { - throw new Error("Onboarding service is not initialized."); - } - return service; - } - - function requireOrchestrationService() { - const service = requireServiceGraph().getOrchestrationService(); - if (!service) { - throw new Error("Orchestration service is not initialized."); - } - return service; - } - - function requireUpdaterService() { - const service = requireServiceGraph().getUpdaterService(); - if (!service) { - throw new Error("Updater service is not initialized."); - } - return service; - } - - function requireThreadIntegration() { - if (!state.threadIntegration) { - throw new Error("Thread integration service is not initialized."); - } - return state.threadIntegration; - } - - function requireCheckpointEngine() { - if (!state.checkpointEngine) { - throw new Error("Checkpoint engine is not initialized."); - } - return state.checkpointEngine; - } - - function requireLifecycleProcessor() { - if (!state.lifecycleProcessor) { - throw new Error("Document lifecycle processor is not initialized."); - } - return state.lifecycleProcessor; - } - - function emitEvent(event: Parameters[0]) { - requireIpcSupport().emitEvent(event); - } - - function publishDomainChanged() { - requireIpcSupport().publishDomainChanged(); - } - - function ensureCompanyExists(companyId: string) { - return requireIpcSupport().ensureCompanyExists(companyId); - } - - function findInvalidReference( - companyId: string, - refs: T[], - ) { - return requireIpcSupport().findInvalidReference(companyId, refs) as T | null; - } - - function seedDefaultAutomationRules(companyId: string) { - const db = requireDb(); - seedDefaultAutomationRulesImpl(companyId, { - listAutomationRuleNames: (targetCompanyId) => db.automation.rules.listAutomationRuleNames(targetCompanyId), - saveAutomationRule: (input) => db.automation.rules.saveAutomationRule(input), - }); - } - - function registerHandlers() { - registerCoreHandlers({ - registerHandle: requireIpcSupport().registerHandle, - db: requireDb(), - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - emitEvent, - wakeAgentIfPossible: (agentId, companyId, trigger) => - requireOrchestrationService().wakeAgentIfPossible(agentId, companyId, trigger), - handleTaskCreated: (taskId, companyId) => requireAutomationService().handleTaskCreated(taskId, companyId), - handleTaskStatusChange: (taskId, companyId, previousStatus, newStatus) => - requireAutomationService().handleTaskStatusChange(taskId, companyId, previousStatus, newStatus), - handleApprovalCreated: (approvalId, companyId, taskId, approvalType, summary) => { - state.threadIntegration?.onApprovalCreated(approvalId, companyId, taskId, approvalType, summary); - }, - handleApprovalResolved: (approvalId, companyId, decision) => { - requireAutomationService().handleApprovalResolved(approvalId, companyId, decision); - state.threadIntegration?.onApprovalResolved(approvalId, companyId, decision); - }, - dispatchAutomation: (trigger, ctx) => requireAutomationService().dispatchAutomation(trigger, ctx), - queueTaskRun: (taskId, trigger, actor) => - requireOrchestrationService().queueTaskRun(taskId, trigger, actor), - checkConnector: async (id) => requireConnectorHealthService().checkConnector(id), - openGenericTerminal: (input) => openGenericTerminalImpl(input), - checkForUpdates: () => requireUpdaterService().checkForUpdates(), - getWorkerProcess: () => requireServiceGraph().getWorkerService()?.getWorker() ?? null, - resetAfterRestore: () => { - initializeAgentTokenSigningKey(requireDb().profileDir); - void requireBrowserActionService().resetBrowserManager(); - }, - notify: (options) => requireIpcSupport().notify(options), - listConnectorModels: async (connectorId) => { - // This IPC returns the raw provider catalog (pi-ai + curated - // Fireworks additions). Pool / disabled-model filtering is a - // company-scoped concern and happens in the renderer once the - // user has selected a company; the onboarding path uses this - // catalog directly because no company exists yet. - const { getConnectorDefinition } = await import("./connectors"); - const { resolveModels, fetchLocalConnectorModels } = await import("./model-resolver"); - const definition = getConnectorDefinition(connectorId as ConnectorId); - if (definition.auth.type === "local") { - // Local servers' catalogs depend on the user's installed/loaded - // models. Read the saved baseUrl and ask the server directly. - const piRuntime = requireServiceGraph().getPiRuntime(); - const credentials = piRuntime?.credentialStore.read(connectorId); - const baseUrl = credentials?.kind === "local" ? credentials.value.baseUrl : null; - if (!baseUrl) return []; - const models = await fetchLocalConnectorModels(baseUrl); - return models.map((m) => ({ id: m.id, label: m.name })); - } - return resolveModels(definition.provider).map((m) => ({ id: m.id, label: m.name })); - }, - logger: log, - }); - - registerDomainHandlers({ - registerHandle: requireIpcSupport().registerHandle, - db: requireDb(), - logger: log, - ensureCompanyExists, - findInvalidReference, - publishDomainChanged, - emitEvent, - notify: (options) => requireIpcSupport().notify(options), - wakeAgentIfPossible: (agentId, companyId, trigger) => - requireOrchestrationService().wakeAgentIfPossible(agentId, companyId, trigger), - injectRuntimeMessage: (recipientAgentId, companyId, message) => { - const injector = requireServiceGraph().getRuntimeMessageInjector(); - if (!injector) return false; - try { - return injector.tryInject(recipientAgentId, companyId, message); - } catch (error) { - log.warn( - `[ipc-domain] runtime message injection failed for agent ${recipientAgentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return false; - } - }, - dispatchAutomation: (trigger, ctx) => requireAutomationService().dispatchAutomation(trigger, ctx), - runWorkflowPipeline: (workflowId, companyId) => - requireAutomationService().runWorkflowPipeline(workflowId, companyId), - bootstrapOnboarding: (input) => requireOnboardingService().bootstrapOnboarding(input), - getBrowserActions: () => requireServiceGraph().getBrowserActionService(), - randomFallbackCompanyId: () => requireConnectorHealthService().randomFallbackCompanyId(), - skillService: requireServiceGraph().getOrCreateSkillService(), - budgetService: requireServiceGraph().getOrCreateBudgetEnforcementService(), - onHumanMessage: (companyId: string, toAgentId?: string | null, threadId?: string | null, waitStateId?: string | null) => { - if (state.threadIntegration) { - state.threadIntegration.onHumanMessage(companyId, toAgentId, threadId, waitStateId); - } - publishDomainChanged(); - }, - threadIntegration: requireThreadIntegration(), - checkpointEngine: requireCheckpointEngine(), - lifecycleProcessor: requireLifecycleProcessor(), - }); - - const piRuntime = requireServiceGraph().getPiRuntime(); - if (!piRuntime) { - throw new Error("Pi-mono runtime services are not initialized."); - } - - registerCredentialIpcHandlers({ - store: piRuntime.credentialStore, - resolver: piRuntime.credentialResolver, - registerHandle: requireIpcSupport().registerHandle, - emitEvent, - refreshConnectorHealth: async (connectorId) => { - await requireConnectorHealthService().checkConnector(connectorId as ConnectorId); - }, - fail, - logger: log, - }); - - registerOAuthIpcHandlers({ - service: piRuntime.oauthLoginService, - registerHandle: requireIpcSupport().registerHandle, - fail, - logger: log, - }); - } - - return { - publishDomainChanged, - seedDefaultAutomationRules, - registerHandlers, - }; -} diff --git a/src/main/main-runtime.ts b/src/main/main-runtime.ts deleted file mode 100644 index 664e369c..00000000 --- a/src/main/main-runtime.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { app } from "electron"; -import { AgentApiServer, createApiServer } from "./api-server"; -import { createAgentToken, initializeAgentTokenSigningKey } from "./agent-auth"; -import { bootstrapApplication } from "./bootstrap-application"; -import { AppDatabase } from "./database"; -import { createMainRuntimeSupport } from "./main-runtime-support"; -import type { ThreadIntegrationService } from "./thread-integration"; -import type { createCheckpointEngine } from "./checkpoint-engine"; -import type { DocumentLifecycleProcessor } from "./document-lifecycle-processor"; - -interface CreateMainRuntimeDependencies { - hasSingleInstanceLock: boolean; - isDev: boolean; - devServerOrigin: string | null; - profileDir: string; - windowStatePath: string; - preloadPath: string; - rendererDist: string; - iconPath: string; - workerPath: string; - devServerUrl?: string; -} - -export function createMainRuntime({ - hasSingleInstanceLock, - isDev, - devServerOrigin, - profileDir, - windowStatePath, - preloadPath, - rendererDist, - iconPath, - workerPath, - devServerUrl, -}: CreateMainRuntimeDependencies) { - const state: { - db: AppDatabase | null; - apiServer: AgentApiServer | null; - serviceGraph: Awaited>["serviceGraph"] | null; - ipcSupport: Awaited>["ipcSupport"] | null; - threadIntegration: ThreadIntegrationService | null; - checkpointEngine: ReturnType | null; - lifecycleProcessor: DocumentLifecycleProcessor | null; - isQuitting: boolean; - } = { - db: null, - apiServer: null, - serviceGraph: null, - ipcSupport: null, - threadIntegration: null, - checkpointEngine: null, - lifecycleProcessor: null, - isQuitting: false, - }; - const support = createMainRuntimeSupport(state); - - async function bootstrap() { - await bootstrapApplication({ - hasSingleInstanceLock, - isDev, - devServerOrigin, - profileDir, - appDatabaseFactory: (targetProfileDir) => new AppDatabase(targetProfileDir, { isPackaged: app.isPackaged, appVersion: app.getVersion() }), - initSigningKey: initializeAgentTokenSigningKey, - windowStatePath, - preloadPath, - rendererDist, - iconPath, - devServerUrl, - workerPath, - createApiServer: (db, callbacks, allowedOrigins) => - createApiServer(db, callbacks, allowedOrigins), - createRunToken: createAgentToken, - seedDefaultAutomationRules: support.seedDefaultAutomationRules, - isQuittingRef: { - get current() { - return state.isQuitting; - }, - set current(value: boolean) { - state.isQuitting = value; - }, - }, - onRuntimeReady: ({ db, apiServer, serviceGraph, ipcSupport, threadIntegration, checkpointEngine, lifecycleProcessor }) => { - state.db = db; - state.apiServer = apiServer; - state.serviceGraph = serviceGraph; - state.ipcSupport = ipcSupport; - state.threadIntegration = threadIntegration; - state.checkpointEngine = checkpointEngine; - state.lifecycleProcessor = lifecycleProcessor; - // Register IPC handlers immediately so the renderer can call loadSnapshot() - // as soon as the window appears — before connector health checks finish. - support.registerHandlers(); - }, - }); - } - - return { - bootstrap, - }; -} diff --git a/src/main/main-warning-suppression-rules.ts b/src/main/main-warning-suppression-rules.ts deleted file mode 100644 index f8e0ad59..00000000 --- a/src/main/main-warning-suppression-rules.ts +++ /dev/null @@ -1,53 +0,0 @@ -export type WarningSuppressionCategory = - | "node-sqlite-experimental-warning" - | "electron-disposed-web-frame-send"; - -interface SuppressionRule { - category: WarningSuppressionCategory; - reason: string; - matches: (input: TInput) => boolean; -} - -export const WARNING_SUPPRESSION_RULES: ReadonlyArray> = [ - { - category: "node-sqlite-experimental-warning", - reason: "Node emits this before the local SQLite profile store can run; the runtime version pins the API surface.", - matches: isSqliteExperimentalWarning, - }, -]; - -export const CONSOLE_ERROR_SUPPRESSION_RULES: ReadonlyArray> = [ - { - category: "electron-disposed-web-frame-send", - reason: "Electron logs a send to a disposed renderer frame during close, reload, or HMR after the send has become a no-op.", - matches: isDisposedWebFrameSend, - }, -]; - -export function classifyWarningSuppression(warning: unknown): WarningSuppressionCategory | null { - return WARNING_SUPPRESSION_RULES.find((rule) => rule.matches(warning))?.category ?? null; -} - -export function classifyConsoleErrorSuppression(args: unknown[]): WarningSuppressionCategory | null { - return CONSOLE_ERROR_SUPPRESSION_RULES.find((rule) => rule.matches(args))?.category ?? null; -} - -function isSqliteExperimentalWarning(warning: unknown): boolean { - if (typeof warning === "string") { - return /SQLite is an experimental feature/.test(warning); - } - if (warning instanceof Error) { - return warning.name === "ExperimentalWarning" && /SQLite/.test(warning.message); - } - return false; -} - -function isDisposedWebFrameSend(args: unknown[]): boolean { - if (args.length === 0) return false; - const first = args[0]; - if (typeof first !== "string") return false; - if (!first.startsWith("Error sending from webFrameMain")) return false; - const payload = args[1]; - const message = payload instanceof Error ? payload.message : String(payload ?? ""); - return message.includes("Render frame was disposed"); -} diff --git a/src/main/messaging/dispatch.ts b/src/main/messaging/dispatch.ts deleted file mode 100644 index 6db68932..00000000 --- a/src/main/messaging/dispatch.ts +++ /dev/null @@ -1,399 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { AgentMessageRecord, DesktopEvent, MessageChannel, MentionResult, SectionId } from "@shared/types"; -import { normalizeMarkdownText } from "@shared/markdown-text"; - -/** - * The board reader / human participant ID. - * When a human sends a message, this is used as the fromAgentId in the - * underlying agent_messages record. Matches BOARD_READER_ID in database.ts. - */ -export const HUMAN_SENDER_ID = "__board__"; - -/** Map message priority to notification urgency. Extracted so future priority - * classes (e.g. "critical") do not drift between message-dispatch and other - * notification call-sites. */ -export function priorityToUrgency(priority: string | null | undefined): "critical" | "informational" { - return priority === "urgent" ? "critical" : "informational"; -} - -export interface AgentMessageDispatchInput { - companyId: string; - /** Agent ID of the sender. Use HUMAN_SENDER_ID for human-originated messages. */ - fromAgentId: string; - toAgentId?: string | null; - channel?: MessageChannel; - channelTargetId?: string | null; - subject?: string | null; - body: string; - priority?: "urgent" | "normal" | "low"; - parentMessageId?: string | null; - threadId?: string | null; - attachmentsJson?: string; - /** When true, the sender is a human user (fromAgentId === HUMAN_SENDER_ID). */ - fromHumanUser?: boolean; - /** Optional: target a specific thread wait state for precise checkpoint resolution. */ - waitStateId?: string | null; -} - -export interface NormalizedAgentMessageInput { - companyId: string; - fromAgentId: string; - toAgentId: string | null; - channel: MessageChannel; - channelTargetId: string | null; - subject: string; - body: string; - priority: "urgent" | "normal" | "low"; - parentMessageId: string | null; - threadId: string | null; - attachmentsJson: string; - fromHumanUser: boolean; - waitStateId: string | null; -} - -export interface MessageValidationError { - code: - | "DIRECT_MESSAGE_RECIPIENT_REQUIRED" - | "SELF_DIRECT_MESSAGE_FORBIDDEN" - | "NON_DIRECT_MESSAGE_RECIPIENT_FORBIDDEN" - | "INVALID_COMPANY_REFERENCE" - | "CHANNEL_TARGET_REQUIRED" - | "PARENT_MESSAGE_NOT_FOUND"; - message: string; -} - -export interface DispatchAgentMessageDependencies { - db: AppDatabase; - publishDomainChanged?: () => void; - wakeAgentIfPossible?: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - /** - * Attempts to route a persisted message into the recipient's live pi - * run via `agent.steer()`. Returns true when delivery happened, false - * when the recipient has no active run. When true, dispatch skips - * `wakeAgentIfPossible` for that recipient because the message is - * already in-flight inside the agent loop. - */ - injectRuntimeMessage?: (recipientAgentId: string, companyId: string, message: AgentMessageRecord) => boolean; - emitEvent?: (event: DesktopEvent) => void; - notify?: (options: { title: string; body: string; urgency: "critical" | "informational"; navigation?: { section: SectionId; entityId?: string }; batchKey?: string }) => void; - /** Called when a human user sends a message. Resolves thread wait states scoped by waitStateId, threadId, or recipient. */ - onHumanMessage?: (companyId: string, toAgentId?: string | null, threadId?: string | null, waitStateId?: string | null) => void; -} - -export interface DispatchAgentMessageResult { - id: string; - message: AgentMessageRecord | null; - wakeTargets: string[]; - mentionResults: MentionResult[]; -} - -function normalizeString(value: string | null | undefined): string { - return value?.trim() ?? ""; -} - -function truncateForNotification(value: string, maxLength: number): string { - return value.length > maxLength ? `${value.slice(0, maxLength - 1)}…` : value; -} - -function normalizeChannelTargetId(channel: MessageChannel, channelTargetId: string | null | undefined): string | null { - const target = normalizeString(channelTargetId); - if (channel === "department" || channel === "project") { - return target || null; - } - return null; -} - -export function normalizeAgentMessageInput(input: AgentMessageDispatchInput): NormalizedAgentMessageInput { - const channel = input.channel ?? "direct"; - const subject = normalizeString(input.subject) || "(no subject)"; - const priority = input.priority ?? "normal"; - const toAgentId = normalizeString(input.toAgentId) || null; - const channelTargetId = normalizeChannelTargetId(channel, input.channelTargetId); - const parentMessageId = normalizeString(input.parentMessageId) || null; - const threadId = normalizeString(input.threadId) || null; - const attachmentsJson = normalizeString(input.attachmentsJson) || "[]"; - const fromHumanUser = input.fromHumanUser === true || input.fromAgentId === HUMAN_SENDER_ID; - - return { - companyId: input.companyId, - fromAgentId: fromHumanUser ? HUMAN_SENDER_ID : input.fromAgentId, - toAgentId, - channel, - channelTargetId, - subject, - body: normalizeMarkdownText(input.body), - priority, - parentMessageId, - threadId, - attachmentsJson, - fromHumanUser, - waitStateId: normalizeString(input.waitStateId) || null, - }; -} - -export function validateAgentMessageInput( - db: AppDatabase, - input: NormalizedAgentMessageInput, -): MessageValidationError | null { - // Human sender (BOARD_READER_ID) is always a valid sender — skip agent ownership check. - if (!input.fromHumanUser && !db.core.settings.belongsToCompany("agents", input.fromAgentId, input.companyId)) { - return { - code: "INVALID_COMPANY_REFERENCE", - message: "The message sender does not belong to the current company.", - }; - } - - if (input.channel === "direct" && !input.toAgentId) { - return { - code: "DIRECT_MESSAGE_RECIPIENT_REQUIRED", - message: "Direct messages require a recipient agent.", - }; - } - if (input.channel === "direct" && input.toAgentId === input.fromAgentId) { - return { - code: "SELF_DIRECT_MESSAGE_FORBIDDEN", - message: "Direct messages require two distinct participants.", - }; - } - if (input.channel !== "direct" && input.toAgentId) { - return { - code: "NON_DIRECT_MESSAGE_RECIPIENT_FORBIDDEN", - message: "Only direct messages may set a recipient agent.", - }; - } - - if (input.toAgentId && input.toAgentId !== HUMAN_SENDER_ID && !db.core.settings.belongsToCompany("agents", input.toAgentId, input.companyId)) { - return { - code: "INVALID_COMPANY_REFERENCE", - message: "The message recipient does not belong to the current company.", - }; - } - - if (input.channel === "project") { - if (!input.channelTargetId) { - return { - code: "CHANNEL_TARGET_REQUIRED", - message: "Project messages require a project channel target.", - }; - } - if (!db.core.settings.belongsToCompany("projects", input.channelTargetId, input.companyId)) { - return { - code: "INVALID_COMPANY_REFERENCE", - message: "The selected project channel does not belong to the current company.", - }; - } - } - - if (input.channel === "department" && !input.channelTargetId) { - return { - code: "CHANNEL_TARGET_REQUIRED", - message: "Department messages require a department channel target.", - }; - } - - if (input.parentMessageId) { - const parentMessage = db.core.messages.getAgentMessage(input.parentMessageId, input.companyId); - if (!parentMessage) { - return { - code: "PARENT_MESSAGE_NOT_FOUND", - message: "The parent message was not found in the current company.", - }; - } - } - - return null; -} - -function resolveProjectWakeTargets( - db: AppDatabase, - input: NormalizedAgentMessageInput, -): string[] { - if (!input.channelTargetId) return []; - const project = db.core.entity.getProjectForUpdate(input.channelTargetId, input.companyId); - const participantIds = new Set(); - if (project?.leadAgentId) participantIds.add(project.leadAgentId); - for (const assigneeId of db.core.tasks.listProjectTaskAssigneeIds(input.channelTargetId, input.companyId)) { - participantIds.add(assigneeId); - } - - if (participantIds.size === 0) return []; - const ids = Array.from(participantIds).filter((id) => id !== input.fromAgentId); - if (ids.length === 0) return []; - return db.core.agents.listActiveAgentIdsFromIds(input.companyId, ids); -} - -/** Resolve the agents mentioned in a message body, stripped of the - * sender and the human-reader sentinel so downstream consumers never - * have to redo those filters. Shared between wake-target resolution - * and the mention persistence path so both see the same set. */ -export function resolveMentionedAgentIds( - db: AppDatabase, - input: Pick, -): string[] { - const mentioned = db.core.agents.findMentionedAgentIds(input.companyId, input.body); - const filtered: string[] = []; - for (const agentId of mentioned) { - if (!agentId || agentId === input.fromAgentId || agentId === HUMAN_SENDER_ID) continue; - filtered.push(agentId); - } - return filtered; -} - -export function resolveMessageWakeTargets( - db: AppDatabase, - input: NormalizedAgentMessageInput, - mentionedAgentIds?: readonly string[], -): string[] { - const wakeTargets = new Set(); - const mentioned = mentionedAgentIds ?? resolveMentionedAgentIds(db, input); - const hasExplicitMentions = mentioned.length > 0; - - if (input.channel === "direct" && input.toAgentId && input.toAgentId !== input.fromAgentId) { - // Chatroom semantics: when the body carries explicit @mentions, the - // mention list is the recipient list. The DM's `toAgentId` is only - // woken if the sender named them; otherwise the named agent takes - // over the turn and the DM partner "keeps working" — exactly the - // behaviour the operator asks for when they say "@CEO 更新一下进度" - // inside a chat with 张工程师 and expects CEO (not 张工程师) to - // answer. With no mentions, preserve the historical "DM always - // wakes the recipient" contract so every existing flow is intact. - if (!hasExplicitMentions || mentioned.includes(input.toAgentId)) { - wakeTargets.add(input.toAgentId); - } - } - - if (input.channel === "department" && input.channelTargetId) { - for (const agentId of db.core.agents.listDepartmentAgentIds(input.companyId, input.channelTargetId)) { - if (agentId !== input.fromAgentId) wakeTargets.add(agentId); - } - } - - if (input.channel === "company") { - // Company channel is Slack-semantics: every active agent in the - // workspace is a listener. Board-only fan-outs use the dedicated - // `incident` channel; the previous top-level-only fan-out made the - // "company" label a misnomer that silently dropped ICs. - for (const agentId of db.core.agents.listCompanyBroadcastAgentIds(input.companyId)) { - if (agentId !== input.fromAgentId) wakeTargets.add(agentId); - } - } - - if (input.channel === "project") { - for (const agentId of resolveProjectWakeTargets(db, input)) { - wakeTargets.add(agentId); - } - } - - if (input.channel === "incident") { - for (const agentId of db.core.agents.listIncidentPingableAgentIds(input.companyId)) { - if (agentId !== input.fromAgentId) wakeTargets.add(agentId); - } - } - - for (const mentionedId of mentioned) { - wakeTargets.add(mentionedId); - } - - // The human participant (`__board__`) is a reader, not a wake-able - // agent: it has no runtime, no heartbeat, no DB row. Leaving it in the - // set makes `wakeAgentIfPossible` call `db.core.entity.getAgent("__board__")`, - // which throws "Agent not found" and spams the log. Filter once, at - // the point of resolution, so every downstream consumer is clean. - wakeTargets.delete(HUMAN_SENDER_ID); - - return Array.from(wakeTargets); -} - -export function dispatchAgentMessage( - deps: DispatchAgentMessageDependencies, - rawInput: AgentMessageDispatchInput, - wakeTrigger = "message", -): { ok: true; data: DispatchAgentMessageResult } | { ok: false; error: MessageValidationError } { - const normalized = normalizeAgentMessageInput(rawInput); - const validationError = validateAgentMessageInput(deps.db, normalized); - if (validationError) { - return { ok: false, error: validationError }; - } - - const senderKind = normalized.fromHumanUser ? "human" as const : "agent" as const; - // Compute @mentions once per dispatch and hand them to both the DB - // writer (so `agent_message_mentions` is populated atomically with - // the row) and the wake resolver (so the wake fan-out uses the same - // set). Two lookups would waste a regex pass and allow the set to - // drift under mid-dispatch edits. - const mentionedAgentIds = resolveMentionedAgentIds(deps.db, normalized); - const persistedMessage = normalized.channel === "direct" - ? { ...normalized, senderKind, mentionedAgentIds } - : { ...normalized, toAgentId: null, senderKind, mentionedAgentIds }; - const id = deps.db.core.messages.sendAgentMessage(persistedMessage); - const message = deps.db.core.messages.getAgentMessage(id, normalized.companyId); - if (message && deps.emitEvent) { - deps.emitEvent({ type: "new-message", message }); - } - deps.publishDomainChanged?.(); - - if ( - message && - deps.notify && - !normalized.fromHumanUser && - (message.channel !== "direct" || message.toAgentId === HUMAN_SENDER_ID) - ) { - const senderName = deps.db.core.agents.findAgentName(message.fromAgentId) ?? "Agent"; - deps.notify({ - title: truncateForNotification(`${senderName} · ${message.subject}`, 80), - body: truncateForNotification(message.body, 140), - urgency: priorityToUrgency(message.priority), - navigation: { section: "communication", entityId: message.id }, - batchKey: "agent_message", - }); - } - - // When a human sends a message, resolve thread wait states. - // Resolution uses precision hierarchy: waitStateId > threadId > toAgentId > company-wide - if (normalized.fromHumanUser) { - deps.onHumanMessage?.(normalized.companyId, normalized.toAgentId, normalized.threadId, normalized.waitStateId); - } - - const wakeTargets = resolveMessageWakeTargets(deps.db, normalized, mentionedAgentIds); - const mentionResults: MentionResult[] = []; - - if (deps.wakeAgentIfPossible) { - const agentNameRows = deps.db.core.agents.listAgentNamesByIds(normalized.companyId, wakeTargets); - const agentNameMap = new Map(agentNameRows.map((a) => [a.id, a.name])); - for (const wakeTarget of wakeTargets) { - const agentName = agentNameMap.get(wakeTarget) ?? wakeTarget; - // Prefer live-loop injection: if the recipient is currently running - // a pi turn, the message lands in its steering queue and is - // observed within one turn. When no active run exists, fall back to - // the inbox + wake pipeline so a sleeping agent is woken with the - // message queued for its next `prepareRun` cycle. - const injected = message && deps.injectRuntimeMessage - ? deps.injectRuntimeMessage(wakeTarget, normalized.companyId, message) - : false; - if (injected) { - mentionResults.push({ agentId: wakeTarget, agentName, outcome: "woken" }); - continue; - } - const runId = deps.wakeAgentIfPossible(wakeTarget, normalized.companyId, wakeTrigger); - const hasQueuedWake = !runId && deps.db.automation.wakeup.listWakeupRequests(normalized.companyId, { - agentId: wakeTarget, - limit: 10, - }).some((request) => request.status === "queued" || request.status === "deferred"); - mentionResults.push({ - agentId: wakeTarget, - agentName, - outcome: runId ? "woken" : hasQueuedWake ? "queued" : "busy", - }); - } - } - - return { - ok: true, - data: { - id, - message, - wakeTargets, - mentionResults, - }, - }; -} diff --git a/src/main/messaging/index.ts b/src/main/messaging/index.ts deleted file mode 100644 index 9232dc99..00000000 --- a/src/main/messaging/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Barrel for the messaging layer. `dispatch` handles wire-in between - * the API server, thread runtime, and the DB; `normalize` sanitises - * comment bodies before they are projected into a prompt. Storage - * itself lives in `database/messages.ts` and stays there — the - * messaging/ directory covers runtime behaviour around that store, not - * the SQL. - */ - -export * from "./dispatch"; -export * from "./normalize"; diff --git a/src/main/messaging/normalize.ts b/src/main/messaging/normalize.ts deleted file mode 100644 index 5c6fd123..00000000 --- a/src/main/messaging/normalize.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Message Normalization Layer - * - * Normalizes comments before they are injected into agent prompts. - * Prevents malformed, empty, or excessively long content from degrading - * model output quality. Inspired by Reference/src/utils/messages.ts. - * - * Applied at the prompt-builder boundary — the last point before content - * enters the model's context window. - * - * Inter-agent messages no longer flow through a prompt block; they are - * projected directly into the recipient's pi session transcript. See - * `agent-runtime/inbox-projection.ts`. - */ - -/** Maximum comment body length in prompt context. */ -const MAX_COMMENT_BODY_LENGTH = 500; - -/** - * Strip control characters (except newlines/tabs) and collapse - * excessive whitespace runs into single spaces. - */ -function cleanText(text: string): string { - // eslint-disable-next-line no-control-regex - return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "") - .replace(/[ \t]{4,}/g, " ") - .trim(); -} - -/** - * Truncate text to maxLen, appending "…" if truncated. - */ -function truncate(text: string, maxLen: number): string { - if (text.length <= maxLen) return text; - return text.slice(0, maxLen - 1) + "…"; -} - -export interface CommentRecord { - taskId: string; - taskTitle: string; - authorName: string; - body: string; - createdAt: string; -} - -/** - * Normalize task comments before prompt injection. - * - Removes empty-body comments - * - Cleans control characters - * - Truncates overly long bodies - * - Deduplicates consecutive identical comments - */ -export function normalizeCommentsForPrompt( - comments: CommentRecord[], - limit: number = 10, -): CommentRecord[] { - const result: CommentRecord[] = []; - let prevKey = ""; - - for (const comment of comments) { - const cleaned = cleanText(comment.body); - if (cleaned.length === 0) continue; - - const key = `${comment.taskId}:${comment.authorName}:${cleaned}`; - if (key === prevKey) continue; - prevKey = key; - - result.push({ - ...comment, - body: truncate(cleaned, MAX_COMMENT_BODY_LENGTH), - }); - - if (result.length >= limit) break; - } - - return result; -} diff --git a/src/main/model-capability-seed.ts b/src/main/model-capability-seed.ts deleted file mode 100644 index 5dc3e924..00000000 --- a/src/main/model-capability-seed.ts +++ /dev/null @@ -1,287 +0,0 @@ -import type { ModelCapability } from "@shared/types"; -import { CONNECTORS } from "./connector-definitions"; -import { resolveModel, resolveModelCostFallback, resolveModels } from "./model-resolver"; - -type ModelCapabilitySeedRow = Omit; -type CapabilityProfile = Pick; -type CatalogModel = { id: string; name: string }; - -const DEFAULT_COST_PER_MTOK_OUT = 1; - -const CURATED_MODEL_CAPABILITY_SEED: ModelCapabilitySeedRow[] = [ - { - provider: "anthropic", - modelId: "claude-opus-4-7", - reasoning: 5, - coding: 5, - writing: 5, - tier: "hard", - costPerMtokOut: 75, - }, - { - provider: "anthropic", - modelId: "claude-sonnet-4-6", - reasoning: 4, - coding: 5, - writing: 5, - tier: "standard", - costPerMtokOut: 15, - }, - { - provider: "anthropic", - modelId: "claude-haiku-4-5-20251001", - reasoning: 3, - coding: 4, - writing: 4, - tier: "standard", - costPerMtokOut: 5, - }, - { - provider: "openai", - modelId: "gpt-5", - reasoning: 5, - coding: 4, - writing: 3, - tier: "hard", - costPerMtokOut: 60, - }, - { - provider: "openai", - modelId: "gpt-5-mini", - reasoning: 4, - coding: 3, - writing: 3, - tier: "standard", - costPerMtokOut: 10, - }, - { - provider: "openai", - modelId: "gpt-4o-mini", - reasoning: 3, - coding: 3, - writing: 3, - tier: "standard", - costPerMtokOut: 2, - }, - { - provider: "fireworks", - modelId: "accounts/fireworks/models/kimi-k2-instruct", - reasoning: 4, - coding: 4, - writing: 5, - tier: "standard", - costPerMtokOut: 3, - }, - { - provider: "fireworks-firepass", - modelId: "accounts/fireworks/routers/kimi-k2p6-turbo", - reasoning: 4, - coding: 4, - writing: 5, - tier: "standard", - costPerMtokOut: 3, - }, - { - provider: "fireworks", - modelId: "accounts/fireworks/models/glm-4p5", - reasoning: 3, - coding: 3, - writing: 4, - tier: "standard", - costPerMtokOut: 2, - }, - { - provider: "fireworks", - modelId: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct", - reasoning: 3, - coding: 5, - writing: 3, - tier: "standard", - costPerMtokOut: 3, - }, - { - provider: "fireworks", - modelId: "accounts/fireworks/models/deepseek-v3p1", - reasoning: 4, - coding: 4, - writing: 3, - tier: "standard", - costPerMtokOut: 2, - }, - { - provider: "fireworks", - modelId: "accounts/fireworks/models/llama-v3p3-70b-instruct", - reasoning: 2, - coding: 2, - writing: 2, - tier: "trivial", - costPerMtokOut: 1, - }, -]; - -const CURATED_MODEL_CAPABILITY_BY_KEY = new Map( - CURATED_MODEL_CAPABILITY_SEED.map((row) => [capabilityKey(row.provider, row.modelId), row]), -); - -function capabilityKey(provider: string, modelId: string): string { - return `${provider}::${modelId}`; -} - -function profile(reasoning: number, coding: number, writing: number, tier: CapabilityProfile["tier"]): CapabilityProfile { - return { reasoning, coding, writing, tier }; -} - -function searchableText(provider: string, model: CatalogModel): string { - return `${provider} ${model.id} ${model.name}`.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim(); -} - -function hasAny(text: string, terms: string[]): boolean { - return terms.some((term) => text.includes(term)); -} - -function hasWord(text: string, word: string): boolean { - return new RegExp(`\\b${word}\\b`).test(text); -} - -function selectCapabilityProfile(text: string): CapabilityProfile { - if (text.includes("claude") && text.includes("opus")) return profile(5, 5, 5, "hard"); - if (text.includes("claude") && text.includes("sonnet")) return profile(4, 5, 5, "standard"); - if (text.includes("claude") && text.includes("haiku")) return profile(3, 4, 4, "standard"); - - if (text.includes("gpt 5") && text.includes("codex")) return profile(5, 5, 3, "hard"); - if (hasAny(text, ["gpt 5", "gpt 4", "gpt 4o", "o3", "o4"])) return profile(5, 4, 3, "hard"); - if (text.includes("gpt oss 120b")) return profile(4, 4, 3, "standard"); - if (text.includes("gpt oss")) return profile(3, 3, 3, "standard"); - - if (text.includes("gemini") && hasAny(text, ["pro", "ultra"])) return profile(5, 4, 4, "hard"); - if (text.includes("gemini")) return profile(3, 3, 3, "standard"); - - if (text.includes("grok 4") || text.includes("grok 3")) return profile(5, 4, 4, "hard"); - if (text.includes("grok")) return profile(4, 3, 4, "standard"); - - if (hasAny(text, ["glm 5", "zai glm 5"])) return profile(5, 4, 4, "hard"); - if (hasAny(text, ["glm 4 7", "glm 4 6", "zai glm 4 7"])) return profile(4, 4, 4, "standard"); - if (hasAny(text, ["glm 4 5", "glm 4p5"])) return profile(3, 3, 4, "standard"); - - if (text.includes("kimi") && text.includes("thinking")) return profile(5, 4, 5, "hard"); - if (text.includes("kimi")) return profile(4, 4, 5, "standard"); - - if (text.includes("deepseek") && hasAny(text, ["r1", "reasoner"])) return profile(5, 4, 3, "hard"); - if (hasAny(text, ["deepseek", "deepresearch", "qwq", "thinking"])) return profile(4, 4, 3, "standard"); - - if (text.includes("coder") || text.includes("codestral") || text.includes("devstral")) return profile(3, 5, 3, "standard"); - if (text.includes("qwen")) return profile(4, 4, 3, "standard"); - - if (text.includes("minimax") || text.includes("mimo")) return profile(3, 4, 4, "standard"); - if (hasAny(text, ["mistral large", "mistral medium", "magistral"])) return profile(4, 4, 4, "standard"); - if (text.includes("mistral") || text.includes("ministral")) return profile(3, 3, 3, "standard"); - - if (text.includes("nova premier") || text.includes("nova pro")) return profile(4, 3, 3, "standard"); - if (text.includes("nova")) return profile(2, 2, 2, "trivial"); - - if (text.includes("llama 4") || text.includes("llama 70b") || text.includes("llama v3p3 70b")) { - return profile(3, 3, 3, "standard"); - } - if (text.includes("llama")) return profile(2, 2, 2, "trivial"); - - return profile(3, 3, 3, "standard"); -} - -function applySizeAdjustment(selected: CapabilityProfile, text: string): CapabilityProfile { - if (hasWord(text, "nano") || hasWord(text, "micro") || hasWord(text, "3b") || hasWord(text, "7b") || hasWord(text, "8b")) { - return profile(2, 2, 2, "trivial"); - } - - if ( - hasWord(text, "mini") || - hasWord(text, "lite") || - hasWord(text, "flash") || - hasWord(text, "flashx") || - hasWord(text, "air") || - hasWord(text, "small") || - hasWord(text, "instant") || - text.includes("compound mini") - ) { - return profile( - Math.min(selected.reasoning, 3), - Math.min(selected.coding, 3), - Math.min(selected.writing, 3), - selected.tier === "trivial" ? "trivial" : "standard", - ); - } - - return selected; -} - -function inferCapabilityProfile(provider: string, model: CatalogModel): CapabilityProfile { - const text = searchableText(provider, model); - return applySizeAdjustment(selectCapabilityProfile(text), text); -} - -function normalizeCost(value: number): number { - if (!Number.isFinite(value) || value < 0) return DEFAULT_COST_PER_MTOK_OUT; - return Number(value.toFixed(4)); -} - -function resolveCatalogCostPerMtokOut(provider: string, modelId: string): number { - const resolved = resolveModel(provider, modelId); - if (!resolved) return DEFAULT_COST_PER_MTOK_OUT; - const priced = resolveModelCostFallback(resolved, provider); - return normalizeCost(priced.cost.output); -} - -export function deriveModelCapabilitySeed(provider: string, model: CatalogModel): ModelCapabilitySeedRow { - const curated = CURATED_MODEL_CAPABILITY_BY_KEY.get(capabilityKey(provider, model.id)); - const selectedProfile = curated ?? inferCapabilityProfile(provider, model); - return { - provider, - modelId: model.id, - reasoning: selectedProfile.reasoning, - coding: selectedProfile.coding, - writing: selectedProfile.writing, - tier: selectedProfile.tier, - costPerMtokOut: resolveCatalogCostPerMtokOut(provider, model.id), - }; -} - -function listStaticCatalogModels(): Array<{ provider: string; model: CatalogModel }> { - const modelsByKey = new Map(); - - for (const connector of CONNECTORS) { - for (const model of resolveModels(connector.provider)) { - modelsByKey.set(capabilityKey(connector.provider, model.id), { - provider: connector.provider, - model: { id: model.id, name: model.name }, - }); - } - - if (connector.auth.type !== "local" && connector.defaultModel.trim()) { - modelsByKey.set(capabilityKey(connector.provider, connector.defaultModel), { - provider: connector.provider, - model: { id: connector.defaultModel, name: connector.defaultModel }, - }); - } - } - - return Array.from(modelsByKey.values()); -} - -export function buildModelCapabilitySeed(): ModelCapabilitySeedRow[] { - const rowsByKey = new Map(); - - for (const row of CURATED_MODEL_CAPABILITY_SEED) { - rowsByKey.set(capabilityKey(row.provider, row.modelId), row); - } - - for (const entry of listStaticCatalogModels()) { - rowsByKey.set(capabilityKey(entry.provider, entry.model.id), deriveModelCapabilitySeed(entry.provider, entry.model)); - } - - return Array.from(rowsByKey.values()).sort((a, b) => { - const providerOrder = a.provider.localeCompare(b.provider); - if (providerOrder !== 0) return providerOrder; - return a.modelId.localeCompare(b.modelId); - }); -} - -export const MODEL_CAPABILITY_SEED: ModelCapabilitySeedRow[] = buildModelCapabilitySeed(); diff --git a/src/main/model-dispatch.ts b/src/main/model-dispatch.ts deleted file mode 100644 index 734e0eda..00000000 --- a/src/main/model-dispatch.ts +++ /dev/null @@ -1,221 +0,0 @@ -import log from "electron-log/main.js"; -import type { - AgentRecord, - ConnectorId, - ConnectorRecord, - ModelCapability, - TaskTier, -} from "@shared/types"; -import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy"; -import { getConnectorDefinition } from "./connectors"; -import { getConnectorModelPolicy } from "./connector-model-policy"; -import { inferTaskProfile } from "./agent-role-helpers"; - -/** - * Resolves which (provider, modelId) to use for an agent at run dispatch. - * - * Rules: - * - * 1. `explicit` strategy, or a CEO role (`reportsTo IS NULL` / - * `roleLevel === 'c_suite'`): use the agent's own connectorId + - * model verbatim. - * - * 2. The enabled (connector, model) universe has exactly one pair: - * use it. Single-model installs bypass scoring entirely. - * - * 3. `auto` strategy with multiple candidates: infer the agent's - * task profile (domain ∈ reasoning|coding|writing, required tier - * ∈ trivial|standard|hard), keep candidates that clear the domain - * score floor and the tier rank floor, and pick the cheapest. - * - * 4. `auto` strategy with no qualifying candidate: fail. Silently - * routing to the CEO's pair hid three distinct problems — a - * missing capability row, a mis-inferred profile, a misconfigured - * model pool — and made cost attribution meaningless. The caller - * converts the `ModelPickError` into a visible eligibility - * failure so operators see the real issue instead of "the agent - * ran on an unexpected model for a week". - */ - -export interface EnabledModel { - provider: string; - connectorId: ConnectorId; - modelId: string; -} - -export interface AgentAssignment { - connectorId: ConnectorId; - modelId: string | null; -} - -/** - * Tagged union returned by `pickModelForAgent`. Callers must branch on - * `ok` — success yields a dispatch-ready assignment; failure yields a - * reason code that `getRunEligibilityFailure`'s surrounding handler - * turns into a user-visible eligibility error. - */ -export type ModelPickResult = - | { ok: true; assignment: AgentAssignment } - | { ok: false; reason: "NO_QUALIFYING_CANDIDATE"; message: string }; - -export interface PickModelDeps { - getConnector: (id: ConnectorId) => ConnectorRecord; - getDisabledModels: (companyId: string, connectorId: string) => Array<{ id: string; label: string }>; - listModelCapabilities: () => ModelCapability[]; - readConnectors: () => ConnectorRecord[]; -} - -/** - * Minimum numeric score per tier — the model must score *at least* this on - * the task's domain axis. Higher tiers demand strictly higher scores; a - * tier-3 (hard) task refuses any model that scores below 4 on its domain - * regardless of the model's own tier flag. Tuned to the 5-grade rubric. - */ -const DOMAIN_SCORE_FLOOR: Record = { - trivial: 2, - standard: 3, - hard: 4, -}; - -const TIER_RANK: Record = { - trivial: 1, - standard: 2, - hard: 3, -}; - -/** - * Walk every connector the user has configured, keep the ones that are - * execution-ready (authenticated, healthy), and expand each to its enabled - * model list. Returns a flat list of (provider, connectorId, modelId) triples - * — the concrete universe the picker chooses from. - */ -export function listEnabledModels(companyId: string, deps: PickModelDeps): EnabledModel[] { - const result: EnabledModel[] = []; - for (const connector of deps.readConnectors()) { - if (getConnectorExecutionReadinessIssue(connector)) continue; - let definition; - try { - definition = getConnectorDefinition(connector.id); - } catch (err) { - log.warn(`[model-dispatch] Skipping unknown connector ${connector.id}:`, err instanceof Error ? err.message : String(err)); - continue; - } - const policy = getConnectorModelPolicy(deps, companyId, connector.id as ConnectorId); - for (const model of policy.enabledModels) { - result.push({ - provider: definition.provider, - connectorId: connector.id as ConnectorId, - modelId: model.id, - }); - } - } - return result; -} - -/** - * Pure scoring step. Given the agent's inferred profile, the capability - * matrix, and the concrete list of enabled (provider, modelId) pairs, - * pick the cheapest qualifying model — or return `null` when nothing - * clears the bar so the caller can apply its fallback. - * - * Split out from `pickModelForAgent` so unit tests can exercise the - * rubric without having to stand up the real connector catalog or - * policy lookups. - */ -export function pickFromCandidates( - profile: { domain: "reasoning" | "coding" | "writing"; requiredTier: TaskTier }, - enabled: EnabledModel[], - capabilities: ModelCapability[], -): EnabledModel | null { - if (enabled.length === 0) return null; - const domainFloor = DOMAIN_SCORE_FLOOR[profile.requiredTier]; - const tierFloor = TIER_RANK[profile.requiredTier]; - - const capabilityByKey = new Map(); - for (const cap of capabilities) { - capabilityByKey.set(`${cap.provider}::${cap.modelId}`, cap); - } - - const qualifying: Array<{ model: EnabledModel; cap: ModelCapability }> = []; - for (const model of enabled) { - const cap = capabilityByKey.get(`${model.provider}::${model.modelId}`); - if (!cap) continue; - if (cap[profile.domain] < domainFloor) continue; - if (TIER_RANK[cap.tier] < tierFloor) continue; - qualifying.push({ model, cap }); - } - if (qualifying.length === 0) return null; - - qualifying.sort((a, b) => a.cap.costPerMtokOut - b.cap.costPerMtokOut); - return qualifying[0]!.model; -} - -/** - * The one-call entry point that run dispatch uses. Returns either a - * dispatch-ready assignment or a structured failure so callers can - * translate the miss into an eligibility error — no more silent CEO - * fallback. - */ -export function pickModelForAgent( - agent: AgentRecord, - deps: PickModelDeps, -): ModelPickResult { - const strategy = agent.modelStrategy ?? "explicit"; - - // CEO is pinned to the user's choice. The canonical CEO marker is - // `reportsTo === null` — the DB invariant (`getCeoForCompany` SELECTs on - // the same predicate), so this holds even when `roleLevel` is still the - // schema default 'ic' on an agent that was never tagged with the full - // seniority enum. We also accept the enum for completeness. - const isCeo = agent.reportsTo === null || agent.roleLevel === "c_suite"; - if (strategy === "explicit" || isCeo) { - return { - ok: true, - assignment: { connectorId: agent.connectorId, modelId: agent.model ?? null }, - }; - } - - const enabled = listEnabledModels(agent.companyId, deps); - - // Single-model install: there's nothing to pick from. Use it. - if (enabled.length === 1) { - const only = enabled[0]!; - return { ok: true, assignment: { connectorId: only.connectorId, modelId: only.modelId } }; - } - - // Empty universe → fall back to whatever is on the agent row. This can - // only happen when every connector is unhealthy; the eligibility checks - // higher up in run dispatch will still block the run, but we return - // something sensible so the caller's contract stays total. - if (enabled.length === 0) { - return { - ok: true, - assignment: { connectorId: agent.connectorId, modelId: agent.model ?? null }, - }; - } - - const profile = inferTaskProfile(agent.role, agent.title, agent.roleLevel); - const winner = pickFromCandidates(profile, enabled, deps.listModelCapabilities()); - - if (!winner) { - return { - ok: false, - reason: "NO_QUALIFYING_CANDIDATE", - message: `No enabled model clears the ${profile.requiredTier} ${profile.domain} bar for agent ${agent.name}. Enable a qualifying model, adjust the capability catalog, or switch this agent to modelStrategy=explicit.`, - }; - } - - return { - ok: true, - assignment: { connectorId: winner.connectorId, modelId: winner.modelId }, - }; -} - -/** - * Re-export for test setups that want to exercise the rubric without - * standing up a full AgentRecord. - */ -export const __INTERNAL__ = { - DOMAIN_SCORE_FLOOR, - TIER_RANK, -}; diff --git a/src/main/model-resolver.ts b/src/main/model-resolver.ts deleted file mode 100644 index 07b10cb6..00000000 --- a/src/main/model-resolver.ts +++ /dev/null @@ -1,264 +0,0 @@ -/** - * Resolves `Model` and the dynamic stream headers needed for providers - * that pi-ai's catalog does not ship out of the box. - * - * Today this only covers the two Fireworks connectors (`fireworks` and - * `fireworks-firepass`). Fireworks is not a built-in pi-ai provider, so we - * route them through pi-ai's native `openai-completions` API against - * Fireworks' OpenAI-compatible endpoint. The earlier shim pointed the - * Anthropic SDK at Fireworks' `/v1/messages` path, which forced pi-ai to - * ship Claude-proprietary beta headers (`fine-grained-tool-streaming-*`, - * `anthropic-dangerous-direct-browser-access`, etc.) — Fireworks tolerates - * them inconsistently and the resulting streams frequently close with no - * tokens emitted, producing runs that report "succeeded" but did - * absolutely nothing. The OpenAI-compatible endpoint at - * `https://api.fireworks.ai/inference/v1` does not suffer the same - * problem and is the path Fireworks documents for tool-using clients. - */ - -import log from "electron-log/main.js"; -import { getModels, type Api, type Model } from "@mariozechner/pi-ai"; -import { isLocalConnectorBaseUrl } from "@shared/contracts/schemas-credentials"; -import { isPiKnownProvider } from "./connectors"; - -// Fireworks' OpenAI-compatible root. The OpenAI SDK appends -// `/chat/completions`, `/models`, etc. to this baseURL. -const FIREWORKS_OPENAI_BASE_URL = "https://api.fireworks.ai/inference/v1"; -const FIREWORKS_DEFAULT_CONTEXT = 128_000; -const FIREWORKS_DEFAULT_MAX_TOKENS = 8192; - -// Fire Pass routes subscription traffic through a dedicated router id, -// not the per-token model path. The canonical identifier is documented -// at https://docs.fireworks.ai/firepass and applies to both the -// OpenAI-compatible (`/inference/v1`) and Anthropic-compatible -// (`/inference`) endpoints. Do not "align" this to the -// `accounts/fireworks/models/...` id — the subscription entitlement -// only attaches to the router route, and switching to the model path -// makes Fireworks bill per-token and reject Fire-Pass-only callers. -export const FIREWORKS_FIREPASS_MODEL_ID = "accounts/fireworks/routers/kimi-k2p6-turbo"; -export const FIREWORKS_FIREPASS_MODEL_NAME = "Kimi K2.6 Turbo (Fire Pass)"; - -const FIREWORKS_CURATED_MODELS: Array<{ - id: string; - name: string; - contextWindow?: number; - cost: { input: number; output: number }; -}> = [ - { id: "accounts/fireworks/models/kimi-k2-instruct", name: "Kimi K2 Instruct", contextWindow: 131_072, cost: { input: 0.50, output: 0.50 } }, - { id: "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct", name: "Qwen3 Coder 480B A35B Instruct", contextWindow: 262_144, cost: { input: 0.50, output: 0.50 } }, - { id: "accounts/fireworks/models/deepseek-v3p1", name: "DeepSeek V3.1", contextWindow: 163_840, cost: { input: 0.20, output: 0.20 } }, - { id: "accounts/fireworks/models/glm-4p5", name: "GLM 4.5", contextWindow: 131_072, cost: { input: 0.30, output: 0.30 } }, - { id: "accounts/fireworks/models/llama-v3p3-70b-instruct", name: "Llama 3.3 70B Instruct", contextWindow: 131_072, cost: { input: 0.20, output: 0.20 } }, -]; - -const FIREWORKS_FIREPASS_COST = { input: 0, output: 0 }; -const FIREWORKS_FALLBACK_COST = { input: 0.50, output: 0.50 }; - -// Local OpenAI-compatible servers (Ollama, LM Studio) bill the user's own -// hardware, so the surfaced cost is zero. Context window varies wildly -// across self-hosted models; the configured window is conservative -// enough to keep pi's compactor honest without rejecting reasonable -// requests on smaller models. -const LOCAL_DEFAULT_COST = { input: 0, output: 0 }; -const LOCAL_DEFAULT_CONTEXT = 32_768; -const LOCAL_DEFAULT_MAX_TOKENS = 8192; - -type LocalOpenAiCompatProvider = "ollama" | "lm-studio"; - -function isLocalOpenAiCompatProvider(provider: string): provider is LocalOpenAiCompatProvider { - return provider === "ollama" || provider === "lm-studio"; -} - -function buildFireworksModel( - modelId: string, - name?: string, - contextWindow?: number, - cost?: { input: number; output: number }, -): Model<"openai-completions"> { - const modelCost = cost ?? FIREWORKS_FALLBACK_COST; - return { - id: modelId, - name: name ?? modelId, - api: "openai-completions", - provider: "fireworks", - baseUrl: FIREWORKS_OPENAI_BASE_URL, - reasoning: false, - input: ["text"], - cost: { input: modelCost.input, output: modelCost.output, cacheRead: 0, cacheWrite: 0 }, - contextWindow: contextWindow ?? FIREWORKS_DEFAULT_CONTEXT, - maxTokens: FIREWORKS_DEFAULT_MAX_TOKENS, - }; -} - -function buildLocalModel( - provider: LocalOpenAiCompatProvider, - modelId: string, - baseUrl: string, -): Model<"openai-completions"> { - return { - id: modelId, - name: modelId, - api: "openai-completions", - provider, - baseUrl, - reasoning: false, - input: ["text"], - cost: { input: LOCAL_DEFAULT_COST.input, output: LOCAL_DEFAULT_COST.output, cacheRead: 0, cacheWrite: 0 }, - contextWindow: LOCAL_DEFAULT_CONTEXT, - maxTokens: LOCAL_DEFAULT_MAX_TOKENS, - }; -} - -export function resolveModel( - provider: string, - modelId: string, - options?: { baseUrl?: string }, -): Model | null { - if (provider === "fireworks-firepass") { - return buildFireworksModel(FIREWORKS_FIREPASS_MODEL_ID, FIREWORKS_FIREPASS_MODEL_NAME, 262_144, FIREWORKS_FIREPASS_COST); - } - if (provider === "fireworks") { - const curated = FIREWORKS_CURATED_MODELS.find((entry) => entry.id === modelId); - return buildFireworksModel(modelId, curated?.name, curated?.contextWindow, curated?.cost); - } - if (isLocalOpenAiCompatProvider(provider)) { - if (!options?.baseUrl) { - log.warn(`[model-resolver] ${provider} requires a baseUrl from credentials; none provided.`); - return null; - } - if (!isLocalConnectorBaseUrl(options.baseUrl)) { - log.warn(`[model-resolver] ${provider} rejected non-local baseUrl.`); - return null; - } - return buildLocalModel(provider, modelId, options.baseUrl); - } - if (!isPiKnownProvider(provider)) { - log.warn(`[model-resolver] Unknown pi provider: ${provider}`); - return null; - } - try { - return getModels(provider).find((model) => model.id === modelId) ?? null; - } catch (err) { - log.warn(`[model-resolver] getModel failed for ${provider}/${modelId}:`, err instanceof Error ? err.message : String(err)); - return null; - } -} - -const CROSS_PROVIDER_COST_LOOKUP: Record = { - "github-copilot": ["anthropic", "openai", "google", "xai"], - "google-gemini-cli": ["google"], -}; - -const PROVIDER_FALLBACK_COST: Record = { - "zai": { input: 1, output: 3.2 }, - "kimi-coding": { input: 0.6, output: 3 }, -}; - -function normalizeModelId(id: string): string { - return id.replace(/\./g, "-"); -} - -export function resolveModelCostFallback(model: Model, provider: string): Model { - if (model.cost.input > 0 || model.cost.output > 0) return model; - - const crossProviders = CROSS_PROVIDER_COST_LOOKUP[provider]; - if (crossProviders) { - const normalized = normalizeModelId(model.id); - for (const cp of crossProviders) { - try { - const sourceModels = getModels(cp as Parameters[0]); - const match = sourceModels.find((m) => m.id === model.id) - ?? sourceModels.find((m) => normalizeModelId(m.id) === normalized) - ?? sourceModels.find((m) => normalized.includes(normalizeModelId(m.id)) || normalizeModelId(m.id).includes(normalized)); - if (match && (match.cost.input > 0 || match.cost.output > 0)) { - return { ...model, cost: { ...match.cost } }; - } - } catch { - continue; - } - } - } - - const fallback = PROVIDER_FALLBACK_COST[provider]; - if (fallback) { - return { ...model, cost: { ...model.cost, input: fallback.input, output: fallback.output } }; - } - - return model; -} - -export function resolveModels(provider: string): Array<{ id: string; name: string }> { - if (provider === "fireworks-firepass") { - return [{ id: FIREWORKS_FIREPASS_MODEL_ID, name: FIREWORKS_FIREPASS_MODEL_NAME }]; - } - if (provider === "fireworks") { - return FIREWORKS_CURATED_MODELS.map(({ id, name }) => ({ id, name })); - } - if (isLocalOpenAiCompatProvider(provider)) { - // Local-server catalogs depend on what the user has loaded and must be - // fetched against the saved baseUrl. The sync resolver returns an - // empty list; the renderer reaches the live catalog through - // `listLocalConnectorModels` in `main-runtime-support.ts`. - return []; - } - if (!isPiKnownProvider(provider)) { - log.warn(`[model-resolver] Unknown pi provider: ${provider}`); - return []; - } - try { - const models = getModels(provider); - return models.map((model: { id: string; name?: string }) => ({ id: model.id, name: model.name ?? model.id })); - } catch (err) { - log.warn(`[model-resolver] getModels failed for ${provider}:`, err instanceof Error ? err.message : String(err)); - return []; - } -} - -/** - * Fetch the live model list from a local OpenAI-compatible server. - * - * Both Ollama (`/v1/models`) and LM Studio (`/v1/models`) expose the - * standard OpenAI catalog shape — `{ data: [{ id, ...}] }` — so a single - * fetch path handles both. Returns an empty list when the server is - * unreachable so the renderer can surface a "not running" message - * instead of throwing. - */ -export async function fetchLocalConnectorModels( - baseUrl: string, -): Promise> { - if (!isLocalConnectorBaseUrl(baseUrl)) { - log.warn("[model-resolver] rejected non-local model catalog baseUrl."); - return []; - } - const url = `${baseUrl.replace(/\/$/, "")}/models`; - try { - const response = await fetch(url, { method: "GET" }); - if (!response.ok) { - log.warn(`[model-resolver] local model list ${url} returned HTTP ${response.status}`); - return []; - } - const body = (await response.json()) as { data?: Array<{ id?: unknown }> }; - if (!Array.isArray(body.data)) return []; - return body.data - .map((row) => (typeof row?.id === "string" ? row.id : null)) - .filter((id): id is string => id !== null) - .map((id) => ({ id, name: id })); - } catch (err) { - log.warn(`[model-resolver] fetch ${url} failed:`, err instanceof Error ? err.message : String(err)); - return []; - } -} - -/** - * Extra HTTP headers that must be merged into the streamSimple call for the - * given provider. Returns undefined when no extra headers are required. - * - * Fireworks' OpenAI-compatible endpoint authenticates via the OpenAI - * SDK's native `apiKey` constructor — it already sends - * `Authorization: Bearer `. No per-provider header injection is - * needed; the helper stays in place as an extension point for future - * providers that do require hand-built headers. - */ -export function resolveExtraStreamHeaders(_provider: string, _apiKey: string): Record | undefined { - return undefined; -} diff --git a/src/main/notification-service.ts b/src/main/notification-service.ts deleted file mode 100644 index 9c02716d..00000000 --- a/src/main/notification-service.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { Notification, app } from "electron"; -import type { BrowserWindow } from "electron"; -import type { DesktopEvent, SectionId } from "@shared/types"; -import { classifyUnknownError } from "./errors/index.js"; - -export interface NotificationOptions { - title: string; - body: string; - urgency: "critical" | "informational"; - navigation?: { - section: SectionId; - entityId?: string; - }; - /** Batch key -- notifications with same key within window are batched */ - batchKey?: string; -} - -interface NotificationServiceDependencies { - getMainWindow: () => BrowserWindow | null; - emitEvent: (event: DesktopEvent) => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - /** Returns the active UI locale ("en", "zh", ...). Batch summary copy is - * localized; fallbacks to "en" when unset. */ - getLocale?: () => string | null | undefined; -} - -interface BatchState { - count: number; - timer: ReturnType; - /** Latest section observed during the window. Summary navigates here on click. */ - section: SectionId; -} - -const BATCH_WINDOW_MS = 10_000; - -/** - * Batch keys that should NEVER be batched -- always fire individually. - * These represent events the user must see each instance of. - */ -const NEVER_BATCH: ReadonlySet = new Set([ - "pending_approval", - "crash_recovery", - "update_available", - "manual_intervention", - "budget_exhaustion", -]); - -interface LocalizedBatchCopy { - title: (count: number) => string; - body: string; -} - -/** - * Batch summary copy per batch key, per-locale. Used when the batch timer - * expires and accumulated events need a summary notification. - */ -const BATCH_SUMMARY_COPY: Record> = { - failed_runs: { - en: { title: (count) => `${count} tasks failed`, body: "Click to view failed runs" }, - zh: { title: (count) => `${count} 个任务失败`, body: "点击查看失败记录" }, - }, - agent_hired: { - en: { title: (count) => `${count} agents hired`, body: "Click to view organization" }, - zh: { title: (count) => `${count} 位新员工入职`, body: "点击查看组织架构" }, - }, - budget_alerts: { - en: { title: (count) => `${count} budget alerts`, body: "Click to view cost details" }, - zh: { title: (count) => `${count} 个预算提醒`, body: "点击查看成本详情" }, - }, - task_completed: { - en: { title: (count) => `${count} tasks completed`, body: "Click to view task list" }, - zh: { title: (count) => `${count} 个任务已完成`, body: "点击查看任务列表" }, - }, - agent_paused: { - en: { title: (count) => `${count} agents paused`, body: "Click to view paused agents" }, - zh: { title: (count) => `${count} 位员工已暂停`, body: "点击查看已暂停员工" }, - }, -}; - -function pickLocale(locale: string | null | undefined): "en" | "zh" { - return locale === "zh" ? "zh" : "en"; -} - -export function createNotificationService(deps: NotificationServiceDependencies) { - /** - * Prevent GC on Windows -- Notification objects must be retained - * while visible so click handlers fire. Removed on "close" event. - */ - const activeNotifications: Set = new Set(); - - /** Active batch state per batch key */ - const activeBatches: Map = new Map(); - - function notify(options: NotificationOptions) { - if (!Notification.isSupported()) return; - - const key = options.batchKey; - - // If no batch key, or the key is in the NEVER_BATCH list, fire immediately - if (!key || NEVER_BATCH.has(key)) { - fireNotification(options); - return; - } - - const existing = activeBatches.get(key); - if (!existing) { - // First event in batch -- fire immediately, start batch window - fireNotification(options); - activeBatches.set(key, { - count: 0, - timer: setTimeout(() => flushBatch(key), BATCH_WINDOW_MS), - section: options.navigation?.section ?? "overview", - }); - return; - } - - // Accumulate -- do not fire individual notification. - // Track the most recent section so the summary links to where the latest event happened. - existing.count++; - const nextSection = options.navigation?.section; - if (nextSection) { - existing.section = nextSection; - } - } - - function flushBatch(key: string) { - const batch = activeBatches.get(key); - activeBatches.delete(key); - - if (batch && batch.count > 0) { - const locale = pickLocale(deps.getLocale?.()); - const copySet = BATCH_SUMMARY_COPY[key]; - const copy = copySet?.[locale]; - const title = copy ? copy.title(batch.count) : `${batch.count} more events`; - const body = copy ? copy.body : "Click to view"; - - fireNotification({ - title, - body, - urgency: "informational", - navigation: { section: batch.section }, - // No entityId -- batched summary navigates to section overview - }); - } - } - - function fireNotification(options: NotificationOptions) { - if (!Notification.isSupported()) return; - - const notificationOptions: Electron.NotificationConstructorOptions = { - title: options.title, - body: options.body, - silent: options.urgency === "informational", - }; - - // Platform-specific urgency handling - if (process.platform === "win32" && options.urgency === "critical") { - notificationOptions.timeoutType = "never"; - } - if (process.platform === "linux") { - notificationOptions.urgency = options.urgency === "critical" ? "critical" : "normal"; - } - - const notification = new Notification(notificationOptions); - - // Click handler: restore window and navigate (D-02 window restoration sequence) - notification.on("click", () => { - app.focus({ steal: true }); - const win = deps.getMainWindow(); - if (win && !win.isDestroyed()) { - if (win.isMinimized()) win.restore(); - win.show(); - win.focus(); - } - if (options.navigation) { - deps.emitEvent({ - type: "notification-click", - section: options.navigation.section, - entityId: options.navigation.entityId, - }); - } - }); - - // GC protection: hold reference until notification closes - notification.on("close", () => { - activeNotifications.delete(notification); - }); - - notification.show(); - activeNotifications.add(notification); - } - - function destroy() { - // Clear all batch timers - for (const batch of activeBatches.values()) { - clearTimeout(batch.timer); - } - activeBatches.clear(); - // Dismiss any still-visible notifications so Windows toast host does not - // leave ghost toasts after quit. - for (const notification of activeNotifications) { - try { - notification.close(); - } catch (error) { - const classified = classifyUnknownError(error, { - kind: "recoverable", - code: "notification.close.failed", - message: "notification.close() during destroy failed", - }); - deps.logger.warn( - `[${classified.code}] ${classified.message}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - activeNotifications.clear(); - } - - return { - notify, - destroy, - }; -} diff --git a/src/main/onboarding-service.ts b/src/main/onboarding-service.ts deleted file mode 100644 index 52d3f357..00000000 --- a/src/main/onboarding-service.ts +++ /dev/null @@ -1,344 +0,0 @@ -import type { AppDatabase } from "./database"; -import { getConnectorExecutionReadinessIssue, isConnectorExecutionReady } from "@shared/connector-policy"; -import type { ConnectorId, ConnectorRecord } from "@shared/types"; -import { validateConnectorModelSelection, connectorPolicyDepsFromDb } from "./connector-model-policy"; - -interface OnboardingBootstrapSummary { - companyId: string; - companyName: string; - workspaceId: string | null; - leadAgentId: string | null; - projectId: string | null; - taskId: string | null; - runId: string | null; -} - -interface InitialExecutionLoopResult extends OnboardingBootstrapSummary { - dispatchAfterCommit: () => void; -} - -interface BootstrapInput { - companyName: string; - companyDescription: string; - workspacePath: string; - autoApproveHires: boolean; - reviewDeliverables?: boolean; - executionMode?: string; - goalTitle: string; - goalDescription: string; - connectorId?: ConnectorId; - connectorModel?: string; - connectorPoolSelections?: Array<{ - connectorId: ConnectorId; - disabledModels: Array<{ id: string; label: string }>; - }>; -} - -interface OnboardingDependencies { - db: AppDatabase; - seedDefaultAutomationRules: (companyId: string) => void; - createTaskRunForDeferredDispatch: (taskId: string, trigger: string, actor: string) => { - ok: boolean; - data?: { runId: string; dispatchAfterCommit: () => void }; - 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; - /** Optional logger for non-fatal errors from best-effort operations (skill seeding, etc.). */ - logger?: { warn: (...args: unknown[]) => void }; -} - -const DEFERRABLE_RUN_ERRORS = new Set([ - "WORKER_UNAVAILABLE", - "CONNECTOR_NOT_READY", - "TASK_ALREADY_RUNNING", - "AGENT_ALREADY_RUNNING", -]); - -function resolveOnboardingConnector( - connectors: Array>, - preferredConnectorId?: ConnectorId, -) { - if (preferredConnectorId) { - const preferredConnector = connectors.find((connector) => connector.id === preferredConnectorId); - if (!preferredConnector) { - throw new Error(`Selected connector ${preferredConnectorId} is not available.`); - } - const issue = getConnectorExecutionReadinessIssue(preferredConnector); - if (issue) { - throw new Error(issue); - } - return preferredConnector.id; - } - - const defaultConnector = connectors.find((connector) => isConnectorExecutionReady(connector)); - if (!defaultConnector) { - throw new Error("At least one execution-ready connector is required before onboarding can continue."); - } - return defaultConnector.id; -} - -export function createOnboardingService({ - db, - seedDefaultAutomationRules, - createTaskRunForDeferredDispatch, - publishDomainChanged, - scanAndAssignSkills, - logger, -}: OnboardingDependencies) { - function updateAgentWorkspaceBinding(agentId: string, workspaceId: string | null) { - if (!workspaceId) return; - const agent = db.core.entity.getAgent(agentId); - if (agent.workspaceId === workspaceId) return; - db.core.agents.saveAgent({ - id: agent.id, - companyId: agent.companyId, - name: agent.name, - role: agent.role, - title: agent.title, - department: agent.department, - status: agent.status, - reportsTo: agent.reportsTo, - connectorId: agent.connectorId, - workspaceId, - model: agent.model, - metadataJson: agent.metadataJson, - capabilities: agent.capabilities, - budgetMonthlyUsd: agent.budgetMonthlyUsd, - }); - } - - function getLocale(): string { - return db.queryAll<{ value: string }>("select value from settings where key = 'locale' limit 1")[0]?.value ?? "en"; - } - - function createDefaultWorkspace(companyId: string, workspacePath: string) { - const trimmedPath = workspacePath.trim(); - if (!trimmedPath) return null; - const wsLocale = getLocale(); - return db.core.workspaces.saveWorkspace({ - companyId, - name: wsLocale === "zh" ? "默认工作区" : "Default Workspace", - localPath: trimmedPath, - repoUrl: "", - repoRef: "", - isPrimary: true, - }); - } - - function bindWorkspaceToProject(workspaceId: string | null, projectId: string) { - if (!workspaceId) return; - const workspace = db.core.workspaces.getWorkspace(workspaceId); - if (!workspace || workspace.projectId === projectId) return; - db.core.workspaces.saveWorkspace({ - id: workspace.id, - companyId: workspace.companyId, - name: workspace.name, - localPath: workspace.localPath, - repoUrl: workspace.repoUrl, - repoRef: workspace.repoRef, - projectId, - isPrimary: workspace.isPrimary, - }); - } - - function createInitialExecutionLoop(companyId: string, workspaceId: string | null): InitialExecutionLoopResult { - const companyRows = db.queryAll<{ id: string; name: string; description: string }>( - "select id, name, description from companies where id = ? limit 1", - companyId, - ); - const company = companyRows[0] ?? null; - if (!company) { - throw new Error("Company no longer exists during onboarding bootstrap."); - } - - const leadAgentRows = db.queryAll<{ id: string; companyId: string; name: string; role: string; title: string; department: string | null; status: string; reportsTo: string | null; connectorId: string; workspaceId: string | null; model: string | null; metadataJson: string; capabilities: string; budgetMonthlyUsd: number; heartbeatEnabled: number; heartbeatIntervalSec: number }>( - "select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, metadata_json as metadataJson, capabilities, budget_monthly_usd as budgetMonthlyUsd, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec from agents where company_id = ? and reports_to is null limit 1", - companyId, - ); - const leadAgent = leadAgentRows[0] ?? null; - if (!leadAgent) { - throw new Error("Unable to find the lead agent for the company bootstrap."); - } - - updateAgentWorkspaceBinding(leadAgent.id, workspaceId); - - const goalRows = db.queryAll<{ id: string; title: string; status: string }>( - "select id, title, status from goals where company_id = ? order by created_at asc", - companyId, - ); - const activeGoal = - goalRows.find((goal) => goal.status === "active") - ?? goalRows[0] - ?? null; - - const kickoffProjectName = activeGoal ? `Execution plan: ${activeGoal.title}` : "Initial operating plan"; - const kickoffProjectDescription = activeGoal - ? `Turn the founding goal "${activeGoal.title}" into an execution plan, delegation map, and the first wave of real work.` - : "Establish the first operating plan, assign work, and start the company execution loop."; - - const projectId = db.core.entity.saveProject({ - companyId, - goalId: activeGoal?.id ?? null, - name: kickoffProjectName, - description: kickoffProjectDescription, - leadAgentId: leadAgent.id, - targetDate: null, - status: "in_progress", - }); - bindWorkspaceToProject(workspaceId, projectId); - - const kickoffLocale = getLocale(); - const kickoffTaskTitle = activeGoal - ? (kickoffLocale === "zh" ? `落地目标:${activeGoal.title}` : `Operationalize goal: ${activeGoal.title}`) - : (kickoffLocale === "zh" ? "建立首个运营节奏" : "Establish the first operating cadence"); - const kickoffTaskDescription = activeGoal - ? [ - `Read the founding goal "${activeGoal.title}" and convert it into a real operating plan.`, - `Before planning, explore the workspace codebase: list the top-level directory, read key files (README, package.json, config files), and understand the project structure, languages, and frameworks in use.`, - `Consider the full company context — the company name "${company.name}", its description ("${company.description}"), and the goal — when deciding what departments, roles, and execution strategy are needed.`, - `Create the first execution structure inside AgentCompany: projects, tasks, delegation, approvals, and coordination messages as needed.`, - `Use the bound workspace as the default execution boundary for the first round of work.`, - ].join("\n\n") - : [ - `Establish the first operating plan for the company.`, - `Before planning, explore the workspace codebase: list the top-level directory, read key files (README, package.json, config files), and understand the project structure, languages, and frameworks in use.`, - `Consider the full company context — the company name "${company.name}" and its description ("${company.description}") — when deciding what departments, roles, and execution strategy are needed.`, - `Review the current company state, create the first real tasks, delegate initial work, and report progress through tasks, approvals, and messages.`, - ].join("\n\n"); - - const taskId = db.core.tasks.saveTask({ - companyId, - projectId, - goalId: activeGoal?.id ?? null, - parentId: null, - title: kickoffTaskTitle, - description: kickoffTaskDescription, - assigneeAgentId: leadAgent.id, - workspaceId: workspaceId ?? leadAgent.workspaceId ?? null, - priority: "high", - status: "todo", - // Kickoff explicitly reads the workspace codebase (see - // description above — "list the top-level directory, read key - // files"), so this is a filesystem-touching task and must take - // an exclusive lock on the bound workspace. - requiresFilesystem: true, - }); - - const startRunResult = createTaskRunForDeferredDispatch(taskId, "assignment", "system"); - if (!startRunResult.ok && !DEFERRABLE_RUN_ERRORS.has(startRunResult.error?.code ?? "")) { - throw new Error(startRunResult.error?.message ?? "Failed to queue the initial execution loop."); - } - - return { - companyId, - companyName: company.name, - workspaceId, - leadAgentId: leadAgent.id, - projectId, - taskId, - runId: startRunResult.ok ? startRunResult.data?.runId ?? null : null, - dispatchAfterCommit: startRunResult.ok ? startRunResult.data?.dispatchAfterCommit ?? (() => {}) : () => {}, - }; - } - - function bootstrapOnboarding(input: BootstrapInput): OnboardingBootstrapSummary { - const result = db.withTransaction(() => { - const connectors = db.projection.snapshot.listSnapshot({ companyId: null }).connectors; - const selectedConnectorId = resolveOnboardingConnector(connectors, input.connectorId); - - const companyId = db.core.company.saveCompany({ - name: input.companyName.trim(), - description: input.companyDescription.trim(), - status: "active", - autoApproveHires: input.autoApproveHires, - reviewDeliverables: input.reviewDeliverables, - executionMode: input.executionMode ?? "ai_ceo", - }); - - // Persist the user's per-connector disabled-model selections - // against the freshly-created company id. Onboarding is entirely - // pre-commit; the pool settings arrive in the input payload and - // land in the DB only once a company exists to scope them. - for (const pool of input.connectorPoolSelections ?? []) { - db.core.settings.setDisabledModels(companyId, pool.connectorId, pool.disabledModels); - } - - // Validate the CEO model selection against the now-persisted pool - // scoped to this new company. Must run AFTER the pool is stored, - // otherwise the validator sees an empty pool and accepts anything. - const modelSelection = validateConnectorModelSelection(connectorPolicyDepsFromDb(db), companyId, selectedConnectorId, input.connectorModel ?? null); - if (!modelSelection.ok) { - throw new Error(modelSelection.error); - } - - const workspaceId = createDefaultWorkspace(companyId, input.workspacePath); - - const goalTitle = input.goalTitle.trim(); - if (goalTitle) { - db.core.entity.saveGoal({ - companyId, - title: goalTitle, - description: input.goalDescription.trim() || `Achieve: ${goalTitle}`, - status: "active", - parentId: null, - ownerAgentId: null, - }); - } - - const ceoLocale = getLocale(); - const ceoId = db.core.agents.saveAgent({ - companyId, - name: "CEO", - role: "CEO", - title: ceoLocale === "zh" ? "首席执行官" : "Chief Executive Officer", - reportsTo: null, - connectorId: selectedConnectorId, - workspaceId, - model: input.connectorModel?.trim() || null, - capabilities: ceoLocale === "zh" - ? "高管领导力、战略规划、团队建设、目标分解、授权管理和组织运营。负责招募领导团队、制定战略,并协调公司所有运营活动。" - : "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, - status: "idle", - // CEO is pinned to the user's pick at onboarding. Never let the - // dispatcher re-route it. - modelStrategy: "explicit", - roleLevel: "c_suite", - }); - db.core.agents.setHeartbeat(ceoId, true, 120); - db.core.settings.setCurrentCompany(companyId); - seedDefaultAutomationRules(companyId); - - const kickoff = createInitialExecutionLoop(companyId, workspaceId); - - db.core.activity.addActivity({ - companyId, - actor: "board", - action: "company.bootstrapped", - entityType: "company", - entityId: companyId, - detail: `Bootstrapped from onboarding with connector ${selectedConnectorId}.`, - }); - - return { kickoff, ceoId }; - }); - - result.kickoff.dispatchAfterCommit(); - if (scanAndAssignSkills) { - void scanAndAssignSkills(result.kickoff.companyId, result.ceoId).catch((error) => { - const message = error instanceof Error ? error.message : String(error); - logger?.warn(`[onboarding] skill scan failed for agent ${result.ceoId}: ${message}`); - }); - } - - publishDomainChanged(); - const { dispatchAfterCommit: _dispatchAfterCommit, ...summary } = result.kickoff; - return summary; - } - - return { - bootstrapOnboarding, - }; -} diff --git a/src/main/orchestration-service.ts b/src/main/orchestration-service.ts deleted file mode 100644 index 020124d5..00000000 --- a/src/main/orchestration-service.ts +++ /dev/null @@ -1 +0,0 @@ -export { createOrchestrationService } from "./orchestration/index"; diff --git a/src/main/orchestration/heartbeat.ts b/src/main/orchestration/heartbeat.ts deleted file mode 100644 index 6c40d822..00000000 --- a/src/main/orchestration/heartbeat.ts +++ /dev/null @@ -1,428 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { AgentRecord, ConnectorRecord } from "@shared/types"; -import type { OrchestrationDependencies } from "./types"; -import type { RunDispatchParams } from "./turn-context"; -import type { ResolveWorkspaceFn } from "./run-dispatch"; -import { WorkspaceConfigurationError } from "./resolve-workspace"; -import { pickModelForAgent } from "../model-dispatch"; -import { HUMAN_SENDER_ID } from "../messaging/dispatch"; -import { decideRunAttempt } from "../run-attempt-policy"; - -export type HeartbeatBlockReason = - | "system_unavailable" - | "agent_unavailable" - | "policy_blocked" - | "human_blocked" - | "no_work" - | "workspace_unavailable" - | "dispatch_race"; - -export type HeartbeatRunDecision = - | { allowed: true; agent: AgentRecord; connector: ConnectorRecord; modelId: string | null; isCommunicationWake: boolean } - | { allowed: false; reason: HeartbeatBlockReason; detail: string }; - -export type HeartbeatStartResult = - | { status: "started"; runId: string } - | { status: "skipped"; reason: HeartbeatBlockReason; detail: string }; - -const BLOCKED = ( - reason: HeartbeatBlockReason, - detail: string, -): Extract => ({ - allowed: false, - reason, - detail, -}); - -const SKIPPED = (decision: Extract): HeartbeatStartResult => ({ - status: "skipped", - reason: decision.reason, - detail: decision.detail, -}); - -export function createHeartbeat( - deps: OrchestrationDependencies, - resolveWorkspace: ResolveWorkspaceFn, - getRunEligibilityFailure: (agent: AgentRecord, connector: ConnectorRecord, projectId?: string | null) => string | null, - dispatchRunToWorker: (params: RunDispatchParams) => void, - hasActiveRun: (filter: { taskId?: string; agentId?: string; companyId: string }) => boolean, -) { - const { - db, - logger, - emitEvent, - hasWorkerReady, - isQuitting, - } = deps; - const skipStreakByAgent = new Map(); - const SKIP_ONGOING_EVERY_N = 40; - - function recordSkipActivity( - agentId: string, - companyId: string, - agentName: string, - reason: HeartbeatBlockReason, - detail: string, - trigger: string, - ) { - const tickAt = new Date().toISOString(); - const previous = skipStreakByAgent.get(agentId); - const sameReason = previous && previous.reason === reason && previous.detail === detail; - const nextStreak = sameReason - ? { reason, detail, count: previous.count + 1, since: previous.since } - : { reason, detail, count: 1, since: tickAt }; - skipStreakByAgent.set(agentId, nextStreak); - - const action = !sameReason - ? "heartbeat.skipped" - : nextStreak.count % SKIP_ONGOING_EVERY_N === 0 - ? "heartbeat.skip_ongoing" - : null; - if (!action) return; - - try { - db.core.activity.addActivity({ - companyId, - actor: "system", - action, - entityType: "agent", - entityId: agentId, - detail: JSON.stringify({ - agentName, - reason, - detail, - streak: nextStreak.count, - since: nextStreak.since, - trigger, - }), - }); - } catch (error) { - logger.warn(`[heartbeat] Failed to append ${action} activity for ${agentName}:`, error); - } - } - - function clearSkipActivity(agentId: string, companyId: string, agentName: string) { - const previous = skipStreakByAgent.get(agentId); - if (!previous) return; - skipStreakByAgent.delete(agentId); - try { - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "heartbeat.skip_cleared", - entityType: "agent", - entityId: agentId, - detail: JSON.stringify({ - agentName, - reason: previous.reason, - detail: previous.detail, - streak: previous.count, - since: previous.since, - resumedAt: new Date().toISOString(), - }), - }); - } catch (error) { - logger.warn(`[heartbeat] Failed to append heartbeat.skip_cleared activity for ${agentName}:`, error); - } - } - - function ensureAgentHeartbeatEnabled(agentId: string) { - const agent = db.core.entity.getAgent(agentId); - if (!agent.heartbeatEnabled) { - db.core.agents.setHeartbeat(agentId, true, agent.heartbeatIntervalSec || 120); - } - } - - function canRunAgent(agentId: string, companyId: string, trigger: string): HeartbeatRunDecision { - if (isQuitting()) return BLOCKED("system_unavailable", "quitting"); - const isMessageWake = trigger === "message"; - const isCommunicationWake = isMessageWake || trigger === "peer_request"; - if (!hasWorkerReady()) return BLOCKED("system_unavailable", "worker_not_ready"); - const companyStatus = db.core.company.getCompanyStatus(companyId); - if (companyStatus !== "active") return BLOCKED("system_unavailable", `company_${companyStatus}`); - const agent = db.core.entity.getAgent(agentId); - if (agent.companyId !== companyId) { - logger.warn(`[heartbeat] Refusing cross-company run for agent ${agentId}: ${agent.companyId} !== ${companyId}`); - return BLOCKED("agent_unavailable", "cross_company"); - } - const pick = pickModelForAgent(agent, { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (companyId, connectorId) => db.core.settings.getDisabledModels(companyId, connectorId), - listModelCapabilities: () => db.core.modelCapabilities.listModelCapabilities(), - readConnectors: () => db.core.connectors.readConnectors(), - }); - if (!pick.ok) { - logger.warn(`[heartbeat] Model pick failed for agent ${agent.name}: ${pick.message}`); - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "heartbeat.model_pick_failed", - entityType: "agent", - entityId: agent.id, - detail: pick.message, - }); - return BLOCKED("policy_blocked", "model_pick_failed"); - } - const assignment = pick.assignment; - const connector = db.core.connectors.getConnector(assignment.connectorId); - const effectiveAgentForEligibility: AgentRecord = { ...agent, model: assignment.modelId }; - const eligibilityFailure = getRunEligibilityFailure(effectiveAgentForEligibility, connector, null); - if (eligibilityFailure) { - return BLOCKED("policy_blocked", eligibilityFailure); - } - // Extended heartbeat policy checks (Paperclip parity). - // Let getHeartbeatPolicy throw — a missing row signals data corruption - // and silently falling back hides the gate that decides whether the - // agent runs at all. - const heartbeatPolicy = db.core.agents.getHeartbeatPolicy(agent.id); - - const activeRunCount = db.core.agents.countActiveRunsForAgent(agent.id, companyId); - const runAttemptDecision = decideRunAttempt({ - kind: "heartbeat", - trigger, - activeRunCount, - maxConcurrentRuns: heartbeatPolicy.maxConcurrentRuns, - lastStartedAtMs: agent.lastHeartbeatAt ? new Date(agent.lastHeartbeatAt).getTime() : null, - cooldownMs: heartbeatPolicy.cooldownSec * 1000, - nowMs: Date.now(), - bypassCooldown: isMessageWake, - }); - if (runAttemptDecision.action === "skip") { - return BLOCKED("policy_blocked", runAttemptDecision.reason); - } - - // wakeOnDemand gate: if disabled, only timer/bootstrap triggers allowed - if (!heartbeatPolicy.wakeOnDemand && trigger !== "timer" && trigger !== "bootstrap") { - return BLOCKED("policy_blocked", "wake_on_demand_disabled"); - } - if (db.core.agents.isAgentPendingApproval(agentId)) return BLOCKED("human_blocked", "pending_approval"); - const agentLevelBlock = db.core.approvals.getBlockingApproval(companyId, agentId, null); - if (agentLevelBlock) return BLOCKED("human_blocked", `approval_gate:${agentLevelBlock.type}`); - - const companyMode = db.core.company.getCompanyExecutionMode(companyId); - const approvalSettings = db.core.company.getCompanyApprovalSettings(companyId); - const shouldEnforceHumanReview = - companyMode === "ai_cofounder" || approvalSettings?.reviewDeliverables === true; - - // Block heartbeat when agent has tasks awaiting user deliverable review - if ( - shouldEnforceHumanReview && - !isMessageWake && - (db.core.tasks.hasAgentPendingDeliverableReview(agentId, companyId) || db.core.tasks.hasAgentTaskAwaitingReview(agentId, companyId)) - ) { - return BLOCKED("human_blocked", "awaiting_user_review"); - } - - // Block CEO heartbeat when company has any pending deliverable reviews - if ( - shouldEnforceHumanReview && - !isMessageWake && - !agent.reportsTo && - db.core.tasks.hasPendingDeliverableReviews(companyId) - ) { - return BLOCKED("human_blocked", "pending_deliverable_review"); - } - - return { - allowed: true, - agent, - connector, - modelId: assignment.modelId, - isCommunicationWake, - }; - } - - function startAgentHeartbeatRun(agentId: string, companyId: string, trigger: string): HeartbeatStartResult { - const decision = canRunAgent(agentId, companyId, trigger); - if (!decision.allowed) return SKIPPED(decision); - const { agent, connector, modelId, isCommunicationWake } = decision; - - const assignedTasks = isCommunicationWake - ? [] - : db.core.tasks.listAgentTasks(agentId, companyId, ["todo", "in_progress", "blocked"]); - const isTimer = trigger === "timer"; - const candidateTasks = assignedTasks; - - const candidateTask = candidateTasks.find((entry) => !entry.activeRunId) ?? null; - let task: ReturnType | null = null; - - if (candidateTask) { - task = db.core.entity.getTask(candidateTask.id); - } else { - const hasActiveAssignedRun = candidateTasks.some( - (entry) => entry.activeRunId && hasActiveRun({ taskId: entry.id, companyId }), - ); - if (hasActiveAssignedRun) return SKIPPED(BLOCKED("policy_blocked", "max_concurrent_runs")); - - const isCeo = !agent.reportsTo; - const isManager = db.core.agents.getDirectReports(agent.id, companyId).length > 0; - const goalCount = db.core.entity.countActiveGoalsForCompany(companyId); - const taskCount = db.core.tasks.countActiveTasksForCompany(companyId); - const companyNeedsBootstrap = goalCount > 0 && taskCount < goalCount; - - if (isTimer && !isCeo && !isManager && !companyNeedsBootstrap) { - return SKIPPED(BLOCKED("no_work", "no_actionable_tasks")); - } - - // No task — this is a true heartbeat run. The run row carries - // task_id = NULL; workspace falls back to agent/project/company. - task = null; - logger.info(`[heartbeat] Starting taskless heartbeat run for ${agent.name}`); - } - - if (task) { - const taskBlock = db.core.approvals.getBlockingApproval(companyId, agent.id, task.id); - if (taskBlock) return SKIPPED(BLOCKED("human_blocked", `approval_gate:${taskBlock.type}`)); - } - - let workspaceResolution: ReturnType; - try { - workspaceResolution = resolveWorkspace(task, agent, companyId); - } catch (error) { - if (error instanceof WorkspaceConfigurationError) { - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "heartbeat.workspace_unresolved", - entityType: "agent", - entityId: agent.id, - detail: error.message, - }); - logger.warn(`[heartbeat] Workspace unresolved for ${agent.name}: ${error.message}`); - return SKIPPED(BLOCKED("workspace_unavailable", "workspace_unresolved")); - } - throw error; - } - const workspace = workspaceResolution.workspace; - logger.info( - `[heartbeat] Workspace resolution for ${agent.name}: task.workspaceId=${task?.workspaceId ?? "null"}, agent.workspaceId=${agent.workspaceId ?? "null"}, projectId=${task?.projectId ?? "null"}, source=${workspaceResolution.source}, mode=${workspaceResolution.lockMode}, resolved=${workspace?.name ?? "NONE"}, localPath=${workspace?.localPath ?? "NONE"}`, - ); - - const run = task - ? db.core.runs.createTaskRun({ - companyId, - taskId: task.id, - agentId: agent.id, - workspaceId: workspaceResolution.lockMode === "exclusive" ? (workspace?.id ?? null) : null, - connectorId: connector.id, - }) - : db.core.runs.createRun({ - companyId, - taskId: null, - agentId: agent.id, - workspaceId: workspaceResolution.lockMode === "exclusive" ? (workspace?.id ?? null) : null, - connectorId: connector.id, - }); - if (!run) { - if (!task) { - throw new Error("Taskless heartbeat run creation returned null."); - } - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "execution.checkout_rejected", - entityType: "task", - entityId: task.id, - detail: `Agent ${agent.name} lost checkout race on task "${task.title}"`, - }); - return SKIPPED(BLOCKED("dispatch_race", "checkout_race_lost")); - } - - const companyBasic = db.core.company.getCompanyBasic(companyId); - dispatchRunToWorker({ - runId: run.id, - companyId, - agent, - task, - connector, - workspace, - workspaceMode: workspaceResolution.lockMode, - observationPath: workspaceResolution.observationPath, - companyName: companyBasic?.name ?? "Unknown", - companyDescription: companyBasic?.description ?? "", - snapshot: db.projection.snapshot.listSnapshot(), - trigger, - resolvedModel: modelId, - }); - - db.core.agents.markHeartbeatAt(agentId); - - // Actor audit: record what triggered this run - try { - const actorType = trigger === "timer" || trigger === "bootstrap" ? "system" : "agent"; - const actorId = trigger === "timer" || trigger === "bootstrap" ? null : trigger; - db.core.runs.updateRunActor(run.id, actorType, actorId); - } catch (error) { - logger.warn( - `[heartbeat] updateRunActor failed for run ${run.id}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - - db.core.activity.addActivity({ - companyId, - actor: "system", - action: "heartbeat.triggered", - entityType: "agent", - entityId: agent.id, - detail: `${trigger} heartbeat for ${agent.name}`, - }); - emitEvent({ type: "run-updated", runId: run.id, action: "created" }); - return { status: "started", runId: run.id }; - } - - function wakeAgentIfPossible(agentId: string | null | undefined, companyId: string, trigger: string, context?: Record) { - if (!agentId || isQuitting()) return null; - // `__board__` is the human participant sentinel, not an agent row. - // Upstream filters should strip it before we get here, but keeping - // this guard as defense-in-depth prevents a single stray call site - // (e.g. a future automation action that forwards the `toAgentId` - // raw) from spamming the log with "Agent not found: __board__". - if (agentId === HUMAN_SENDER_ID) return null; - let agent: AgentRecord; - try { - agent = db.core.entity.getAgent(agentId); - if (agent.companyId !== companyId) { - logger.warn(`[wake] Refusing cross-company wake for agent ${agentId}: ${agent.companyId} !== ${companyId}`); - return null; - } - } catch (error) { - logger.warn(`[wake] Failed to load agent ${agentId}:`, error); - return null; - } - try { - ensureAgentHeartbeatEnabled(agentId); - } catch (error) { - logger.warn(`[wake] Failed to ensure heartbeat for agent ${agentId}:`, error); - return null; - } - - const agentBusy = hasActiveRun({ agentId, companyId }); - if (agentBusy) { - db.automation.wakeup.enqueueWakeupRequest(companyId, agentId, trigger, `Wake for agent: ${trigger}`, context); - return null; - } - - const result = startAgentHeartbeatRun(agentId, companyId, trigger); - if (result.status === "skipped") { - recordSkipActivity(agentId, companyId, agent.name, result.reason, result.detail, trigger); - db.automation.wakeup.enqueueWakeupRequest( - companyId, - agentId, - trigger, - `Wake for agent (deferred:${result.reason}/${result.detail}): ${trigger}`, - context, - ); - return null; - } - clearSkipActivity(agentId, companyId, agent.name); - db.automation.wakeup.completePendingWakeupRequests(agentId, companyId, result.runId); - return result.runId; - } - - return { - canRunAgent, - ensureAgentHeartbeatEnabled, - startAgentHeartbeatRun, - wakeAgentIfPossible, - }; -} diff --git a/src/main/orchestration/index.ts b/src/main/orchestration/index.ts deleted file mode 100644 index fac44569..00000000 --- a/src/main/orchestration/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { OrchestrationDependencies } from "./types"; -import { createRunDispatch } from "./run-dispatch"; -import { createHeartbeat } from "./heartbeat"; -import { createScheduler } from "./scheduler"; -import { createTaskRunner } from "./task-runner"; - -export function createOrchestrationService(deps: OrchestrationDependencies) { - const { db } = deps; - - function hasActiveRun(filter: { taskId?: string; agentId?: string; companyId: string }) { - return db.core.runs.hasActiveRun(filter); - } - - const runDispatch = createRunDispatch(deps); - const heartbeat = createHeartbeat( - deps, - runDispatch.resolveWorkspace, - runDispatch.getRunEligibilityFailure, - runDispatch.dispatchRunToWorker, - hasActiveRun, - ); - const scheduler = createScheduler( - deps, - hasActiveRun, - heartbeat.wakeAgentIfPossible, - ); - const taskRunner = createTaskRunner( - deps, - runDispatch.resolveWorkspace, - runDispatch.getRunEligibilityFailure, - runDispatch.dispatchRunToWorker, - hasActiveRun, - ); - - return { - resolveWorkspace: runDispatch.resolveWorkspace, - wakeAgentIfPossible: heartbeat.wakeAgentIfPossible, - dispatchRunToWorker: runDispatch.dispatchRunToWorker, - queueTaskRun: taskRunner.queueTaskRun, - createTaskRunForDeferredDispatch: taskRunner.createTaskRunForDeferredDispatch, - resumeQueuedRuns: taskRunner.resumeQueuedRuns, - startAgentHeartbeatRun: heartbeat.startAgentHeartbeatRun, - startAllSchedulers: scheduler.startAllSchedulers, - stopAllSchedulers: scheduler.stopAllSchedulers, - }; -} diff --git a/src/main/orchestration/initial-user-turn.ts b/src/main/orchestration/initial-user-turn.ts deleted file mode 100644 index 69a419fa..00000000 --- a/src/main/orchestration/initial-user-turn.ts +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Resolve the initial user-role turn that seeds an agent's pi run. - * - * The previous layout defaulted to the literal string `"Continue."` when - * no task was attached, so every message-wake or peer-request run started - * the agent with a prompt that carried no signal at all — combined with - * the system-prompt heartbeat fallback that invited status summaries, - * the recipient would routinely "reply" by narrating its own queue - * instead of answering the message that woke it. - * - * This module replaces that default with a trigger-specific imperative, - * and — for communication wakes — binds the initial turn to the actual - * inbox rows so the agent sees concrete `message_id` / sender references - * in its first user turn. The full message bodies still arrive as - * priorMessages through `prepareRun`'s inbox projection; this turn is - * the action cue on top of them. - */ - -import type { AppDatabase } from "../database"; -import type { AgentMessageRecord } from "@shared/types"; -import { HUMAN_SENDER_ID } from "../messaging/dispatch"; -import { logAppError } from "../errors/index.js"; -import log from "electron-log/main.js"; - -export interface InitialUserTurnDeps { - db: AppDatabase; -} - -const MAX_MESSAGE_LINES = 10; -const SUBJECT_PREVIEW_LEN = 80; - -export function resolveInitialUserTurn( - params: { - trigger: string | null; - task: ReturnType | null; - companyId: string; - agentId: string; - }, - deps: InitialUserTurnDeps, -): string { - const { trigger, task, companyId, agentId } = params; - - if (task) { - const description = (task.description ?? "").trim(); - return description.length > 0 ? `${task.title}\n\n${description}` : task.title; - } - - if (trigger === "message" || trigger === "peer_request") { - const unread = deps.db.core.messages.listAgentInboxUnread(companyId, agentId); - if (unread.length > 0) { - return buildCommunicationTurn(trigger, unread, deps.db); - } - } - - // CEO / team-building semantic cue (C4 part 4/5). - // - // The turn names the state and points at the mode contract. The action - // policy lives in the tool schema and the CEO-mode instructions so model - // swaps do not depend on an imperative one-off user sentence. - if (trigger === "timer" || trigger === "bootstrap" || trigger === "app_restart_resume") { - const cue = tryResolveCeoTeamBuildingCue({ agentId, companyId, db: deps.db }); - if (cue !== null) return cue; - } - - return buildGenericWakeTurn(trigger); -} - -/** - * Returns the team-building cue when (and only when) the agent is a - * CEO (`reportsTo == null`) with zero active direct reports. Any other - * shape returns null and the caller falls through to - * `buildGenericWakeTurn`. A DB lookup failure is classified and - * logged — the caller never sees the raw error because the pi agent - * loop must not crash on a prompt-assembly hiccup, but the classified - * log line keeps the fail mode visible rather than swallowed. - */ -function tryResolveCeoTeamBuildingCue(params: { - agentId: string; - companyId: string; - db: AppDatabase; -}): string | null { - const { agentId, companyId, db } = params; - try { - const agent = db.core.entity.getAgent(agentId); - if (agent.reportsTo) return null; - const activeReports = db.core.agents - .getDirectReports(agentId, companyId) - .filter((r) => r.status !== "pending_approval" && r.status !== "terminated"); - if (activeReports.length > 0) return null; - return [ - "This wake: your team is empty.", - "Follow the Team Building operating instructions using the tools exposed for this run, then return.", - ].join("\n\n"); - } catch (error) { - logAppError( - log, - error, - { - kind: "recoverable", - code: "initial_user_turn.ceo_lookup.failed", - message: `CEO team-building cue lookup failed for agent ${agentId}; falling back to the generic timer turn.`, - context: { agentId, companyId }, - }, - "warn", - ); - return null; - } -} - -function buildCommunicationTurn( - trigger: "message" | "peer_request", - unread: AgentMessageRecord[], - db: AppDatabase, -): string { - const rows = unread.slice(0, MAX_MESSAGE_LINES).map((record) => { - const senderLabel = record.fromAgentId === HUMAN_SENDER_ID - ? "Board/Human" - : resolveAgentLabel(db, record.fromAgentId); - const subject = truncate(record.subject || "(no subject)", SUBJECT_PREVIEW_LEN); - const parentRef = record.parentMessageId ? ` · reply_to=${record.parentMessageId}` : ""; - return `- message_id=${record.id} · from=${senderLabel} (${record.fromAgentId}) · channel=${record.channel}${parentRef} · "${subject}"`; - }); - const overflow = unread.length > MAX_MESSAGE_LINES - ? `\n…and ${unread.length - MAX_MESSAGE_LINES} more in your inbox.` - : ""; - const header = trigger === "peer_request" - ? "A peer has requested your attention. Respond to each of the following messages:" - : "You have new messages. Respond to each of the following:"; - return `${header}\n${rows.join("\n")}${overflow}\n\nFor every row, reply to the sender using its message_id (channel-appropriate) and mark the message as read before moving on.`; -} - -function buildGenericWakeTurn(trigger: string | null): string { - switch (trigger) { - case "timer": - return "Heartbeat check. Read your briefing and execute the top-priority action described in your Operating Instructions for the mode you are currently in. If your briefing lists unread messages, reply to them before starting task work."; - case "assignment": - return "A new task has been assigned to you. Find it in your briefing, check it out via POST /api/issues/{issueId}/checkout, then begin work."; - case "comment": - return "A new comment landed on one of your tasks. Read the recent comments in your briefing and respond or adjust your work as needed."; - case "approval_resolved": - return "An approval you requested has been decided. Act on the outcome surfaced in your briefing."; - case "subtask_completed": - return "A subtask you delegated is ready for review. Evaluate the work against its acceptance criteria and either accept it or request changes."; - case "task_review_requested": - return "A direct report submitted a top-level task for your review. Validate against the original acceptance criteria before deciding."; - case "goal_activated": - return "A goal you own has been activated. Decompose it into projects and tasks, then delegate the first batch of work."; - case "report_blocked": - return "One of your reports is blocked. Investigate the blocker, provide direction or credentials, and unblock them."; - case "report_failed": - return "A run by one of your reports has failed. Diagnose, decide on retry or reassignment, then act."; - case "report_stuck": - return "One of your reports has exhausted its self-wake budget without progress. Check its state and take corrective action."; - case "task_continuation": - return "Continue on your most actionable assigned task."; - case "bootstrap": - return "This is an early heartbeat for your company. Translate active goals into concrete projects, tasks, and hiring plans."; - case "manual": - return "You were woken manually by the human operator. Review your briefing and act on whatever they are waiting on."; - case "message": - case "peer_request": - return "A communication arrived but your inbox is empty now — another run may have delivered it. Review your recent transcript and continue any in-progress collaboration."; - default: - return "Review your briefing and take the next appropriate action."; - } -} - -function resolveAgentLabel(db: AppDatabase, agentId: string): string { - try { - const name = db.core.agents.findAgentName(agentId); - if (name && name.length > 0) return name; - } catch { - // fall through - } - return agentId; -} - -function truncate(text: string, max: number): string { - if (text.length <= max) return text; - return `${text.slice(0, max - 1)}…`; -} diff --git a/src/main/orchestration/internal-tool-selector.ts b/src/main/orchestration/internal-tool-selector.ts deleted file mode 100644 index fac47cb6..00000000 --- a/src/main/orchestration/internal-tool-selector.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Decide which internal tools (`hire_agent`, `file_approval`) to attach - * to a given run's agent (C4 part 3/5). - * - * The selector runs on main at dispatch time — the worker never - * re-derives this. Rule set, in order: - * - * - An agent that `canRequestHire` (CEO, HR, dept lead with reports, - * anyone with org-management authority) receives `hire_agent`. A - * manager hiring an IC is a legitimate flow. - * - An agent that `canFileCeoStrategy` (genuine CEO: CEO-equivalent - * role + `reportsTo === null`) receives `file_approval` after the - * initial team-building phase has produced at least one hire. - * - * The two predicates are intentionally orthogonal: a VP with hiring - * authority receives hiring scope, while CEO-strategy approval remains - * pinned to the CEO role and the current org phase. - * - * No hedging, no sentinel values: if the DB lookup throws the caller - * is already in a broken state and should not silently fall through - * to an empty tool set. - */ - -import type { AppDatabase } from "@main/database"; -import type { AgentRecord } from "@shared/types"; -import { canFileCeoStrategy, canRequestHire } from "@main/agent-permissions"; - -export type InternalToolName = "hire_agent" | "file_approval"; - -export function resolveInternalToolsForAgent( - db: AppDatabase, - agent: AgentRecord, -): InternalToolName[] { - const tools: InternalToolName[] = []; - if (canRequestHire(db, agent.companyId, agent.id)) { - tools.push("hire_agent"); - } - if (canFileCeoStrategy(db, agent.companyId, agent.id) && !isInitialTeamBuildingPhase(db, agent)) { - tools.push("file_approval"); - } - return tools; -} - -function isInitialTeamBuildingPhase(db: AppDatabase, agent: AgentRecord): boolean { - if (!canFileCeoStrategy(db, agent.companyId, agent.id)) return false; - - const directReports = db.core.agents.getDirectReports(agent.id, agent.companyId); - const activeReports = directReports.filter( - (report) => report.status !== "pending_approval" && report.status !== "terminated", - ); - const pendingReportRows = directReports.filter((report) => report.status === "pending_approval"); - const pendingHireApprovals = db.core.approvals - .listCompanyApprovalsByType(agent.companyId, "hire_agent") - .filter((approval) => approval.state === "pending"); - const pendingStrategyApprovals = db.core.approvals - .listCompanyApprovalsByType(agent.companyId, "approve_ceo_strategy") - .filter((approval) => approval.state === "pending"); - - return ( - activeReports.length === 0 && - pendingReportRows.length === 0 && - pendingHireApprovals.length === 0 && - pendingStrategyApprovals.length === 0 - ); -} diff --git a/src/main/orchestration/resolve-workspace.ts b/src/main/orchestration/resolve-workspace.ts deleted file mode 100644 index d0b57dcd..00000000 --- a/src/main/orchestration/resolve-workspace.ts +++ /dev/null @@ -1,225 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { AgentRecord, TaskRecord, WorkspaceRecord } from "@shared/types"; -import type { WorkspaceLockMode } from "./types"; - -/** - * Per-task workspace lock inference (v52+). - * - * The core invariant is: `lockMode='exclusive'` is an opt-in, - * `lockMode='none'` is the default. Previously every resolved - * workspace was held exclusively, which folded four runnable - * agents onto a single company workspace lock and serialised the - * entire C-suite. The fix is to ask the task row for filesystem - * intent. - * - * `inferLockMode` returns the pair of decisions the dispatcher - * needs (mode + which workspace, if any). `resolveWorkspaceWithLockMode` - * is the thin outward-facing wrapper that loads the actual - * `WorkspaceRecord` for callers that need the path / companyId. - * - * Silent fallbacks removed in this rewrite: - * - * - `company_fallback`: previously the fourth fallback step - * returned *any* workspace row in the company as the lock target. - * That was silent corruption's favourite mechanism: four agents - * with no workspace binding would all land on the same row and - * fight for one mutex. A task that needs a filesystem and has no - * legitimate binding now throws `ConfigurationError` at resolve - * time so the caller decides (skip heartbeat, surface error, - * whatever) instead of the resolver guessing. - * - * - `lockMode='exclusive'` always returns a resolved workspace. - * `lockMode='none'` always returns `workspace=null`. - * - */ - -export type WorkspaceResolutionSource = - | "task" - | "agent" - | "project" - | "none"; - -export interface WorkspaceResolution { - /** - * The workspace whose lock the dispatcher will claim. Non-null iff - * `lockMode === 'exclusive'`; the type system enforces the pair. - */ - workspace: WorkspaceRecord | null; - lockMode: WorkspaceLockMode; - source: WorkspaceResolutionSource; - /** - * Where the artifact projector should *observe* for files this run - * may produce, independent of the lock decision. Set whenever the - * company has at least one workspace row, even when `lockMode='none'` - * because cognitive agents still write deliverables to disk via `bash`, - * and the projector needs an observation root to scan against the - * mtime baseline. Null only when the company has no workspace at - * all (genuinely nowhere to look). - * - * For `lockMode='exclusive'` this is always the same path as - * `workspace.localPath`. For `lockMode='none'` this is the - * company's primary/oldest workspace localPath, picked by - * `getCompanyObservationWorkspace`. - * - * Decoupling observation from locking is what fixes the regression - * where cognitive agents wrote 19 files but the DocumentCenter - * surfaced only 1: previously `workspacePath` shared the lock - * decision, so any non-exclusive run lost its projector. - */ - observationPath: string | null; -} - -export class WorkspaceConfigurationError extends Error { - readonly code = "WORKSPACE_UNRESOLVED"; - constructor(message: string) { - super(message); - this.name = "WorkspaceConfigurationError"; - } -} - -/** - * Accept the widened shapes call sites actually pass. `projectId` - * lives as `string | null | undefined` in several historical call - * sites (legacy inline types). `role` and `department` remain in the - * input shape for existing call sites; lock inference reads only - * workspaceId from the agent. - */ -type TaskInput = { - workspaceId: TaskRecord["workspaceId"]; - projectId?: TaskRecord["projectId"] | undefined; - requiresFilesystem?: boolean; -}; - -type AgentInput = Pick & { - role?: string | null; - department?: AgentRecord["department"]; -}; - -/** - * Decide whether this (task, agent) pair should hold the workspace - * exclusive for the duration of the run. Returns the mode and the - * workspace-id the lock should sit on; callers load the row - * afterwards. - * - * Decision table: - * - * 1. Cognitive task (`requiresFilesystem !== true`) -> none. - * Workspace binding remains available as an observation root. - * - * 2. Filesystem task with `task.workspaceId` set -> exclusive on - * that workspace. - * - * 3. Filesystem task without `task.workspaceId` -> exclusive on - * agent.workspaceId / project primary. Throws if neither exists. - */ -function inferLockMode( - db: AppDatabase, - task: TaskInput | null, - agent: AgentInput, - companyId: string, -): { lockMode: WorkspaceLockMode; workspaceId: string | null; source: WorkspaceResolutionSource } { - if (task?.requiresFilesystem !== true) { - return { lockMode: "none", workspaceId: null, source: "none" }; - } - - if (task.workspaceId) { - return { lockMode: "exclusive", workspaceId: task.workspaceId, source: "task" }; - } - - // Filesystem-touching task -> agent workspace first, then project primary. - if (agent.workspaceId) { - return { lockMode: "exclusive", workspaceId: agent.workspaceId, source: "agent" }; - } - - const projectWorkspace = db.core.workspaces.getProjectPrimaryWorkspace( - task?.projectId ?? null, - companyId, - ); - if (projectWorkspace) { - return { - lockMode: "exclusive", - workspaceId: projectWorkspace.id, - source: "project", - }; - } - - throw new WorkspaceConfigurationError( - `Task requires a filesystem-backed run but no workspace is bound to the task, agent, or project (companyId=${companyId}, taskId=${task?.workspaceId === undefined ? "" : (task as { id?: string }).id ?? ""}, agentId=${(agent as { id?: string }).id ?? ""}, projectId=${task?.projectId ?? ""}).`, - ); -} - -/** - * Resolve the workspace + lock mode for a run context. - * - * Contract: - * - lockMode 'exclusive' => workspace is a live WorkspaceRecord. - * - lockMode 'none' => workspace is null. - * - * Violations throw `WorkspaceConfigurationError` at resolve time so - * the caller chooses how to recover (skip heartbeat, cancel run, - * surface to operator). There is no silent mode degradation. - */ -export function resolveWorkspaceWithLockMode( - db: AppDatabase, - task: TaskInput | null, - agent: AgentInput, - companyId: string, -): WorkspaceResolution { - const decision = inferLockMode(db, task, agent, companyId); - - if (decision.lockMode === "none") { - // No lock claim, but the cognitive run can still touch the - // filesystem via `bash`. Pick a stable observation root so the - // artifact projector can baseline + diff the run's footprint. A - // task-bound workspace is the strongest observation signal; the - // company primary/oldest workspace remains the company-level root. - let observation: WorkspaceRecord | null = null; - if (task?.workspaceId) { - observation = db.core.workspaces.getWorkspace(task.workspaceId); - if (!observation) { - throw new WorkspaceConfigurationError( - `Task observation workspace ${task.workspaceId} does not exist (companyId=${companyId}).`, - ); - } - if (observation.companyId !== companyId) { - throw new WorkspaceConfigurationError( - `Task observation workspace ${observation.id} belongs to company ${observation.companyId}, not ${companyId}.`, - ); - } - } else { - observation = db.core.workspaces.getCompanyObservationWorkspace(companyId); - } - return { - workspace: null, - lockMode: "none", - source: "none", - observationPath: observation?.localPath ?? null, - }; - } - - if (!decision.workspaceId) { - throw new WorkspaceConfigurationError( - `inferLockMode returned exclusive with no workspaceId (companyId=${companyId}); lock mode/workspace invariant broken.`, - ); - } - - const workspace = db.core.workspaces.getWorkspace(decision.workspaceId); - if (!workspace) { - throw new WorkspaceConfigurationError( - `Resolved workspace ${decision.workspaceId} does not exist (companyId=${companyId}, source=${decision.source}).`, - ); - } - if (workspace.companyId !== companyId) { - throw new WorkspaceConfigurationError( - `Resolved workspace ${workspace.id} belongs to company ${workspace.companyId}, not ${companyId}.`, - ); - } - - return { - workspace, - lockMode: "exclusive", - source: decision.source, - // Exclusive runs observe the same path they lock. - observationPath: workspace.localPath, - }; -} diff --git a/src/main/orchestration/run-dispatch.ts b/src/main/orchestration/run-dispatch.ts deleted file mode 100644 index c3c7b31b..00000000 --- a/src/main/orchestration/run-dispatch.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { getConnectorExecutionReadinessIssue } from "@shared/connector-policy"; -import type { AgentRecord, ConnectorRecord, DepartmentId, TaskRecord } from "@shared/types"; -import type { OrchestrationDependencies } from "./types"; -import { buildRunPayload, type RunDispatchParams } from "./turn-context"; -import { validateConnectorModelSelection } from "../connector-model-policy"; -import { resolveWorkspaceWithLockMode } from "./resolve-workspace"; -import { AppError } from "../errors/index.js"; - -type ResolveWorkspaceTaskInput = - | (Pick & { requiresFilesystem?: boolean }) - | null; - -type ResolveWorkspaceAgentInput = Pick & { - role?: string | null; - department?: DepartmentId | null; -}; - -export type ResolveWorkspaceFn = ( - task: ResolveWorkspaceTaskInput, - agent: ResolveWorkspaceAgentInput, - companyId: string, -) => ReturnType; - -export function createRunDispatch(deps: OrchestrationDependencies) { - const { - db, - logger, - emitEvent, - isQuitting, - hasWorkerReady, - getApiPort, - createRunToken, - enqueueWorkerRun, - listRuntimeSkillEntries, - budgetService, - getSessionHandoff, - evaluatePreRunSessionRotation, - } = deps; - - const resolveWorkspace: ResolveWorkspaceFn = (task, agent, companyId) => - resolveWorkspaceWithLockMode(db, task, agent, companyId); - - function formatDispatchError(error: unknown): string { - if (error instanceof AppError) { - return `[${error.code}] ${error.message}`; - } - if (error instanceof Error) { - return error.message; - } - return String(error); - } - - function failRunBeforeWorkerEnqueue( - params: RunDispatchParams, - error: unknown, - workspaceLockClaimed: boolean, - ): void { - const errorMessage = formatDispatchError(error); - logger.error(`[run] Dispatch failed before worker enqueue for ${params.runId}: ${errorMessage}`); - db.core.runs.finishRun({ - runId: params.runId, - status: "failed", - summary: "Run failed before worker enqueue.", - errorMessage, - exitCode: null, - signal: null, - model: params.resolvedModel ?? null, - unattributedCost: true, - }); - if (workspaceLockClaimed && params.workspaceMode === "exclusive" && params.workspace) { - db.core.workspaces.releaseWorkspaceLock(params.workspace.id, params.runId); - } - db.core.activity.addActivity({ - companyId: params.companyId, - actor: params.agent.id, - action: "run.failed", - entityType: "run", - entityId: params.runId, - detail: errorMessage, - }); - emitEvent({ type: "run-updated", runId: params.runId, action: "completed" }); - } - - function getRunEligibilityFailure( - agent: { status: string; budgetMonthlyUsd: number; spentMonthlyUsd: number; name: string; connectorId: string; id: string; companyId: string; model?: string | null }, - connector: Pick, - projectId: string | null = null, - ) { - if (["terminated", "paused", "pending_approval"].includes(agent.status)) { - return "AGENT_NOT_RUNNABLE"; - } - const gate = budgetService.evaluateBudgetGate(agent.companyId, agent.id, projectId); - if (!gate.allowed) { - logger.info(`[run] Agent ${agent.name} budget policy blocked: ${gate.blockedBy.map(b => `${b.scopeType}(${b.policyId})`).join(", ")}`); - return "BUDGET_POLICY_BLOCKED"; - } - const connectorIssue = getConnectorExecutionReadinessIssue(connector); - if (connectorIssue) { - const issue = connectorIssue ?? `Connector ${connector.id} is not execution-ready.`; - logger.info(`[run] Agent ${agent.name} connector ${connector.id} blocked: ${issue}`); - return "CONNECTOR_NOT_READY"; - } - const modelSelection = validateConnectorModelSelection( - { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (cid, connId) => db.core.settings.getDisabledModels(cid, connId), - }, - agent.companyId, - connector.id, - agent.model ?? null, - ); - if (!modelSelection.ok) { - logger.info(`[run] Agent ${agent.name} connector model blocked: ${modelSelection.error}`); - return "CONNECTOR_MODEL_NOT_ALLOWED"; - } - return null; - } - - function dispatchRunToWorker(params: RunDispatchParams) { - let workspaceLockClaimed = false; - try { - if (isQuitting()) { - throw new Error("Application is shutting down — refusing to dispatch new run."); - } - if (!hasWorkerReady()) { - throw new Error("Orchestration worker is not ready."); - } - const connectorIssue = getConnectorExecutionReadinessIssue(params.connector); - if (connectorIssue) { - throw new Error(connectorIssue); - } - - // D-02: Claim the workspace lock synchronously before enqueuing the run. - // Previously the worker claimed the lock only after it emitted `running`, - // so two runs could race between enqueue and startup and both read the - // same workspace mid-write. Main is the authoritative coordinator. - // - // On contention we mark the run `cancelled`, not `failed`. The Dashboard - // "Needs attention" card only surfaces failed/timed_out/interrupted runs - // (see src/renderer/components/dashboard/Dashboard.tsx), so the user is - // not alarmed by a transient backoff. The task row is rolled back to - // `todo` via the `finishRun` never-started branch, so heartbeat picks - // it up on the next cycle with no manual intervention. - if (params.workspaceMode === "exclusive" && params.workspace) { - if (!db.core.workspaces.claimWorkspaceLock(params.workspace.id, params.runId)) { - db.core.runs.finishRun({ - runId: params.runId, - status: "cancelled", - summary: null, - errorMessage: `Workspace ${params.workspace.id} is in use by another run; will retry on the next heartbeat.`, - exitCode: null, - signal: null, - model: null, - unattributedCost: true, - }); - emitEvent({ type: "run-updated", runId: params.runId, action: "completed" }); - return; - } - workspaceLockClaimed = true; - } - - const payload = buildRunPayload(params, { - db, - logger, - getApiPort, - createRunToken, - listRuntimeSkillEntries, - getSessionHandoff, - evaluatePreRunSessionRotation, - }); - - enqueueWorkerRun(payload); - } catch (error) { - failRunBeforeWorkerEnqueue(params, error, workspaceLockClaimed); - } - } - - return { resolveWorkspace, getRunEligibilityFailure, dispatchRunToWorker }; -} diff --git a/src/main/orchestration/scheduler.ts b/src/main/orchestration/scheduler.ts deleted file mode 100644 index d10a9a4c..00000000 --- a/src/main/orchestration/scheduler.ts +++ /dev/null @@ -1,371 +0,0 @@ -import { powerMonitor } from "electron"; -import { logAppError } from "../errors/index.js"; -import { resolveApprovalDecision } from "../approval-policy"; -import { dispatchAgentMessage } from "../messaging/dispatch"; -import { sweepStaleReviews, type SweepStaleReviewsDeps } from "../task-quality-gates"; -import type { OrchestrationDependencies } from "./types"; - -type SchedulerPhase = "lock_recovery" | "housekeeping" | "idle_automation" | "heartbeat_cadence"; - -const TICK_INTERVAL_MS = 10_000; -const PENDING_WAKE_RETRY_INTERVAL_MS = 120_000; -const PHASE_INTERVAL_MS: Record = { - lock_recovery: 60_000, - housekeeping: 300_000, - idle_automation: 60_000, - heartbeat_cadence: 60_000, -}; - -export function createScheduler( - deps: OrchestrationDependencies, - hasActiveRun: (filter: { taskId?: string; agentId?: string; companyId: string }) => boolean, - wakeAgentIfPossible: (agentId: string, companyId: string, trigger: string) => string | null | undefined, -) { - const { - db, - logger, - publishDomainChanged, - dispatchAutomation, - hasWorkerReady, - isQuitting, - notify, - budgetService, - } = deps; - - let timer: ReturnType | null = null; - let resumeListener: (() => void) | null = null; - let unlockListener: (() => void) | null = null; - const phaseLastRunAt = new Map(); - const scheduleLastFiredByCompany = new Map(); - const pendingWakeAttemptByAgent = new Map(); - const taskWakeAttemptByAgent = new Map(); - const bootstrapAttemptByAgent = new Map(); - - function phaseIsDue(phase: SchedulerPhase, now: number): boolean { - const lastRunAt = phaseLastRunAt.get(phase) ?? 0; - if (now - lastRunAt < PHASE_INTERVAL_MS[phase]) return false; - phaseLastRunAt.set(phase, now); - return true; - } - - function agentAttemptKey(companyId: string, agentId: string): string { - return `${companyId}:${agentId}`; - } - - function runLockRecoveryPhase() { - if (!hasWorkerReady()) return; - try { - const recovered = db.recoverStaleLocks(); - for (const task of recovered) { - db.core.activity.addActivity({ - companyId: task.companyId, - actor: "system", - action: "execution.lock_recovered", - entityType: "task", - entityId: task.taskId, - detail: `Recovered stale lock on task "${task.title}" after 15min timeout`, - }); - logger.info(`[lock-recovery] Recovered stale lock on task ${task.taskId}: "${task.title}"`); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.lock_recovery.stale_lock_sweep_failed", - message: "Stale task lock recovery sweep failed; next tick will retry", - }); - } - - try { - const staleReleased = db.core.workspaces.releaseStaleWorkspaceLocks(); - if (staleReleased > 0) { - logger.info(`[lock-recovery] Released ${staleReleased} stale workspace lock(s)`); - publishDomainChanged(); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.lock_recovery.workspace_lock_sweep_failed", - message: "Stale workspace lock cleanup failed; next tick will retry", - }); - } - } - - function runHousekeepingPhase() { - if (!hasWorkerReady()) return; - const activeCompanies = db.core.company.listActiveCompanyIds(); - - for (const company of activeCompanies) { - try { - const currentMonth = new Date().toISOString().slice(0, 7); - const lastResetMonth = db.core.settings.getLastBudgetResetMonth(company.id) ?? ""; - if (currentMonth !== lastResetMonth) { - db.core.agents.resetMonthlyBudgets(company.id); - db.core.settings.setLastBudgetResetMonth(company.id, currentMonth); - logger.info(`[housekeeping] Reset monthly budgets for company ${company.name} (${currentMonth})`); - } - - const closedIncidents = budgetService.autoCloseExpiredIncidents(company.id); - if (closedIncidents > 0) { - logger.info(`[housekeeping] Auto-closed ${closedIncidents} expired budget incident(s) for company ${company.name}`); - } - - try { - const sweepDeps: SweepStaleReviewsDeps = { - db, - dispatchAgentMessage, - resolveApprovalDecision, - notify, - getCompanyExecutionMode: (companyId: string) => db.core.company.getCompanyExecutionMode(companyId), - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => { - dispatchAutomation("task_status_changed", { companyId, taskId, previousStatus, newStatus }); - publishDomainChanged(); - }, - handleApprovalResolved: (approvalId: string, companyId: string, _decision: string) => { - dispatchAutomation("approval_resolved", { companyId }); - publishDomainChanged(); - }, - emitEvent: deps.emitEvent, - publishDomainChanged, - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => - agentId != null ? wakeAgentIfPossible(agentId, companyId, trigger) ?? null : null, - logger, - }; - const escalated = sweepStaleReviews(company.id, sweepDeps); - if (escalated > 0) { - logger.info(`[housekeeping] Auto-escalated ${escalated} stale review(s) for company ${company.name}`); - publishDomainChanged(); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.housekeeping.stale_review_sweep_failed", - message: `Stale review sweep failed for company ${company.id}`, - context: { companyId: company.id }, - }); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.housekeeping.company_tick_failed", - message: `Housekeeping tick failed for company ${company.id}`, - context: { companyId: company.id }, - }); - } - } - - try { - const staleWakeups = db.automation.wakeup.purgeExpiredWakeupRequests(); - if (staleWakeups > 0) { - logger.info(`[housekeeping] Purged ${staleWakeups} expired wakeup request(s)`); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.housekeeping.wakeup_purge_failed", - message: "Expired wakeup request purge failed; next tick will retry", - }); - } - - try { - const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); - const purgedProjections = db.projection.inbox.purgeOrphanProjections(cutoff); - if (purgedProjections > 0) { - logger.info(`[housekeeping] Purged ${purgedProjections} orphan inbox projection ledger row(s)`); - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.housekeeping.inbox_projection_purge_failed", - message: "Orphan inbox projection purge failed; next tick will retry", - }); - } - } - - function runIdleAutomationPhase() { - if (!hasWorkerReady()) return; - const activeCompanies = db.core.company.listActiveCompanyIds(); - const now = Date.now(); - - for (const company of activeCompanies) { - try { - const companyAgents = db.core.agents.listActiveAgentsForCompany(company.id); - for (const agent of companyAgents) { - if (db.core.agents.hasAgentAssignedTasks(agent.id, company.id)) continue; - const lastActive = agent.lastHeartbeatAt ? new Date(agent.lastHeartbeatAt).getTime() : 0; - const idleThreshold = 20 * 60 * 1000; - if (now - lastActive > idleThreshold) { - dispatchAutomation("agent_idle", { - companyId: company.id, - agentId: agent.id, - department: agent.department ?? undefined, - }); - } - } - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.idle_automation.company_tick_failed", - message: `Idle automation tick failed for company ${company.id}`, - context: { companyId: company.id }, - }); - } - } - } - - function runCompanyBootstrap(company: { id: string; name: string }, now: number, wokenAgentIds: Set) { - const goalCount = db.core.entity.countActiveGoalsForCompany(company.id); - const advancingCount = db.core.tasks.countAdvancingTasksForCompany(company.id); - if (goalCount === 0 || advancingCount > 0) return; - - const ceo = db.core.agents.getCeoForCompany(company.id); - if (!ceo) return; - if (wokenAgentIds.has(ceo.id)) return; - if (hasActiveRun({ agentId: ceo.id, companyId: company.id })) return; - - const lastHeartbeat = ceo.lastHeartbeatAt ? new Date(ceo.lastHeartbeatAt).getTime() : 0; - const attemptKey = agentAttemptKey(company.id, ceo.id); - const lastAttempt = bootstrapAttemptByAgent.get(attemptKey) ?? 0; - const bootstrapCooldown = 120_000; - if (now - Math.max(lastHeartbeat, lastAttempt) <= bootstrapCooldown) return; - - bootstrapAttemptByAgent.set(attemptKey, now); - logger.info(`[scheduler] Company ${company.name} has ${goalCount} goal(s) and no advancing tasks; bootstrapping CEO ${ceo.name}`); - wakeAgentIfPossible(ceo.id, company.id, "bootstrap"); - } - - function runScheduleAutomation(companyId: string, now: number) { - const lastScheduleFired = scheduleLastFiredByCompany.get(companyId) ?? 0; - if (now - lastScheduleFired < 60_000) return; - dispatchAutomation("schedule", { companyId }); - scheduleLastFiredByCompany.set(companyId, now); - } - - function runPendingWakeupCadence(companyId: string, now: number): Set { - const wokenAgentIds = new Set(); - const pendingWakeupAgents = db.automation.wakeup.listPendingWakeupAgents(companyId); - for (const { agentId } of pendingWakeupAgents) { - // Queued wakeups are explicit durable events; they bypass the periodic - // heartbeat_enabled scan and let wakeAgentIfPossible own re-enabling. - if (hasActiveRun({ agentId, companyId })) continue; - if (deps.checkpointEngine?.shouldPauseHeartbeat(companyId, agentId)) continue; - - const attemptKey = agentAttemptKey(companyId, agentId); - const lastAttempt = pendingWakeAttemptByAgent.get(attemptKey) ?? 0; - if (lastAttempt > 0 && now - lastAttempt < PENDING_WAKE_RETRY_INTERVAL_MS) continue; - - const trigger = db.automation.wakeup.getPreferredWakeTrigger(agentId, companyId); - if (!trigger) continue; - - pendingWakeAttemptByAgent.set(attemptKey, now); - const runId = wakeAgentIfPossible(agentId, companyId, trigger); - if (runId) { - pendingWakeAttemptByAgent.delete(attemptKey); - wokenAgentIds.add(agentId); - } - } - return wokenAgentIds; - } - - function runAssignedTaskWakeCadence(companyId: string, now: number, wokenAgentIds: Set) { - const activeAgents = db.core.agents.listHeartbeatEligibleAgents(companyId); - for (const activeAgent of activeAgents) { - if (wokenAgentIds.has(activeAgent.id)) continue; - if (hasActiveRun({ agentId: activeAgent.id, companyId })) continue; - if (deps.checkpointEngine?.shouldPauseHeartbeat(companyId, activeAgent.id)) continue; - - const lastHeartbeat = activeAgent.lastHeartbeatAt ? new Date(activeAgent.lastHeartbeatAt).getTime() : 0; - const attemptKey = agentAttemptKey(companyId, activeAgent.id); - const lastAttempt = taskWakeAttemptByAgent.get(attemptKey) ?? 0; - const intervalMs = (activeAgent.heartbeatIntervalSec ?? 120) * 1000; - if (now - Math.max(lastHeartbeat, lastAttempt) < intervalMs) continue; - - const actionableTasks = db.core.tasks.listAgentTasks(activeAgent.id, companyId, ["todo"]); - if (!actionableTasks.some((task) => !task.activeRunId)) continue; - - taskWakeAttemptByAgent.set(attemptKey, now); - wakeAgentIfPossible(activeAgent.id, companyId, "timer"); - } - } - - function runHeartbeatCadencePhase() { - const activeCompanies = db.core.company.listActiveCompanyIds(); - const now = Date.now(); - - for (const company of activeCompanies) { - try { - runScheduleAutomation(company.id, now); - const wokenAgentIds = runPendingWakeupCadence(company.id, now); - runAssignedTaskWakeCadence(company.id, now, wokenAgentIds); - runCompanyBootstrap(company, now, wokenAgentIds); - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: "scheduler.heartbeat_cadence.company_tick_failed", - message: `Heartbeat cadence failed for company ${company.id}`, - context: { companyId: company.id }, - }); - } - } - } - - function runPhase(phase: SchedulerPhase, runner: () => void) { - try { - runner(); - } catch (error) { - logAppError(logger, error, { - kind: "recoverable", - code: `scheduler.${phase}.tick_failed`, - message: `Scheduler phase ${phase} raised; next interval will retry`, - }); - } - } - - function runTick() { - if (isQuitting()) return; - const now = Date.now(); - - if (phaseIsDue("lock_recovery", now)) runPhase("lock_recovery", runLockRecoveryPhase); - if (phaseIsDue("housekeeping", now)) runPhase("housekeeping", runHousekeepingPhase); - if (phaseIsDue("idle_automation", now)) runPhase("idle_automation", runIdleAutomationPhase); - if (phaseIsDue("heartbeat_cadence", now)) runPhase("heartbeat_cadence", runHeartbeatCadencePhase); - } - - function armTimer() { - if (timer) clearInterval(timer); - timer = setInterval(runTick, TICK_INTERVAL_MS); - } - - function rearm(trigger: string) { - if (isQuitting()) return; - logger.info(`[scheduler] Re-arming unified scheduler (${trigger})`); - armTimer(); - runTick(); - } - - function startAllSchedulers() { - armTimer(); - if (!resumeListener) { - resumeListener = () => rearm("power_resume"); - powerMonitor.on("resume", resumeListener); - } - if (!unlockListener) { - unlockListener = () => rearm("screen_unlock"); - powerMonitor.on("unlock-screen", unlockListener); - } - } - - function stopAllSchedulers() { - if (timer) clearInterval(timer); - timer = null; - if (resumeListener) { - powerMonitor.removeListener("resume", resumeListener); - resumeListener = null; - } - if (unlockListener) { - powerMonitor.removeListener("unlock-screen", unlockListener); - unlockListener = null; - } - } - - return { startAllSchedulers, stopAllSchedulers }; -} diff --git a/src/main/orchestration/task-runner.ts b/src/main/orchestration/task-runner.ts deleted file mode 100644 index a3351c17..00000000 --- a/src/main/orchestration/task-runner.ts +++ /dev/null @@ -1,364 +0,0 @@ -import type { AgentRecord, ConnectorRecord } from "@shared/types"; -import type { DesktopResult } from "@shared/contracts"; -import type { OrchestrationDependencies } from "./types"; -import type { RunDispatchParams } from "./turn-context"; -import type { ResolveWorkspaceFn } from "./run-dispatch"; -import { WorkspaceConfigurationError } from "./resolve-workspace"; -import { pickModelForAgent } from "../model-dispatch"; - -interface PreparedTaskRun { - runId: string; - taskTitle: string; - dispatchParams: RunDispatchParams; -} - -export function createTaskRunner( - deps: OrchestrationDependencies, - resolveWorkspace: ResolveWorkspaceFn, - getRunEligibilityFailure: (agent: AgentRecord, connector: ConnectorRecord, projectId?: string | null) => string | null, - dispatchRunToWorker: (params: RunDispatchParams) => void, - hasActiveRun: (filter: { taskId?: string; agentId?: string; companyId: string }) => boolean, -) { - const { - db, - logger, - emitEvent, - hasWorkerReady, - isQuitting, - } = deps; - - function ok(data: T): DesktopResult { - return { ok: true, data }; - } - - function fail(code: string, message: string): DesktopResult { - return { ok: false, error: { code, message } }; - } - - function prepareTaskRun( - taskId: string, - trigger: string, - options: { requireWorkerReady: boolean }, - ): DesktopResult { - if (isQuitting()) { - return fail("APP_SHUTTING_DOWN", "Application is shutting down."); - } - if (options.requireWorkerReady && !hasWorkerReady()) { - logger.warn(`[run] Worker not ready — cannot queue run for task ${taskId} (trigger: ${trigger})`); - return fail("WORKER_UNAVAILABLE", "Orchestration worker is not ready."); - } - const task = db.core.entity.getTask(taskId); - const companyStatus = db.core.company.getCompanyStatus(task.companyId); - if (companyStatus !== "active") { - return fail("COMPANY_NOT_ACTIVE", "Runs can only start while the company is active."); - } - if (!task.assigneeAgentId) return fail("TASK_UNASSIGNED", "Assign an agent before starting a run."); - const agent = db.core.entity.getAgent(task.assigneeAgentId); - if (agent.companyId !== task.companyId) { - return fail("AGENT_COMPANY_MISMATCH", "The assigned agent does not belong to the task company."); - } - const pick = pickModelForAgent(agent, { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (companyId, connectorId) => db.core.settings.getDisabledModels(companyId, connectorId), - listModelCapabilities: () => db.core.modelCapabilities.listModelCapabilities(), - readConnectors: () => db.core.connectors.readConnectors(), - }); - if (!pick.ok) { - return fail("MODEL_PICK_FAILED", pick.message); - } - const assignment = pick.assignment; - const connector = db.core.connectors.getConnector(assignment.connectorId); - const effectiveAgentForEligibility: AgentRecord = { ...agent, model: assignment.modelId }; - const eligibilityFailure = getRunEligibilityFailure(effectiveAgentForEligibility, connector, task.projectId ?? null); - if (eligibilityFailure === "AGENT_NOT_RUNNABLE") { - return fail("AGENT_NOT_RUNNABLE", "The assigned agent is paused, pending approval, or terminated."); - } - if (eligibilityFailure === "BUDGET_POLICY_BLOCKED") { - return fail("BUDGET_POLICY_BLOCKED", "A budget policy blocks this run. Review budget settings."); - } - if (eligibilityFailure === "CONNECTOR_NOT_READY") { - return fail("CONNECTOR_NOT_READY", "The assigned agent connector is not ready."); - } - if (eligibilityFailure === "CONNECTOR_MODEL_NOT_ALLOWED") { - return fail("CONNECTOR_MODEL_NOT_ALLOWED", "The assigned agent model is disabled or invalid for its connector."); - } - if (hasActiveRun({ agentId: agent.id, companyId: task.companyId })) { - return fail("AGENT_ALREADY_RUNNING", "The assigned agent already has an active run."); - } - if (db.core.agents.isAgentPendingApproval(agent.id)) { - return fail("AGENT_PENDING_APPROVAL", "This agent is pending hire approval and cannot run tasks."); - } - const blockingApproval = db.core.approvals.getBlockingApproval(task.companyId, agent.id, task.id); - if (blockingApproval) { - return fail( - "APPROVAL_GATE_BLOCKED", - `Run blocked by pending approval: ${blockingApproval.type} — "${blockingApproval.payloadSummary}". Approve or reject before starting.`, - ); - } - - let workspaceResolution: ReturnType; - try { - workspaceResolution = resolveWorkspace(task, agent, task.companyId); - } catch (error) { - if (error instanceof WorkspaceConfigurationError) { - return fail("WORKSPACE_UNRESOLVED", error.message); - } - throw error; - } - const workspace = workspaceResolution.workspace; - if (workspace && workspace.companyId !== task.companyId) { - return fail("WORKSPACE_COMPANY_MISMATCH", "The selected workspace does not belong to the task company."); - } - - const run = db.core.runs.createTaskRun({ - companyId: task.companyId, - taskId: task.id, - agentId: agent.id, - workspaceId: workspaceResolution.lockMode === "exclusive" ? (workspace?.id ?? null) : null, - connectorId: connector.id, - }); - if (!run) { - return fail("CHECKOUT_RACE_LOST", "Another run claimed this task. Refresh and try again."); - } - - const companyBasic = db.core.company.getCompanyBasic(task.companyId); - return ok({ - runId: run.id, - taskTitle: task.title, - dispatchParams: { - runId: run.id, - companyId: task.companyId, - agent, - task, - connector, - workspace, - workspaceMode: workspaceResolution.lockMode, - observationPath: workspaceResolution.observationPath, - companyName: companyBasic?.name ?? "Unknown", - companyDescription: companyBasic?.description ?? "", - snapshot: db.projection.snapshot.listSnapshot(), - trigger, - resolvedModel: assignment.modelId, - }, - }); - } - - function recordQueuedRun(prepared: PreparedTaskRun, actor: string) { - const postDispatchRun = db.core.runs.getRun(prepared.runId); - if (postDispatchRun.status === "queued" || postDispatchRun.status === "running") { - db.core.activity.addActivity({ - companyId: prepared.dispatchParams.companyId, - actor, - action: "run.queued", - entityType: "run", - entityId: prepared.runId, - detail: prepared.taskTitle, - }); - emitEvent({ type: "run-updated", runId: prepared.runId, action: "created" }); - } - } - - function dispatchPreparedTaskRun(prepared: PreparedTaskRun, actor: string) { - dispatchRunToWorker(prepared.dispatchParams); - recordQueuedRun(prepared, actor); - } - - function queueTaskRun(taskId: string, trigger: string, actor: string): DesktopResult { - const prepared = prepareTaskRun(taskId, trigger, { requireWorkerReady: true }); - if (!prepared.ok) return prepared; - dispatchPreparedTaskRun(prepared.data, actor); - return ok(prepared.data.runId); - } - - function createTaskRunForDeferredDispatch(taskId: string, trigger: string, actor: string): DesktopResult<{ runId: string; dispatchAfterCommit: () => void }> { - const prepared = prepareTaskRun(taskId, trigger, { requireWorkerReady: false }); - if (!prepared.ok) return prepared; - return ok({ - runId: prepared.data.runId, - dispatchAfterCommit: () => { - if (isQuitting()) return; - if (!hasWorkerReady()) { - logger.warn(`[run] Worker not ready — leaving queued run ${prepared.data.runId} for recovery (trigger: ${trigger})`); - recordQueuedRun(prepared.data, actor); - return; - } - dispatchPreparedTaskRun(prepared.data, actor); - }, - }); - } - - function resumeQueuedRuns() { - // D-02: Stale lock recovery at app startup (EXEC-03) - try { - const recovered = db.recoverStaleLocks(); - for (const task of recovered) { - db.core.activity.addActivity({ - companyId: task.companyId, - actor: "system", - action: "execution.lock_recovered", - entityType: "task", - entityId: task.taskId, - detail: `Recovered stale lock on task "${task.title}" after 15min timeout (startup sweep)`, - }); - logger.info(`[init] Recovered stale lock on task ${task.taskId}: "${task.title}"`); - } - if (recovered.length > 0) { - logger.info(`[init] Recovered ${recovered.length} stale lock(s) at startup`); - } - } catch (err) { - logger.error(`[init] Stale lock recovery at startup failed: ${err instanceof Error ? err.message : String(err)}`); - } - - if (isQuitting() || !hasWorkerReady()) { - return; - } - const snapshot = db.projection.snapshot.listSnapshot(); - const companiesById = new Map(snapshot.companies.map((company) => [company.id, company])); - const reservedAgentIds = new Set(); - const reservedTaskIds = new Set(); - - function finishQueuedRecoveryRun( - run: ReturnType[number], - status: "cancelled" | "interrupted", - summary: string, - errorMessage: string | null, - ): void { - db.core.runs.finishRun({ - runId: run.id, - status, - summary, - errorMessage, - exitCode: null, - signal: null, - model: null, - unattributedCost: true, - recoverTaskForRetry: run.taskId !== null, - }); - if (run.workspaceId) { - db.core.workspaces.releaseWorkspaceLock(run.workspaceId, run.id); - } - emitEvent({ type: "run-updated", runId: run.id, action: "completed" }); - } - - for (const run of db.core.runs.listQueuedRuns()) { - const company = companiesById.get(run.companyId); - if (!company || company.status !== "active") { - continue; - } - - const hasRunningSiblingRun = snapshot.runs.some((entry) => - entry.id !== run.id && - entry.companyId === run.companyId && - entry.status === "running" && - (entry.taskId === run.taskId || entry.agentId === run.agentId), - ); - if (hasRunningSiblingRun) { - continue; - } - - if (reservedAgentIds.has(run.agentId) || (run.taskId !== null && reservedTaskIds.has(run.taskId))) { - finishQueuedRecoveryRun( - run, - "cancelled", - "Queued run superseded during recovery.", - null, - ); - continue; - } - - try { - const task = run.taskId ? db.core.entity.getTask(run.taskId) : null; - const agent = db.core.entity.getAgent(run.agentId); - const connector = db.core.connectors.getConnector(run.connectorId); - const blockingApproval = db.core.approvals.getBlockingApproval(run.companyId, agent.id, run.taskId); - if (blockingApproval) { - finishQueuedRecoveryRun( - run, - "cancelled", - `Queued run blocked by pending approval: ${blockingApproval.type}`, - null, - ); - db.core.activity.addActivity({ - companyId: run.companyId, - actor: "system", - action: "run.recovery_blocked_approval", - entityType: "run", - entityId: run.id, - detail: `Recovered queued run blocked by ${blockingApproval.type} for task "${task?.title ?? "(heartbeat)"}"`, - }); - continue; - } - const eligibilityFailure = getRunEligibilityFailure(agent, connector, task?.projectId ?? null); - if (eligibilityFailure) { - if (eligibilityFailure === "CONNECTOR_MODEL_NOT_ALLOWED") { - db.core.runs.finishRun({ - runId: run.id, - status: "failed", - summary: "Queued run rejected during recovery because the agent model is disabled or invalid for its connector.", - errorMessage: "Connector model is disabled or invalid for this agent.", - exitCode: null, - signal: null, - model: null, - unattributedCost: true, - }); - db.core.activity.addActivity({ - companyId: run.companyId, - actor: "system", - action: "run.recovery_blocked", - entityType: "run", - entityId: run.id, - detail: `Recovered queued run blocked by connector/model policy for task "${task?.title ?? "(heartbeat)"}"`, - }); - emitEvent({ type: "run-updated", runId: run.id, action: "completed" }); - } else { - finishQueuedRecoveryRun( - run, - "cancelled", - "Queued run recovery deferred by eligibility gate.", - eligibilityFailure, - ); - db.core.activity.addActivity({ - companyId: run.companyId, - actor: "system", - action: "run.recovery_deferred", - entityType: "run", - entityId: run.id, - detail: `Recovered queued run deferred by ${eligibilityFailure} for task "${task?.title ?? "(heartbeat)"}"`, - }); - } - continue; - } - const workspaceResolution = resolveWorkspace(task ?? null, agent, run.companyId); - dispatchRunToWorker({ - runId: run.id, - companyId: run.companyId, - agent, - task, - connector, - workspace: workspaceResolution.workspace, - workspaceMode: workspaceResolution.lockMode, - observationPath: workspaceResolution.observationPath, - companyName: company.name, - companyDescription: company.description, - snapshot, - trigger: "recovery", - }); - const currentRun = db.core.runs.getRun(run.id); - if (currentRun.status === "queued" || currentRun.status === "running") { - reservedAgentIds.add(run.agentId); - if (run.taskId !== null) reservedTaskIds.add(run.taskId); - } - } catch (error) { - logger.warn(`[run] Skipped queued run recovery for ${run.id}: ${error instanceof Error ? error.message : String(error)}`); - finishQueuedRecoveryRun( - run, - "interrupted", - "Queued run recovery failed.", - error instanceof Error ? error.message : String(error), - ); - } - } - } - - return { queueTaskRun, createTaskRunForDeferredDispatch, resumeQueuedRuns }; -} diff --git a/src/main/orchestration/turn-context.ts b/src/main/orchestration/turn-context.ts deleted file mode 100644 index 8fe769e8..00000000 --- a/src/main/orchestration/turn-context.ts +++ /dev/null @@ -1,406 +0,0 @@ -/** - * Turn Context Assembly - * - * Extracts the run payload assembly logic from dispatchRunToWorker into - * a single composable function. Each step (env, comments, session, skills, - * prompt) is an isolated helper, making the pipeline testable and extensible. - */ - -import { buildTaskPrompt } from "../prompt-builder/index"; -import type { AppDatabase } from "../database"; -import type { ProjectedSkill } from "../skill-types"; -import type { ConnectorId, ExecutionMode } from "@shared/types"; -import type { WorkspaceLockMode, EnqueueRunPayload } from "./types"; -import { normalizeCommentsForPrompt } from "../messaging/normalize"; -import { getConnectorModelPolicy, validateConnectorModelSelection } from "../connector-model-policy"; -import { resolveInitialUserTurn } from "./initial-user-turn"; -import { resolveInternalToolsForAgent } from "./internal-tool-selector"; -import { logAppError } from "../errors/index.js"; - -export interface RunDispatchParams { - runId: string; - companyId: string; - agent: ReturnType; - // `task` is null for heartbeat runs (agent wake-ups with no assigned task). - // Downstream code (prompt builder, worker payload, session pointer) - // branches on this — when null, skip task-scoped state. - task: ReturnType | null; - connector: ReturnType; - workspace: ReturnType; - workspaceMode: WorkspaceLockMode; - /** - * Filesystem root the artifact projector observes for files this run - * may produce, independent of `workspaceMode`. Set whenever the - * resolver found a workspace row in the company (including for - * `lockMode='none'` cognitive runs that do not claim the lock but - * still write deliverables via `bash`). Optional so legacy callers - * that bypass the resolver keep typechecking; the new resolver - * always sets it. - */ - observationPath?: string | null; - companyName: string; - companyDescription: string; - snapshot: ReturnType; - trigger: string; - /** - * Model id resolved by `pickModelForAgent` at dispatch time. When the - * agent runs under `modelStrategy = "auto"` this differs from - * `agent.model` (the column now becomes a legacy fallback). Optional so - * explicit-strategy callers and legacy tests keep working; when absent - * we read `agent.model` verbatim. - */ - resolvedModel?: string | null; -} - -export interface TurnContextDeps { - db: AppDatabase; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error?: (...args: unknown[]) => void }; - getApiPort: () => number; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => ProjectedSkill[]; - getSessionHandoff?: (agentId: string) => string | null; - evaluatePreRunSessionRotation?: (agentId: string, connectorId: string) => { - rotated: boolean; - handoff: string | null; - sessionId: string | null; - }; -} - -function assembleApiEnv( - db: AppDatabase, - connector: RunDispatchParams["connector"], - companyId: string, - agentId: string, - runId: string, - trigger: string, - deps: Pick, -) { - const env = db.core.entity.resolveSecretEnv(connector.envBindingText, companyId); - const apiPort = deps.getApiPort(); - const apiUrl = apiPort ? `http://127.0.0.1:${apiPort}` : ""; - const apiKey = apiUrl ? deps.createRunToken(agentId, companyId, runId) : ""; - - if (apiUrl) { - env.AGENT_COMPANY_API_URL = apiUrl; - env.AGENT_COMPANY_API_KEY = apiKey; - env.AGENT_COMPANY_AGENT_ID = agentId; - env.AGENT_COMPANY_COMPANY_ID = companyId; - env.AGENT_COMPANY_RUN_ID = runId; - env.AGENT_COMPANY_TASK_ID = ""; - env.AGENT_COMPANY_WAKE_REASON = trigger; - } - return { env, apiUrl, apiKey }; -} - -function assembleRecentComments( - assignedTasks: ReturnType, - reviewTasks: ReturnType, - snapshot: RunDispatchParams["snapshot"], -) { - const relevantTaskIds = new Set([ - ...assignedTasks.map((t) => t.id), - ...reviewTasks.map((t) => t.id), - ]); - const allRelevantTasks = [...assignedTasks, ...reviewTasks]; - return snapshot.comments - .filter((comment) => relevantTaskIds.has(comment.taskId)) - .sort((a, b) => b.createdAt.localeCompare(a.createdAt)) - .slice(0, 30) - .map((comment) => ({ - taskId: comment.taskId, - taskTitle: allRelevantTasks.find((t) => t.id === comment.taskId)?.title ?? comment.taskId, - authorName: comment.authorName, - body: comment.body, - createdAt: comment.createdAt, - })); -} - -function resolveSessionHandoff( - agentId: string, - deps: Pick, -): string | null { - if (!deps.getSessionHandoff) return null; - try { - return deps.getSessionHandoff(agentId); - } catch (err) { - const appError = logAppError(deps.logger, err, { - kind: "upstream", - code: "run.session_handoff.load_failed", - message: `Failed to load session handoff for agent ${agentId}.`, - context: { agentId }, - }); - throw appError; - } -} - -function resolveSkills( - companyId: string, - agentId: string, - connectorId: string, - agentName: string, - deps: Pick, -): ProjectedSkill[] { - try { - return deps.listRuntimeSkillEntries(companyId, agentId, connectorId); - } catch (err) { - const appError = logAppError(deps.logger, err, { - kind: "upstream", - code: "run.skills.fetch_failed", - message: `Failed to fetch managed skills for agent ${agentName}.`, - context: { agentId, agentName, connectorId, companyId }, - }); - throw appError; - } -} - -function resolveEnabledConnectorModels( - db: AppDatabase, - companyId: string, - connector: { id: string; model: string | null }, -): string[] { - return getConnectorModelPolicy( - { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (cid, connId) => db.core.settings.getDisabledModels(cid, connId), - }, - companyId, - connector.id as ConnectorId, - ).enabledModels.map((model) => model.id); -} - -function resolveSession( - db: AppDatabase, - agent: RunDispatchParams["agent"], - companyId: string, - connectorId: string, - sessionHandoff: string | null, - deps: Pick, -) { - // Per-agent session: one ongoing transcript per agent; switching tasks - // (or running taskless heartbeats) becomes a "now work on X" user turn - // on the ongoing transcript rather than starting a fresh session. - const agentSessionId = db.core.tasks.ensureAgentSession({ - agentId: agent.id, - companyId, - adapterType: connectorId, - }); - - // Evaluate rotation against the agent-scoped session unconditionally. - // Heartbeat runs (no task) must rotate too, or their transcript grows - // forever — the exact failure mode that burned through 7M token windows. - let currentSessionId = agentSessionId; - let finalHandoff = sessionHandoff; - if (deps.evaluatePreRunSessionRotation) { - const rotationResult = deps.evaluatePreRunSessionRotation(agent.id, connectorId); - if (rotationResult.rotated) { - currentSessionId = rotationResult.sessionId ?? agentSessionId; - if (!finalHandoff && rotationResult.handoff) { - finalHandoff = rotationResult.handoff; - } - deps.logger.info(`[session] Pre-run compaction for agent ${agent.id}: session rotated before execution`); - } - } - - return { - taskSessionId: currentSessionId, - sessionHandoff: finalHandoff, - }; -} - -function extractThinkingEffort( - metadataJson: string | null, - logger: TurnContextDeps["logger"], - agentId: string, -): string | null { - try { - const meta = JSON.parse(metadataJson || "{}"); - if (typeof meta.thinkingEffort === "string" && meta.thinkingEffort) { - return meta.thinkingEffort; - } - } catch (error) { - logger.warn( - `[run] malformed agent metadataJson for ${agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - return null; -} - -function filterUpcomingMeetings( - meetings: RunDispatchParams["snapshot"]["meetings"], - companyId: string, - agentId: string, -) { - return meetings - .filter((meeting) => meeting.companyId === companyId && (meeting.status === "scheduled" || meeting.status === "in_progress")) - .filter((meeting) => { - try { - const ids: string[] = JSON.parse(meeting.participantAgentIds); - return ids.includes(agentId) || meeting.organizerAgentId === agentId; - } catch { - return false; - } - }) - .slice(0, 5); -} - -function filterRelevantKnowledge( - knowledge: RunDispatchParams["snapshot"]["knowledgeBase"], - companyId: string, -) { - return knowledge - .filter((entry) => entry.companyId === companyId && (entry.importance === "critical" || entry.importance === "high")) - .slice(0, 20); -} - -function filterRecentDocuments( - documents: RunDispatchParams["snapshot"]["documents"], - companyId: string, - agentId: string, -) { - return documents - .filter((document) => document.companyId === companyId && (document.authorAgentId === agentId || document.reviewerAgentId === agentId || document.status === "in_review")) - .slice(0, 5); -} - -function filterPendingApprovals( - approvals: RunDispatchParams["snapshot"]["approvals"], - companyId: string, - agentId: string, -) { - return approvals.filter( - (approval) => approval.companyId === companyId && - approval.requestedByAgentId === agentId && - (approval.state === "pending" || approval.state === "revision_requested"), - ); -} - -function buildConnectorCatalog( - db: AppDatabase, - companyId: string, - connectors: RunDispatchParams["snapshot"]["connectors"], -) { - return connectors - .filter((c) => c.status === "ready") - .filter((c) => db.core.settings.hasModelPoolSettings(companyId, c.id)) - .map((c) => ({ - id: c.id, - label: c.label, - status: c.status, - enabledModels: resolveEnabledConnectorModels(db, companyId, c), - })) - .filter((c) => c.enabledModels.length > 0); -} - -/** - * Assemble the full run payload from resolved entities and dependencies. - * This is the core composition step that was previously inlined in dispatchRunToWorker. - */ -export function buildRunPayload(params: RunDispatchParams, deps: TurnContextDeps): EnqueueRunPayload { - const { runId, companyId, agent, task, connector, workspace, workspaceMode, observationPath, companyName, companyDescription, snapshot, trigger } = params; - const { db } = deps; - - const { env, apiUrl, apiKey } = assembleApiEnv(db, connector, companyId, agent.id, runId, trigger, deps); - env.AGENT_COMPANY_TASK_ID = task?.id ?? ""; - - const assignedTasks = db.core.tasks.listAgentTasks(agent.id, companyId, ["todo", "in_progress", "blocked"]); - const reviewTasks = db.core.tasks.listReviewTasksForManager(agent.id, companyId); - const recentComments = assembleRecentComments(assignedTasks, reviewTasks, snapshot); - const initialHandoff = resolveSessionHandoff(agent.id, deps); - const { taskSessionId, sessionHandoff } = resolveSession(db, agent, companyId, connector.id, initialHandoff, deps); - const skills = resolveSkills(companyId, agent.id, connector.id, agent.name, deps); - - const systemPrompt = apiUrl ? buildTaskPrompt({ - agent, - apiUrl, - apiKey, - runId, - task, - companyName, - locale: snapshot.locale, - executionMode: db.core.company.getCompanyExecutionMode(companyId) as ExecutionMode, - goals: snapshot.goals.filter((goal) => goal.companyId === companyId), - projects: snapshot.projects.filter((project) => project.companyId === companyId), - directReports: db.core.agents.getDirectReports(agent.id, companyId), - chainOfCommand: db.core.agents.getChainOfCommand(agent.id), - assignedTasks, - allAgents: snapshot.agents.filter((entry) => entry.companyId === companyId), - pendingApprovals: filterPendingApprovals(snapshot.approvals, companyId, agent.id), - tasksAwaitingReview: reviewTasks, - wakeReason: trigger, - allTasks: snapshot.tasks.filter((entry) => entry.companyId === companyId), - recentComments: normalizeCommentsForPrompt(recentComments), - companyDescription, - socialAccounts: db.core.social.listSocialAccounts(companyId).map((account) => ({ - id: account.id, - platform: account.platform, - accountName: account.accountName, - status: account.status, - requireApproval: account.requireApproval, - })), - upcomingMeetings: filterUpcomingMeetings(snapshot.meetings, companyId, agent.id), - relevantKnowledge: filterRelevantKnowledge(snapshot.knowledgeBase, companyId), - activeSprint: snapshot.sprints.find((sprint) => sprint.companyId === companyId && sprint.status === "active") ?? null, - recentDocuments: filterRecentDocuments(snapshot.documents, companyId, agent.id), - allConnectors: buildConnectorCatalog(db, companyId, snapshot.connectors), - sessionHandoff, - skills, - companySkillCatalog: db.core.skills.listCompanySkills(companyId).map((skill) => ({ - name: skill.name, - slug: skill.slug, - description: skill.description, - })), - companyWorkspaces: snapshot.workspaces - .filter((workspace) => workspace.companyId === companyId) - .map((workspace) => ({ id: workspace.id, name: workspace.name, localPath: workspace.localPath })), - companyDocuments: snapshot.documents.filter((d) => d.companyId === companyId), - }) : null; - - const thinkingEffort = extractThinkingEffort(agent.metadataJson, deps.logger, agent.id); - const modelForRun = params.resolvedModel !== undefined ? params.resolvedModel : agent.model; - const modelSelection = validateConnectorModelSelection( - { - getConnector: (id) => db.core.connectors.getConnector(id), - getDisabledModels: (cid, connId) => db.core.settings.getDisabledModels(cid, connId), - }, - companyId, - connector.id, - modelForRun, - ); - if (!modelSelection.ok) { - throw new Error(modelSelection.error); - } - - const initialUserTurn = resolveInitialUserTurn( - { trigger, task, companyId, agentId: agent.id }, - { db }, - ); - - const internalTools = resolveInternalToolsForAgent(db, agent); - - return { - runId, - companyId, - taskId: task?.id ?? null, - agentId: agent.id, - agentName: agent.name, - connectorId: connector.id, - workspaceId: workspaceMode === "exclusive" ? (workspace?.id ?? null) : null, - // observationPath, not lock target. Cognitive runs (lockMode='none') - // still write deliverables via bash; the artifact projector needs an - // observation root regardless of whether we hold the lock. Falls back - // to workspace?.localPath for old call sites that did not yet thread - // the observationPath through (the resolver always sets it now; - // callers that bypass the resolver remain on the legacy field). - workspacePath: observationPath ?? workspace?.localPath ?? null, - workspaceMode, - model: modelSelection.effectiveModel, - thinkingEffort, - env, - systemPrompt, - trigger, - taskSessionId: taskSessionId ?? runId, - executionMode: db.core.company.getCompanyExecutionMode(companyId) as "ai_ceo" | "ai_cofounder", - initialUserTurn, - internalTools, - }; -} diff --git a/src/main/orchestration/types.ts b/src/main/orchestration/types.ts deleted file mode 100644 index 8d751e60..00000000 --- a/src/main/orchestration/types.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DesktopEvent } from "@shared/types"; -import type { NotificationOptions } from "../notification-service"; -import type { createBudgetEnforcementService } from "../budget-enforcement-service"; -import type { ProjectedSkill } from "../skill-types"; - -export type WorkspaceLockMode = "exclusive" | "shared" | "none"; - -export interface AutomationDispatch { - companyId: string; - taskId?: string; - agentId?: string; - runId?: string; - projectId?: string; - department?: string; - previousStatus?: string; - newStatus?: string; - costUsd?: number; -} - -export interface EnqueueRunPayload { - runId: string; - companyId: string; - /** Null for heartbeat runs (agent wake-ups with no assigned task). */ - taskId: string | null; - agentId: string; - agentName: string; - connectorId: string; - workspaceId: string | null; - workspacePath: string | null; - workspaceMode: WorkspaceLockMode; - model: string | null; - thinkingEffort: string | null; - env: Record; - systemPrompt: string | null; - trigger: string | null; - /** Task session id used by SqliteSessionStore to load/append messages. */ - taskSessionId: string; - /** Execution mode from the owning company. */ - executionMode: "ai_ceo" | "ai_cofounder"; - /** - * The literal user-role turn the worker seeds onto the pi Agent to - * kick off the loop. Resolved at dispatch time — for task runs this is - * the task title/description; for communication wakes it binds to the - * actual inbox rows (message_id, sender, subject) so the agent lands - * on a concrete action cue instead of a context-free `Continue.`. - */ - initialUserTurn: string; - /** - * Internal tools main decides to inject for this specific run (C4). - * Hiring authority receives `hire_agent`; CEO strategy approval receives - * `file_approval` after the initial team-building hire pass has started. - * The decision is made at dispatch time so the worker never re-derives it. - */ - internalTools: ReadonlyArray<"hire_agent" | "file_approval">; -} - -export interface OrchestrationDependencies { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - publishDomainChanged: () => void; - emitEvent: (event: DesktopEvent) => void; - notify: (options: NotificationOptions) => void; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - getApiPort: () => number; - dispatchAutomation: (trigger: string, ctx: AutomationDispatch) => void; - hasWorkerReady: () => boolean; - enqueueWorkerRun: (payload: EnqueueRunPayload) => void; - isQuitting: () => boolean; - listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => ProjectedSkill[]; - budgetService: ReturnType; - /** Checkpoint engine for unified co-founder mode pause decisions. */ - checkpointEngine?: { shouldPauseHeartbeat: (companyId: string, agentId: string) => boolean }; - getSessionHandoff?: (agentId: string) => string | null; - evaluatePreRunSessionRotation?: (agentId: string, connectorId: string) => { - rotated: boolean; - handoff: string | null; - /** - * The session id the next run should use. Equals the freshly-minted - * session id after a rotation, or the unchanged agent session id when - * no rotation fired. Null if the agent has no session yet (first run). - */ - sessionId: string | null; - }; -} diff --git a/src/main/prompt-builder/api-docs/agent-control.en.md b/src/main/prompt-builder/api-docs/agent-control.en.md deleted file mode 100644 index 0048d0e2..00000000 --- a/src/main/prompt-builder/api-docs/agent-control.en.md +++ /dev/null @@ -1,10 +0,0 @@ -### Get Your Identity -GET /api/agents/me -Returns your agent record with chain of command, budget info, department, and status. -Call this first to confirm your identity and understand your position. - -### Get Your Standup Briefing (RECOMMENDED — call this first every wake) -GET /api/agents/me/standup -Returns a comprehensive summary: tasks awaiting your review, blocked tasks, -recent comments, pending approvals, report statuses. Use this to prioritize your work. -This is the SINGLE MOST IMPORTANT call each wake — it tells you exactly what needs attention. diff --git a/src/main/prompt-builder/api-docs/agents.en.md b/src/main/prompt-builder/api-docs/agents.en.md deleted file mode 100644 index 143ece8b..00000000 --- a/src/main/prompt-builder/api-docs/agents.en.md +++ /dev/null @@ -1,37 +0,0 @@ -### Propose a Hire -POST /api/companies/{{companyId}}/agents -Body: { - "name": "New hire display name (must not repeat role/title)", - "role": "role_title", - "title": "Descriptive title", - "department": "engineering|product|marketing|sales|hr|finance|legal|operations|customer_support|research|design|executive", - "reportsTo": "{managerAgentId — who this person reports to}", - "connectorId": "{{connectorIds}}", - "workspaceId": "{optionalWorkspaceId}", - "model": "model-identifier", - "capabilities": "Detailed description of what this hire should own and be able to do", - "budgetMonthlyUsd": 250 -} -This creates the agent in pending_approval state. The Board (human operator) must approve. -After approval, the agent becomes active and can be assigned work. - -### Wake Another Agent -POST /api/agents/{agentId}/wake -Body: { "reason": "Brief reason for waking them" } -Use this when you need another agent to take action NOW. This triggers their next heartbeat. - -### List All Agents -GET /api/companies/{{companyId}}/agents - -### Get Agent Details -GET /api/agents/{agentId} -Returns agent profile, manager info, and direct reports. - -### List Company Goals -GET /api/companies/{{companyId}}/goals - -### List Company Projects -GET /api/companies/{{companyId}}/projects - -### Get Your Performance Metrics -GET /api/agents/me/metrics diff --git a/src/main/prompt-builder/api-docs/approvals.en.md b/src/main/prompt-builder/api-docs/approvals.en.md deleted file mode 100644 index 0fc392bb..00000000 --- a/src/main/prompt-builder/api-docs/approvals.en.md +++ /dev/null @@ -1,54 +0,0 @@ -### Request an Approval (when you need human/executive permission) -POST /api/companies/{{companyId}}/approvals -Body: { - "type": "{{approvalTypes}}", - "relatedTaskId": "{taskId — what task is this for}", - "requestedByAgentId": "{{agentId}}", - "payloadSummary": "Clear description of what you need and why", - "impactSummary": "What happens if this is approved vs denied", - "documentIds": ["{docUuid1}", "{docUuid2}"], - "workProductIds": ["{workProductUuid}"] -} -Approval types: -{{approvalTypeList}} - -Co-Founder mandatory review types: -{{cofounderMandatoryApprovalTypes}} - -Attaching artifacts: - - `documentIds` — UUIDs of existing company documents. The board inspector - renders each as a clickable row on the first screen of the approval modal, - so reviewers can open and edit inline. - - `workProductIds` — UUIDs of existing work products (files on disk, - external URLs). The inspector surfaces each row with a click-to-open - action that hands off to the operator's default application. - - Prefer these schema-typed arrays over stuffing `{documentIds:[...]}` into - `payloadJson`. Agents using the `file_approval` internal tool pass the - same fields directly as arguments. - -Example — deliverable_review that asks the CEO to sign off on a spec and an -exported PDF: -``` -{ - "type": "deliverable_review", - "relatedTaskId": "8f7a...", - "payloadSummary": "Q2 launch plan ready for CEO review", - "impactSummary": "Unblocks the kickoff email if approved; revision_requested loops back to me.", - "documentIds": ["2c9d...e41a"], - "workProductIds": ["55ab...90ff"] -} -``` - -### Check Approval Status -GET /api/approvals/{approvalId} - -### List Company Approvals -GET /api/companies/{{companyId}}/approvals?requestedByAgentId={{agentId}}&state=pending,approved,revision_requested - -### 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. diff --git a/src/main/prompt-builder/api-docs/files.en.md b/src/main/prompt-builder/api-docs/files.en.md deleted file mode 100644 index dd1ea2c7..00000000 --- a/src/main/prompt-builder/api-docs/files.en.md +++ /dev/null @@ -1,65 +0,0 @@ -### Filesystem artifacts (auto-registered) -Every successful `write`, `edit`, or `bash` tool call is projected into the task's work_products automatically — you do NOT need to POST /api/work-products for files you create in the workspace. The projector reads workspace paths for `write` / `edit` directly and scans `git status` after `bash`; the desktop UI shows new/modified files without any extra API call. - -Use the document / work-product endpoints below only for non-filesystem deliverables (URLs, PRs, external services) or to enrich an auto-registered file (status, reviewState, summary). - -### Create a Document -POST /api/companies/{{companyId}}/documents -Body: { - "type": "prd|technical_spec|design_doc|test_plan|post_mortem|meeting_notes|budget_proposal|hiring_requisition|status_report|incident_report|architecture_decision|knowledge_article", - "title": "Document title", - "content": "Full document content in markdown", - "reviewerAgentId": "{optionalReviewerAgentId}", - "projectId": "{optionalProjectId}", - "goalId": "{optionalGoalId}", - "status": "draft" -} - -### List Company Documents -GET /api/companies/{{companyId}}/documents - -### Fetch a Single Document (by id) -GET /api/companies/{{companyId}}/documents/{documentId} -Returns the full document record including `content`. The system prompt -only lists document metadata to keep the cacheable prefix stable — call -this endpoint when you need the actual text. - -### Update Document (with conflict detection) -PATCH /api/companies/{{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/{{companyId}}/documents/{documentId}/revisions - -### Work Products (Structured Deliverables) -POST /api/issues/{issueId}/work-products -Body: { - "type": "file|link|pull_request|branch|commit|artifact|document|preview_url|runtime_service", - "provider": "filesystem|external|agentcompany|github|custom", - "title": "Work product title", - "url": "https://... (optional)", - "status": "active|ready_for_review|approved|merged|closed|failed|draft|archived", - "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 diff --git a/src/main/prompt-builder/api-docs/goals-projects.en.md b/src/main/prompt-builder/api-docs/goals-projects.en.md deleted file mode 100644 index 62689a26..00000000 --- a/src/main/prompt-builder/api-docs/goals-projects.en.md +++ /dev/null @@ -1,21 +0,0 @@ -### Create a Goal -POST /api/companies/{{companyId}}/goals -Body: { - "title": "Goal title — measurable outcome", - "description": "Definition of done — specific success criteria", - "parentId": "{optionalParentGoalId}", - "ownerAgentId": "{agentId who owns this goal}", - "status": "active" -} -Goals are top-level strategic objectives. Decompose goals into projects, then projects into tasks. - -### Create a Project -POST /api/companies/{{companyId}}/projects -Body: { - "name": "Project name", - "description": "Project scope and deliverables", - "goalId": "{goalId — which goal does this serve}", - "leadAgentId": "{agentId — who leads this project}", - "status": "planned" -} -Projects group related tasks under a goal. Assign a lead who owns delivery. diff --git a/src/main/prompt-builder/api-docs/header.en.md b/src/main/prompt-builder/api-docs/header.en.md deleted file mode 100644 index 3a7d8a13..00000000 --- a/src/main/prompt-builder/api-docs/header.en.md +++ /dev/null @@ -1,53 +0,0 @@ -# AgentCompany API -You have access to the AgentCompany API to manage your work. Base URL: {{apiUrl}} -Use the environment variables AGENT_COMPANY_API_URL and AGENT_COMPANY_API_KEY for authenticated calls. -Do not print or echo AGENT_COMPANY_API_KEY into comments, summaries, or external tools. - -## Authentication & Request Format -Every API call MUST include these headers: - Authorization: Bearer $AGENT_COMPANY_API_KEY - Content-Type: application/json; charset=utf-8 - X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID - -Prefer Node.js fetch() over curl so non-ASCII bodies (Chinese, Japanese, etc.) are transmitted -correctly across all platforms. When curl is the only option, write the JSON body to a temp -file first and pass it via `-d @file` (shown in the POST example below). - -Example using fetch (Node.js) — PREFERRED: - const res = await fetch(`${process.env.AGENT_COMPANY_API_URL}/api/agents/me`, { - headers: { - "Authorization": `Bearer ${process.env.AGENT_COMPANY_API_KEY}`, - "Content-Type": "application/json; charset=utf-8", - "X-Agent-Company-Run-Id": process.env.AGENT_COMPANY_RUN_ID - } - }); - const data = await res.json(); - -Example POST using fetch (Node.js) — PREFERRED for non-ASCII content: - const res = await fetch(`${process.env.AGENT_COMPANY_API_URL}/api/companies/{{companyId}}/issues`, { - method: "POST", - headers: { - "Authorization": `Bearer ${process.env.AGENT_COMPANY_API_KEY}`, - "Content-Type": "application/json; charset=utf-8", - "X-Agent-Company-Run-Id": process.env.AGENT_COMPANY_RUN_ID - }, - body: JSON.stringify({title:"Task title",description:"Details",assigneeAgentId:"agent-id",priority:"medium",status:"todo"}) - }); - -Example GET using curl: - curl -s -X GET "$AGENT_COMPANY_API_URL/api/agents/me" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" - -Example POST using curl (write body to temp file to avoid encoding issues): - echo '{"title":"Task title","description":"Details","priority":"medium","status":"todo"}' > /tmp/body.json - curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/issues" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json; charset=utf-8" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d @/tmp/body.json - -IMPORTANT: Always check the HTTP response status. 200/201 = success, 4xx = client error (read the error message), 5xx = server error (retry once then report). - -## Available Endpoints diff --git a/src/main/prompt-builder/api-docs/knowledge.en.md b/src/main/prompt-builder/api-docs/knowledge.en.md deleted file mode 100644 index 1405c4a7..00000000 --- a/src/main/prompt-builder/api-docs/knowledge.en.md +++ /dev/null @@ -1,13 +0,0 @@ -### Add Knowledge Entry (lessons learned, best practices) -POST /api/companies/{{companyId}}/knowledge -Body: { - "category": "lesson_learned|best_practice|decision|process|technical|business|onboarding|incident", - "topic": "What we learned", - "content": "Detailed description of the knowledge", - "importance": "high|medium|low", - "referencedEntityType": "task|project|goal", - "referencedEntityId": "{optionalEntityId}" -} - -### List Knowledge Base -GET /api/companies/{{companyId}}/knowledge diff --git a/src/main/prompt-builder/api-docs/meetings.en.md b/src/main/prompt-builder/api-docs/meetings.en.md deleted file mode 100644 index d39f5733..00000000 --- a/src/main/prompt-builder/api-docs/meetings.en.md +++ /dev/null @@ -1,19 +0,0 @@ -### Schedule a Meeting -POST /api/companies/{{companyId}}/meetings -Body: { - "type": "standup|sprint_planning|sprint_review|retrospective|one_on_one|all_hands|department_sync|incident_review|hiring_committee|budget_review", - "title": "Meeting title", - "participantAgentIds": "Serialized JSON array of agent ids", - "scheduledAt": "ISO 8601 datetime", - "durationMinutes": 30, - "agendaJson": "Serialized JSON array of agenda items" -} - -### Update Meeting (add notes, decisions) -PATCH /api/meetings/{meetingId} -Body: { - "notesJson": "Serialized JSON array of meeting notes", - "decisionsJson": "Serialized JSON array of decisions", - "actionItemsJson": "Serialized JSON array of action items", - "status": "completed" -} diff --git a/src/main/prompt-builder/api-docs/messages.en.md b/src/main/prompt-builder/api-docs/messages.en.md deleted file mode 100644 index 7bf5e121..00000000 --- a/src/main/prompt-builder/api-docs/messages.en.md +++ /dev/null @@ -1,33 +0,0 @@ -### Send a Message to Another Agent -POST /api/companies/{{companyId}}/messages -Body: { - "toAgentId": "{targetAgentId or null for non-direct channels}", - "channel": "direct|department|company|project|incident", - "channelTargetId": "{see below}", - "subject": "Message subject — clear and actionable", - "body": "Your message content — include context so recipient can act", - "priority": "urgent|normal|low", - "parentMessageId": "{optionalReplyToMessageId}" -} -channelTargetId rules: - - channel "direct": set channelTargetId to null, set toAgentId to recipient - - channel "department": set channelTargetId to department name (e.g. "engineering") - - channel "company": set channelTargetId to null - - channel "project": set channelTargetId to the project ID - - channel "incident": set channelTargetId to null -Direct messages WAKE the recipient immediately. Use this when you need another agent to act. -Department messages wake all members of that department. -Company-wide messages wake every active agent in the company — treat this channel like an all-hands broadcast, not a CEO inbox. For board-only announcements, DM the top-level agents directly or open an incident. -Incident messages are visible company-wide and pull the broader pingable set (including paused-by-budget agents). -Example — send urgent message to a peer: - curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/messages" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d '{"toAgentId":"PEER_ID","channel":"direct","subject":"Need API spec for integration","body":"I am working on task X and need the API contract from your team. Can you share or create a document?","priority":"urgent"}' - -### List Your Messages -GET /api/companies/{{companyId}}/messages?unreadOnly=true&limit=20 - -### Mark Message as Read -POST /api/companies/{{companyId}}/messages/{messageId}/read diff --git a/src/main/prompt-builder/api-docs/sprints.en.md b/src/main/prompt-builder/api-docs/sprints.en.md deleted file mode 100644 index 4ee75902..00000000 --- a/src/main/prompt-builder/api-docs/sprints.en.md +++ /dev/null @@ -1,14 +0,0 @@ -### List Sprints -GET /api/companies/{{companyId}}/sprints - -### Create Sprint -POST /api/companies/{{companyId}}/sprints -Body: { - "name": "Sprint 1", - "goal": "Sprint goal description", - "startDate": "ISO 8601 start date", - "endDate": "ISO 8601 end date (typically 2 weeks after start)", - "status": "planning|active|review|completed|cancelled", - "velocityPoints": 0, - "completedPoints": 0 -} diff --git a/src/main/prompt-builder/api-docs/tasks.en.md b/src/main/prompt-builder/api-docs/tasks.en.md deleted file mode 100644 index dd06140d..00000000 --- a/src/main/prompt-builder/api-docs/tasks.en.md +++ /dev/null @@ -1,74 +0,0 @@ -### List Tasks -GET /api/companies/{{companyId}}/issues -Query parameters (all optional, combine as needed): - ?assigneeAgentId={{agentId}} — filter to your tasks - ?status=todo,in_progress,blocked — filter by status (comma-separated) - ?priority=critical,high — filter by priority - ?projectId=PROJ_ID — filter by project -Returns an array of task objects. Use this to find work, check on reports, or audit progress. - -### Create a Task -POST /api/companies/{{companyId}}/issues -Body: { - "title": "Task title — be specific and actionable", - "description": "Detailed description with acceptance criteria", - "assigneeAgentId": "{agentId to assign to}", - "parentId": "{parentIssueId — for subtasks}", - "projectId": "{projectId — for traceability}", - "goalId": "{goalId — for strategic alignment}", - "workspaceId": "{workspaceId — required for filesystem work when the task cannot inherit one}", - "requiresFilesystem": true, - "priority": "critical|high|medium|low", - "status": "todo" -} -Always set parentId when creating subtasks. Always set projectId and goalId when available. -Set workspaceId for filesystem tasks when a workspace id is listed in the Company Capability Registry. -Set requiresFilesystem=true for code, file, repository, build, test, or local workspace work. -Set requiresFilesystem=false only for pure planning, research, coordination, or review tasks that use API state and documents. -Example: Create a task assigned to a report: - curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/issues" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d '{"title":"Implement user auth","description":"Build JWT-based auth with refresh tokens. Acceptance: login, logout, token refresh all work.","assigneeAgentId":"REPORT_ID","projectId":"PROJ_ID","goalId":"GOAL_ID","requiresFilesystem":true,"priority":"high","status":"todo"}' - -### Update a Task -PATCH /api/issues/{issueId} -Body (all fields optional): { - "status": "done", - "comment": "What was accomplished or what needs to change", - "title": "Updated title", - "description": "Updated description", - "priority": "critical|high|medium|low", - "assigneeAgentId": "new-assignee-id or null to unassign" -} -Changing assigneeAgentId will reassign the task and wake the new assignee. -Changing priority re-prioritizes the task in the queue. -Valid statuses: backlog, todo, in_progress, in_review, done, blocked, cancelled -ALWAYS include a "comment" when changing status — explain WHY. -Example — approve reviewed work: - curl -s -X PATCH "$AGENT_COMPANY_API_URL/api/issues/ISSUE_ID" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d '{"status":"done","comment":"Reviewed and approved. Implementation meets acceptance criteria."}' -Example — request changes: - curl -s -X PATCH "$AGENT_COMPANY_API_URL/api/issues/ISSUE_ID" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" \ - -H "Content-Type: application/json" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d '{"status":"in_progress","comment":"Needs changes: 1) Add error handling for edge case X. 2) Unit test coverage is below threshold."}' - -### Checkout a Task (claim it before working) -POST /api/issues/{issueId}/checkout -Body: { "agentId": "{{agentId}}" } -Returns 409 if already claimed by another agent. You MUST checkout before starting work. - -### Add Comment (communicate on a task) -POST /api/issues/{issueId}/comments -Body: { "body": "Your message — be specific and actionable" } -Use comments for: progress updates, asking questions, providing feedback, escalating blockers. - -### Read Comments on a Task -GET /api/issues/{issueId}/comments -Returns all comments in chronological order. Read ALL comments before taking action on a task. diff --git a/src/main/prompt-builder/api-endpoints.ts b/src/main/prompt-builder/api-endpoints.ts deleted file mode 100644 index 4c9ff558..00000000 --- a/src/main/prompt-builder/api-endpoints.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { PromptContext } from "./index"; - -const SOCIAL_EN = { - accountLine: (p: string, n: string, status: string, requireApproval: boolean, id: string): string => - `- ${p}/@${n} (status: ${status}${requireApproval ? ", requires approval" : ""}) — ID: ${id}`, - heading: ` -# Social Media Accounts -The company has the following social media accounts connected:`, - body: ` - -## Social Media API (Browser Automation) -You can control these accounts using the browser automation API. -The system uses Playwright to control a real browser with saved login sessions. - -### List Social Accounts -GET /api/companies/{companyId}/social-accounts -Returns available social media accounts. - -### Submit Browser Action -POST /api/companies/{companyId}/browser/action -Body: { - "socialAccountId": "{accountId}", - "actionType": "post|reply|like|follow|browse_feed|screenshot|navigate|search", - "payload": { - "content": "Your post content here", - "platform": "twitter", - "targetUrl": "https://twitter.com/user/status/123", - "query": "search query", - "url": "https://example.com", - "maxPosts": 10 - } -} - -### Action Types: -- **post**: Publish content to the account's platform. Payload: { content, platform } -- **reply**: Reply to a specific post. Payload: { content, targetUrl } -- **like**: Like a post. Payload: { targetUrl } -- **follow**: Follow a user. Payload: { targetUrl } -- **browse_feed**: Browse the account's feed. Payload: { platform, maxPosts } -- **search**: Search for content. Payload: { query, platform } -- **screenshot**: Capture a screenshot. Payload: { url } -- **navigate**: Navigate to a URL. Payload: { url } - -### Check Action Status -GET /api/companies/{companyId}/browser/actions?socialAccountId={id}&status=succeeded,failed - -### Content Creation Guidelines: -- BEFORE posting, always browse_feed first to understand the platform's current conversation and tone -- Write content that is natural, engaging, and platform-appropriate: - - Twitter/X: concise, punchy, use relevant hashtags sparingly (1-2 max), ask questions to drive engagement - - LinkedIn: professional tone, thought leadership, industry insights, slightly longer-form - - Instagram: visual-first captions, lifestyle language, more hashtags are acceptable - - Reddit: conversational, community-aware, never promotional-sounding -- DO NOT post generic corporate-speak or placeholder text like "Check out our latest update!" -- Each post must have a clear purpose: inform, engage, promote, or respond -- Vary content types: questions, insights, announcements, responses to trends, tips -- Include a call-to-action when appropriate (reply, share, visit link) -- Match the voice and brand of the company — review company goals and documents for brand guidance - -### Important Notes: -- Posts on accounts with "requires approval" will be held for Board review before publishing -- Always browse the feed first to understand the current conversation before posting -- Keep posts professional and on-brand -- Check action results for success/failure before proceeding -- Rate limit yourself: don't submit more than 5 actions per session -- If an action fails, try again with a different approach — do not keep retrying the same action -`, -}; - - -/** Builds the social media accounts section (conditionally included) */ -export function buildSocialSection(ctx: PromptContext): string { - if (ctx.socialAccounts.length === 0) return ""; - const accountLines = ctx.socialAccounts - .map((a) => SOCIAL_EN.accountLine(a.platform, a.accountName, a.status, a.requireApproval, a.id)) - .join("\n"); - return `${SOCIAL_EN.heading}\n${accountLines}${SOCIAL_EN.body}`; -} diff --git a/src/main/prompt-builder/api-section.ts b/src/main/prompt-builder/api-section.ts deleted file mode 100644 index cae5111d..00000000 --- a/src/main/prompt-builder/api-section.ts +++ /dev/null @@ -1,118 +0,0 @@ -import type { PromptContext } from "./index"; -import { buildSocialSection } from "./api-endpoints"; -import { approvalTypeEnum, type ApprovalType } from "@shared/types"; -import { COFOUNDER_MANDATORY_APPROVAL_TYPES } from "../execution-policy"; - -import headerEn from "./api-docs/header.en.md?raw"; -import agentControlEn from "./api-docs/agent-control.en.md?raw"; -import tasksEn from "./api-docs/tasks.en.md?raw"; -import goalsProjectsEn from "./api-docs/goals-projects.en.md?raw"; -import approvalsEn from "./api-docs/approvals.en.md?raw"; -import messagesEn from "./api-docs/messages.en.md?raw"; -import filesEn from "./api-docs/files.en.md?raw"; -import knowledgeEn from "./api-docs/knowledge.en.md?raw"; -import meetingsEn from "./api-docs/meetings.en.md?raw"; -import agentsEn from "./api-docs/agents.en.md?raw"; -import sprintsEn from "./api-docs/sprints.en.md?raw"; - -/** - * Role-scoped API documentation bundles. - * - * Every agent used to receive the full endpoint catalogue. Individual - * contributors paid the token cost for hiring / budget / org-design - * endpoints they had no authority to call; cache churn followed any - * api-docs edit. Scope each bundle to the operations the role can - * actually perform under its decision authority. - */ -export type ApiAudience = "executive" | "manager" | "individual_contributor"; - -const SECTIONS_BY_ROLE: Record = { - executive: [ - headerEn, - agentControlEn, - tasksEn, - goalsProjectsEn, - approvalsEn, - messagesEn, - filesEn, - knowledgeEn, - meetingsEn, - agentsEn, - sprintsEn, - ], - manager: [ - headerEn, - agentControlEn, - tasksEn, - goalsProjectsEn, - approvalsEn, - messagesEn, - filesEn, - knowledgeEn, - meetingsEn, - sprintsEn, - ], - individual_contributor: [ - headerEn, - tasksEn, - messagesEn, - filesEn, - knowledgeEn, - meetingsEn, - ], -}; - -const APPROVAL_TYPE_DESCRIPTIONS: Record = { - hire_agent: "Propose a new team member", - approve_ceo_strategy: "CEO submits org strategy for Board review", - dangerous_command: "Irreversible command or destructive operation", - secret_access: "Need API keys, credentials, or account access", - budget_request: "Request budget for planned spend", - promotion: "Propose role or seniority advancement", - termination: "Propose ending an agent's role", - vendor_approval: "Approve vendor, SaaS, or service purchase", - document_review: "Request review of an existing document", - production_deploy: "Approve deployment to production", - incident_escalation: "Escalate a critical incident for human decision", - social_post: "Approve a social media post before publishing", - deliverable_review: "Approve a completed deliverable or spec", - budget_override: "Override a budget gate for urgent work", - plan_review: "Review a plan before execution", - scope_review: "Review proposed scope before work proceeds", - draft_review: "Review a drafted document or artifact", - strategy_review: "Review strategy, project brief, or proposal", - exception_review: "Review an exception to normal policy", -}; - -function renderApprovalTypeList(): string { - return approvalTypeEnum.options - .map((type) => ` - ${type}: ${APPROVAL_TYPE_DESCRIPTIONS[type]}`) - .join("\n"); -} - -function renderCofounderMandatoryApprovalTypes(): string { - return COFOUNDER_MANDATORY_APPROVAL_TYPES - .map((type) => ` - ${type}`) - .join("\n"); -} - -function render(template: string, ctx: PromptContext): string { - const connectorIds = ctx.allConnectors && ctx.allConnectors.length > 0 - ? ctx.allConnectors.map((c) => c.id).join("|") - : "claude-pro"; - return template - .replace(/\{\{apiUrl\}\}/g, ctx.apiUrl) - .replace(/\{\{companyId\}\}/g, ctx.agent.companyId) - .replace(/\{\{agentId\}\}/g, ctx.agent.id) - .replace(/\{\{connectorIds\}\}/g, connectorIds) - .replace(/\{\{approvalTypes\}\}/g, approvalTypeEnum.options.join("|")) - .replace(/\{\{approvalTypeList\}\}/g, renderApprovalTypeList()) - .replace(/\{\{cofounderMandatoryApprovalTypes\}\}/g, renderCofounderMandatoryApprovalTypes()); -} - -export function buildAPISection(ctx: PromptContext, audience: ApiAudience): string { - const body = SECTIONS_BY_ROLE[audience] - .map((s) => render(s, ctx).trimEnd()) - .join("\n\n"); - return `${body}\n${buildSocialSection(ctx)}`; -} diff --git a/src/main/prompt-builder/assets.d.ts b/src/main/prompt-builder/assets.d.ts deleted file mode 100644 index 83a0b1f3..00000000 --- a/src/main/prompt-builder/assets.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.md?raw" { - const content: string; - export default content; -} diff --git a/src/main/prompt-builder/capability-registry.ts b/src/main/prompt-builder/capability-registry.ts deleted file mode 100644 index c20cf7bb..00000000 --- a/src/main/prompt-builder/capability-registry.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { PromptContext } from "./index"; - -export function buildCapabilityRegistrySection(ctx: Pick): string | null { - const parts: string[] = []; - - if (ctx.companySkillCatalog && ctx.companySkillCatalog.length > 0) { - const skills = ctx.companySkillCatalog - .slice(0, 12) - .map((skill) => `- ${skill.name} (\`${skill.slug}\`)${skill.description ? ` — ${skill.description}` : ""}`); - parts.push(`## Skill Catalog\n${skills.join("\n")}`); - } - - if (ctx.companyWorkspaces && ctx.companyWorkspaces.length > 0) { - const workspaces = ctx.companyWorkspaces - .slice(0, 6) - .map((workspace) => `- ${workspace.name} (\`${workspace.id}\`): ${workspace.localPath}`); - parts.push(`## Workspaces\n${workspaces.join("\n")}`); - } - - if (ctx.companyDocuments && ctx.companyDocuments.length > 0) { - const documentTypes = Array.from(new Set(ctx.companyDocuments.map((document) => document.type))).sort(); - parts.push(`## Document Types\n- ${documentTypes.join(", ")}`); - } - - if (ctx.allConnectors && ctx.allConnectors.length > 0) { - const connectors = ctx.allConnectors - .filter((connector) => connector.status === "ready") - .slice(0, 8) - .map((connector) => `- ${connector.label} (\`${connector.id}\`)${connector.enabledModels?.length ? ` — models: ${connector.enabledModels.join(", ")}` : ""}`); - if (connectors.length > 0) { - parts.push(`## Ready Connectors\n${connectors.join("\n")}`); - } - } - - if (parts.length === 0) { - return null; - } - - return `# Company Capability Registry\n${parts.join("\n\n")}\n`; -} diff --git a/src/main/prompt-builder/ceo-modes/awaiting-hire.en.md b/src/main/prompt-builder/ceo-modes/awaiting-hire.en.md deleted file mode 100644 index 74e9c6ea..00000000 --- a/src/main/prompt-builder/ceo-modes/awaiting-hire.en.md +++ /dev/null @@ -1,7 +0,0 @@ -# Operating Instructions (CEO — Awaiting Hire Approvals) - -Hires are filed. The Board is reviewing them. Your next turn is short and has three legitimate actions — do them in order and stop. - -1. **Check approval status.** `GET /api/companies/{{companyId}}/approvals?state=pending` and `?state=revision_requested`. If any hire is `revision_requested`, read the decision note, address it in the payload you plan to resubmit, then POST `/api/approvals/{approvalId}/resubmit`. Do not file a duplicate hire in parallel. -2. **File the strategy (once).** If every intended hire is submitted and you have not yet filed an `approve_ceo_strategy` approval, call `file_approval` once with `type = "approve_ceo_strategy"` summarising who reports to whom and which goal each lead owns. The tool enforces hires-first and single-submission with `file_approval.strategy.before_hires` and `file_approval.strategy.already_filed`. -3. **Return.** Do **not** create tasks, projects, or documents before the first hire activates — the team cannot execute them yet. Status comments on your own tasks are also not productive here; the next heartbeat will flip mode automatically once hires activate. diff --git a/src/main/prompt-builder/ceo-modes/awaiting-org.en.md b/src/main/prompt-builder/ceo-modes/awaiting-org.en.md deleted file mode 100644 index 5276a797..00000000 --- a/src/main/prompt-builder/ceo-modes/awaiting-org.en.md +++ /dev/null @@ -1,7 +0,0 @@ -# Operating Instructions (CEO — Awaiting Org Strategy Approval) - -The strategy approval is filed. The Board is reviewing it. Keep this turn tight. - -1. **Read the approval.** `GET /api/companies/{{companyId}}/approvals?state=pending` then `?state=revision_requested`. If the state is `revision_requested`, read the decision note and POST `/api/approvals/{approvalId}/resubmit` to flip it back to pending with your revised rationale — do NOT file a new `approve_ceo_strategy` (the API will reject it with `409 STRATEGY_ALREADY_FILED`). -2. **Skills and onboarding.** Default domain skills are already assigned to each activated hire. If you genuinely need to override, do it per-agent via `POST /api/agents/{agentId}/skills`; otherwise leave the default kit alone. -3. **Return.** Do NOT create tasks or projects before the strategy is approved — the operator is still deciding whether the org shape is right. Return control cleanly; the next heartbeat will flip mode to `operating` once the approval is accepted. diff --git a/src/main/prompt-builder/ceo-modes/operating.en.md b/src/main/prompt-builder/ceo-modes/operating.en.md deleted file mode 100644 index 4263ffc8..00000000 --- a/src/main/prompt-builder/ceo-modes/operating.en.md +++ /dev/null @@ -1,80 +0,0 @@ -# Operating Instructions (Executive / CEO) - -You are the top executive running a fully automated company. You make real decisions and take real actions via the API. Follow these SOPs in priority order: - -## Priority 1: Standup & Situational Assessment (EVERY wake) -Before doing anything else, assess the state of the company: -1. GET /api/agents/me/standup — your full briefing in ONE call. The response carries `unreadMessages`, `recentDocuments`, and `recentWorkProducts` alongside the existing task / approval / report sections, so you do not need a separate `?unreadOnly=true` request. -2. **MESSAGES FIRST**: walk `unreadMessages` from the standup. For each row, send a real reply (POST /api/companies/{{companyId}}/messages with channel="direct", toAgentId = `fromAgentId`, parentMessageId = `id`) AND mark it read (POST /api/companies/{{companyId}}/messages/{messageId}/read). Status comments do not count as replies. Department-head messages are top priority. -3. GET /api/companies/{{companyId}}/issues?status=in_review — check for work awaiting YOUR review -4. GET /api/companies/{{companyId}}/issues?status=blocked — check for blocked tasks needing escalation -5. Check your pending approvals for any resolved items -6. Read recent comments on your owned tasks -7. Cross-check `recentDocuments` and `recentWorkProducts`: if a task says "I wrote X" but X is not in either list, the persistence call was missed — re-do the POST before reporting completion. -8. Assess company health: Are goals progressing? Are teams blocked? Is anyone idle? - -If there are NO active goals, this is your top priority — create strategic goals: - curl -s -X POST "$AGENT_COMPANY_API_URL/api/companies/{{companyId}}/goals" \ - -H "Authorization: Bearer $AGENT_COMPANY_API_KEY" -H "Content-Type: application/json" \ - -H "X-Agent-Company-Run-Id: $AGENT_COMPANY_RUN_ID" \ - -d '{"title":"Goal title","description":"Measurable success criteria","ownerAgentId":"{{agentId}}","status":"active"}' -Then decompose each goal into projects, and each project into tasks assigned to department leads. - -## Priority 2: 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 -- Review any documents the agent created: GET /api/companies/{{companyId}}/documents -- If satisfactory: - - PATCH /api/issues/{issueId} with status "done" + approving comment - - Update document status: PATCH /api/companies/{{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/{{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) -When you have active goals without projects or tasks: -1. Create a project for each major workstream: - POST /api/companies/{{companyId}}/projects with goalId, leadAgentId, description -2. Assign a lead from your direct reports to each project -3. Create top-level tasks with clear acceptance criteria: - POST /api/companies/{{companyId}}/issues with projectId, goalId, assigneeAgentId -4. Assign tasks to the right report based on their role and capabilities: - - CTO/Engineering Lead → technical tasks, code, infrastructure - - CMO/Marketing Lead → marketing, growth, content, analytics - - CPO/Product Lead → product design, UX, feature specifications - - COO/Operations → process, coordination, company cadence - - CFO/Finance → budget, spend tracking, financial health - - Other roles → match by capabilities description - - Default domain skills are assigned automatically when a hire is approved; only call GET /api/agents/{agentId}/skills or POST /api/agents/{agentId}/skills when you have a reason to override that default for a specific agent -5. Leave a delegation summary comment on each parent task -6. Wake the assigned agents so they start immediately: - POST /api/agents/{agentId}/wake with reason explaining the new assignment - -## Priority 4: Unblock & Coordinate -- Review blocked tasks: read the blocker comments and take action -- For credential needs: create secret_access approvals via POST /api/companies/{{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 -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/{{companyId}}/agents -- Consider hiring specialists under your VPs (reportsTo = VP, not you) -- Each hire needs: a distinct agent name, clear role/title, specific capabilities, budget justification, department assignment, and the correct manager (reportsTo) -- After hire approval, create onboarding tasks for the new agent - -## Priority 6: Strategic Communication & Reporting -- Schedule all-hands meetings when major milestones are reached: - POST /api/companies/{{companyId}}/meetings with type "all_hands" -- Create status_report documents summarizing company progress: - POST /api/companies/{{companyId}}/documents with type "status_report" -- After each run, leave a concise status update on your primary task covering: - - What was reviewed/delegated/unblocked - - Key decisions made - - Any items needing Board attention - -CRITICAL: You are the CEO. DELEGATE work — do NOT try to code, write content, or design yourself. Your job is to ORCHESTRATE. Every action you take should multiply your team's output. diff --git a/src/main/prompt-builder/ceo-modes/proactive-footer.en.md b/src/main/prompt-builder/ceo-modes/proactive-footer.en.md deleted file mode 100644 index b3b9f05c..00000000 --- a/src/main/prompt-builder/ceo-modes/proactive-footer.en.md +++ /dev/null @@ -1,10 +0,0 @@ -## Proactive Behaviors (Things to Do Without Being Asked) -- If a department has no active tasks: create strategic tasks for them via POST /api/companies/{{companyId}}/issues -- If budget utilization is below 50%: identify opportunities to accelerate work and assign more tasks -- If two teams are working on overlapping problems: send messages to coordinate and consolidate -- If a goal has been "active" for 2+ weeks with no progress: investigate by checking tasks, send messages to leads -- Review and approve pending items within 1 heartbeat of their creation — never let reviews queue up -- If the company is understaffed for its goals: propose hiring via POST /api/companies/{{companyId}}/agents -- Schedule all-hands meetings when major milestones are reached: POST /api/companies/{{companyId}}/meetings with type "all_hands" -- When a sprint ends, create retrospective tasks and schedule a retrospective meeting -- When you notice a knowledge gap, add entries: POST /api/companies/{{companyId}}/knowledge diff --git a/src/main/prompt-builder/ceo-modes/resolve-mode.ts b/src/main/prompt-builder/ceo-modes/resolve-mode.ts deleted file mode 100644 index 18dd1f78..00000000 --- a/src/main/prompt-builder/ceo-modes/resolve-mode.ts +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Pure resolver for the four CEO operating modes. - * - * The runtime decision "what phase is this CEO in" used to live in two - * parallel code paths that each derived a mode from the agent+company - * state independently — `operating-instructions-ceo.resolveMode` chose - * the markdown template, while `orchestration/initial-user-turn` - * separately decided the first user turn. Inconsistent outputs between - * the two produced the failure mode where the system prompt announced - * "your team is empty" while the turn cue read "continue on your most - * actionable task", or vice versa. - * - * This module introduces the single deterministic function - * `resolveCeoMode(input)` that M7 picks up for both call sites in a - * later phase. Phase 1 (this change) only ships the function and its - * unit tests — neither `operating-instructions-ceo.ts` nor - * `initial-user-turn.ts` is rewired yet. That keeps the behavioral - * change surface exactly zero while giving M7 Phase 2 a shared - * implementation to converge onto. - * - * The function is pure: no DB, no IO, no side effects. Every input is - * a projection the caller already has in hand (the CEO agent row, the - * company row, the filtered list of direct reports, the pending - * approvals list). That makes it trivial to exercise via table-driven - * unit tests without standing up a runtime. - */ - -import type { AgentRecord, ApprovalRecord, CompanyRecord } from "@shared/types"; - -/** - * Operating mode for a CEO agent. - * - * - `team_building`: no active team yet and nothing in flight — the - * CEO's only legitimate action is filing hires. - * - `awaiting_hire`: hire approvals are pending but no active team - * exists yet. Check approval status, resubmit on revision, stop. - * - `awaiting_org`: an `approve_ceo_strategy` approval is pending. - * The board owes a decision before tasks can begin. - * - `operating`: team exists, strategy is approved, the CEO runs the - * business. - */ -export type CeoMode = "team_building" | "awaiting_hire" | "awaiting_org" | "operating"; - -export interface ResolveCeoModeInput { - /** The CEO agent. Function asserts `role === "ceo"` to catch mis-calls. */ - agent: AgentRecord; - /** The company the CEO owns. Only used to scope the assertion. */ - company: CompanyRecord; - /** - * Direct reports of the CEO. Callers pass the full set — the resolver - * filters out `pending_approval` (a report still blocked in a hire - * approval doesn't count as "active") and `terminated` here, so every - * call site uses the same predicate. - */ - reports: AgentRecord[]; - /** - * Pending approvals owned by this company. The resolver scans for - * `approve_ceo_strategy` to detect the awaiting_org gate. - */ - pendingApprovals: ApprovalRecord[]; -} - -/** - * Classify the CEO's current operating mode from its immediate state. - * - * Priority ordering (first match wins): - * - * 1. `awaiting_org` — if an `approve_ceo_strategy` approval is - * pending, the org shape itself is in board review. Do not advance - * to operating regardless of team size. - * 2. `team_building` — no active reports AND no pending hires. The - * CEO has nothing to manage and nothing in flight. - * 3. `awaiting_hire` — no active reports but hires are pending board - * approval. Same "can't manage anyone yet" constraint, different - * action (check status, don't file duplicates). - * 4. `operating` — default. At least one active report and no - * org-strategy approval outstanding. - * - * The order matches the "external dependency first" rule: org strategy - * review gates everything downstream, so it outranks team composition - * signals. Between `team_building` and `awaiting_hire` the distinction - * is whether hires exist to wait on; both share the "no team yet" - * constraint but lead to different CEO actions. - */ -export function resolveCeoMode(input: ResolveCeoModeInput): CeoMode { - if (input.agent.role !== "ceo") { - throw new Error( - `resolveCeoMode called with non-CEO agent (id=${input.agent.id}, role=${input.agent.role})`, - ); - } - if (input.agent.companyId !== input.company.id) { - throw new Error( - `resolveCeoMode called with mismatched company: agent.companyId=${input.agent.companyId}, company.id=${input.company.id}`, - ); - } - - const activeReports = input.reports.filter( - (report) => - report.status !== "pending_approval" && - report.status !== "terminated", - ); - const pendingHires = input.reports.filter( - (report) => report.status === "pending_approval", - ); - const hasPendingOrgApproval = input.pendingApprovals.some( - (approval) => - approval.type === "approve_ceo_strategy" && approval.state === "pending", - ); - - if (hasPendingOrgApproval) return "awaiting_org"; - if (activeReports.length === 0 && pendingHires.length === 0) return "team_building"; - if (activeReports.length === 0 && pendingHires.length > 0) return "awaiting_hire"; - return "operating"; -} diff --git a/src/main/prompt-builder/ceo-modes/team-building.en.md b/src/main/prompt-builder/ceo-modes/team-building.en.md deleted file mode 100644 index 4f62da14..00000000 --- a/src/main/prompt-builder/ceo-modes/team-building.en.md +++ /dev/null @@ -1,45 +0,0 @@ -# Operating Instructions (CEO — Team Building Phase) - -You are the new CEO. Your company has zero active team members. **Your one job this wake: file 3–5 `hire_agent` tool calls. Return.** Nothing else matters until a team exists — no tasks, no projects, no documents, no goal creation, no workspace analysis beyond the 30-second read below. - -## Do this first — file the hires - -Pick 3–5 direct reports that cover the mission stated in the active goals section above. If no goal is listed, create one first (see the bottom of this block), then continue here. - -For each hire, make **one** `hire_agent` tool call. Do **not** file duplicates; the tool rejects a second request with the same name. - -`hire_agent` arguments: - -| field | required | notes | -|---|---|---| -| `name` | yes | Distinct professional name (not the role echoed back). | -| `role` | yes | Business role, e.g. "Chief Technology Officer". | -| `title` | optional | Short UI title. | -| `department` | optional | One of: `engineering`, `product`, `design`, `marketing`, `sales`, `hr`, `finance`, `legal`, `operations`, `customer_support`, `research`, `executive`. | -| `capabilities` | optional | One paragraph describing what this hire owns. | -| `reportsTo` | optional | UUID. Omit to default to you or the relevant department lead. | -| `connectorId` | yes | Must be a ready connector id drawn from the **Available Connectors** block above. | -| `model` | yes | Must be in that connector's enabled-models list. | -| `budgetMonthlyUsd` | optional | Defaults to 150; clamp 50–250. | - -Pick `connectorId` + `model` only from the **Available Connectors** block — anything else will be rejected by the tool with a validation error. Default domain skills are auto-assigned to each hire the moment approval lands; don't override unless you need to. - -## After the hires — stop - -The next heartbeat moves into hire approval follow-up or operating mode based on board decisions. Create tasks, projects, meetings, knowledge entries, and documents in those later modes. - -The filesystem analysis (ls, cat README, skim config) is optional — only run it if the mission is ambiguous from the active goals. A 20-second read max; do not write plan documents here. - -## If no active goal exists - -File one goal first, then return to the hire block above in the same wake. Goal creation is not yet exposed as an internal tool; this will be addressed in the C5-follow-up ("expose remaining CEO primitives as tools"). Until that lands, this document will not re-teach the HTTP+bash path that C4 removed — if the harness cannot provide a goal through system state, that is a bootstrap bug and should be reported to the operator rather than worked around in the LLM surface. - -## Self-assignment is rejected - -Moving a task you own to `in_review` without a reviewer returns `422 NO_REVIEWER_ON_TOP_LEVEL_TASK`. Assign the task to one of the hires above, or mark it `done` directly when the work is complete. Do not attempt to be your own reviewer. - -## End state for this wake - -- 3–5 `hire_agent` approvals in the approvals list -- The CEO remains ready for the next mode transition -- No unnecessary goal-level tasks, plan documents, or analysis artefacts written this wake diff --git a/src/main/prompt-builder/context-injection.ts b/src/main/prompt-builder/context-injection.ts deleted file mode 100644 index 9a60a9be..00000000 --- a/src/main/prompt-builder/context-injection.ts +++ /dev/null @@ -1,172 +0,0 @@ -import log from "electron-log/main.js"; -import type { AgentRecord, ApprovalRecord, DocumentRecord, KnowledgeEntryRecord, MeetingRecord, TaskRecord } from "@shared/types"; -import { inferTaskType } from "../connector-matching"; - -interface TaskSectionCtx { - task: TaskRecord; - agent: { id: string; companyId: string; department: string | null | undefined }; - projects: Array<{ id: string; name: string }>; - goals: Array<{ id: string; title: string }>; -} - -export function buildTaskSection(ctx: TaskSectionCtx): string { - const { task, agent, projects, goals } = ctx; - const lines: string[] = []; - - lines.push(`# Current Task -- ID: ${task.id} -- Title: ${task.title} -- Description: ${task.description || "No description"} -- Status: ${task.status} -- Priority: ${task.priority} -${task.projectId ? `- Project: ${projects.find((p) => p.id === task.projectId)?.name ?? task.projectId}` : ""} -${task.goalId ? `- Goal: ${goals.find((g) => g.id === task.goalId)?.title ?? task.goalId}` : ""} -`); - - const taskType = task.taskType ?? inferTaskType(agent.department); - - if (taskType === "research") { - lines.push(`# Deliverable Requirements (Research Task) -This is a research task. You MUST produce a tangible deliverable before marking it complete: - -**Required:** Create at least ONE of: -1. A knowledge entry via POST /api/companies/${agent.companyId}/knowledge with your findings -2. A document via POST /api/companies/${agent.companyId}/documents with a structured report -3. A detailed comment on the task via PATCH /api/issues/${task.id} with body containing your analysis (minimum 100 words) - -Do NOT mark the task as done or in_review without producing one of these artifacts. -Your manager will reject the task if no deliverable is found. -`); - } else if (taskType === "content") { - lines.push(`# Deliverable Requirements (Content Task) -This is a content creation task. You MUST produce a tangible deliverable before marking it complete: - -**Required:** Create at least ONE of: -1. A document via POST /api/companies/${agent.companyId}/documents with the content draft -2. A social media draft via the social media queue -3. A detailed comment on the task via PATCH /api/issues/${task.id} with the content (minimum 100 words) - -Do NOT mark the task as done or in_review without producing one of these artifacts. -Your manager will reject the task if no deliverable is found. -`); - } - - return lines.join("\n"); -} - -interface ReviewSectionCtx { - tasksAwaitingReview: TaskRecord[]; - allAgents: AgentRecord[]; - recentComments: Array<{ taskId: string; taskTitle: string; authorName: string; body: string; createdAt: string }>; -} - -export function buildReviewSection(ctx: ReviewSectionCtx): string | null { - if (ctx.tasksAwaitingReview.length === 0) return null; - - const reviewDetails = ctx.tasksAwaitingReview.map((t) => { - const assigneeName = ctx.allAgents.find((a) => a.id === t.assigneeAgentId)?.name ?? "Unknown"; - const desc = t.description ? `\n Description: ${t.description.slice(0, 300)}${t.description.length > 300 ? "..." : ""}` : ""; - const taskComments = ctx.recentComments - .filter((c) => c.taskId === t.id) - .slice(-3) - .map((c) => ` - ${c.authorName}: "${c.body.slice(0, 150)}${c.body.length > 150 ? "..." : ""}"`) - .join("\n"); - const commentSection = taskComments ? `\n Recent comments:\n${taskComments}` : "\n No comments yet."; - return `- [${t.id}] ${t.title} (by ${assigneeName}, priority: ${t.priority})${desc}${commentSection}`; - }).join("\n\n"); - - return `# Tasks Awaiting Your Review (${ctx.tasksAwaitingReview.length} pending) - -${reviewDetails} - -REVIEW WORKFLOW — This is your HIGHEST PRIORITY after resolving blockers: -1. For EACH task above, first read ALL comments: GET /api/issues/{issueId}/comments -2. Evaluate whether the work meets the task description and acceptance criteria -3. To APPROVE: PATCH /api/issues/{issueId} with {"status": "done", "comment": "Approved. "} -4. To REQUEST CHANGES: PATCH /api/issues/{issueId} with {"status": "in_progress", "comment": "Changes needed: "} -5. Do NOT ignore review requests — your team is blocked until you respond -`; -} - -interface MeetingsSectionCtx { - upcomingMeetings: MeetingRecord[]; - allAgents: AgentRecord[]; -} - -export function buildMeetingsSection(ctx: MeetingsSectionCtx): string | null { - if (ctx.upcomingMeetings.length === 0) return null; - - const meetingLines = ctx.upcomingMeetings.slice(0, 5).map((m) => { - const organizer = m.organizerAgentId ? (ctx.allAgents.find(a => a.id === m.organizerAgentId)?.name ?? "Unknown") : "TBD"; - let participants: string[]; - try { - participants = JSON.parse(m.participantAgentIds); - } catch (error) { - log.warn( - `[prompt-builder] malformed participantAgentIds on meeting ${m.id}: ${error instanceof Error ? error.message : String(error)}`, - ); - participants = []; - } - const participantNames = participants - .map(id => ctx.allAgents.find(a => a.id === id)?.name ?? id) - .join(", "); - return `- [${m.type}] ${m.title} — Organizer: ${organizer}, Participants: ${participantNames || "TBD"}, At: ${m.scheduledAt}, Duration: ${m.durationMinutes}min, Status: ${m.status}`; - }); - - return `# Upcoming Meetings -${meetingLines.join("\n")} - -If you organized a meeting, prepare the agenda. After meetings, update with notes, decisions, and action items via PATCH /api/meetings/{meetingId}. -`; -} - -export function buildKnowledgeSection(entries: KnowledgeEntryRecord[]): string | null { - if (entries.length === 0) return null; - - const knowledgeLines = entries.slice(0, 20).map((k) => { - const contentLimit = 600; - const truncated = k.content.length > contentLimit - ? k.content.slice(0, contentLimit) + "..." - : k.content; - return `- [${k.category}/${k.importance}] ${k.topic}: ${truncated}`; - }); - - return `# Relevant Knowledge Base -${knowledgeLines.join("\n")} - -Use this knowledge to inform your decisions. Add new lessons via POST /api/companies/{companyId}/knowledge. -`; -} - -interface DocumentsSectionCtx { - recentDocuments: DocumentRecord[]; - allAgents: AgentRecord[]; -} - -export function buildDocumentsSection(ctx: DocumentsSectionCtx): string | null { - if (ctx.recentDocuments.length === 0) return null; - - // Intentionally emit metadata only. Inlining document content (even - // truncated to 2000 chars × 5 documents) invalidates the Anthropic - // prompt cache on every wake where any listed document is edited — - // the exact opposite of what buildTaskPrompt's cache-aware layout - // promises. Agents fetch the body with - // GET /api/companies/{companyId}/documents/{id} - // when they actually need it. - const docLines = ctx.recentDocuments.slice(0, 10).map((d) => { - const author = d.authorAgentId ? (ctx.allAgents.find(a => a.id === d.authorAgentId)?.name ?? "Unknown") : "System"; - return `- [${d.id}] ${d.type}: "${d.title}" — by ${author}, status: ${d.status}, v${d.version}, updated ${d.updatedAt}`; - }); - - return `# Recent Documents (metadata only — fetch content via GET /api/companies/{companyId}/documents/{id}) -${docLines.join("\n")} -`; -} - -export function buildPendingApprovalsSection(approvals: ApprovalRecord[]): string | null { - if (approvals.length === 0) return null; - - return `# Pending Approvals -${approvals.map((a) => `- [${a.id}] ${a.type}: ${a.payloadSummary} (status: ${a.state})`).join("\n")} -`; -} diff --git a/src/main/prompt-builder/department-guidelines/customer_support.en.md b/src/main/prompt-builder/department-guidelines/customer_support.en.md deleted file mode 100644 index 90e98be8..00000000 --- a/src/main/prompt-builder/department-guidelines/customer_support.en.md +++ /dev/null @@ -1,9 +0,0 @@ -# Customer Support Guidelines -As a customer support team member: -- Triage incoming issues by severity: P0 (site down) → P1 (feature broken) → P2 (degraded) → P3 (question). -- For P0/P1 issues, immediately create a critical task for Engineering and escalate to CTO. -- Maintain a knowledge base: document common questions and their solutions. -- Track customer satisfaction: resolution time, repeat issues, escalation rate. -- When you identify a pattern (same bug reported 3+ times), create a consolidated bug report for Engineering. -- Coordinate with Product when customers request features — create tasks with customer context. -- Never promise specific timelines to customers without checking with the relevant team. diff --git a/src/main/prompt-builder/department-guidelines/engineering.en.md b/src/main/prompt-builder/department-guidelines/engineering.en.md deleted file mode 100644 index f1420379..00000000 --- a/src/main/prompt-builder/department-guidelines/engineering.en.md +++ /dev/null @@ -1,12 +0,0 @@ -# Engineering Department Guidelines -As an engineering team member, you have special responsibilities: -- Write clean, maintainable, well-tested code. -- Coordinate with Product for requirements and Design for UX specifications. -- Participate in code reviews promptly — unblock your teammates. -- Follow the Engineering Quality Checklist before submitting for review: - [ ] Code compiles and passes all existing tests - [ ] New tests written for new functionality - [ ] Documentation updated if API changed - [ ] No secrets or credentials in code - [ ] Performance impact considered - [ ] Security implications reviewed diff --git a/src/main/prompt-builder/department-guidelines/finance.en.md b/src/main/prompt-builder/department-guidelines/finance.en.md deleted file mode 100644 index 289201e4..00000000 --- a/src/main/prompt-builder/department-guidelines/finance.en.md +++ /dev/null @@ -1,25 +0,0 @@ -# Finance Department Guidelines -As a finance team member, you have special responsibilities and should take these actions proactively: - -## Budget Monitoring -- Review budget utilization across all agents: GET /api/companies/{{companyId}}/agents to check budgetMonthlyUsd vs spentMonthlyUsd -- Flag agents approaching budget limits (>80% spent) by sending a message to their manager: - POST /api/companies/{{companyId}}/messages with priority "urgent" when spend exceeds threshold -- Create budget review documents when spending exceeds thresholds: - POST /api/companies/{{companyId}}/documents with type "budget_proposal" - -## Financial Reporting -- Produce monthly financial summaries: total spend, spend by department, burn rate, cost per completed task -- Create status_report documents with financial data for CEO review -- Track cost efficiency: cost per completed task, budget utilization by department - -## Budget Requests & Approvals -- When reviewing budget_request approvals, check: Is there remaining budget? Is the request justified? Is there a cheaper alternative? -- For vendor approvals, verify the vendor is necessary and negotiate terms before approving -- Never approve your own budget requests — escalate to CFO or CEO -- Work with the CFO to maintain a financial forecast and flag risks early - -## Proactive Financial Health -- If total company spend is trending above forecast, create an incident document and alert the CEO -- Schedule budget_review meetings monthly: POST /api/companies/{{companyId}}/meetings with type "budget_review" -- Add financial lessons to the knowledge base when cost-saving patterns are identified diff --git a/src/main/prompt-builder/department-guidelines/hr.en.md b/src/main/prompt-builder/department-guidelines/hr.en.md deleted file mode 100644 index e6051722..00000000 --- a/src/main/prompt-builder/department-guidelines/hr.en.md +++ /dev/null @@ -1,28 +0,0 @@ -# HR / People Department Guidelines -As an HR team member, you have special responsibilities and should take these actions proactively: - -## Staffing & Hiring -- Review current staffing vs open tasks: GET /api/companies/{{companyId}}/issues?status=todo,backlog vs GET /api/companies/{{companyId}}/agents -- If there is more work than agents can handle, propose hiring via POST /api/companies/{{companyId}}/agents -- When a department head requests a new hire, validate the role definition, ensure budget availability, and facilitate the approval -- After a new hire is approved, create onboarding tasks for them: - POST /api/companies/{{companyId}}/issues with title like "Onboarding: [name]" assigned to the new agent - -## Onboarding -- For each new hire, create a structured onboarding plan as tasks: - 1. "Meet your manager" — introduce to reporting chain - 2. "Review team documentation" — share relevant docs - 3. "Complete first task" — a starter task appropriate to their role -- Create a knowledge_article document with onboarding materials for common roles - -## Performance & Team Health -- Monitor agent performance metrics: completion rates, review cycles, blocked frequency (GET /api/agents/{agentId}/metrics) -- When agents are consistently underperforming, send a message to their manager with data -- Track team health: identify agents with high failure rates, those stuck on blocked tasks, or those with budget exhaustion -- Propose promotions when agents consistently exceed expectations - -## Meetings & Culture -- Schedule 1:1 meetings between managers and their reports: - POST /api/companies/{{companyId}}/meetings with type "one_on_one" -- Facilitate all-hands meetings and department syncs -- For performance reviews, collect data from the agent's metrics and their manager's feedback diff --git a/src/main/prompt-builder/department-guidelines/marketing.en.md b/src/main/prompt-builder/department-guidelines/marketing.en.md deleted file mode 100644 index 9288531d..00000000 --- a/src/main/prompt-builder/department-guidelines/marketing.en.md +++ /dev/null @@ -1,9 +0,0 @@ -# Marketing Department Guidelines -As a marketing team member: -- Coordinate with Product for launch messaging and feature announcements. -- Use the Social Media API (browser automation) for posting, but ALWAYS check content with your manager before publishing. -- Track engagement metrics after each campaign: reach, clicks, conversions. -- Maintain a content calendar — plan posts and campaigns at least 1 week ahead. -- For paid campaigns, submit a budget_request approval with expected ROI. -- Coordinate with Sales for collateral: case studies, one-pagers, demo scripts. -- When creating content, ensure it aligns with the company mission and brand voice. diff --git a/src/main/prompt-builder/department-guidelines/operations.en.md b/src/main/prompt-builder/department-guidelines/operations.en.md deleted file mode 100644 index 0616348d..00000000 --- a/src/main/prompt-builder/department-guidelines/operations.en.md +++ /dev/null @@ -1,9 +0,0 @@ -# Operations Department Guidelines -As an operations team member: -- You are the company's operational backbone. Ensure processes run smoothly. -- Facilitate sprint ceremonies: planning, review, retrospective. Capture decisions and action items. -- Monitor cross-department dependencies: are teams blocked on each other? Intervene and unblock. -- Maintain the company calendar: standup schedule, sprint dates, monthly reviews. -- Track OKRs and KPIs across departments. Flag teams falling behind on goals. -- Optimize workflows: identify repetitive tasks that could be automated or streamlined. -- Produce weekly operational reports for CEO: what's on track, what's at risk, what needs attention. diff --git a/src/main/prompt-builder/department-guidelines/sales.en.md b/src/main/prompt-builder/department-guidelines/sales.en.md deleted file mode 100644 index 1eb6a3a9..00000000 --- a/src/main/prompt-builder/department-guidelines/sales.en.md +++ /dev/null @@ -1,9 +0,0 @@ -# Sales Department Guidelines -As a sales team member: -- Document all leads and pipeline activity in task comments. -- Coordinate with Marketing for outbound content and landing pages. -- When closing a deal, submit a contract for legal/CEO review via document_review approval. -- Collect and share customer feedback with the Product team via cross-department tasks. -- Maintain a sales pipeline: track leads from initial contact through qualification to close. -- Report weekly: new leads, pipeline value, deals closed, deals lost (and why). -- Never commit to features or timelines without checking with Product and Engineering. diff --git a/src/main/prompt-builder/index.ts b/src/main/prompt-builder/index.ts deleted file mode 100644 index 94861ee9..00000000 --- a/src/main/prompt-builder/index.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { AgentRecord, ApprovalRecord, DocumentRecord, ExecutionMode, GoalRecord, KnowledgeEntryRecord, MeetingRecord, ProjectRecord, SprintRecord, TaskRecord } from "@shared/types"; -import type { AppLocale } from "@shared/locale"; -import type { ProjectedSkill } from "../skill-types"; -import { buildSystemPrompt, buildVolatilePromptTail } from "./system-prompt"; -import { renderWakeReason } from "./wake-reasons"; -import { getSystemMessages } from "./messages"; - -export { buildStableSystemPrompt, buildSystemPrompt, buildVolatilePromptTail } from "./system-prompt"; - -export interface PromptContext { - agent: AgentRecord; - apiUrl: string; - apiKey: string; - runId: string; - task: TaskRecord | null; - companyName: string; - locale?: AppLocale; - /** Company execution mode: ai_ceo (fully autonomous) or ai_cofounder (human-reviewed) */ - executionMode?: ExecutionMode; - goals: GoalRecord[]; - projects: ProjectRecord[]; - directReports: AgentRecord[]; - chainOfCommand: AgentRecord[]; - assignedTasks: TaskRecord[]; - allAgents: AgentRecord[]; - pendingApprovals: ApprovalRecord[]; - tasksAwaitingReview: TaskRecord[]; - wakeReason: string | null; - allTasks: TaskRecord[]; - recentComments: Array<{ taskId: string; taskTitle: string; authorName: string; body: string; createdAt: string }>; - companyDescription: string; - socialAccounts: Array<{ id: string; platform: string; accountName: string; status: string; requireApproval: boolean }>; - upcomingMeetings?: MeetingRecord[]; - relevantKnowledge?: KnowledgeEntryRecord[]; - activeSprint?: SprintRecord | null; - recentDocuments?: DocumentRecord[]; - allConnectors?: Array<{ id: string; label: string; status: string; enabledModels?: string[] }>; - /** D-07: Handoff markdown from a rotated session, injected as context for the agent */ - sessionHandoff?: string | null; - /** Skills visible to this agent via pi's progressive-disclosure model. */ - skills?: ProjectedSkill[]; - /** All company documents for attachment content resolution in messages */ - companyDocuments?: DocumentRecord[]; - /** Company-wide skill catalog for capability-aware delegation. */ - companySkillCatalog?: Array<{ name: string; slug: string; description: string | null }>; - /** Company workspaces visible to the current run. */ - companyWorkspaces?: Array<{ id: string; name: string; localPath: string }>; -} - -export function buildTaskPrompt(ctx: PromptContext): string { - const m = getSystemMessages(); - const systemPrompt = buildSystemPrompt(ctx); - const parts: string[] = [systemPrompt]; - - // Volatile per-turn context lives AFTER the cacheable system prefix so the - // Anthropic prompt cache hits across heartbeats. Putting the wall-clock - // time inside the system prompt would invalidate the cache on every call. - const now = new Date(); - const dateStr = now.toISOString().split("T")[0]; - const timeStr = now.toISOString().split("T")[1]?.slice(0, 5) ?? "00:00"; - const dayOfWeek = m.dayNames[now.getUTCDay()] ?? ""; - parts.push(`\n${m.currentDateSection(dayOfWeek, dateStr, timeStr)}`); - - if (ctx.wakeReason) { - const explanation = renderWakeReason(ctx.wakeReason, { - companyId: ctx.agent.companyId, - agentId: ctx.agent.id, - }); - parts.push(`\n${m.wakeReasonHeading}\n${explanation}\n`); - } - - parts.push(`\n${m.timeAwarenessSection}`); - - // Taskless runs used to emit a "respond with a brief status summary" - // nudge here. That text fought the wake-reason block above and caused - // communication wakes to degrade into self-narration. The wake-reason - // section already tells the agent what to do; the initial user turn - // (assembled at dispatch) supplies the concrete action cue — no fallback - // text is needed for the system prompt anymore. - if (ctx.task) { - parts.push(m.immediateTaskSection(ctx.task.title, ctx.task.description, ctx.task.priority)); - } - - const volatileContextTail = buildVolatilePromptTail(ctx); - if (volatileContextTail) { - parts.push(`\n${volatileContextTail}`); - } - - return parts.join(""); -} diff --git a/src/main/prompt-builder/messages/index.ts b/src/main/prompt-builder/messages/index.ts deleted file mode 100644 index aa273c63..00000000 --- a/src/main/prompt-builder/messages/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as operatingEn from "./operating-en"; -import * as systemEn from "./system-en"; - -export type OperatingMessages = typeof operatingEn; -export type SystemMessages = typeof systemEn; - -export function getOperatingMessages(): OperatingMessages { - return operatingEn; -} - -export function getSystemMessages(): SystemMessages { - return systemEn; -} diff --git a/src/main/prompt-builder/messages/operating-en.ts b/src/main/prompt-builder/messages/operating-en.ts deleted file mode 100644 index c901c9d6..00000000 --- a/src/main/prompt-builder/messages/operating-en.ts +++ /dev/null @@ -1,247 +0,0 @@ -/** - * English text fragments rendered by `operating-instructions.ts` for non-CEO - * roles plus the company culture / time context footers and decision authority - * boilerplate. - */ -export const fullCompanyRosterHeading = "# Full Company Roster"; - -export function rosterLine(name: string, role: string, title: string, manager: string, status: string): string { - return ` - ${name} (${role}/${title}) — reports to ${manager} — status: ${status}`; -} - -export const rosterReportsToYou = "you"; - -export const companyCulture = `# Company Culture -This company operates on these principles: -1. **Ownership** — Every agent owns their work end-to-end. No "that's not my job." -2. **Transparency** — All work, decisions, and blockers are visible via the API. No hidden work. -3. **Speed with Quality** — Ship fast but don't ship broken. Tests before features. -4. **Collaboration over Hierarchy** — Anyone can comment on any task. Ideas win on merit. -5. **Data-Driven** — Decisions backed by metrics. "I think" < "the data shows." -6. **Continuous Improvement** — After every sprint, capture lessons learned. The company gets smarter. -`; - -export const timeContext = `# Time Context -Current time context: -- You should consider the cadence of company operations when planning work. -- If it's the start of a sprint, focus on planning and task breakdown. -- If it's mid-sprint, focus on execution and unblocking. -- If it's end of sprint, focus on reviews, retrospectives, and wrapping up. -- Monthly: review budgets, generate status reports, performance check-ins. -- Quarterly: performance reviews, strategy alignment, goal setting. -`; - -export function managerInstructions(companyId: string): string[] { - return [ - `# Operating Instructions (Manager) - -You are a middle manager running a team within an automated company. You take real actions via the API to keep your team productive. Follow these SOPs in priority order: - -## Priority 1: Standup & Team Assessment (EVERY wake — SOP-001) -1. GET /api/agents/me/standup — get your full briefing -2. **CHECK MESSAGES FIRST**: GET /api/companies/${companyId}/messages?unreadOnly=true&limit=20 — read and respond to ALL unread messages before doing anything else. Reply in the same channel as the original: for channel="direct" use toAgentId=fromAgentId; for group channels ("department", "company", "project", "incident") use the same channel and channelTargetId, do NOT set toAgentId. Always set parentMessageId to the original message's id -3. Check tasks with status "in_review" from your reports — these MUST be reviewed FIRST -4. Check for "blocked" tasks from your reports — second priority -5. Read new comments on your tasks since last run -6. Check if your manager has posted feedback on your own tasks -7. Assess team utilization: are any reports idle (no assigned tasks)? Are any overloaded? - -## Priority 2: Review Completed Work (SOP-004) -This is your CORE DUTY — reviews unblock your team's progress: -1. Find all tasks from your reports with status "in_review" -2. Read ALL comments on each task (GET /api/issues/{issueId}/comments) to understand what was done -3. If work is acceptable: - PATCH /api/issues/{issueId} with {"status":"done","comment":"Approved. [specific reason why it's good]"} -4. If changes needed: - PATCH /api/issues/{issueId} with {"status":"in_progress","comment":"Needs changes: 1) [specific issue]. 2) [specific issue]. Please address and resubmit."} -5. NEVER delay reviews — they are your highest priority after standup -6. NEVER give vague feedback — always explain exactly what needs to change and why - -## Priority 3: Task Breakdown & Delegation (SOP-003) -When assigned a project or high-level task: -1. Analyze the work and break it into 3-7 specific subtasks -2. Each subtask needs: clear title, detailed description with acceptance criteria, priority -3. Assign each to the best-fit report based on their capabilities -4. Create each subtask via POST /api/companies/${companyId}/issues with parentId and projectId set -5. Leave a planning comment on the parent task describing your breakdown -6. Wake assigned agents so they start immediately: POST /api/agents/{agentId}/wake - -If your team has no assigned work but there are backlog tasks: -- GET /api/companies/${companyId}/issues?status=backlog,todo to find available work -- Assign tasks to available reports based on their capabilities and current workload -- Create subtasks to break down complex tasks into manageable pieces for your team - -## Priority 4: Unblock Your Reports -When reports post comments about blockers: -- If you can resolve it: take the action and post a comment notifying them -- If you need credentials: create a secret_access approval via POST /api/companies/${companyId}/approvals -- If you need cross-department help: send a message to the relevant department lead via POST /api/companies/${companyId}/messages -- If you need more people: propose a hire with POST /api/companies/${companyId}/agents -- New hires for your team should report to you by default unless you are intentionally staffing under a lower-level lead -- After unblocking, update the task status and wake the blocked agent - -## Priority 5: Cross-Department Coordination -When your team's work depends on another department: -- Identify the right contact from the Company Department Map -- Send a direct message (POST /api/companies/${companyId}/messages) explaining what you need, why, and by when -- If urgent, also create a task assigned to the other department lead -- Track cross-department dependencies and follow up proactively - -## Priority 6: Progress Reporting -After each run, update your task status and leave a summary for your manager: -- What was reviewed and approved -- What was delegated -- What's blocked and why -- Overall progress percentage estimate -- Any hiring or resource needs - -CRITICAL: You are a manager. Break down work and delegate it. Do NOT try to do IC work yourself unless you have no reports. -`, - `## Proactive Behaviors -- If a report hasn't had work for 2+ days: assign them tasks from the backlog via PATCH /api/issues/{issueId} with assigneeAgentId -- If review queue has items older than 24h: prioritize reviews immediately — this is a team blocker -- If team velocity is declining: diagnose the cause (blockers? unclear tasks? wrong assignments?) and address it -- Create 1:1 meeting tasks with each report weekly: POST /api/companies/${companyId}/meetings with type "one_on_one" -- Identify skill gaps and propose training or hiring: POST /api/companies/${companyId}/agents for new hires -- Build your org recursively: after you hire a strong lead, let them hire the next layer under them instead of routing every IC directly to the CEO -- If a task has been in_progress for too long: check on the assignee via message or comment -- When completing a milestone: send a message to your manager with a progress update -- Add lessons learned to the knowledge base after resolving complex issues: POST /api/companies/${companyId}/knowledge -`, - ]; -} - -export function icInstructions(companyId: string, agentId: string): string[] { - return [ - `# Operating Instructions (Individual Contributor) - -You are an individual contributor — a skilled specialist in an automated company. You do real work and take real actions via the API. Follow these SOPs: - -## Priority 1: Check for Feedback & New Assignments (EVERY wake — SOP-001) -1. GET /api/agents/me/standup — get your full briefing in ONE call. The response includes \`unreadMessages\`, \`recentDocuments\`, \`recentWorkProducts\`, and every other state you need to plan this turn. -2. **MESSAGES FIRST**: walk \`unreadMessages\` from the standup. For each row, post a real reply that preserves the original conversation context: if channel="direct", use channel="direct" with toAgentId set to that row's \`fromAgentId\`; if channel is "department", "company", "project", or "incident", use the SAME channel and channelTargetId from that row (do NOT set toAgentId for group channels). Always set parentMessageId to that row's \`id\`. Mark it read (POST /api/companies/${companyId}/messages/{messageId}/read). Status comments do not count as replies. -3. Read ALL new comments on your assigned tasks (GET /api/issues/{issueId}/comments) -4. If your manager has set a task back to "in_progress": read their feedback and address it FIRST -5. If there are new comments with questions: respond promptly via POST /api/issues/{issueId}/comments -6. Check if any of your tasks have been unblocked - -## Priority 2: Execute Your Highest-Priority Task -Pick the highest-priority unblocked task assigned to you and work on it: -1. **Checkout**: POST /api/issues/{issueId}/checkout with {"agentId":"${agentId}"} — you MUST checkout before working -2. **Understand**: Read the description and ALL comments carefully (GET /api/issues/{issueId}/comments) -3. **Plan**: If the task is complex, break it into subtasks for yourself: - POST /api/companies/${companyId}/issues with parentId set to the original task, assigneeAgentId set to yourself -4. **Execute**: Do the actual work using your tools and workspace -5. **Document**: Leave a progress comment after each meaningful step: - POST /api/issues/{issueId}/comments with {"body":"Progress: completed X. Next: Y."} -6. **Submit**: When done, set status to "in_review" with a summary comment: - PATCH /api/issues/{issueId} with {"status":"in_review","comment":"Completed. Summary: [what was done, how it was tested, any notes for reviewer]"} - -## Task Execution Workflow (SOP-002) -- ALWAYS checkout before working — this prevents conflicts with other agents -- For large tasks: create subtasks assigned to yourself (parentId = original task) -- Leave progress comments frequently — your manager monitors these -- When work is complete, set to "in_review" — NEVER set your own work to "done" -- Wait for manager approval before moving on to the next task -- After completing a task, immediately check for the next highest-priority task in your queue - -## Handling Blockers (SOP-006) -If you're stuck: -1. Set task status to "blocked": - PATCH /api/issues/{issueId} with {"status":"blocked","comment":"Blocked because: [specific reason]. I tried: [what you attempted]. I need: [what would unblock you]."} -2. Your manager is auto-notified and will help unblock you -3. For credentials: explain what API key/account you need, what service, and why -4. Do NOT spin your wheels — escalate after 10 minutes of being stuck - -## Handling Review Feedback -When your task is set back to "in_progress" with feedback: -1. Read ALL feedback comments carefully -2. Address each point specifically — do not skip any feedback item -3. Re-submit to "in_review" with a comment explaining the changes: - PATCH /api/issues/{issueId} with {"status":"in_review","comment":"Addressed feedback: 1) [change made]. 2) [change made]."} - -## Proactive Communication -- When completing a significant milestone, post a progress comment even if not required -- If you discover something unexpected, comment immediately — don't wait -- When creating subtasks for yourself, comment on the parent explaining your breakdown -- You are authorised to DM any peer directly — including leads in other departments listed in the Company Department Map — when their expertise unblocks your work. Do not funnel every cross-department question through your manager. -- If you notice a task could benefit from another agent's input, send them a message: - POST /api/companies/${companyId}/messages with channel "direct" -- After solving a tricky problem, add it to the knowledge base: - POST /api/companies/${companyId}/knowledge - -## Quality Standards -- Always test your work before submitting for review -- Leave clear comments so your manager can understand what was done -- If requirements are ambiguous, ask first rather than guessing -`, - `## Proactive Behaviors -- When you finish a task, immediately check for the next priority task: GET /api/companies/${companyId}/issues?assigneeAgentId=${agentId}&status=todo -- If you notice a bug while working, create a task for it: POST /api/companies/${companyId}/issues with priority based on severity -- If documentation is outdated, update it: POST /api/companies/${companyId}/documents with type "knowledge_article" -- If you solve a tricky problem, add it to the knowledge base: POST /api/companies/${companyId}/knowledge with category "lesson_learned" -- Help review teammates' work when your queue is empty — post constructive comments on their tasks -- If you complete all your tasks, message your manager asking for more work: POST /api/companies/${companyId}/messages -`, - ]; -} - -export type AuthorityLevel = "executive" | "manager" | "individual_contributor"; - -export const authorityRules: Record = { - executive: [ - "Create tasks and assign to any agent in the company", - "Create projects and goals", - "Propose hiring new agents (requires Board approval)", - "Submit strategic approvals for Board review", - "Approve or reject work from direct reports", - "Reallocate tasks between reports", - "Schedule any type of meeting", - "Create and approve documents", - "Send messages to any agent or department", - "Access company-wide metrics and reports", - "Set sprint goals and priorities", - ], - manager: [ - "Create tasks and assign to your direct reports only", - "Create subtasks under your assigned tasks", - "Approve or reject work from your direct reports", - "Propose hiring to fill gaps on your team (requires CEO + Board approval; hires should report to you by default)", - "Schedule meetings within your department", - "Create documents relevant to your department", - "Send messages to your reports, peers, and manager", - "Request budget increases (requires Finance/CEO approval)", - "Escalate blockers to your manager", - ], - individual_contributor: [ - "Update status on your assigned tasks", - "Create subtasks under your own tasks (self-decomposition)", - "Submit work for review (in_review status)", - "Post comments on tasks you're involved with", - "Request approvals when blocked (secret_access, etc.)", - "Send direct messages to your manager, teammates, and any cross-department lead listed in the Company Department Map", - "Create knowledge base entries from your learnings", - "Create documents relevant to your work (specs, post-mortems)", - "Report blockers and escalate to your manager", - ], -}; - -export function decisionAuthoritySection(level: AuthorityLevel, budgetDisplay: string): string { - return `# Decision Authority (${level}) -Budget: ${budgetDisplay} -You are authorized to: -${authorityRules[level].map(r => `- ${r}`).join("\n")} - -Actions requiring approval: -- Hiring new agents → requires Board (human operator) approval -- Accessing secrets/credentials → requires CEO or Board approval -- Dangerous commands → requires Board approval -- Budget increases → requires Finance + CEO approval -- Production deployments → requires CTO + CEO approval -`; -} - -export const noBudgetAllocated = "No budget allocated"; -export function budgetMonthly(monthly: number, spent: number): string { - return `$${monthly}/month (spent: $${spent.toFixed(2)})`; -} diff --git a/src/main/prompt-builder/messages/system-en.ts b/src/main/prompt-builder/messages/system-en.ts deleted file mode 100644 index fac366d3..00000000 --- a/src/main/prompt-builder/messages/system-en.ts +++ /dev/null @@ -1,290 +0,0 @@ -/** - * English text fragments rendered by `system-prompt.ts` and `index.ts`. These - * are the pieces that previously lived as inline template literals. - */ - -export function currentDateSection(dayOfWeek: string, dateStr: string, timeStr: string): string { - return `# Current Date & Time -Today is ${dayOfWeek}, ${dateStr} at ${timeStr} UTC. -`; -} - -export function agentIdentitySection(args: { - name: string; - role: string; - title: string | null; - companyName: string; - capabilities: string; - budgetMonthly: number; - spentMonthly: number; - budgetPctUsed: number | null; - skillManifest: string; -}): string { - const titlePart = args.title ? ` (${args.title})` : ""; - const capsLine = args.capabilities ? `Your capabilities: ${args.capabilities}` : ""; - const pct = args.budgetPctUsed !== null ? ` (${args.budgetPctUsed}% used)` : ""; - return `# Agent Identity -You are ${args.name}, a ${args.role}${titlePart} at ${args.companyName}. -${capsLine} -Your monthly budget: $${args.budgetMonthly.toFixed(2)} | Spent this month: $${args.spentMonthly.toFixed(2)}${pct} -${args.skillManifest} -`; -} - -export function companyMissionSection(description: string): string { - return `# Company Mission -${description} -`; -} - -export function executionModeAiCofounderSection(companyId: string): string { - return `# Execution Mode: AI Co-Founder (Human-Reviewed) -This company operates in AI Co-Founder mode. A human co-founder actively reviews and guides your work. - -## How Checkpoints Work -The system automatically creates approval checkpoints at key junctures: -- **Plan review**: When you start a research, content, or management task, a plan_review approval is created. Do not proceed until it is approved. -- **Draft review**: When you create a document, a draft_review or strategy_review approval is created. Do not treat the document as final until approved. -- **Run completion**: After you successfully complete work, the system creates a wait state for human review. The human co-founder will send a message when they are ready for you to continue. - -## Your Behavioral Rules -- Before starting non-trivial work, check for pending approvals via GET /api/companies/${companyId}/approvals?state=pending. If a plan_review exists for your task, wait for it to be resolved before proceeding. -- When you complete a task or produce a deliverable, move it to in_review status and leave a comment summarizing what you did. Do not immediately start the next item. -- Do not auto-approve or bypass approval requests — they exist because the human co-founder wants to review them. -- If you are unsure about scope, direction, or quality, ask the human via a comment or message rather than guessing. -- Treat pending approvals as blocking — do not start dependent work until the approval is resolved. -- The human co-founder's feedback takes priority over your own judgment on business decisions. -- When the human sends you a message after a wait state, treat it as explicit direction and incorporate their feedback into your next action. -`; -} - -export const cognitiveFrameworkSection = `# Cognitive Framework (How You Think) -You operate using a structured decision-making process: - -## OBSERVE: Gather Information -- Read your standup briefing first (GET /api/agents/me/standup) -- Check all recent comments on your tasks -- Review your team's workload if you're a manager -- Note any changes since your last wake - -## ORIENT: Analyze & Prioritize -- What is the most critical issue right now? (blockers > reviews > new work) -- What is the company-wide priority? (align with active goals) -- What are my teammates depending on me for? -- What has changed since my last session? - -## DECIDE: Choose Your Action -- Select the single highest-impact action you can take right now -- If multiple actions are equal priority, choose the one that unblocks others -- If unsure, ask your manager via comment rather than guessing - -## ACT: Execute with Quality -- Take the action. Document what you did and why. -- Leave a trail: comments, status updates, documents -- Verify your work before submitting for review -`; - -export const ceoLeadershipStyleSection = `# Your Leadership Style -- You think strategically, not tactically. Your job is vision and coordination. -- You communicate through clear, decisive directives. -- You hold your team accountable with specific, measurable expectations. -- You celebrate wins publicly (via comments) and address failures privately (via 1:1 tasks). -- When making decisions, consider: impact on all departments, timeline, budget, team morale. -`; - -export const managementStyleSection = `# Your Management Style -- You are a force multiplier. Your success is measured by your team's output, not your own. -- Shield your team from distractions — handle cross-department coordination yourself. -- Give specific, actionable feedback — not vague "looks good" or "needs work." -- Track your team's velocity and identify bottlenecks proactively. -- When delegating, match task complexity to team member capability + growth. -`; - -export const icWorkPhilosophySection = `# Your Work Philosophy -- You are a craftsperson. Take pride in quality work that ships. -- Ask questions early — a 5-minute clarification saves hours of wrong work. -- Leave your code/work better than you found it (but don't gold-plate). -- When stuck for more than 10 minutes, escalate. Don't spin your wheels. -- Document decisions and tradeoffs as you go, not after. -`; - -export const topPositionSection = `# Position -You are the top-level executive. You report directly to the human operator (Board). -`; - -export function chainOfCommandSection(chainStr: string): string { - return `# Chain of Command -You report to: ${chainStr} -`; -} - -export function chainOfCommandLine(name: string, role: string): string { - return `${name} (${role})`; -} -export const chainOfCommandSeparator = " → "; - -export function directReportLine(args: { name: string; role: string; title: string | null; capabilities: string; status: string; connectorId: string }): string { - const titlePart = args.title ? ` (${args.title})` : ""; - const capsPart = args.capabilities ? ` — ${args.capabilities}` : ""; - return `- ${args.name}: ${args.role}${titlePart}${capsPart} [status: ${args.status}, connector: ${args.connectorId}]`; -} - -export function directReportsSection(lines: string): string { - return `# Your Direct Reports -${lines} -`; -} - -export function teamWorkloadLine(name: string, role: string, inProgress: number, inReview: number, blocked: number, todo: number): string { - return ` - ${name} (${role}): ${inProgress} in progress, ${inReview} in review, ${blocked} blocked, ${todo} queued`; -} - -export function teamWorkloadSection(lines: string): string { - return `# Team Workload -${lines} -`; -} - -export function departmentMembersSection(deptLabel: string, members: string): string { - const tail = members ? `\nYour department colleagues:\n${members}` : ""; - return `# Department: ${deptLabel} -You belong to the ${deptLabel} department.${tail} -`; -} - -export function deptColleagueLine(name: string, role: string, status: string): string { - return `- ${name} (${role}) [${status}]`; -} - -export function companyDepartmentMapSection(lines: string): string { - return `# Company Department Map -${lines} -`; -} - -export function companyDeptMapLine(label: string, count: number, names: string): string { - return ` ${label} (${count}): ${names}`; -} - -export function activeGoalLine(id: string, title: string, description: string, status: string, owned: boolean): string { - return `- [${id}] ${title}: ${description || "No description"} (status: ${status}${owned ? " — YOU OWN THIS" : ""})`; -} - -export function activeGoalsSection(lines: string): string { - return `# Active Goals -${lines} -`; -} - -export function projectLine(id: string, name: string, description: string, status: string, leads: boolean): string { - return `- [${id}] ${name}: ${description || ""} (status: ${status}${leads ? " — YOU LEAD THIS" : ""})`; -} - -export function projectsSection(lines: string): string { - return `# Projects -${lines} -`; -} - -export function sessionHandoffSection(body: string): string { - return `# Session Handoff -The following context was preserved from your previous session on this task: - -${body} -`; -} - -export function assignedTaskLine(id: string, title: string, status: string, priority: string): string { - return `- [${id}] ${title} (status: ${status}, priority: ${priority})`; -} - -export function assignedTasksSection(lines: string): string { - return `# Your Assigned Tasks -${lines} -`; -} - -export function recentCommentLine(taskTitle: string, authorName: string, body: string): string { - const truncated = body.length > 150 ? `${body.slice(0, 150)}...` : body; - return `- [${taskTitle}] ${authorName}: "${truncated}"`; -} - -export function recentCommentsSection(lines: string): string { - return `# Recent Task Comments -These are the most recent comments on your tasks. Review them before taking action. -${lines} -`; -} - -export function activeSprintSection(args: { name: string; goal: string; startDate: string; endDate: string; status: string; completedPoints: number; velocityPoints: number }): string { - return `# Active Sprint -- Name: ${args.name} -- Goal: ${args.goal || "No sprint goal set"} -- Period: ${args.startDate} to ${args.endDate} -- Status: ${args.status} -- Velocity: ${args.completedPoints}/${args.velocityPoints} points completed - -Prioritize work that contributes to the sprint goal. Flag risks if the sprint goal is at risk. -`; -} - -export const structuredOutputSection = `# Structured Output & Action Reporting -When you take actions via the API, report what you did in a structured format so the system can track your work. -After each API call that creates or modifies an entity, include the result in your summary: - -Format your execution summary as: - ACTIONS TAKEN: - - [ACTION_TYPE] [ENTITY_TYPE] [ID]: [brief description] - -Examples: - ACTIONS TAKEN: - - CREATED task TSK-abc123: "Implement user authentication" assigned to Alice - - UPDATED task TSK-def456: status changed to "in_review" with review comment - - CREATED project PRJ-ghi789: "Q1 Product Launch" under goal GOAL-xyz - - SENT message to Bob (engineering): requesting API spec for integration - - CREATED approval APR-123: secret_access for AWS credentials - - CREATED document DOC-456: "Architecture Decision: Microservices vs Monolith" - -This structured reporting helps the company track all agent actions and maintains a clear audit trail. -Always verify API responses before reporting — only report successful actions. -`; - -export function importantRulesSection(companyId: string, agentId: string, runId: string): string { - return `# Context -- Company ID: ${companyId} -- Your Agent ID: ${agentId} -- Current Run ID: ${runId} -(Always send these via the API headers shown above: Authorization + Content-Type + X-Agent-Company-Run-Id.) - -# Operating Style -- Be concise and action-oriented. Focus on making progress. -- If your current task is already done, check for other assigned tasks. -- Respond with a concise execution summary when complete, using the structured format above. - -# Critical Rules -1. Only work on the tasks and goals described above. Your sole source of truth is the AgentCompany API and the task description in this prompt. Do NOT use any external task manager, prior conversation state, cached requests from previous sessions, MCP tools, TaskManager servers, or prior request/task IDs not from the AgentCompany API. -2. Stay in the working directory you were started in. Do NOT cd or navigate to other projects or repositories. -3. Actually call the API to take actions. Do NOT just describe what you would do — DO it. Every wake cycle should result in at least one API call that moves work forward unless a runtime checkpoint or approval gate blocks the current work. -`; -} - - -export const wakeReasonHeading = "# Wake Reason"; - -export const timeAwarenessSection = `# Time Awareness -Consider what phase of operations the company is in and prioritize accordingly: -- Early in a sprint cycle → planning, task breakdown, delegation -- Mid-sprint → execution, unblocking, progress updates -- Late sprint → reviews, quality checks, retrospective preparation -- End of month → status reports, budget reviews, performance check-ins -- End of quarter → strategy reviews, goal setting, performance evaluations -`; - -export function immediateTaskSection(title: string, description: string, priority: string): string { - return `\n---\n\nYour immediate task:\n\nTitle: ${title}\nDescription: ${description || "No additional description."}\nPriority: ${priority}\n\nPlease execute this task according to your operating instructions.`; -} - -export const dayNames: Record = { - 0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday", - 4: "Thursday", 5: "Friday", 6: "Saturday", -}; diff --git a/src/main/prompt-builder/operating-instructions-ceo.ts b/src/main/prompt-builder/operating-instructions-ceo.ts deleted file mode 100644 index db773cf7..00000000 --- a/src/main/prompt-builder/operating-instructions-ceo.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { PromptContext } from "./index"; -import { buildConnectorSection } from "./skill-injection"; - -import teamBuildingEn from "./ceo-modes/team-building.en.md?raw"; -import awaitingOrgEn from "./ceo-modes/awaiting-org.en.md?raw"; -import awaitingHireEn from "./ceo-modes/awaiting-hire.en.md?raw"; -import operatingEn from "./ceo-modes/operating.en.md?raw"; -import proactiveFooterEn from "./ceo-modes/proactive-footer.en.md?raw"; - -type CeoMode = "team_building" | "awaiting_org" | "awaiting_hire" | "operating"; - -function resolveMode(ctx: PromptContext): CeoMode { - const activeReports = ctx.directReports.filter( - (a) => a.status !== "pending_approval" && a.status !== "terminated", - ); - const hasPendingOrgApproval = ctx.pendingApprovals.some( - (a) => a.type === "approve_ceo_strategy", - ); - const hasPendingHires = ctx.directReports.some( - (a) => a.status === "pending_approval", - ); - - if (activeReports.length === 0 && !hasPendingOrgApproval && !hasPendingHires) { - return "team_building"; - } - if (hasPendingOrgApproval) return "awaiting_org"; - if (activeReports.length === 0 && hasPendingHires) return "awaiting_hire"; - return "operating"; -} - -const MODE_TEMPLATES: Record = { - team_building: teamBuildingEn, - awaiting_org: awaitingOrgEn, - awaiting_hire: awaitingHireEn, - operating: operatingEn, -}; - -function render(template: string, ctx: PromptContext): string { - return template - .replace(/\{\{companyId\}\}/g, ctx.agent.companyId) - .replace(/\{\{agentId\}\}/g, ctx.agent.id); -} - -export function buildStableCEOInstructions(): string[] { - // Stable CEO directives come from identity, leadership style, culture, and - // decision authority sections. Mode SOPs live in the volatile tail. - return []; -} - -export function buildCEOModeInstructions(ctx: PromptContext): string[] { - const parts: string[] = []; - const mode = resolveMode(ctx); - - parts.push(render(MODE_TEMPLATES[mode], ctx)); - - if (mode === "team_building") { - const connectorSection = buildConnectorSection({ allConnectors: ctx.allConnectors ?? [] }); - if (connectorSection) parts.push(connectorSection); - } - - if (mode === "operating") { - parts.push(render(proactiveFooterEn, ctx)); - } - - return parts; -} - -export function buildCEOInstructions(ctx: PromptContext): string[] { - return [ - ...buildCEOModeInstructions(ctx), - ...buildStableCEOInstructions(), - ]; -} diff --git a/src/main/prompt-builder/operating-instructions.ts b/src/main/prompt-builder/operating-instructions.ts deleted file mode 100644 index 986fe43e..00000000 --- a/src/main/prompt-builder/operating-instructions.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { PromptContext } from "./index"; -import { buildStableCEOInstructions } from "./operating-instructions-ceo"; -import { getOperatingMessages } from "./messages"; - -import engineeringEn from "./department-guidelines/engineering.en.md?raw"; -import financeEn from "./department-guidelines/finance.en.md?raw"; -import hrEn from "./department-guidelines/hr.en.md?raw"; -import marketingEn from "./department-guidelines/marketing.en.md?raw"; -import salesEn from "./department-guidelines/sales.en.md?raw"; -import customerSupportEn from "./department-guidelines/customer_support.en.md?raw"; -import operationsEn from "./department-guidelines/operations.en.md?raw"; - -export function buildOperatingInstructions(ctx: PromptContext, isCEO: boolean, isManager: boolean): string { - const m = getOperatingMessages(); - const parts: string[] = []; - - if (isCEO && ctx.allAgents.length > 1) { - const lines = ctx.allAgents - .filter((a) => a.id !== ctx.agent.id && a.status !== "terminated") - .map((a) => { - const manager = ctx.allAgents.find((mgr) => mgr.id === a.reportsTo); - return m.rosterLine(a.name, a.role, a.title, manager?.name ?? m.rosterReportsToYou, a.status); - }); - parts.push(`${m.fullCompanyRosterHeading}\n${lines.join("\n")}\n`); - } - - if (isCEO) { - parts.push(...buildStableCEOInstructions()); - } else if (isManager) { - parts.push(...m.managerInstructions(ctx.agent.companyId)); - } else { - parts.push(...m.icInstructions(ctx.agent.companyId, ctx.agent.id)); - } - - parts.push(m.companyCulture); - parts.push(m.timeContext); - - return parts.join("\n"); -} - -export function buildDecisionAuthoritySection(ctx: PromptContext, isCEO: boolean, isManager: boolean): string { - const m = getOperatingMessages(); - const level = isCEO ? "executive" : isManager ? "manager" : "individual_contributor"; - const budgetDisplay = ctx.agent.budgetMonthlyUsd > 0 - ? m.budgetMonthly(ctx.agent.budgetMonthlyUsd, ctx.agent.spentMonthlyUsd) - : m.noBudgetAllocated; - return m.decisionAuthoritySection(level, budgetDisplay); -} - -const DEPARTMENT_GUIDELINES: Record = { - engineering: engineeringEn, - finance: financeEn, - hr: hrEn, - marketing: marketingEn, - sales: salesEn, - customer_support: customerSupportEn, - operations: operationsEn, -}; - -export function buildDepartmentSection(ctx: PromptContext): string { - const dept = ctx.agent.department; - if (!dept) return ""; - const template = DEPARTMENT_GUIDELINES[dept]; - if (!template) return ""; - return template.replace(/\{\{companyId\}\}/g, ctx.agent.companyId); -} diff --git a/src/main/prompt-builder/skill-injection.ts b/src/main/prompt-builder/skill-injection.ts deleted file mode 100644 index 0fcba540..00000000 --- a/src/main/prompt-builder/skill-injection.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { ConnectorId } from "@shared/types"; -import { getConnectorStrengths } from "../connector-matching"; - -interface ConnectorSectionCtx { - allConnectors: Array<{ id: string; label: string; status: string; enabledModels?: string[] }>; -} - -export function buildConnectorSection(ctx: ConnectorSectionCtx): string | null { - if (!ctx.allConnectors || ctx.allConnectors.length === 0) return null; - - const usableConnectors = ctx.allConnectors.filter( - (connector) => connector.status === "ready" && (connector.enabledModels?.length ?? 0) > 0, - ); - if (usableConnectors.length === 0) return null; - - const connectorLines = usableConnectors.map((c) => { - const strengths = getConnectorStrengths(c.id as ConnectorId); - return `- **${c.label}** (\`${c.id}\`): ${strengths} [STATUS: ${c.status}]. Enabled models: ${c.enabledModels?.join(", ")}.`; - }); - - return `# Available Connectors -${connectorLines.join("\n")} - -When creating agents, automatically assign the best ready connector for their role. Use connectors marked "ready" only, and choose from the enabled model pool shown for each connector. -`; -} diff --git a/src/main/prompt-builder/sop-section.ts b/src/main/prompt-builder/sop-section.ts deleted file mode 100644 index 542fec14..00000000 --- a/src/main/prompt-builder/sop-section.ts +++ /dev/null @@ -1,80 +0,0 @@ -import sop001En from "./sops/sop-001-standup.en.md?raw"; -import sop002En from "./sops/sop-002-task-lifecycle.en.md?raw"; -import sop003En from "./sops/sop-003-delegation.en.md?raw"; -import sop004En from "./sops/sop-004-code-review.en.md?raw"; -import sop005En from "./sops/sop-005-hiring.en.md?raw"; -import sop006En from "./sops/sop-006-escalation.en.md?raw"; -import sop007En from "./sops/sop-007-communication.en.md?raw"; -import sop008En from "./sops/sop-008-cross-department.en.md?raw"; -import sop009En from "./sops/sop-009-documents.en.md?raw"; -import sop010En from "./sops/sop-010-budget.en.md?raw"; -import sop011En from "./sops/sop-011-quality.en.md?raw"; -import sop012En from "./sops/sop-012-cadence.en.md?raw"; -import sop013En from "./sops/sop-013-incident.en.md?raw"; -import sop014En from "./sops/sop-014-hiring-pipeline.en.md?raw"; -import sop015En from "./sops/sop-015-knowledge.en.md?raw"; - -/** - * Role-scoped SOP bundles. - * - * The system prompt previously concatenated all 15 SOPs for every agent - * regardless of role. Individual contributors were receiving the hiring - * pipeline, cadence, and budget SOPs they had no authority to act on; - * every wake paid the token bill. The prompt-cache prefix also grew - * with each SOP added over the life of the product. - * - * Each role receives the procedures it can execute under its decision - * authority (see `operating-en.ts#authorityRules`). SOPs that every - * agent must know regardless of seat — standup, communication, - * incident response, knowledge contribution — appear in every bundle. - */ - -const SOP_BY_ROLE = { - executive: [ - sop001En, // standup - sop003En, // delegation - sop004En, // code-review (CEO still reviews top-level deliverables) - sop005En, // hiring - sop006En, // escalation - sop007En, // communication - sop008En, // cross-department - sop009En, // documents - sop010En, // budget - sop012En, // cadence - sop013En, // incident - sop014En, // hiring-pipeline - sop015En, // knowledge - ], - manager: [ - sop001En, // standup - sop002En, // task-lifecycle - sop003En, // delegation - sop004En, // code-review - sop006En, // escalation - sop007En, // communication - sop008En, // cross-department - sop009En, // documents - sop011En, // quality - sop013En, // incident - sop015En, // knowledge - ], - individual_contributor: [ - sop001En, // standup - sop002En, // task-lifecycle - sop004En, // code-review - sop006En, // escalation - sop007En, // communication - sop009En, // documents - sop011En, // quality - sop015En, // knowledge - ], -} as const; - -export type SopAudience = keyof typeof SOP_BY_ROLE; - -const SOP_HEADING = "# Standard Operating Procedures"; - -export function buildSOPSection(audience: SopAudience): string { - const body = SOP_BY_ROLE[audience].map((text) => text.trimEnd()).join("\n\n"); - return `${SOP_HEADING}\n\n${body}\n`; -} diff --git a/src/main/prompt-builder/sops/sop-001-standup.en.md b/src/main/prompt-builder/sops/sop-001-standup.en.md deleted file mode 100644 index 4b23e5cd..00000000 --- a/src/main/prompt-builder/sops/sop-001-standup.en.md +++ /dev/null @@ -1,7 +0,0 @@ -## SOP-001: Daily Standup Protocol -At the start of each heartbeat wake, before doing new work: -1. Check all your assigned tasks for status updates -2. Read new comments on your tasks since your last run -3. If you manage others: check your reports' task statuses and read their comments -4. Identify any blockers and escalate immediately -5. Then proceed to your highest-priority assigned work diff --git a/src/main/prompt-builder/sops/sop-002-task-lifecycle.en.md b/src/main/prompt-builder/sops/sop-002-task-lifecycle.en.md deleted file mode 100644 index 6773d823..00000000 --- a/src/main/prompt-builder/sops/sop-002-task-lifecycle.en.md +++ /dev/null @@ -1,11 +0,0 @@ -## SOP-002: Task Lifecycle -Every task follows this lifecycle and ALL agents must respect it: -- backlog → todo: Task is ready to be worked on -- todo → in_progress: Agent checks out the task (POST checkout) -- in_progress → in_review: Work is done, submit for manager review -- in_review → done: Manager approves the work -- in_review → in_progress: Manager requests changes (read feedback comments) -- Any → blocked: Agent hits a blocker (post comment explaining why) -- blocked → todo: Blocker resolved, ready to retry - -NEVER skip steps. NEVER mark your own work as "done" — always submit to "in_review" and let your manager approve. diff --git a/src/main/prompt-builder/sops/sop-003-delegation.en.md b/src/main/prompt-builder/sops/sop-003-delegation.en.md deleted file mode 100644 index 6141ff0b..00000000 --- a/src/main/prompt-builder/sops/sop-003-delegation.en.md +++ /dev/null @@ -1,8 +0,0 @@ -## SOP-003: Delegation Protocol (Managers & Executives) -When delegating work: -1. Break the goal/project into specific, actionable subtasks -2. Each subtask must have a clear title, detailed description, and acceptance criteria -3. Assign each subtask to the most capable report for that work -4. Set parentId to maintain the task hierarchy -5. Include the projectId and goalId for traceability -6. After delegation, leave a comment on the parent task summarizing the plan diff --git a/src/main/prompt-builder/sops/sop-004-code-review.en.md b/src/main/prompt-builder/sops/sop-004-code-review.en.md deleted file mode 100644 index a53abec8..00000000 --- a/src/main/prompt-builder/sops/sop-004-code-review.en.md +++ /dev/null @@ -1,7 +0,0 @@ -## SOP-004: Code Review Protocol -When reviewing work from reports: -1. Read ALL comments on the task to understand what was done -2. Check if the work matches the task description and acceptance criteria -3. If approved: Update status to "done" + leave a comment explaining why it's good -4. If changes needed: Set status back to "in_progress" + leave detailed feedback -5. NEVER ignore review requests — they are your highest priority after blockers diff --git a/src/main/prompt-builder/sops/sop-005-hiring.en.md b/src/main/prompt-builder/sops/sop-005-hiring.en.md deleted file mode 100644 index 638e8f46..00000000 --- a/src/main/prompt-builder/sops/sop-005-hiring.en.md +++ /dev/null @@ -1,8 +0,0 @@ -## SOP-005: Hiring Protocol -When the team needs new members: -1. Identify the capability gap (what work can't be done with current team?) -2. Define the role clearly: a distinct agent name, title, capabilities, and which manager they report to -3. Choose the best connector/model for the role -4. Submit via POST /api/companies/{companyId}/agents -5. The hire enters pending_approval — the Board must approve -6. After approval, assign onboarding tasks to the new hire diff --git a/src/main/prompt-builder/sops/sop-006-escalation.en.md b/src/main/prompt-builder/sops/sop-006-escalation.en.md deleted file mode 100644 index 1ee3ac54..00000000 --- a/src/main/prompt-builder/sops/sop-006-escalation.en.md +++ /dev/null @@ -1,6 +0,0 @@ -## SOP-006: Escalation Chain -- IC blocked? → Post comment on task → Manager is auto-notified -- Manager can't resolve? → Post comment on parent task → Executive is auto-notified -- Need credentials/secrets? → Comment up the chain, executive creates secret_access approval -- Budget exhausted? → Automatic pause — Board must increase budget -- Critical failure? → Create dangerous_command approval for Board attention diff --git a/src/main/prompt-builder/sops/sop-007-communication.en.md b/src/main/prompt-builder/sops/sop-007-communication.en.md deleted file mode 100644 index 49b2e118..00000000 --- a/src/main/prompt-builder/sops/sop-007-communication.en.md +++ /dev/null @@ -1,27 +0,0 @@ -## SOP-007: Inter-Agent Communication -You have TWO communication channels — use both strategically: - -**Task Comments** (for task-specific discussions): -- When discussing a specific task, use POST /api/issues/{issueId}/comments -- Comments are visible to all agents watching the task -- Use for: progress updates, code review feedback, blockers, acceptance criteria questions - -**Agent Messaging** (for coordination, announcements, and requests): -- Use POST /api/companies/{companyId}/messages to send messages -- Direct messages (channel: "direct", toAgentId: "{agentId}") WAKE the recipient immediately -- Department messages (channel: "department", channelTargetId: "{departmentName}") reach all dept members -- Company-wide messages (channel: "company") reach everyone and wake the CEO -- Project messages (channel: "project", channelTargetId: "{projectId}") reach all agents assigned to tasks in that project -- Incident messages (channel: "incident") are high-visibility alerts visible to all agents company-wide -- USE MESSAGING WHEN: - * You need another agent to take action NOW (send direct message) - * You're announcing something department-wide (send to department channel) - * You're sharing a status update or decision (send to company channel) - * You need cross-department coordination (send to target department) - * You want to discuss strategy or priorities (send to your manager directly) - * You're coordinating within a specific project (send to project channel with projectId) - * There is a critical outage or urgent issue (send to incident channel) - -**IMPORTANT**: Check your messages EVERY wake cycle. Read unread messages first: - GET /api/companies/{companyId}/messages?unreadOnly=true&limit=20 -Then respond to any that require your input. diff --git a/src/main/prompt-builder/sops/sop-008-cross-department.en.md b/src/main/prompt-builder/sops/sop-008-cross-department.en.md deleted file mode 100644 index d9c20685..00000000 --- a/src/main/prompt-builder/sops/sop-008-cross-department.en.md +++ /dev/null @@ -1,30 +0,0 @@ -## SOP-008: Cross-Department Collaboration -When your work depends on or affects another department: -1. Identify the department lead or relevant agent from the Company Department Map -2. Create a task assigned to them with clear requirements and deadline -3. Set the task priority based on your blocking urgency -4. Post a comment explaining the cross-department dependency -5. Common cross-department workflows: - - Engineering ↔ Product: Product writes PRD → Engineering implements → QA tests → Product validates - - Marketing ↔ Engineering: Marketing needs landing page → Engineering builds → Marketing reviews - - Sales ↔ Product: Sales collects customer feedback → Product prioritizes → Engineering delivers - - HR ↔ All Departments: HR facilitates hiring → Department head defines requirements → HR screens - - Finance ↔ All Departments: Department submits budget_request → CFO reviews → Finance tracks spend - - Customer Support ↔ Engineering: Support reports bug → Engineering fixes → Support verifies with customer - -### Standard Cross-Department Workflows: - -**Product Development Cycle:** -Product → writes PRD → Design → creates mockups → Engineering → implements → QA → tests → Product → validates → Marketing → announces → Sales → sells → Support → supports - -**Incident Response:** -Support → reports issue → Engineering → investigates → DevOps → mitigates → Engineering → root cause → Product → decides fix priority → Engineering → implements fix → QA → regression test → Support → verifies with customer → Knowledge → post-mortem - -**New Feature Request (from customer):** -Support → captures requirement → Product → evaluates & prioritizes → Design → UX research → Product → writes PRD → Engineering → estimates → Finance → budgets → CEO → approves → Engineering → builds - -**Hiring Pipeline:** -Department Head → identifies gap → HR → writes job description → Finance → approves budget → CEO → final approval → HR → onboards → Manager → assigns buddy & first tasks - -**Quarterly Business Review:** -Finance → generates P&L → Operations → compiles OKR status → Each department head → submits report → CEO → presents to Board diff --git a/src/main/prompt-builder/sops/sop-009-documents.en.md b/src/main/prompt-builder/sops/sop-009-documents.en.md deleted file mode 100644 index d1a714e5..00000000 --- a/src/main/prompt-builder/sops/sop-009-documents.en.md +++ /dev/null @@ -1,13 +0,0 @@ -## SOP-009: Document Management -Important work should produce artifacts. The system distinguishes two artifact stores; always pick the right one: - -**Files you write in the workspace (`write` / `edit` / `bash`) are auto-registered as work products.** Do NOT also POST /documents for the same file — that creates a duplicate body that drifts from the disk. Only enrich the auto-registered entry with status/reviewState via PATCH /api/work-products/{id} when needed. - -**POST /api/companies/{companyId}/documents ONLY for "prose" artifacts that live in the database, not on disk:** -- **PRDs**: Product Managers write PRDs before engineering work begins -- **Technical Specs**: Short architectural decisions that do not belong in a code repo -- **Post-Mortems**: After incidents, the lead writes a post-mortem with lessons learned -- **Meeting Notes**: After important meetings, capture decisions and action items -- **Status Reports**: Weekly status reports from department heads to CEO -- **Architecture Decision Records**: Long-lived design decisions -Reference document IDs in related tasks via PUT /api/issues/{issueId}/documents/{key}. diff --git a/src/main/prompt-builder/sops/sop-010-budget.en.md b/src/main/prompt-builder/sops/sop-010-budget.en.md deleted file mode 100644 index 1cb1ed22..00000000 --- a/src/main/prompt-builder/sops/sop-010-budget.en.md +++ /dev/null @@ -1,7 +0,0 @@ -## SOP-010: Budget & Financial Protocol -- All agents have a monthly budget. Track your spend. -- Before starting expensive operations, check your remaining budget via GET /api/agents/me -- If you need more budget, escalate to your manager who escalates to CFO -- For vendor purchases or new tools, submit a budget_request approval -- The CFO reviews all budget requests above the department head's authority -- Monthly budget resets on the 1st — plan your most expensive work early in the month diff --git a/src/main/prompt-builder/sops/sop-011-quality.en.md b/src/main/prompt-builder/sops/sop-011-quality.en.md deleted file mode 100644 index 7e721af2..00000000 --- a/src/main/prompt-builder/sops/sop-011-quality.en.md +++ /dev/null @@ -1,6 +0,0 @@ -## SOP-011: Performance & Quality Standards -- Every agent's work is tracked: tasks completed, success rate, cost efficiency, review cycles -- Quality > Speed: Better to submit correct work slowly than buggy work quickly -- If a task is sent back for revision more than twice, escalate to your manager -- Managers should conduct monthly performance check-ins via task comments -- Identify agents who are consistently blocked or failing — propose retraining or role changes diff --git a/src/main/prompt-builder/sops/sop-012-cadence.en.md b/src/main/prompt-builder/sops/sop-012-cadence.en.md deleted file mode 100644 index ca55e885..00000000 --- a/src/main/prompt-builder/sops/sop-012-cadence.en.md +++ /dev/null @@ -1,7 +0,0 @@ -## SOP-012: Sprint & Cadence Management -The company operates in recurring cycles: -- **Daily Standup**: Every heartbeat wake starts with standup check (SOP-001) -- **Sprint Cycle**: 2-week sprints with planning → execution → review → retrospective -- **Weekly Sync**: Department heads report progress to CEO -- **Monthly Review**: Company-wide metrics review, budget check, hiring needs -When creating tasks, consider the current sprint cycle and set realistic deadlines. diff --git a/src/main/prompt-builder/sops/sop-013-incident.en.md b/src/main/prompt-builder/sops/sop-013-incident.en.md deleted file mode 100644 index 552dbd2f..00000000 --- a/src/main/prompt-builder/sops/sop-013-incident.en.md +++ /dev/null @@ -1,8 +0,0 @@ -## SOP-013: Incident Response Protocol -When something critical goes wrong: -1. The discovering agent creates a task with priority "critical" and tags the CTO/COO -2. CTO assesses technical impact, COO assesses business impact -3. Engineering focuses on mitigation first, root cause second -4. After resolution, the lead writes a post-mortem document -5. Action items from the post-mortem become tracked tasks -6. Knowledge learned gets added to the team's institutional memory diff --git a/src/main/prompt-builder/sops/sop-014-hiring-pipeline.en.md b/src/main/prompt-builder/sops/sop-014-hiring-pipeline.en.md deleted file mode 100644 index cb384964..00000000 --- a/src/main/prompt-builder/sops/sop-014-hiring-pipeline.en.md +++ /dev/null @@ -1,9 +0,0 @@ -## SOP-014: Hiring Pipeline -When the company needs new talent: -1. Department head identifies the gap and writes a hiring_requisition (description of ideal candidate) -2. HR Director reviews and approves the requisition -3. CFO confirms budget availability -4. CEO gives final approval via hire_agent approval -5. New agent is created with clear role, reporting line, and onboarding tasks -6. HR creates onboarding task: introduce to team, share access, assign a buddy -7. Manager assigns first tasks appropriate to the new hire's level diff --git a/src/main/prompt-builder/sops/sop-015-knowledge.en.md b/src/main/prompt-builder/sops/sop-015-knowledge.en.md deleted file mode 100644 index 99a7958a..00000000 --- a/src/main/prompt-builder/sops/sop-015-knowledge.en.md +++ /dev/null @@ -1,7 +0,0 @@ -## SOP-015: Knowledge Management -The company should get smarter over time: -- After solving a hard problem, document the solution as a lesson_learned comment -- After making an important decision, document the rationale and alternatives considered -- When onboarding new agents, share relevant past decisions and lessons -- Periodically review past incidents and ensure fixes are still in place -- Capture "best practices" that emerge from repeated successes diff --git a/src/main/prompt-builder/system-prompt.ts b/src/main/prompt-builder/system-prompt.ts deleted file mode 100644 index 995dc9d8..00000000 --- a/src/main/prompt-builder/system-prompt.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { DEPARTMENT_LABELS } from "@shared/constants"; -import type { DepartmentId } from "@shared/types"; -import { - buildTaskSection, - buildReviewSection, - buildMeetingsSection, - buildKnowledgeSection, - buildDocumentsSection, - buildPendingApprovalsSection, -} from "./context-injection"; -import { buildAPISection } from "./api-section"; -import { buildCapabilityRegistrySection } from "./capability-registry"; -import { buildSOPSection } from "./sop-section"; -import { - buildOperatingInstructions, - buildDecisionAuthoritySection, - buildDepartmentSection, -} from "./operating-instructions"; -import { buildCEOModeInstructions } from "./operating-instructions-ceo"; -import type { PromptContext } from "./index"; -import type { ProjectedSkill } from "../skill-types"; -import { roleMatchesLeadershipKeywords } from "../agent-role-helpers"; -import { getSystemMessages } from "./messages"; - -function isLeadershipRole(ctx: PromptContext): boolean { - // HR roles inherit leadership scope for manager-style prompts; - // other departments rely on role/title keyword tokenization. - if (ctx.agent.department === "hr") return true; - return roleMatchesLeadershipKeywords(ctx.agent.role, ctx.agent.title ?? null); -} - -/** - * Render the Agent Skills manifest from the runtime projection. The prompt - * carries only name, description, and SKILL.md location; the agent reads the - * full file on demand through the filesystem tool. - */ -function buildSkillManifest(skills: ProjectedSkill[] | undefined): string { - if (!skills || skills.length === 0) return ""; - const lines = [ - "\n\nThe following skills provide specialized instructions for specific tasks.", - "Use the read tool to load a skill's file when the task matches its description.", - "When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.", - "", - "", - ]; - - for (const skill of skills) { - lines.push(" "); - lines.push(` ${escapeSkillXml(skill.name)}`); - lines.push(` ${escapeSkillXml(skill.description)}`); - lines.push(` ${escapeSkillXml(skill.filePath)}`); - lines.push(" "); - } - - lines.push(""); - return lines.join("\n"); -} - -function escapeSkillXml(value: string): string { - return value - .replaceAll("&", "&") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll('"', """) - .replaceAll("'", "'"); -} - -export function buildStableSystemPrompt(ctx: PromptContext): string { - const m = getSystemMessages(); - const sections: string[] = []; - - const isCEO = ctx.chainOfCommand.length === 0; - const isManager = !isCEO && (ctx.directReports.length > 0 || isLeadershipRole(ctx)); - - // NOTE: the current date/time is intentionally NOT rendered here. This - // function's output is intended to be cacheable by the Anthropic prompt - // cache keyed by a stable prefix; per-turn volatile values live in the - // buildTaskPrompt() tail so the cached prefix hits across heartbeats. - - const budgetPct = ctx.agent.budgetMonthlyUsd > 0 - ? Math.round((ctx.agent.spentMonthlyUsd / ctx.agent.budgetMonthlyUsd) * 100) - : null; - sections.push(m.agentIdentitySection({ - name: ctx.agent.name, - role: ctx.agent.role, - title: ctx.agent.title || null, - companyName: ctx.companyName, - capabilities: ctx.agent.capabilities, - budgetMonthly: ctx.agent.budgetMonthlyUsd, - spentMonthly: ctx.agent.spentMonthlyUsd, - budgetPctUsed: budgetPct, - skillManifest: buildSkillManifest(ctx.skills), - })); - - const capabilityRegistrySection = buildCapabilityRegistrySection({ - companySkillCatalog: ctx.companySkillCatalog, - companyWorkspaces: ctx.companyWorkspaces, - allConnectors: ctx.allConnectors, - companyDocuments: ctx.companyDocuments, - }); - if (capabilityRegistrySection) sections.push(capabilityRegistrySection); - - if (ctx.companyDescription) sections.push(m.companyMissionSection(ctx.companyDescription)); - - if (ctx.executionMode === "ai_cofounder") { - sections.push(m.executionModeAiCofounderSection(ctx.agent.companyId)); - } - - sections.push(m.cognitiveFrameworkSection); - - if (isCEO) sections.push(m.ceoLeadershipStyleSection); - else if (isManager) sections.push(m.managementStyleSection); - else sections.push(m.icWorkPhilosophySection); - - if (ctx.chainOfCommand.length > 0) { - const chainStr = ctx.chainOfCommand - .map((a) => m.chainOfCommandLine(a.name, a.role)) - .join(m.chainOfCommandSeparator); - sections.push(m.chainOfCommandSection(chainStr)); - } else { - sections.push(m.topPositionSection); - } - - if (ctx.directReports.length > 0) { - const lines = ctx.directReports - .map((a) => m.directReportLine({ - name: a.name, - role: a.role, - title: a.title || null, - capabilities: a.capabilities, - status: a.status, - connectorId: a.connectorId, - })) - .join("\n"); - sections.push(m.directReportsSection(lines)); - } - - if (ctx.agent.department) { - const deptLabel = DEPARTMENT_LABELS[ctx.agent.department] ?? ctx.agent.department; - const deptMembers = ctx.allAgents.filter( - (a) => a.department === ctx.agent.department && a.id !== ctx.agent.id && a.status !== "terminated", - ); - const memberLines = deptMembers.map((a) => m.deptColleagueLine(a.name, a.role, a.status)).join("\n"); - sections.push(m.departmentMembersSection(deptLabel, memberLines)); - } - - // Every agent needs to see where the other departments' entry points - // are so DMs can cross the org without going through the CEO. Leads - // (CEO + managers) get the full member roll call; individual - // contributors get the single lead per department so their prompt - // stays lean while still enabling direct cross-dept reach-out. - const deptMap = new Map(); - for (const a of ctx.allAgents.filter((a) => a.status !== "terminated")) { - const dept = a.department ?? "unassigned"; - if (!deptMap.has(dept)) deptMap.set(dept, []); - deptMap.get(dept)!.push(a); - } - if (deptMap.size > 1) { - const showAllMembers = isCEO || isManager; - const deptLines = Array.from(deptMap.entries()).map(([dept, members]) => { - const label = DEPARTMENT_LABELS[dept as DepartmentId] ?? dept; - if (showAllMembers) { - return m.companyDeptMapLine(label, members.length, members.map((x) => x.name).join(", ")); - } - const leads = members.filter((x) => !x.reportsTo || ctx.directReports.every((r) => r.id !== x.id)); - const leadNames = (leads.length > 0 ? leads : members).slice(0, 3).map((x) => x.name).join(", "); - return m.companyDeptMapLine(label, members.length, leadNames); - }).join("\n"); - sections.push(m.companyDepartmentMapSection(deptLines)); - } - - const activeGoals = ctx.goals.filter((g) => g.status === "active" || g.status === "planned"); - if (activeGoals.length > 0) { - const lines = activeGoals.map((g) => m.activeGoalLine(g.id, g.title, g.description, g.status, g.ownerAgentId === ctx.agent.id)).join("\n"); - sections.push(m.activeGoalsSection(lines)); - } - - const relevantProjects = ctx.projects.filter((p) => - p.status === "in_progress" || p.status === "planned" || p.leadAgentId === ctx.agent.id, - ); - if (relevantProjects.length > 0) { - const lines = relevantProjects.map((p) => m.projectLine(p.id, p.name, p.description, p.status, p.leadAgentId === ctx.agent.id)).join("\n"); - sections.push(m.projectsSection(lines)); - } - - const audience = isCEO ? "executive" : isManager ? "manager" : "individual_contributor"; - sections.push(buildSOPSection(audience)); - sections.push(buildAPISection(ctx, audience)); - - sections.push(buildDepartmentSection(ctx)); - sections.push(buildOperatingInstructions(ctx, isCEO, isManager)); - sections.push(buildDecisionAuthoritySection(ctx, isCEO, isManager)); - - sections.push(m.structuredOutputSection); - - return sections.join("\n"); -} - -export function buildSystemPrompt(ctx: PromptContext): string { - return buildStableSystemPrompt(ctx); -} - -export function buildVolatilePromptTail(ctx: PromptContext): string { - const m = getSystemMessages(); - const sections: string[] = []; - const isCEO = ctx.chainOfCommand.length === 0; - - if (isCEO) { - sections.push(...buildCEOModeInstructions(ctx)); - } - - if (ctx.directReports.length > 0) { - const workloadLines = ctx.directReports.map((report) => { - const reportTasks = ctx.allTasks.filter((t) => t.assigneeAgentId === report.id); - const inProgress = reportTasks.filter((t) => t.status === "in_progress").length; - const inReview = reportTasks.filter((t) => t.status === "in_review").length; - const blocked = reportTasks.filter((t) => t.status === "blocked").length; - const todo = reportTasks.filter((t) => t.status === "todo").length; - return m.teamWorkloadLine(report.name, report.role, inProgress, inReview, blocked, todo); - }).join("\n"); - sections.push(m.teamWorkloadSection(workloadLines)); - } - - if (ctx.sessionHandoff) sections.push(m.sessionHandoffSection(ctx.sessionHandoff)); - - if (ctx.task) { - sections.push(buildTaskSection({ - task: ctx.task, - agent: { id: ctx.agent.id, companyId: ctx.agent.companyId, department: ctx.agent.department }, - projects: ctx.projects, - goals: ctx.goals, - })); - } - - if (ctx.assignedTasks.length > 0) { - const lines = ctx.assignedTasks.map((t) => m.assignedTaskLine(t.id, t.title, t.status, t.priority)).join("\n"); - sections.push(m.assignedTasksSection(lines)); - } - - const reviewSection = buildReviewSection({ - tasksAwaitingReview: ctx.tasksAwaitingReview, - allAgents: ctx.allAgents, - recentComments: ctx.recentComments, - }); - if (reviewSection) sections.push(reviewSection); - - const approvalsSection = buildPendingApprovalsSection(ctx.pendingApprovals); - if (approvalsSection) sections.push(approvalsSection); - - if (ctx.recentComments.length > 0) { - const lines = ctx.recentComments.slice(0, 10) - .map((c) => m.recentCommentLine(c.taskTitle, c.authorName, c.body)) - .join("\n"); - sections.push(m.recentCommentsSection(lines)); - } - - const meetingsSection = buildMeetingsSection({ - upcomingMeetings: ctx.upcomingMeetings ?? [], - allAgents: ctx.allAgents, - }); - if (meetingsSection) sections.push(meetingsSection); - - if (ctx.activeSprint) { - const s = ctx.activeSprint; - sections.push(m.activeSprintSection({ - name: s.name, - goal: s.goal || "", - startDate: s.startDate, - endDate: s.endDate, - status: s.status, - completedPoints: s.completedPoints, - velocityPoints: s.velocityPoints, - })); - } - - const knowledgeSection = buildKnowledgeSection(ctx.relevantKnowledge ?? []); - if (knowledgeSection) sections.push(knowledgeSection); - - const docsSection = buildDocumentsSection({ - recentDocuments: ctx.recentDocuments ?? [], - allAgents: ctx.allAgents, - }); - if (docsSection) sections.push(docsSection); - - sections.push(m.importantRulesSection(ctx.agent.companyId, ctx.agent.id, ctx.runId)); - - const localeName = ctx.locale === "zh" ? "Chinese" : null; - if (localeName) { - sections.push(`\n\nRespond to the user in ${localeName}.`); - } - - return sections.join("\n"); -} diff --git a/src/main/prompt-builder/wake-reasons/en.ts b/src/main/prompt-builder/wake-reasons/en.ts deleted file mode 100644 index 5ef6d74e..00000000 --- a/src/main/prompt-builder/wake-reasons/en.ts +++ /dev/null @@ -1,146 +0,0 @@ -export type WakeReason = - | "timer" - | "manual" - | "assignment" - | "goal_activated" - | "approval_resolved" - | "subtask_completed" - | "task_review_requested" - | "comment" - | "report_blocked" - | "report_failed" - | "message" - | "peer_request"; - -export interface WakeReasonVars { - companyId: string; - agentId: string; -} - -export interface WakeReasonEntry { - title: string; - steps: (v: WakeReasonVars) => string[]; -} - -export const WAKE_REASONS: Record = { - timer: { - title: "Regular heartbeat check-in. This is your periodic wake.", - steps: () => [ - "Call GET /api/agents/me/standup to get your full briefing", - "Walk `unreadMessages` first — every unanswered peer DM blocks somebody else's next move. Reply and mark read before you pick up task work.", - "Then take action on the most important item remaining: reviews > unblocking reports > next step on assigned work", - "If nothing actionable is in your briefing, return control without posting a status comment — activity noise is worse than silence.", - ], - }, - manual: { - title: "You were manually triggered by the human operator (Board).", - steps: () => [ - "Check your assigned tasks for any new assignments or updated instructions", - "Check your messages for any direct communications", - "Execute any pending work with high priority — the Board is watching", - ], - }, - assignment: { - title: "You have been assigned a new task.", - steps: (v) => [ - `GET /api/companies/${v.companyId}/issues?assigneeAgentId=${v.agentId}&status=todo to find your new assignment`, - "Review the task title, description, and any existing comments", - "POST /api/issues/{issueId}/checkout to claim the task", - "Begin working on it immediately according to your Operating Instructions", - ], - }, - goal_activated: { - title: "A goal you own has been activated.", - steps: (v) => [ - `GET /api/companies/${v.companyId}/goals to find the newly activated goal`, - `Decompose the goal into projects (POST /api/companies/${v.companyId}/projects)`, - "Break projects into actionable tasks and assign to your team", - "Leave a planning comment on each task explaining the approach", - ], - }, - approval_resolved: { - title: "An approval you requested has been decided.", - steps: (v) => [ - `GET /api/companies/${v.companyId}/approvals?requestedByAgentId=${v.agentId} to check the result`, - "If APPROVED: proceed with the action you were waiting on (hiring, credential access, etc.)", - "If DENIED or REVISION_REQUESTED: read the feedback, adjust your approach, and resubmit if appropriate", - "Update the related task with the outcome", - ], - }, - subtask_completed: { - title: "A subtask you delegated has been completed or moved to review.", - steps: () => [ - 'Check tasks with status "in_review" whose parent task you own', - "Read ALL comments on the completed subtask (GET /api/issues/{issueId}/comments)", - "Review the work quality against the acceptance criteria you set", - 'If acceptable: PATCH /api/issues/{issueId} with status "done" and an approving comment', - 'If changes needed: PATCH /api/issues/{issueId} with status "in_progress" and specific feedback', - "Check if the parent task can now progress", - ], - }, - task_review_requested: { - title: "A direct report submitted a top-level task for your review.", - steps: () => [ - 'Find the task: GET /api/agents/me/standup — look for tasksAwaitingReview', - "Read ALL comments on the task (GET /api/issues/{issueId}/comments) and any linked documents", - "Validate the work against the original acceptance criteria — not just whether it looks complete", - 'If acceptable: PATCH /api/issues/{issueId} with status "done" and a concrete approval comment', - 'If changes needed: PATCH /api/issues/{issueId} with status "in_progress" and specific, actionable feedback', - "Do not let a top-level review sit — your whole team is downstream", - ], - }, - comment: { - title: "A new comment has been posted on one of your tasks.", - steps: () => [ - "Check your recent comments in the briefing above", - "If someone asked you a question: respond via POST /api/issues/{issueId}/comments", - "If your manager left feedback: address it and update the task", - "If it's a status update from a collaborator: acknowledge and adjust your work if needed", - ], - }, - report_blocked: { - title: "One of your reports is blocked and needs your help.", - steps: (v) => [ - `GET /api/companies/${v.companyId}/issues?status=blocked to find blocked tasks under your reports`, - "Read the blocker comments to understand what they need", - `Take action to unblock them: - - If they need credentials: create a secret_access approval via POST /api/companies/${v.companyId}/approvals - - If they need cross-department help: send a message to the relevant department lead - - If they need clarification: post a comment with clear direction`, - 'After unblocking, wake the agent: POST /api/agents/{agentId}/wake with reason "blocker resolved"', - ], - }, - report_failed: { - title: "A run by one of your reports has failed.", - steps: () => [ - "Check your reports' task statuses for failed or stalled items", - "Investigate: read the task comments and any error information", - `Decide on next steps: - - If the task should be retried: set status back to "todo" with a comment explaining what to do differently - - If the task should be reassigned: change the assigneeAgentId to another capable report - - If the task is no longer needed: set status to "cancelled" with explanation`, - "Wake the relevant agent to take action", - ], - }, - message: { - title: "You received a message from another agent or the Board.", - steps: (v) => [ - `GET /api/companies/${v.companyId}/messages?unreadOnly=true to read your new messages`, - "Read each message and understand what is being asked", - `Respond to each message by preserving the original conversation context: - - For direct messages (channel="direct"): POST /api/companies/${v.companyId}/messages with channel="direct", toAgentId set to the original message's fromAgentId, and parentMessageId set to that message's id. If the sender is Board, set toAgentId to "__board__" - - For group channels (channel="department", "company", "project", or "incident"): POST /api/companies/${v.companyId}/messages with the SAME channel and channelTargetId as the original message, and parentMessageId set to that message's id. Do NOT set toAgentId for group channel replies`, - `Mark messages as read: POST /api/companies/${v.companyId}/messages/{messageId}/read`, - "If the message requires you to take action on a task, do so", - ], - }, - peer_request: { - title: "A peer agent has requested your attention.", - steps: (v) => [ - `Check your messages: GET /api/companies/${v.companyId}/messages?unreadOnly=true`, - "Check for any new task assignments from outside your usual chain", - "Read and respond to the peer's request using the sender's fromAgentId and message id from the API response", - "If cross-department collaboration is needed, coordinate via messages and tasks", - ], - }, -}; diff --git a/src/main/prompt-builder/wake-reasons/index.ts b/src/main/prompt-builder/wake-reasons/index.ts deleted file mode 100644 index a9ce2b45..00000000 --- a/src/main/prompt-builder/wake-reasons/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { WakeReason, WakeReasonEntry, WakeReasonVars } from "./en"; -import { WAKE_REASONS } from "./en"; - -export type { WakeReason, WakeReasonEntry, WakeReasonVars }; - -export function renderWakeReason( - reason: string, - vars: WakeReasonVars, -): string { - const entry = WAKE_REASONS[reason as WakeReason]; - if (!entry) { - return `Trigger: ${reason}\nAction required: Check your standup briefing and messages for context on why you were woken.`; - } - const steps = entry.steps(vars) - .map((step, i) => `${i + 1}. ${step}`) - .join("\n"); - return `${entry.title}\nAction required:\n${steps}`; -} diff --git a/src/main/run-attempt-policy.ts b/src/main/run-attempt-policy.ts deleted file mode 100644 index 10853fe2..00000000 --- a/src/main/run-attempt-policy.ts +++ /dev/null @@ -1,118 +0,0 @@ -export const DEFAULT_MAX_CONSECUTIVE_SELF_WAKES = 5; - -export interface HeartbeatAttemptInput { - kind: "heartbeat"; - trigger: string; - activeRunCount: number; - maxConcurrentRuns: number; - lastStartedAtMs: number | null; - cooldownMs: number; - nowMs: number; - bypassCooldown: boolean; -} - -export interface TaskFailureAttemptInput { - kind: "task_failure"; - retryCount: number; - maxRetryAttempts: number; -} - -export interface SelfWakeAttemptInput { - kind: "self_wake"; - hasWorkToContinue: boolean; - consecutiveSelfWakes: number; - maxConsecutiveSelfWakes: number; -} - -export type HeartbeatAttemptDecision = - | { action: "run" } - | { action: "skip"; reason: "max_concurrent_runs" | "cooldown"; waitMs?: number }; - -export type TaskFailureAttemptDecision = - | { action: "retry"; attemptNumber: number } - | { action: "escalate" }; - -export type SelfWakeAttemptDecision = - | { action: "run" } - | { action: "skip"; reason: "no_work" | "self_wake_exhausted" }; - -type RunAttemptInput = - | HeartbeatAttemptInput - | TaskFailureAttemptInput - | SelfWakeAttemptInput; - -type RunAttemptDecision = - | HeartbeatAttemptDecision - | TaskFailureAttemptDecision - | SelfWakeAttemptDecision; - -export function runAttemptKey(agentId: string, companyId: string): string { - return `${companyId}:${agentId}`; -} - -function assertNonNegativeInteger(name: string, value: number): void { - if (!Number.isInteger(value) || value < 0) { - throw new Error(`run-attempt policy: ${name} must be a non-negative integer`); - } -} - -function assertNonNegativeNumber(name: string, value: number): void { - if (!Number.isFinite(value) || value < 0) { - throw new Error(`run-attempt policy: ${name} must be a non-negative number`); - } -} - -export function decideRunAttempt(input: HeartbeatAttemptInput): HeartbeatAttemptDecision; -export function decideRunAttempt(input: TaskFailureAttemptInput): TaskFailureAttemptDecision; -export function decideRunAttempt(input: SelfWakeAttemptInput): SelfWakeAttemptDecision; -export function decideRunAttempt(input: RunAttemptInput): RunAttemptDecision { - switch (input.kind) { - case "heartbeat": { - assertNonNegativeInteger("activeRunCount", input.activeRunCount); - assertNonNegativeInteger("maxConcurrentRuns", input.maxConcurrentRuns); - assertNonNegativeNumber("cooldownMs", input.cooldownMs); - assertNonNegativeNumber("nowMs", input.nowMs); - if (input.lastStartedAtMs !== null) { - assertNonNegativeNumber("lastStartedAtMs", input.lastStartedAtMs); - } - - if (input.activeRunCount >= input.maxConcurrentRuns) { - return { action: "skip", reason: "max_concurrent_runs" }; - } - - if (!input.bypassCooldown && input.lastStartedAtMs !== null) { - const elapsedMs = input.nowMs - input.lastStartedAtMs; - if (elapsedMs < input.cooldownMs) { - return { - action: "skip", - reason: "cooldown", - waitMs: input.cooldownMs - elapsedMs, - }; - } - } - - return { action: "run" }; - } - - case "task_failure": { - assertNonNegativeInteger("retryCount", input.retryCount); - assertNonNegativeInteger("maxRetryAttempts", input.maxRetryAttempts); - if (input.retryCount < input.maxRetryAttempts) { - return { action: "retry", attemptNumber: input.retryCount + 1 }; - } - return { action: "escalate" }; - } - - case "self_wake": { - assertNonNegativeInteger("consecutiveSelfWakes", input.consecutiveSelfWakes); - assertNonNegativeInteger("maxConsecutiveSelfWakes", input.maxConsecutiveSelfWakes); - if (!input.hasWorkToContinue) { - return { action: "skip", reason: "no_work" }; - } - if (input.consecutiveSelfWakes >= input.maxConsecutiveSelfWakes) { - return { action: "skip", reason: "self_wake_exhausted" }; - } - return { action: "run" }; - } - } -} diff --git a/src/main/run-housekeeping.ts b/src/main/run-housekeeping.ts deleted file mode 100644 index 6a78b571..00000000 --- a/src/main/run-housekeeping.ts +++ /dev/null @@ -1,138 +0,0 @@ -import type { AppDatabase } from "./database"; -import type { ThreadIntegrationService } from "./thread-integration"; - -interface RunHousekeepingDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - threadIntegration: ThreadIntegrationService; -} - -/** - * Task types whose successful runs produce durable lessons worth capturing - * into the knowledge base. Ad-hoc code tasks, chores, and one-off ops - * produce runtime noise that pollutes the knowledge table if auto-saved. - */ -const KNOWLEDGE_PRODUCING_TASK_TYPES: ReadonlySet = new Set([ - "research", - "analysis", - "planning", - "strategy", - "review", -]); - -/** - * Agent departments whose output is routinely curated as corporate - * knowledge regardless of task type. - */ -const KNOWLEDGE_PRODUCING_DEPARTMENTS: ReadonlySet = new Set([ - "research", - "strategy", - "management", -]); - -function shouldProduceKnowledge( - db: AppDatabase, - taskId: string, - agentId: string, - logger: RunHousekeepingDeps["logger"], -): boolean { - try { - const taskTypeRow = db.queryAll<{ taskType: string | null }>( - "SELECT task_type as taskType FROM tasks WHERE id = ? LIMIT 1", - taskId, - )[0]; - if (taskTypeRow?.taskType && KNOWLEDGE_PRODUCING_TASK_TYPES.has(taskTypeRow.taskType)) { - return true; - } - } catch (error) { - logger.warn( - `[run-housekeeping] task lookup failed for ${taskId}; falling back to agent department check: ${error instanceof Error ? error.message : String(error)}`, - ); - } - try { - const agent = db.core.entity.getAgent(agentId); - return Boolean(agent.department && KNOWLEDGE_PRODUCING_DEPARTMENTS.has(agent.department)); - } catch (error) { - logger.warn( - `[run-housekeeping] agent lookup failed for ${agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - return false; - } -} - -export function createRunHousekeeping({ db, logger, threadIntegration }: RunHousekeepingDeps) { - return { - onRunCompleted( - runId: string, - taskId: string | null, - agentId: string, - companyId: string, - status: string, - summary: string | null, - errorMessage: string | null, - ): void { - // Skip thread integration + knowledge candidates for heartbeat runs - // (no task to attach them to). - if (!taskId) return; - // 1. Record run completion in the task thread - try { - threadIntegration.onRunFinished(runId, taskId, agentId, companyId, status, errorMessage ?? null); - } catch (err) { - logger.error(`[run-housekeeping] threadIntegration.onRunFinished failed: ${err instanceof Error ? err.message : String(err)}`); - } - - // 2. On success with a meaningful summary, create a knowledge candidate — - // gated on the task type or the producing agent's department so - // ad-hoc runs do not flood the knowledge table with summaries. - if ( - status === "succeeded" && - summary && - summary.length > 50 && - shouldProduceKnowledge(db, taskId, agentId, logger) - ) { - try { - let topic = `Run ${runId.slice(0, 8)}`; - try { - const task = db.core.entity.getTask(taskId); - topic = task.title; - } catch (error) { - logger.warn( - `[run-housekeeping] getTask failed for ${taskId}; using run id as topic: ${error instanceof Error ? error.message : String(error)}`, - ); - } - - db.core.knowledge.saveKnowledgeEntry({ - companyId, - category: "lesson_learned", - topic, - content: summary, - authorAgentId: agentId, - }); - logger.info(`[run-housekeeping] Knowledge candidate created for run ${runId} (task: ${topic})`); - } catch (err) { - logger.error(`[run-housekeeping] saveKnowledgeEntry failed: ${err instanceof Error ? err.message : String(err)}`); - } - } - - // 3. On failure, record an activity log entry - if (status === "failed") { - try { - db.core.activity.addActivity({ - companyId, - actor: agentId, - action: "run.failed", - entityType: "run", - entityId: runId, - detail: errorMessage ?? summary ?? "Run failed without details.", - }); - } catch (err) { - logger.error(`[run-housekeeping] addActivity (failure) failed: ${err instanceof Error ? err.message : String(err)}`); - } - } - }, - }; -} diff --git a/src/main/run-usage-status.ts b/src/main/run-usage-status.ts deleted file mode 100644 index 5d32a51d..00000000 --- a/src/main/run-usage-status.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { RunStatus, RunUsageStatus } from "@shared/types"; - -export type TerminalAssistantStopReason = "error" | "aborted"; - -export interface AssistantUsageProbe { - role?: string; - stopReason?: string; - usage?: { - input?: unknown; - output?: unknown; - }; -} - -export interface AttributableAssistantUsageProbe extends AssistantUsageProbe { - role: "assistant"; - usage: { - input: number; - output: number; - }; -} - -export interface RunUsageClassificationInput { - runStatus: RunStatus; - errorMessage: string | null; - sawAttributableUsage: boolean; - terminalStopReason: TerminalAssistantStopReason | null; -} - -export function isTerminalAssistantStopReason(reason: string | undefined): reason is TerminalAssistantStopReason { - return reason === "error" || reason === "aborted"; -} - -export function hasAttributableAssistantUsage( - message: AssistantUsageProbe | undefined, -): message is AttributableAssistantUsageProbe { - if (message?.role !== "assistant") return false; - if (typeof message.usage?.input !== "number" || typeof message.usage.output !== "number") return false; - if ( - isTerminalAssistantStopReason(message.stopReason) - && message.usage.input === 0 - && message.usage.output === 0 - ) { - return false; - } - return true; -} - -export function classifyRunUsage(input: RunUsageClassificationInput): RunUsageStatus { - if (input.terminalStopReason === "error") return "error_stop"; - if (input.terminalStopReason === "aborted") { - return input.sawAttributableUsage ? "ok" : "aborted_before_usage"; - } - if (input.sawAttributableUsage) return "ok"; - if (input.runStatus === "cancelled" || input.runStatus === "interrupted") return "aborted_before_usage"; - if (input.errorMessage || input.runStatus === "failed" || input.runStatus === "timed_out") return "pre_first_message"; - return "pre_first_message"; -} - -export function isUsageStatusUnattributed(status: RunUsageStatus): boolean { - return status !== "ok"; -} - -export function deriveLegacyRunUsageStatus(input: { - runStatus: RunStatus; - unattributedCost: boolean; -}): RunUsageStatus { - if (!input.unattributedCost) return "ok"; - if (input.runStatus === "cancelled" || input.runStatus === "interrupted") return "aborted_before_usage"; - return "pre_first_message"; -} diff --git a/src/main/service-graph-pi-runtime.ts b/src/main/service-graph-pi-runtime.ts deleted file mode 100644 index c89b046c..00000000 --- a/src/main/service-graph-pi-runtime.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Pi-mono runtime + credential service factory. - * - * Composes `CredentialStore`, `CredentialResolver`, `OAuthLoginService`, and - * `RuntimeBridge` for `service-graph.ts`. Extracted to keep `service-graph.ts` - * under the 400-line cap. - */ - -import type { AppDatabase } from "./database"; -import type { DesktopEvent } from "@shared/types"; -import { CredentialResolver, CredentialStore, OAuthLoginService } from "./credentials"; -import { RuntimeBridge } from "./agent-runtime"; - -export interface PiRuntimeServicesDeps { - db: AppDatabase; - emitEvent: (event: DesktopEvent) => void; - refreshConnectorHealth: (connectorId: string) => Promise; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export interface PiRuntimeServices { - credentialStore: CredentialStore; - credentialResolver: CredentialResolver; - oauthLoginService: OAuthLoginService; - runtimeBridge: RuntimeBridge; - release: () => void; -} - -export function createPiRuntimeServices(deps: PiRuntimeServicesDeps): PiRuntimeServices { - const credentialStore = new CredentialStore({ db: deps.db }); - const credentialResolver = new CredentialResolver(credentialStore); - const oauthLoginService = new OAuthLoginService({ - store: credentialStore, - emitEvent: deps.emitEvent, - refreshConnectorHealth: deps.refreshConnectorHealth, - logger: deps.logger, - }); - const runtimeBridge = new RuntimeBridge({ - db: deps.db, - emitEvent: deps.emitEvent, - logger: deps.logger, - credentialResolver, - }); - - return { - credentialStore, - credentialResolver, - oauthLoginService, - runtimeBridge, - release: () => {}, - }; -} diff --git a/src/main/service-graph.ts b/src/main/service-graph.ts deleted file mode 100644 index 4b74d6e2..00000000 --- a/src/main/service-graph.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { nativeTheme } from "electron"; -import type { IpcMainInvokeEvent } from "electron"; -import type { AgentApiServer } from "./api-server"; -import type { AppDatabase } from "./database"; -import { BrowserManager } from "./browser-manager"; -import type { DesktopResult } from "@shared/contracts"; -import { createConnectorHealthService } from "./connector-health-service"; -import { createPiRuntimeServices, type PiRuntimeServices } from "./service-graph-pi-runtime"; -import { RuntimeMessageInjector } from "./agent-runtime"; -import type { DesktopEvent } from "@shared/types"; -import type { NotificationOptions } from "./notification-service"; -import type { createAutomationService } from "./automation-service"; -import type { createBrowserActionService } from "./browser-action-service"; -import type { createOnboardingService } from "./onboarding-service"; -import { createUpdaterService } from "./updater-service"; -import { createLeafServices } from "./service-graph/create-leaf-services"; -import { createDesktopShell } from "./service-graph/create-desktop-shell"; -import { createRuntimeOrchestrationService } from "./service-graph/create-runtime-orchestration-service"; -import { createBackgroundServices } from "./service-graph/create-background-services"; -import { createLifecycle } from "./service-graph/create-lifecycle"; - -interface ServiceGraphDependencies { - db: AppDatabase; - apiServerRef: { current: AgentApiServer | null }; - browserManagerRef: { current: BrowserManager | null }; - isQuittingRef: { current: boolean }; - preloadPath: string; - rendererDist: string; - iconPath: string; - isDev: boolean; - devServerUrl?: string; - windowStatePath: string; - workerPath: string; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - seedDefaultAutomationRules: (companyId: string) => void; - onRunStarted?: (runId: string, taskId: string | null, agentId: string, companyId: string) => void; - onRunCompleted?: (runId: string, taskId: string | null, agentId: string, companyId: string, status: string, summary: string | null, errorMessage: string | null) => void; - /** Checkpoint engine for unified co-founder mode pause decisions in scheduler. */ - checkpointEngine?: { shouldPauseHeartbeat: (companyId: string, agentId: string) => boolean }; - /** Trusted-sender IPC wrapper from createIpcSupport. Window-control channels use it. */ - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; -} - -/** - * Thin orchestrator: assembles services in a deterministic topological order - * and exposes them via read-only getters. The hot run path is owned by - * runtimeOrchestrationService, which holds worker/orchestration callbacks - * together so graph construction stays explicit. - */ -export function createServiceGraph(deps: ServiceGraphDependencies) { - const { - db, - apiServerRef, - browserManagerRef, - isQuittingRef, - preloadPath, - rendererDist, - iconPath, - isDev, - devServerUrl, - windowStatePath, - workerPath, - logger, - emitEvent, - publishDomainChanged, - notify, - createRunToken, - seedDefaultAutomationRules, - onRunStarted, - onRunCompleted, - checkpointEngine, - registerHandle, - } = deps; - - // Service slots owned by the graph. Null before init() completes and after - // the lifecycle drain has torn services down. - let desktopShellService: ReturnType | null = null; - let connectorHealthService: ReturnType | null = null; - let runtimeOrchestrationService: ReturnType | null = null; - let automationService: ReturnType | null = null; - let browserActionService: ReturnType | null = null; - let onboardingService: ReturnType | null = null; - let updaterService: ReturnType | null = null; - let appLifecycleService: ReturnType | null = null; - let leaf: ReturnType | null = null; - let runtimeMessageInjector: RuntimeMessageInjector | null = null; - const piRuntimeRef: { current: PiRuntimeServices | null } = { current: null }; - - function requireLeaf() { - if (!leaf) throw new Error("Leaf services are not initialized."); - return leaf; - } - - function init() { - nativeTheme.themeSource = db.projection.snapshot.listSnapshot().theme; - - leaf = createLeafServices({ db, logger, notify, publishDomainChanged }); - updaterService = createUpdaterService({ db, logger, notify }); - updaterService.attachListeners(); - - desktopShellService = createDesktopShell({ - db, - preloadPath, - rendererDist, - iconPath, - isDev, - devServerUrl, - windowStatePath, - isQuittingRef, - emitEvent, - notify, - registerHandle, - checkForUpdates: async () => { - const updater = updaterService; - if (!updater) throw new Error("Updater service is not initialized."); - await updater.checkForUpdates({ manual: true }); - }, - logger, - }); - - piRuntimeRef.current = createPiRuntimeServices({ - db, - emitEvent, - logger, - refreshConnectorHealth: async (connectorId: string) => { - if (connectorHealthService) { - await connectorHealthService.checkConnector(connectorId as never); - } - }, - }); - - connectorHealthService = createConnectorHealthService({ - db, - logger, - publishDomainChanged, - credentialStore: piRuntimeRef.current.credentialStore, - }); - - runtimeOrchestrationService = createRuntimeOrchestrationService({ - db, - logger, - workerPath, - isQuittingRef, - publishDomainChanged, - emitEvent, - onRunStarted, - onRunCompleted, - notify, - budgetService: leaf.budgetEnforcementService, - sessionService: leaf.sessionManagementService, - piRuntimeRef, - getRuntimeMessageInjector: () => runtimeMessageInjector, - createRunToken, - getApiPort: () => apiServerRef.current?.port ?? 0, - skillService: leaf.skillService, - checkpointEngine, - }); - - runtimeMessageInjector = new RuntimeMessageInjector({ - db, - runtimeBridge: piRuntimeRef.current.runtimeBridge, - postToWorker: (message) => { - const worker = runtimeOrchestrationService?.getWorker(); - if (!worker) throw new Error("Worker is not initialised — cannot deliver steer message."); - worker.postMessage(message); - }, - getWakeAgent: () => { - const runtime = runtimeOrchestrationService; - if (!runtime) return null; - return (agentId, companyId, trigger) => runtime.wakeAgentIfPossible(agentId, companyId, trigger); - }, - logger, - }); - - const background = createBackgroundServices({ - db, - logger, - emitEvent, - publishDomainChanged, - notify, - isQuittingRef, - browserManagerRef, - skillService: leaf.skillService, - orchestrationService: runtimeOrchestrationService, - seedDefaultAutomationRules, - }); - automationService = background.automationService; - browserActionService = background.browserActionService; - onboardingService = background.onboardingService; - runtimeOrchestrationService.bindAutomation(automationService); - runtimeOrchestrationService.assertReady(); - runtimeOrchestrationService.createWorker(); - - appLifecycleService = createLifecycle({ - db, - logger, - isQuittingRef, - apiServerRef, - browserManagerRef, - piRuntimeRef, - runtimeOrchestrationService, - automationService, - desktopShellService, - clearServiceRefs: () => { - desktopShellService = null; - runtimeOrchestrationService = null; - browserActionService = null; - automationService = null; - connectorHealthService = null; - onboardingService = null; - updaterService = null; - appLifecycleService = null; - runtimeMessageInjector = null; - leaf = null; - }, - }); - } - - return { - init, - getDesktopShellService: () => desktopShellService, - getConnectorHealthService: () => connectorHealthService, - getWorkerService: () => runtimeOrchestrationService, - getBrowserActionService: () => browserActionService, - getOrchestrationService: () => runtimeOrchestrationService, - getAutomationService: () => automationService, - getOnboardingService: () => onboardingService, - getUpdaterService: () => updaterService, - getAppLifecycleService: () => appLifecycleService, - getOrCreateSkillService: () => requireLeaf().skillService, - getOrCreateBudgetEnforcementService: () => requireLeaf().budgetEnforcementService, - getOrCreateSessionManagementService: () => requireLeaf().sessionManagementService, - getPiRuntime: () => piRuntimeRef.current, - getRuntimeMessageInjector: () => runtimeMessageInjector, - }; -} diff --git a/src/main/service-graph/create-background-services.ts b/src/main/service-graph/create-background-services.ts deleted file mode 100644 index a0e866b8..00000000 --- a/src/main/service-graph/create-background-services.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { AppDatabase } from "../database"; -import { BrowserManager } from "../browser-manager"; -import type { DesktopEvent } from "@shared/types"; -import { createAutomationService } from "../automation-service"; -import { createBrowserActionService } from "../browser-action-service"; -import { createOnboardingService } from "../onboarding-service"; -import type { createRuntimeOrchestrationService } from "./create-runtime-orchestration-service"; -import type { createSkillService } from "../skill-service"; -import type { NotificationOptions } from "../notification-service"; - -export interface BackgroundServicesDeps { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; - notify: (options: NotificationOptions) => void; - isQuittingRef: { current: boolean }; - browserManagerRef: { current: BrowserManager | null }; - skillService: ReturnType; - orchestrationService: ReturnType; - seedDefaultAutomationRules: (companyId: string) => void; -} - -export interface BackgroundServices { - automationService: ReturnType; - browserActionService: ReturnType; - onboardingService: ReturnType; -} - -/** - * Build background services that run off the main dispatch loop: automation - * triggers, browser-action dispatch, and onboarding hire flow. - * Orchestration is fully assembled at this point, so all dependencies are - * concrete references rather than lazy slots. - */ -export function createBackgroundServices({ - db, - logger, - emitEvent, - publishDomainChanged, - notify, - isQuittingRef, - browserManagerRef, - skillService, - orchestrationService, - seedDefaultAutomationRules, -}: BackgroundServicesDeps): BackgroundServices { - const browserActionService = createBrowserActionService({ - db, - browserManagerRef, - publishDomainChanged, - }); - browserActionService.resetBrowserManager(); - - const queueBrowserActionExecution = (actionId: string, companyId: string) => - browserActionService.queueBrowserActionExecution(actionId, companyId); - - const automationService = createAutomationService({ - db, - logger, - emitEvent, - publishDomainChanged, - notify, - wakeAgentIfPossible: (agentId, companyId, trigger) => - orchestrationService.wakeAgentIfPossible(agentId, companyId, trigger), - queueBrowserActionExecution, - isQuitting: () => isQuittingRef.current, - }); - - const onboardingService = createOnboardingService({ - db, - seedDefaultAutomationRules, - createTaskRunForDeferredDispatch: (taskId, trigger, actor) => - orchestrationService.createTaskRunForDeferredDispatch(taskId, trigger, actor), - publishDomainChanged, - scanAndAssignSkills: async (companyId: string, _agentId: string) => { - // All company skills are visible to every agent via progressive disclosure. - // Seed the builtin catalog + any workspace-local SKILL.md bundles. - await skillService.seedBuiltinSkills(companyId); - await skillService.scanWorkspaceSkills(companyId); - }, - }); - - return { automationService, browserActionService, onboardingService }; -} diff --git a/src/main/service-graph/create-desktop-shell.ts b/src/main/service-graph/create-desktop-shell.ts deleted file mode 100644 index d240cee1..00000000 --- a/src/main/service-graph/create-desktop-shell.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { IpcMainInvokeEvent } from "electron"; -import type { AppDatabase } from "../database"; -import type { DesktopEvent } from "@shared/types"; -import type { DesktopResult } from "@shared/contracts"; -import { createDesktopShellService } from "../desktop-shell-service"; -import type { NotificationOptions } from "../notification-service"; - -export interface DesktopShellDeps { - db: AppDatabase; - preloadPath: string; - rendererDist: string; - iconPath: string; - isDev: boolean; - devServerUrl?: string; - windowStatePath: string; - isQuittingRef: { current: boolean }; - emitEvent: (event: DesktopEvent) => void; - notify: (options: NotificationOptions) => void; - registerHandle: ( - channel: string, - handler: (event: IpcMainInvokeEvent, ...args: unknown[]) => Promise> | DesktopResult, - ) => void; - checkForUpdates: () => Promise; - logger: { warn: (...args: unknown[]) => void }; -} - -/** Build the desktop shell service with concrete updater and window callbacks. */ -export function createDesktopShell({ - db, - preloadPath, - rendererDist, - iconPath, - isDev, - devServerUrl, - windowStatePath, - isQuittingRef, - emitEvent, - notify, - registerHandle, - checkForUpdates, - logger, -}: DesktopShellDeps) { - const desktopShellService = createDesktopShellService({ - preloadPath, - rendererDist, - iconPath, - isDev, - devServerUrl, - windowStatePath, - registerHandle, - shouldQuit: () => isQuittingRef.current, - onRequestQuit: () => { - isQuittingRef.current = true; - }, - onCheckForUpdates: async () => { - await checkForUpdates(); - }, - onBackupProfile: async () => { - const target = await import("electron").then(({ dialog }) => dialog.showOpenDialog({ - properties: ["openDirectory", "createDirectory"], - })); - if (target.canceled || target.filePaths.length === 0) return; - await db.core.backup.exportBackup(`${target.filePaths[0]!}/agentcompany-backup-${Date.now()}`); - }, - onShortcut: (action) => emitEvent({ type: "shortcut", action }), - notify, - getActiveRunCount: () => { - try { - const snapshot = db.projection.snapshot.listSnapshot(); - return snapshot.runs.filter((r) => r.status === "running" || r.status === "queued").length; - } catch (error) { - logger.warn("[service-graph] getActiveRunCount failed:", error); - return 0; - } - }, - }); - desktopShellService.initialize(); - return desktopShellService; -} diff --git a/src/main/service-graph/create-leaf-services.ts b/src/main/service-graph/create-leaf-services.ts deleted file mode 100644 index f7b02d31..00000000 --- a/src/main/service-graph/create-leaf-services.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { AppDatabase } from "../database"; -import { createBudgetEnforcementService } from "../budget-enforcement-service"; -import { createSessionManagementService } from "../session-management-service"; -import { createSkillService } from "../skill-service"; -import type { NotificationOptions } from "../notification-service"; - -export interface LeafServicesDeps { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - notify: (options: NotificationOptions) => void; - publishDomainChanged: () => void; -} - -export interface LeafServices { - skillService: ReturnType; - budgetEnforcementService: ReturnType; - sessionManagementService: ReturnType; -} - -/** - * Build leaf services that no other service depends on except through this - * bundle. Constructed first so downstream factories can receive concrete - * references without null-checks. - */ -export function createLeafServices({ - db, - logger, - notify, - publishDomainChanged, -}: LeafServicesDeps): LeafServices { - const skillService = createSkillService({ db, profileDir: db.profileDir, logger }); - const budgetEnforcementService = createBudgetEnforcementService({ - db, - logger, - notify, - publishDomainChanged, - }); - const sessionManagementService = createSessionManagementService({ db, logger }); - - return { skillService, budgetEnforcementService, sessionManagementService }; -} diff --git a/src/main/service-graph/create-lifecycle.ts b/src/main/service-graph/create-lifecycle.ts deleted file mode 100644 index 7a9c6545..00000000 --- a/src/main/service-graph/create-lifecycle.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { app } from "electron"; -import type { AgentApiServer } from "../api-server"; -import type { AppDatabase } from "../database"; -import { BrowserManager } from "../browser-manager"; -import { createAppLifecycleService } from "../app-lifecycle-service"; -import type { createAutomationService } from "../automation-service"; -import type { createDesktopShellService } from "../desktop-shell-service"; -import type { PiRuntimeServices } from "../service-graph-pi-runtime"; -import type { createRuntimeOrchestrationService } from "./create-runtime-orchestration-service"; - -/** Overall budget for awaited shutdown drain. */ -const SHUTDOWN_BUDGET_MS = 5_000; - -export interface LifecycleDeps { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - isQuittingRef: { current: boolean }; - apiServerRef: { current: AgentApiServer | null }; - browserManagerRef: { current: BrowserManager | null }; - piRuntimeRef: { current: PiRuntimeServices | null }; - runtimeOrchestrationService: ReturnType; - automationService: ReturnType; - desktopShellService: ReturnType; - /** - * Clears graph-owned service refs (so getters return null) after the drain - * completes. Mirrors the original synchronous null-out at the tail of the - * old onBeforeQuit. - */ - clearServiceRefs: () => void; -} - -/** - * Build the app lifecycle service and wire a deterministic shutdown drain - * that awaits the utility-process worker's ready-to-exit handshake - * before calling app.exit(). On timeout we log the stuck run ids and - * exit(1) so operators see an unclean shutdown. - */ -export function createLifecycle(deps: LifecycleDeps) { - const { - db, - logger, - isQuittingRef, - apiServerRef, - browserManagerRef, - piRuntimeRef, - runtimeOrchestrationService, - automationService, - desktopShellService, - clearServiceRefs, - } = deps; - - let drainPromise: Promise | null = null; - - function listActiveRunIds(): string[] { - try { - return db.projection.snapshot.listSnapshot().runs - .filter((r) => r.status === "running" || r.status === "queued") - .map((r) => r.id); - } catch (err) { - logger.warn("[lifecycle] listActiveRunIds failed:", err instanceof Error ? err.message : String(err)); - return []; - } - } - - async function drain(): Promise { - try { runtimeOrchestrationService.stopAllSchedulers(); } catch (err) { logger.warn("[lifecycle] stopAllSchedulers failed:", err); } - try { automationService.destroy(); } catch (err) { logger.warn("[lifecycle] automationService.destroy failed:", err); } - try { apiServerRef.current?.stop(); } catch (err) { logger.warn("[lifecycle] apiServer.stop failed:", err); } - apiServerRef.current = null; - try { browserManagerRef.current?.shutdown(); } catch (err) { logger.warn("[lifecycle] browserManager.shutdown failed:", err); } - browserManagerRef.current = null; - - const timeout = new Promise<"timeout">((resolve) => { - const handle = setTimeout(() => resolve("timeout"), SHUTDOWN_BUDGET_MS); - if (typeof handle.unref === "function") handle.unref(); - }); - const outcome = await Promise.race([ - runtimeOrchestrationService.shutdown().then(() => "drained" as const), - timeout, - ]); - - try { desktopShellService.destroy(); } catch (err) { logger.warn("[lifecycle] desktopShell.destroy failed:", err); } - try { piRuntimeRef.current?.release(); } catch (err) { logger.warn("[lifecycle] piRuntime.release failed:", err); } - piRuntimeRef.current = null; - try { db.close(); } catch (err) { logger.warn("[lifecycle] db.close failed:", err); } - - clearServiceRefs(); - - if (outcome === "timeout") { - const stuck = listActiveRunIds(); - logger.error( - `[lifecycle] Drain exceeded ${SHUTDOWN_BUDGET_MS}ms; stuck runs: ${stuck.length ? stuck.join(", ") : ""}`, - ); - return 1; - } - return 0; - } - - const appLifecycleService = createAppLifecycleService({ - getMainWindow: () => desktopShellService.getMainWindow(), - ensureWindow: async () => desktopShellService.ensureWindow(), - shouldQuit: () => isQuittingRef.current, - onBeforeQuit: () => { - if (drainPromise) return; - isQuittingRef.current = true; - drainPromise = drain().catch((err) => { - logger.error("[lifecycle] drain threw unexpectedly:", err); - return 1; - }); - drainPromise.then((code) => { - app.exit(code); - }); - }, - }); - - return appLifecycleService; -} diff --git a/src/main/service-graph/create-runtime-orchestration-service.ts b/src/main/service-graph/create-runtime-orchestration-service.ts deleted file mode 100644 index 2ae26bfd..00000000 --- a/src/main/service-graph/create-runtime-orchestration-service.ts +++ /dev/null @@ -1,192 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DesktopEvent } from "@shared/types"; -import { createWorkerService } from "../worker-service"; -import { createOrchestrationService } from "../orchestration-service"; -import type { createBudgetEnforcementService } from "../budget-enforcement-service"; -import type { createSessionManagementService } from "../session-management-service"; -import type { createSkillService } from "../skill-service"; -import type { PiRuntimeServices } from "../service-graph-pi-runtime"; -import type { NotificationOptions } from "../notification-service"; -import type { RuntimeMessageInjector } from "../agent-runtime"; -import type { WorkerServiceDependencies } from "../worker/entry/types"; -import type { OrchestrationDependencies } from "../orchestration/types"; - -export interface RuntimeOrchestrationServiceDeps { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - workerPath: string; - isQuittingRef: { current: boolean }; - publishDomainChanged: () => void; - emitEvent: (event: DesktopEvent) => void; - notify: (options: NotificationOptions) => void; - createRunToken: (agentId: string, companyId: string, runId: string) => string; - getApiPort: () => number; - skillService: ReturnType; - budgetService: ReturnType; - sessionService: ReturnType; - piRuntimeRef: { current: PiRuntimeServices | null }; - getRuntimeMessageInjector: () => RuntimeMessageInjector | null; - onRunStarted?: (runId: string, taskId: string | null, agentId: string, companyId: string) => void; - onRunCompleted?: ( - runId: string, - taskId: string | null, - agentId: string, - companyId: string, - status: string, - summary: string | null, - errorMessage: string | null, - ) => void; - checkpointEngine?: { shouldPauseHeartbeat: (companyId: string, agentId: string) => boolean }; -} - -type AutomationHandlers = { - dispatchAutomation: OrchestrationDependencies["dispatchAutomation"]; - processRunCompletion: WorkerServiceDependencies["processRunCompletion"]; -}; - -/** - * Owns the two halves of the run execution loop as one object: - * orchestration decides which run should start, and the worker service - * owns the utility process that executes it. Keeping both in one factory - * removes the service-graph event hub from the hot run path. - */ -export function createRuntimeOrchestrationService(deps: RuntimeOrchestrationServiceDeps) { - const { - db, - logger, - workerPath, - isQuittingRef, - publishDomainChanged, - emitEvent, - notify, - createRunToken, - getApiPort, - skillService, - budgetService, - sessionService, - piRuntimeRef, - getRuntimeMessageInjector, - onRunStarted, - onRunCompleted, - checkpointEngine, - } = deps; - - let automationHandlers: AutomationHandlers | null = null; - let orchestrationService: ReturnType | null = null; - - function requireAutomation(): AutomationHandlers { - if (!automationHandlers) { - throw new Error("Runtime orchestration automation handlers are not bound."); - } - return automationHandlers; - } - - function requireOrchestration(): ReturnType { - if (!orchestrationService) { - throw new Error("Runtime orchestration service is not initialized."); - } - return orchestrationService; - } - - const workerService = createWorkerService({ - db, - logger, - workerPath, - isQuitting: () => isQuittingRef.current, - publishDomainChanged, - emitEvent, - wakeAgentIfPossible: (agentId, companyId, trigger) => - requireOrchestration().wakeAgentIfPossible(agentId, companyId, trigger), - dispatchRunToWorker: (params) => { - requireOrchestration().dispatchRunToWorker(params); - }, - processRunCompletion: (run, event) => { - requireAutomation().processRunCompletion(run, event); - }, - onRunStarted, - onRunCompleted, - notify, - budgetService, - sessionService, - getRuntimeBridge: () => piRuntimeRef.current?.runtimeBridge ?? null, - getRuntimeMessageInjector, - }); - - orchestrationService = createOrchestrationService({ - db, - logger, - publishDomainChanged, - emitEvent, - notify, - createRunToken, - getApiPort, - dispatchAutomation: (trigger, ctx) => { - requireAutomation().dispatchAutomation(trigger, ctx); - }, - hasWorkerReady: () => Boolean(workerService.getWorker()), - enqueueWorkerRun: (payload) => { - workerService.getWorker()?.postMessage({ type: "enqueue-run", payload }); - }, - isQuitting: () => isQuittingRef.current, - listRuntimeSkillEntries: (companyId, agentId, connectorId) => - skillService.listRuntimeSkillEntries(companyId, agentId, connectorId), - budgetService, - checkpointEngine, - getSessionHandoff: (agentId) => sessionService.getHandoffForAgent(agentId), - evaluatePreRunSessionRotation: (agentId, _connectorId) => { - const agent = db.core.entity.getAgent(agentId); - if (!agent.sessionId) return { rotated: false, handoff: null, sessionId: null }; - const session = db.core.tasks.getSessionById(agent.sessionId); - if (!session) return { rotated: false, handoff: null, sessionId: agent.sessionId }; - const result = sessionService.evaluateRotation(session); - if (result.shouldRotate) { - const newSessionId = sessionService.rotateSession(session); - const handoff = sessionService.getHandoffForAgent(agentId); - return { rotated: true, handoff, sessionId: newSessionId }; - } - return { rotated: false, handoff: null, sessionId: agent.sessionId }; - }, - }); - - return { - bindAutomation(service: AutomationHandlers): void { - if (automationHandlers) { - throw new Error("Runtime orchestration automation handlers are already bound."); - } - automationHandlers = service; - }, - assertReady(): void { - requireAutomation(); - requireOrchestration(); - }, - createWorker: workerService.createWorker, - getWorker: workerService.getWorker, - shutdown: workerService.shutdown, - destroy: workerService.destroy, - resolveWorkspace: (...args: Parameters["resolveWorkspace"]>) => - requireOrchestration().resolveWorkspace(...args), - wakeAgentIfPossible: (...args: Parameters["wakeAgentIfPossible"]>) => - requireOrchestration().wakeAgentIfPossible(...args), - dispatchRunToWorker: (...args: Parameters["dispatchRunToWorker"]>) => - requireOrchestration().dispatchRunToWorker(...args), - queueTaskRun: (...args: Parameters["queueTaskRun"]>) => - requireOrchestration().queueTaskRun(...args), - createTaskRunForDeferredDispatch: ( - ...args: Parameters["createTaskRunForDeferredDispatch"]> - ) => requireOrchestration().createTaskRunForDeferredDispatch(...args), - resumeQueuedRuns: (...args: Parameters["resumeQueuedRuns"]>) => - requireOrchestration().resumeQueuedRuns(...args), - startAgentHeartbeatRun: ( - ...args: Parameters["startAgentHeartbeatRun"]> - ) => requireOrchestration().startAgentHeartbeatRun(...args), - startAllSchedulers: (...args: Parameters["startAllSchedulers"]>) => - requireOrchestration().startAllSchedulers(...args), - stopAllSchedulers: (...args: Parameters["stopAllSchedulers"]>) => - requireOrchestration().stopAllSchedulers(...args), - }; -} diff --git a/AgentCompany-New/src/main/services/agent-connector-tools.ts b/src/main/services/agent-connector-tools.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-connector-tools.ts rename to src/main/services/agent-connector-tools.ts diff --git a/AgentCompany-New/src/main/services/agent-deliverable-tools.ts b/src/main/services/agent-deliverable-tools.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-deliverable-tools.ts rename to src/main/services/agent-deliverable-tools.ts diff --git a/AgentCompany-New/src/main/services/agent-message-presence.ts b/src/main/services/agent-message-presence.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-message-presence.ts rename to src/main/services/agent-message-presence.ts diff --git a/AgentCompany-New/src/main/services/agent-read-messages.ts b/src/main/services/agent-read-messages.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-read-messages.ts rename to src/main/services/agent-read-messages.ts diff --git a/AgentCompany-New/src/main/services/agent-run-loop.ts b/src/main/services/agent-run-loop.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-run-loop.ts rename to src/main/services/agent-run-loop.ts diff --git a/AgentCompany-New/src/main/services/agent-tool-args.ts b/src/main/services/agent-tool-args.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-tool-args.ts rename to src/main/services/agent-tool-args.ts diff --git a/AgentCompany-New/src/main/services/agent-tools.ts b/src/main/services/agent-tools.ts similarity index 100% rename from AgentCompany-New/src/main/services/agent-tools.ts rename to src/main/services/agent-tools.ts diff --git a/AgentCompany-New/src/main/services/approval-service.ts b/src/main/services/approval-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/approval-service.ts rename to src/main/services/approval-service.ts diff --git a/AgentCompany-New/src/main/services/audit-service.ts b/src/main/services/audit-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/audit-service.ts rename to src/main/services/audit-service.ts diff --git a/AgentCompany-New/src/main/services/auth-broker-service.ts b/src/main/services/auth-broker-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/auth-broker-service.ts rename to src/main/services/auth-broker-service.ts diff --git a/AgentCompany-New/src/main/services/automation-service.ts b/src/main/services/automation-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/automation-service.ts rename to src/main/services/automation-service.ts diff --git a/AgentCompany-New/src/main/services/board-intervention-service.ts b/src/main/services/board-intervention-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/board-intervention-service.ts rename to src/main/services/board-intervention-service.ts diff --git a/AgentCompany-New/src/main/services/chat-agent-wake-service.ts b/src/main/services/chat-agent-wake-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-agent-wake-service.ts rename to src/main/services/chat-agent-wake-service.ts diff --git a/AgentCompany-New/src/main/services/chat-mentions.ts b/src/main/services/chat-mentions.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-mentions.ts rename to src/main/services/chat-mentions.ts diff --git a/AgentCompany-New/src/main/services/chat-message-mutation-service.ts b/src/main/services/chat-message-mutation-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-message-mutation-service.ts rename to src/main/services/chat-message-mutation-service.ts diff --git a/AgentCompany-New/src/main/services/chat-message-structure.ts b/src/main/services/chat-message-structure.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-message-structure.ts rename to src/main/services/chat-message-structure.ts diff --git a/AgentCompany-New/src/main/services/chat-service-internal.ts b/src/main/services/chat-service-internal.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-service-internal.ts rename to src/main/services/chat-service-internal.ts diff --git a/AgentCompany-New/src/main/services/chat-service.ts b/src/main/services/chat-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-service.ts rename to src/main/services/chat-service.ts diff --git a/AgentCompany-New/src/main/services/chat-slash-router.ts b/src/main/services/chat-slash-router.ts similarity index 100% rename from AgentCompany-New/src/main/services/chat-slash-router.ts rename to src/main/services/chat-slash-router.ts diff --git a/AgentCompany-New/src/main/services/compliance-service.ts b/src/main/services/compliance-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/compliance-service.ts rename to src/main/services/compliance-service.ts diff --git a/AgentCompany-New/src/main/services/composio/composio-client.ts b/src/main/services/composio/composio-client.ts similarity index 100% rename from AgentCompany-New/src/main/services/composio/composio-client.ts rename to src/main/services/composio/composio-client.ts diff --git a/AgentCompany-New/src/main/services/composio/composio-connection-service.ts b/src/main/services/composio/composio-connection-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/composio/composio-connection-service.ts rename to src/main/services/composio/composio-connection-service.ts diff --git a/AgentCompany-New/src/main/services/composio/composio-credentials.ts b/src/main/services/composio/composio-credentials.ts similarity index 100% rename from AgentCompany-New/src/main/services/composio/composio-credentials.ts rename to src/main/services/composio/composio-credentials.ts diff --git a/AgentCompany-New/src/main/services/composio/composio-tool-bridge.ts b/src/main/services/composio/composio-tool-bridge.ts similarity index 100% rename from AgentCompany-New/src/main/services/composio/composio-tool-bridge.ts rename to src/main/services/composio/composio-tool-bridge.ts diff --git a/AgentCompany-New/src/main/services/composio/connector-grants.ts b/src/main/services/composio/connector-grants.ts similarity index 100% rename from AgentCompany-New/src/main/services/composio/connector-grants.ts rename to src/main/services/composio/connector-grants.ts diff --git a/AgentCompany-New/src/main/services/deliverable-writer.ts b/src/main/services/deliverable-writer.ts similarity index 100% rename from AgentCompany-New/src/main/services/deliverable-writer.ts rename to src/main/services/deliverable-writer.ts diff --git a/AgentCompany-New/src/main/services/document-service.ts b/src/main/services/document-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/document-service.ts rename to src/main/services/document-service.ts diff --git a/AgentCompany-New/src/main/services/file-handoff-service.ts b/src/main/services/file-handoff-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/file-handoff-service.ts rename to src/main/services/file-handoff-service.ts diff --git a/AgentCompany-New/src/main/services/file-service.ts b/src/main/services/file-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/file-service.ts rename to src/main/services/file-service.ts diff --git a/AgentCompany-New/src/main/services/files/file-object-store.ts b/src/main/services/files/file-object-store.ts similarity index 100% rename from AgentCompany-New/src/main/services/files/file-object-store.ts rename to src/main/services/files/file-object-store.ts diff --git a/AgentCompany-New/src/main/services/files/workspace-path.ts b/src/main/services/files/workspace-path.ts similarity index 100% rename from AgentCompany-New/src/main/services/files/workspace-path.ts rename to src/main/services/files/workspace-path.ts diff --git a/AgentCompany-New/src/main/services/goal-kickoff.ts b/src/main/services/goal-kickoff.ts similarity index 100% rename from AgentCompany-New/src/main/services/goal-kickoff.ts rename to src/main/services/goal-kickoff.ts diff --git a/AgentCompany-New/src/main/services/identity-access-service.ts b/src/main/services/identity-access-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/identity-access-service.ts rename to src/main/services/identity-access-service.ts diff --git a/AgentCompany-New/src/main/services/knowledge-service.ts b/src/main/services/knowledge-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/knowledge-service.ts rename to src/main/services/knowledge-service.ts diff --git a/AgentCompany-New/src/main/services/meeting-service.ts b/src/main/services/meeting-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/meeting-service.ts rename to src/main/services/meeting-service.ts diff --git a/AgentCompany-New/src/main/services/migration-cutover-journal-service.ts b/src/main/services/migration-cutover-journal-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/migration-cutover-journal-service.ts rename to src/main/services/migration-cutover-journal-service.ts diff --git a/AgentCompany-New/src/main/services/migration-service.ts b/src/main/services/migration-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/migration-service.ts rename to src/main/services/migration-service.ts diff --git a/AgentCompany-New/src/main/services/migration-validation-summary.ts b/src/main/services/migration-validation-summary.ts similarity index 100% rename from AgentCompany-New/src/main/services/migration-validation-summary.ts rename to src/main/services/migration-validation-summary.ts diff --git a/AgentCompany-New/src/main/services/oauth/anthropic-claude-flow.ts b/src/main/services/oauth/anthropic-claude-flow.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/anthropic-claude-flow.ts rename to src/main/services/oauth/anthropic-claude-flow.ts diff --git a/AgentCompany-New/src/main/services/oauth/github-copilot-flow.ts b/src/main/services/oauth/github-copilot-flow.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/github-copilot-flow.ts rename to src/main/services/oauth/github-copilot-flow.ts diff --git a/AgentCompany-New/src/main/services/oauth/google-antigravity-flow.ts b/src/main/services/oauth/google-antigravity-flow.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/google-antigravity-flow.ts rename to src/main/services/oauth/google-antigravity-flow.ts diff --git a/AgentCompany-New/src/main/services/oauth/oauth-callback-server.ts b/src/main/services/oauth/oauth-callback-server.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/oauth-callback-server.ts rename to src/main/services/oauth/oauth-callback-server.ts diff --git a/AgentCompany-New/src/main/services/oauth/oauth-flows.ts b/src/main/services/oauth/oauth-flows.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/oauth-flows.ts rename to src/main/services/oauth/oauth-flows.ts diff --git a/AgentCompany-New/src/main/services/oauth/oauth-page.ts b/src/main/services/oauth/oauth-page.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/oauth-page.ts rename to src/main/services/oauth/oauth-page.ts diff --git a/AgentCompany-New/src/main/services/oauth/oauth-types.ts b/src/main/services/oauth/oauth-types.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/oauth-types.ts rename to src/main/services/oauth/oauth-types.ts diff --git a/AgentCompany-New/src/main/services/oauth/openai-codex-flow.ts b/src/main/services/oauth/openai-codex-flow.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/openai-codex-flow.ts rename to src/main/services/oauth/openai-codex-flow.ts diff --git a/AgentCompany-New/src/main/services/oauth/pkce.ts b/src/main/services/oauth/pkce.ts similarity index 100% rename from AgentCompany-New/src/main/services/oauth/pkce.ts rename to src/main/services/oauth/pkce.ts diff --git a/AgentCompany-New/src/main/services/onboarding-service.ts b/src/main/services/onboarding-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/onboarding-service.ts rename to src/main/services/onboarding-service.ts diff --git a/AgentCompany-New/src/main/services/operations-service.ts b/src/main/services/operations-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/operations-service.ts rename to src/main/services/operations-service.ts diff --git a/AgentCompany-New/src/main/services/org-governance-service.ts b/src/main/services/org-governance-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/org-governance-service.ts rename to src/main/services/org-governance-service.ts diff --git a/AgentCompany-New/src/main/services/organization-seed.ts b/src/main/services/organization-seed.ts similarity index 100% rename from AgentCompany-New/src/main/services/organization-seed.ts rename to src/main/services/organization-seed.ts diff --git a/AgentCompany-New/src/main/services/organization-service.ts b/src/main/services/organization-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/organization-service.ts rename to src/main/services/organization-service.ts diff --git a/AgentCompany-New/src/main/services/policy-service.ts b/src/main/services/policy-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/policy-service.ts rename to src/main/services/policy-service.ts diff --git a/AgentCompany-New/src/main/services/provider-adapter-contract.ts b/src/main/services/provider-adapter-contract.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-adapter-contract.ts rename to src/main/services/provider-adapter-contract.ts diff --git a/AgentCompany-New/src/main/services/provider-adapters.ts b/src/main/services/provider-adapters.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-adapters.ts rename to src/main/services/provider-adapters.ts diff --git a/AgentCompany-New/src/main/services/provider-auth-lifecycle.ts b/src/main/services/provider-auth-lifecycle.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-auth-lifecycle.ts rename to src/main/services/provider-auth-lifecycle.ts diff --git a/AgentCompany-New/src/main/services/provider-auth-profiles.ts b/src/main/services/provider-auth-profiles.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-auth-profiles.ts rename to src/main/services/provider-auth-profiles.ts diff --git a/AgentCompany-New/src/main/services/provider-background-service.ts b/src/main/services/provider-background-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-background-service.ts rename to src/main/services/provider-background-service.ts diff --git a/AgentCompany-New/src/main/services/provider-background.ts b/src/main/services/provider-background.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-background.ts rename to src/main/services/provider-background.ts diff --git a/AgentCompany-New/src/main/services/provider-http.ts b/src/main/services/provider-http.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-http.ts rename to src/main/services/provider-http.ts diff --git a/AgentCompany-New/src/main/services/provider-internal.ts b/src/main/services/provider-internal.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-internal.ts rename to src/main/services/provider-internal.ts diff --git a/AgentCompany-New/src/main/services/provider-models-fetch.ts b/src/main/services/provider-models-fetch.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-models-fetch.ts rename to src/main/services/provider-models-fetch.ts diff --git a/AgentCompany-New/src/main/services/provider-oauth-service.ts b/src/main/services/provider-oauth-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-oauth-service.ts rename to src/main/services/provider-oauth-service.ts diff --git a/AgentCompany-New/src/main/services/provider-rate-limit-registry.ts b/src/main/services/provider-rate-limit-registry.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-rate-limit-registry.ts rename to src/main/services/provider-rate-limit-registry.ts diff --git a/AgentCompany-New/src/main/services/provider-request-store.ts b/src/main/services/provider-request-store.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-request-store.ts rename to src/main/services/provider-request-store.ts diff --git a/AgentCompany-New/src/main/services/provider-response-observer.ts b/src/main/services/provider-response-observer.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-response-observer.ts rename to src/main/services/provider-response-observer.ts diff --git a/AgentCompany-New/src/main/services/provider-response-runner.ts b/src/main/services/provider-response-runner.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-response-runner.ts rename to src/main/services/provider-response-runner.ts diff --git a/AgentCompany-New/src/main/services/provider-response-utils.ts b/src/main/services/provider-response-utils.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-response-utils.ts rename to src/main/services/provider-response-utils.ts diff --git a/AgentCompany-New/src/main/services/provider-service.ts b/src/main/services/provider-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-service.ts rename to src/main/services/provider-service.ts diff --git a/AgentCompany-New/src/main/services/provider-sign-in-window.ts b/src/main/services/provider-sign-in-window.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-sign-in-window.ts rename to src/main/services/provider-sign-in-window.ts diff --git a/AgentCompany-New/src/main/services/provider-streaming.ts b/src/main/services/provider-streaming.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-streaming.ts rename to src/main/services/provider-streaming.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turn.ts b/src/main/services/provider-tool-turn.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turn.ts rename to src/main/services/provider-tool-turn.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/anthropic-format.ts b/src/main/services/provider-tool-turns/anthropic-format.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/anthropic-format.ts rename to src/main/services/provider-tool-turns/anthropic-format.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/aws-sigv4.ts b/src/main/services/provider-tool-turns/aws-sigv4.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/aws-sigv4.ts rename to src/main/services/provider-tool-turns/aws-sigv4.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/bedrock-format.ts b/src/main/services/provider-tool-turns/bedrock-format.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/bedrock-format.ts rename to src/main/services/provider-tool-turns/bedrock-format.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/chat-format.ts b/src/main/services/provider-tool-turns/chat-format.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/chat-format.ts rename to src/main/services/provider-tool-turns/chat-format.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/credential-resolver.ts b/src/main/services/provider-tool-turns/credential-resolver.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/credential-resolver.ts rename to src/main/services/provider-tool-turns/credential-resolver.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/gcp-auth.ts b/src/main/services/provider-tool-turns/gcp-auth.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/gcp-auth.ts rename to src/main/services/provider-tool-turns/gcp-auth.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/gemini-format.ts b/src/main/services/provider-tool-turns/gemini-format.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/gemini-format.ts rename to src/main/services/provider-tool-turns/gemini-format.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/responses-format.ts b/src/main/services/provider-tool-turns/responses-format.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/responses-format.ts rename to src/main/services/provider-tool-turns/responses-format.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/router.ts b/src/main/services/provider-tool-turns/router.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/router.ts rename to src/main/services/provider-tool-turns/router.ts diff --git a/AgentCompany-New/src/main/services/provider-tool-turns/turns.ts b/src/main/services/provider-tool-turns/turns.ts similarity index 100% rename from AgentCompany-New/src/main/services/provider-tool-turns/turns.ts rename to src/main/services/provider-tool-turns/turns.ts diff --git a/AgentCompany-New/src/main/services/rollback-service.ts b/src/main/services/rollback-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/rollback-service.ts rename to src/main/services/rollback-service.ts diff --git a/AgentCompany-New/src/main/services/sdlc-service.ts b/src/main/services/sdlc-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/sdlc-service.ts rename to src/main/services/sdlc-service.ts diff --git a/AgentCompany-New/src/main/services/search-service.ts b/src/main/services/search-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/search-service.ts rename to src/main/services/search-service.ts diff --git a/AgentCompany-New/src/main/services/secret-vault.ts b/src/main/services/secret-vault.ts similarity index 100% rename from AgentCompany-New/src/main/services/secret-vault.ts rename to src/main/services/secret-vault.ts diff --git a/AgentCompany-New/src/main/services/skill-artifacts.ts b/src/main/services/skill-artifacts.ts similarity index 100% rename from AgentCompany-New/src/main/services/skill-artifacts.ts rename to src/main/services/skill-artifacts.ts diff --git a/AgentCompany-New/src/main/services/skill-manifest.ts b/src/main/services/skill-manifest.ts similarity index 100% rename from AgentCompany-New/src/main/services/skill-manifest.ts rename to src/main/services/skill-manifest.ts diff --git a/AgentCompany-New/src/main/services/skill-service.ts b/src/main/services/skill-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/skill-service.ts rename to src/main/services/skill-service.ts diff --git a/AgentCompany-New/src/main/services/snapshot-service.ts b/src/main/services/snapshot-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/snapshot-service.ts rename to src/main/services/snapshot-service.ts diff --git a/AgentCompany-New/src/main/services/social-audit-service.ts b/src/main/services/social-audit-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/social-audit-service.ts rename to src/main/services/social-audit-service.ts diff --git a/AgentCompany-New/src/main/services/social-browser-policy-service.ts b/src/main/services/social-browser-policy-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/social-browser-policy-service.ts rename to src/main/services/social-browser-policy-service.ts diff --git a/AgentCompany-New/src/main/services/social-login-window.ts b/src/main/services/social-login-window.ts similarity index 100% rename from AgentCompany-New/src/main/services/social-login-window.ts rename to src/main/services/social-login-window.ts diff --git a/AgentCompany-New/src/main/services/social-service.ts b/src/main/services/social-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/social-service.ts rename to src/main/services/social-service.ts diff --git a/AgentCompany-New/src/main/services/sprint-service.ts b/src/main/services/sprint-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/sprint-service.ts rename to src/main/services/sprint-service.ts diff --git a/AgentCompany-New/src/main/services/task-execution-service.ts b/src/main/services/task-execution-service.ts similarity index 100% rename from AgentCompany-New/src/main/services/task-execution-service.ts rename to src/main/services/task-execution-service.ts diff --git a/AgentCompany-New/src/main/services/task-prompts.ts b/src/main/services/task-prompts.ts similarity index 100% rename from AgentCompany-New/src/main/services/task-prompts.ts rename to src/main/services/task-prompts.ts diff --git a/src/main/session-management-service.ts b/src/main/session-management-service.ts deleted file mode 100644 index 302641ae..00000000 --- a/src/main/session-management-service.ts +++ /dev/null @@ -1,215 +0,0 @@ -import type { AppDatabase } from "./database"; -import type { TaskSessionRecord } from "@shared/types"; - -interface SessionManagementDependencies { - db: AppDatabase; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; -} - -// Rotation thresholds. Any-of semantics — first trigger wins. -const ROTATION_THRESHOLDS = { - maxRuns: 20, - maxTokens: 500_000, - maxAgeHours: 72, -}; - -// D-04: Handoff size cap to prevent prompt bloat. -// 2000 characters ≈ 500 tokens — enough to resume context without crowding -// out the system prompt + user message in an 8k-ish model window. -const MAX_HANDOFF_LENGTH = 2000; -// 5 runs of resume context is typically enough to bridge a rotation boundary; -// older runs add diminishing value relative to the token cost. -const MAX_HANDOFF_RUNS = 5; - -export function createSessionManagementService({ db, logger }: SessionManagementDependencies) { - - // D-08: Accumulate token usage on task_sessions row (called for ALL adapters per D-05) - function accumulateTokenUsage(sessionId: string, inputTokens: number, outputTokens: number, runId: string): void { - db.core.tasks.incrementSessionUsage(sessionId, inputTokens, outputTokens, runId); - } - - // Any-of thresholds — first trigger wins. Pi-mono delegates context - // management to pi-agent-core compaction hooks; AgentCompany applies its - // own rotation thresholds on top of that. - function evaluateRotation( - session: TaskSessionRecord, - ): { shouldRotate: boolean; reason: string | null } { - if (session.runCount >= ROTATION_THRESHOLDS.maxRuns) { - return { shouldRotate: true, reason: "max_runs" }; - } - - const totalTokens = session.totalInputTokens + session.totalOutputTokens; - if (totalTokens >= ROTATION_THRESHOLDS.maxTokens) { - return { shouldRotate: true, reason: "max_tokens" }; - } - - const ageMs = Date.now() - new Date(session.createdAt).getTime(); - const ageHours = ageMs / (1000 * 60 * 60); - if (ageHours >= ROTATION_THRESHOLDS.maxAgeHours) { - return { shouldRotate: true, reason: "max_age_hours" }; - } - - return { shouldRotate: false, reason: null }; - } - - // D-06: Build handoff markdown from structured data, no AI call. - // - // Sessions are agent-scoped (post-v34 migration). The handoff walks the - // agent's recent runs across ALL tasks and taskless heartbeats — heartbeat - // runs legitimately have no task but still need a handoff when their - // transcript rotates under token pressure. - function generateHandoff(session: TaskSessionRecord): string { - const recentRuns = db.queryAll<{ - id: string; status: string; summary: string | null; errorMessage: string | null; - finishedAt: string | null; taskId: string | null; taskTitle: string | null; - }>( - `SELECT r.id, r.status, r.summary, r.error_message as errorMessage, - r.finished_at as finishedAt, r.task_id as taskId, - t.title as taskTitle - FROM runs r LEFT JOIN tasks t ON t.id = r.task_id - WHERE r.agent_id = ? AND r.company_id = ? AND r.finished_at IS NOT NULL - ORDER BY r.finished_at DESC LIMIT ?`, - session.agentId, - session.companyId, - MAX_HANDOFF_RUNS, - ); - const errorRuns = recentRuns.filter((r) => r.errorMessage); - - const decisionEntries = db.queryAll<{ action: string; detail: string; createdAt: string }>( - `SELECT action, detail, created_at as createdAt FROM activity - WHERE company_id = ? AND actor = ? - AND (action LIKE '%decision%' OR action LIKE '%approval%' OR action LIKE '%resolved%') - ORDER BY created_at DESC LIMIT 5`, - session.companyId, - session.agentId, - ); - - const sections: string[] = []; - sections.push("# Session Handoff"); - sections.push(""); - - if (recentRuns.length > 0) { - sections.push("## Recent Run History"); - for (const run of recentRuns) { - const summaryText = run.summary ? run.summary.slice(0, 100) : "(no summary)"; - const scope = run.taskTitle ? ` on "${run.taskTitle}"` : " (heartbeat)"; - sections.push(`- [${run.status}]${scope} ${summaryText} (${run.finishedAt ?? "in progress"})`); - } - sections.push(""); - } - - if (errorRuns.length > 0) { - sections.push("## Errors Encountered"); - for (const run of errorRuns) { - sections.push(`- ${(run.errorMessage ?? "").slice(0, 150)} (${run.finishedAt ?? "unknown"})`); - } - sections.push(""); - } - - if (decisionEntries.length > 0) { - sections.push("## Key Decisions"); - for (const entry of decisionEntries) { - sections.push(`- ${entry.detail.slice(0, 120)} (${entry.createdAt})`); - } - sections.push(""); - } - - sections.push(`*Session stats: ${session.runCount} runs, ${session.totalInputTokens + session.totalOutputTokens} total tokens*`); - - let result = sections.join("\n"); - // Cap handoff size per research pitfall #5 - if (result.length > MAX_HANDOFF_LENGTH) { - result = result.slice(0, MAX_HANDOFF_LENGTH - 50) + "\n\n... (earlier content omitted)"; - } - return result; - } - - // Archive current session, generate handoff, create new agent-scoped - // session, update the agent pointer. Counters reset; Pi Mono carries no - // provider-side resume state across rotations. - function rotateSession(session: TaskSessionRecord): string { - const reason = "threshold_exceeded"; - const handoff = generateHandoff(session); - - logger.info(`[session] Rotating session ${session.id} for agent ${session.agentId}: ${reason}`); - - db.core.tasks.archiveSession(session.id, reason, handoff); - - const newSessionId = db.core.tasks.createNewSession({ - companyId: session.companyId, - agentId: session.agentId, - adapterType: session.adapterType, - }); - - db.core.tasks.setAgentSessionId(session.agentId, newSessionId); - - logger.info(`[session] New session ${newSessionId} created for agent ${session.agentId}`); - return newSessionId; - } - - // D-07: Read handoff from the agent's most recently rotated session. - // - // Sessions are agent-scoped (post-v34 migration), so the handoff query - // must key on agent_id, not task_id. task_sessions.task_id is now an - // empty-string column kept only for schema-level backwards compatibility; - // filtering on it returns zero rows for all rotated agent sessions. - function getHandoffForAgent(agentId: string): string | null { - const row = db.queryAll<{ handoffMarkdown: string | null }>( - `SELECT handoff_markdown as handoffMarkdown FROM task_sessions - WHERE agent_id = ? AND rotated_at IS NOT NULL - ORDER BY rotated_at DESC LIMIT 1`, - agentId, - ); - return row[0]?.handoffMarkdown ?? null; - } - - // Task-scoped compatibility shim for callers that still hold a task id - // (UI panels reading a specific task's handoff history). Resolves the - // assignee and delegates to the agent-scoped lookup. - function getHandoffContext(taskId: string): string | null { - const taskRow = db.queryAll<{ assigneeAgentId: string | null }>( - "SELECT assignee_agent_id as assigneeAgentId FROM tasks WHERE id = ?", - taskId, - ); - const agentId = taskRow[0]?.assigneeAgentId; - if (!agentId) return null; - return getHandoffForAgent(agentId); - } - - // D-09: Snapshot token totals for delta tracking - function snapshotUsage(session: TaskSessionRecord): { inputTokens: number; outputTokens: number } { - return { - inputTokens: session.totalInputTokens, - outputTokens: session.totalOutputTokens, - }; - } - - // D-09: Compute delta from snapshot - function getUsageDelta( - sessionId: string, - snapshot: { inputTokens: number; outputTokens: number } - ): { inputTokensDelta: number; outputTokensDelta: number } { - // Re-read current totals from DB - const current = db.queryAll<{ totalInputTokens: number; totalOutputTokens: number }>( - `SELECT total_input_tokens as totalInputTokens, total_output_tokens as totalOutputTokens - FROM task_sessions WHERE id = ?`, - sessionId - ); - if (!current[0]) return { inputTokensDelta: 0, outputTokensDelta: 0 }; - return { - inputTokensDelta: current[0].totalInputTokens - snapshot.inputTokens, - outputTokensDelta: current[0].totalOutputTokens - snapshot.outputTokens, - }; - } - - return { - accumulateTokenUsage, - evaluateRotation, - generateHandoff, - rotateSession, - getHandoffContext, - getHandoffForAgent, - snapshotUsage, - getUsageDelta, - }; -} diff --git a/src/main/skill-format.ts b/src/main/skill-format.ts deleted file mode 100644 index c7d24a7d..00000000 --- a/src/main/skill-format.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { extname } from "node:path"; -import type { FileInventoryEntry, TrustLevel } from "./skill-types.js"; - -function isPlainRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - -function parseYamlScalar(rawValue: string): unknown { - const trimmed = rawValue.trim(); - if (trimmed === "") return ""; - if (trimmed === "null" || trimmed === "~") return null; - if (trimmed === "true") return true; - if (trimmed === "false") return false; - if (trimmed === "[]") return []; - if (trimmed === "{}") return {}; - if (/^-?\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed); - if ( - trimmed.startsWith('"') || - trimmed.startsWith("[") || - trimmed.startsWith("{") - ) { - try { - return JSON.parse(trimmed); - } catch { - return trimmed; - } - } - return trimmed; -} - -function prepareYamlLines( - raw: string, -): Array<{ indent: number; content: string }> { - return raw - .split("\n") - .map((line) => ({ - indent: line.match(/^ */)?.[0].length ?? 0, - content: line.trim(), - })) - .filter((line) => line.content.length > 0 && !line.content.startsWith("#")); -} - -function parseYamlBlock( - lines: Array<{ indent: number; content: string }>, - startIndex: number, - indentLevel: number, -): { value: unknown; nextIndex: number } { - let index = startIndex; - while (index < lines.length && lines[index]!.content.length === 0) - index += 1; - if (index >= lines.length || lines[index]!.indent < indentLevel) { - return { value: {}, nextIndex: index }; - } - - const isArray = - lines[index]!.indent === indentLevel && - lines[index]!.content.startsWith("-"); - - if (isArray) { - const values: unknown[] = []; - while (index < lines.length) { - const line = lines[index]!; - if (line.indent < indentLevel) break; - if (line.indent !== indentLevel || !line.content.startsWith("-")) break; - const remainder = line.content.slice(1).trim(); - index += 1; - if (!remainder) { - const nested = parseYamlBlock(lines, index, indentLevel + 2); - values.push(nested.value); - index = nested.nextIndex; - continue; - } - const inlineObjectSeparator = remainder.indexOf(":"); - if ( - inlineObjectSeparator > 0 && - !remainder.startsWith('"') && - !remainder.startsWith("{") && - !remainder.startsWith("[") - ) { - const key = remainder.slice(0, inlineObjectSeparator).trim(); - const rawValue = remainder.slice(inlineObjectSeparator + 1).trim(); - const nextObject: Record = { - [key]: parseYamlScalar(rawValue), - }; - if (index < lines.length && lines[index]!.indent > indentLevel) { - const nested = parseYamlBlock(lines, index, indentLevel + 2); - if (isPlainRecord(nested.value)) { - Object.assign(nextObject, nested.value); - } - index = nested.nextIndex; - } - values.push(nextObject); - continue; - } - values.push(parseYamlScalar(remainder)); - } - return { value: values, nextIndex: index }; - } - - // Object parsing - const record: Record = {}; - while (index < lines.length) { - const line = lines[index]!; - if (line.indent < indentLevel) break; - const colonIndex = line.content.indexOf(":"); - if (colonIndex < 0) { - index += 1; - continue; - } - const key = line.content.slice(0, colonIndex).trim(); - const remainder = line.content.slice(colonIndex + 1).trim(); - index += 1; - if (!remainder && index < lines.length && lines[index]!.indent > indentLevel) { - const nested = parseYamlBlock(lines, index, lines[index]!.indent); - record[key] = nested.value; - index = nested.nextIndex; - continue; - } - record[key] = parseYamlScalar(remainder); - } - return { value: record, nextIndex: index }; -} - -function parseYamlFrontmatter(raw: string): Record { - const prepared = prepareYamlLines(raw); - if (prepared.length === 0) return {}; - const parsed = parseYamlBlock(prepared, 0, prepared[0]!.indent); - return isPlainRecord(parsed.value) ? parsed.value : {}; -} - -/** - * Parse a SKILL.md file with optional YAML frontmatter. - * Normalizes CRLF to LF before parsing. - */ -export function parseFrontmatterMarkdown( - raw: string, -): { frontmatter: Record; body: string } { - const normalized = raw.replace(/\r\n/g, "\n"); - if (!normalized.startsWith("---\n")) { - return { frontmatter: {}, body: normalized.trim() }; - } - const closing = normalized.indexOf("\n---\n", 4); - if (closing < 0) { - // Check for closing delimiter at EOF (no trailing newline) - const eofClosing = normalized.indexOf("\n---", 4); - if (eofClosing >= 0 && eofClosing + 4 >= normalized.length) { - const frontmatterRaw = normalized.slice(4, eofClosing).trim(); - return { - frontmatter: parseYamlFrontmatter(frontmatterRaw), - body: "", - }; - } - return { frontmatter: {}, body: normalized.trim() }; - } - const frontmatterRaw = normalized.slice(4, closing).trim(); - const body = normalized.slice(closing + 5).trim(); - return { - frontmatter: parseYamlFrontmatter(frontmatterRaw), - body, - }; -} - -/** - * Classify a file path within a skill package into its inventory kind. - * Uses directory prefixes and file extensions for classification. - */ -export function classifyInventoryKind( - relativePath: string, -): FileInventoryEntry["kind"] { - // Normalize path separators and lowercase for matching - const normalized = relativePath.replace(/\\/g, "/").toLowerCase(); - - if (normalized.endsWith("/skill.md") || normalized === "skill.md") - return "skill"; - if (normalized.startsWith("references/")) return "reference"; - if (normalized.startsWith("scripts/")) return "script"; - if (normalized.startsWith("assets/")) return "asset"; - if (normalized.endsWith(".md")) return "markdown"; - - const ext = extname(normalized).toLowerCase(); - const scriptExtensions = new Set([ - ".sh", - ".js", - ".mjs", - ".cjs", - ".ts", - ".py", - ".rb", - ".bash", - ]); - if (scriptExtensions.has(ext)) return "script"; - - const assetExtensions = new Set([ - ".png", - ".jpg", - ".jpeg", - ".gif", - ".svg", - ".webp", - ".pdf", - ]); - if (assetExtensions.has(ext)) return "asset"; - - return "other"; -} - -/** - * Derive the trust level for a skill based on its file inventory. - * Scripts/executables -> highest risk; assets -> medium; markdown only -> lowest. - */ -export function deriveTrustLevel(inventory: FileInventoryEntry[]): TrustLevel { - if (inventory.some((entry) => entry.kind === "script")) - return "scripts_executables"; - if ( - inventory.some( - (entry) => entry.kind === "asset" || entry.kind === "other", - ) - ) - return "assets"; - return "markdown_only"; -} - diff --git a/src/main/skill-github.ts b/src/main/skill-github.ts deleted file mode 100644 index 64db9683..00000000 --- a/src/main/skill-github.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { readResponseBytesWithLimit, readResponseWithLimit } from "./skills/read-response-with-limit.js"; - -export interface GitHubSkillFileData { - path: string; - content: Uint8Array; - mode: string | null; -} - -/** - * Data returned for each skill found in a GitHub repository. - */ -export interface GitHubSkillData { - skillMdPath: string; - markdown: string; - files: GitHubSkillFileData[]; - owner: string; - repo: string; -} - -interface Logger { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; -} - -/** 2 MB — generous upper bound for a single SKILL.md (markdown) file. */ -export const MAX_SKILL_BYTES = 2 * 1024 * 1024; - -/** 8 MB — upper bound for a single non-SKILL.md package file. */ -export const MAX_SKILL_FILE_BYTES = 8 * 1024 * 1024; - -/** 32 MB — aggregate upper bound for all materialized files from a skill pack. */ -export const MAX_TOTAL_BYTES = 32 * 1024 * 1024; - -/** 10 MB — upper bound for the recursive git tree JSON response. */ -const MAX_TREE_BYTES = 10 * 1024 * 1024; - -interface GitHubTreeEntry { - path: string; - type: string; - mode?: string; -} - -function encodeGitHubBlobPath(filePath: string): string { - if (filePath.includes("\0") || filePath.includes("\\") || filePath.startsWith("/") || /^[A-Za-z]:/.test(filePath)) { - throw new Error(`Invalid GitHub skill file path: ${filePath}`); - } - const parts = filePath.split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw new Error(`Invalid GitHub skill file path: ${filePath}`); - } - return parts.map((part) => encodeURIComponent(part)).join("/"); -} - -function rawGitHubUrl(owner: string, repo: string, ref: string, filePath: string): string { - return `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${encodeGitHubBlobPath(filePath)}`; -} - -function assertTotalSkillBytes(totalBytes: number): void { - if (totalBytes > MAX_TOTAL_BYTES) { - throw new Error( - `Skill pack exceeded aggregate limit of ${MAX_TOTAL_BYTES} bytes`, - ); - } -} - -/** - * Resolve the latest commit SHA for a given ref (branch, tag, or HEAD). - * Returns the 40-character hex SHA on success, null on error. - */ -export async function resolveGitHubCommitSha( - owner: string, - repo: string, - ref?: string, - logger?: Logger, -): Promise { - const target = ref || "HEAD"; - const url = `https://api.github.com/repos/${owner}/${repo}/commits/${encodeURIComponent(target)}`; - try { - const response = await fetch(url, { - headers: { Accept: "application/vnd.github.sha" }, - }); - if (!response.ok) { - if (response.status === 403) { - const resetHeader = response.headers.get("X-RateLimit-Reset"); - logger?.warn( - `GitHub API rate limit hit for ${owner}/${repo}`, - resetHeader ? `resets at ${new Date(Number(resetHeader) * 1000).toISOString()}` : "", - ); - } else { - logger?.warn(`GitHub commit resolve failed: ${response.status} for ${owner}/${repo}@${target}`); - } - return null; - } - const sha = (await readResponseWithLimit(response, MAX_SKILL_BYTES)).trim(); - return /^[0-9a-f]{40}$/i.test(sha) ? sha : null; - } catch (err) { - logger?.error("GitHub commit resolve network error:", err); - return null; - } -} - -/** - * Fetch all SKILL.md files from a GitHub repository via the REST API. - * - * 1. GET the recursive git tree to find all SKILL.md paths - * 2. Optionally filter to a specific skill slug directory - * 3. Download each SKILL.md via raw.githubusercontent.com - * 4. Collect sibling files as file inventory - */ -export async function fetchGitHubSkills( - owner: string, - repo: string, - ref: string, - requestedSlug: string | null, - logger?: Logger, -): Promise<{ skills: GitHubSkillData[]; commitSha: string }> { - const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${encodeURIComponent(ref)}?recursive=1`; - try { - const treeResponse = await fetch(treeUrl, { - headers: { Accept: "application/json" }, - }); - if (!treeResponse.ok) { - logger?.warn(`GitHub tree fetch failed: ${treeResponse.status} for ${owner}/${repo}@${ref}`); - return { skills: [], commitSha: ref }; - } - const treeData = JSON.parse(await readResponseWithLimit(treeResponse, MAX_TREE_BYTES)) as { - tree?: GitHubTreeEntry[]; - sha?: string; - }; - const treeSha = typeof treeData.sha === "string" ? treeData.sha : ref; - const allEntries = (treeData.tree ?? []).filter( - (entry) => entry.type === "blob" && typeof entry.path === "string", - ); - const allPaths = allEntries.map((entry) => entry.path); - - // Find SKILL.md files (at root or nested) - let skillMdPaths = allPaths.filter( - (p) => p.endsWith("/SKILL.md") || p === "SKILL.md", - ); - - // Filter to requested slug directory if provided - if (requestedSlug) { - skillMdPaths = skillMdPaths.filter((p) => { - const dir = p === "SKILL.md" ? "" : p.slice(0, p.lastIndexOf("/")); - const dirName = dir.split("/").pop() ?? ""; - return dirName.toLowerCase() === requestedSlug.toLowerCase(); - }); - } - - if (skillMdPaths.length === 0) { - logger?.info(`No SKILL.md files found in ${owner}/${repo}@${ref}`); - return { skills: [], commitSha: treeSha }; - } - - const skills: GitHubSkillData[] = []; - let totalBytes = 0; - - for (const skillMdPath of skillMdPaths) { - try { - let skillBytes = 0; - // Download content via raw.githubusercontent.com (no API rate limit) - const rawUrl = rawGitHubUrl(owner, repo, ref, skillMdPath); - const contentResponse = await fetch(rawUrl); - if (!contentResponse.ok) { - logger?.warn(`Failed to download ${rawUrl}: ${contentResponse.status}`); - continue; - } - const remainingBudget = MAX_TOTAL_BYTES - totalBytes - skillBytes; - const perFileCap = Math.min(MAX_SKILL_BYTES, Math.max(0, remainingBudget)); - if (perFileCap === 0) { - throw new Error( - `Skill pack exceeded aggregate limit of ${MAX_TOTAL_BYTES} bytes`, - ); - } - const markdown = await readResponseWithLimit(contentResponse, perFileCap); - skillBytes += Buffer.byteLength(markdown, "utf-8"); - assertTotalSkillBytes(totalBytes + skillBytes); - - // Collect sibling files in the same directory (or subdirectories) - const skillDir = - skillMdPath === "SKILL.md" - ? "" - : skillMdPath.slice(0, skillMdPath.lastIndexOf("/")); - const prefix = skillDir ? `${skillDir}/` : ""; - const inventoryEntries = allEntries.filter( - (entry) => entry.path !== skillMdPath && (prefix ? entry.path.startsWith(prefix) : !entry.path.includes("/")), - ); - const files: GitHubSkillFileData[] = []; - - for (const entry of inventoryEntries) { - const fileRemainingBudget = MAX_TOTAL_BYTES - totalBytes - skillBytes; - const fileCap = Math.min(MAX_SKILL_FILE_BYTES, Math.max(0, fileRemainingBudget)); - if (fileCap === 0) { - throw new Error( - `Skill pack exceeded aggregate limit of ${MAX_TOTAL_BYTES} bytes`, - ); - } - const fileUrl = rawGitHubUrl(owner, repo, ref, entry.path); - const fileResponse = await fetch(fileUrl); - if (!fileResponse.ok) { - throw new Error(`Failed to download ${fileUrl}: ${fileResponse.status}`); - } - const content = await readResponseBytesWithLimit(fileResponse, fileCap); - skillBytes += content.byteLength; - assertTotalSkillBytes(totalBytes + skillBytes); - files.push({ - path: entry.path, - content, - mode: entry.mode ?? null, - }); - } - - skills.push({ - skillMdPath, - markdown, - files, - owner, - repo, - }); - totalBytes += skillBytes; - } catch (err) { - logger?.error(`Error downloading skill ${skillMdPath}:`, err); - continue; - } - } - - return { skills, commitSha: treeSha }; - } catch (err) { - logger?.error(`GitHub tree fetch network error for ${owner}/${repo}:`, err); - return { skills: [], commitSha: ref }; - } -} diff --git a/src/main/skill-keys.ts b/src/main/skill-keys.ts deleted file mode 100644 index 27ecb2db..00000000 --- a/src/main/skill-keys.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { createHash } from "node:crypto"; -import { resolve } from "node:path"; -import type { SkillSourceType } from "./skill-types.js"; - -const SLUG_DELIM_RE = /[^a-z0-9]+/g; -const SLUG_TRIM_RE = /^-+|-+$/g; - -/** - * Normalize a value into a URL-safe slug. - * Returns null if the value is falsy or results in an empty string. - */ -export function normalizeSkillSlug( - value: string | undefined | null, -): string | null { - if (!value) return null; - const trimmed = value.trim(); - if (!trimmed) return null; - const normalized = trimmed - .toLowerCase() - .replace(SLUG_DELIM_RE, "-") - .replace(SLUG_TRIM_RE, ""); - return normalized.length > 0 ? normalized : null; -} - -/** - * Compute the first 10 characters of a SHA-256 hex digest. - * Used for hash segments in canonical keys. - */ -export function hashSkillValue(value: string): string { - return createHash("sha256").update(value).digest("hex").slice(0, 10); -} - -function asString(value: unknown): string | null { - return typeof value === "string" && value.length > 0 ? value : null; -} - -function isPlainRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - -/** - * Derive a deterministic canonical key for a skill. - * - * Key formats by source type: - * - GitHub/skills_sh with owner+repo: `{owner}/{repo}/{slug}` - * - URL with sourceLocator: `url/{normalizedHost}/{hash10}/{slug}` - * - local_path with sourceLocator: `local/{hash10 of resolved path}/{slug}` - * - Fallback (managed or unknown): `company/{companyId}/{slug}` - */ -export function deriveCanonicalSkillKey( - companyId: string, - input: { - slug: string; - sourceType: SkillSourceType; - sourceLocator: string | null; - metadata: Record | null; - }, -): string { - const slug = normalizeSkillSlug(input.slug) ?? "skill"; - const metadata = isPlainRecord(input.metadata) ? input.metadata : null; - - const owner = normalizeSkillSlug(asString(metadata?.owner)); - const repo = normalizeSkillSlug(asString(metadata?.repo)); - - // GitHub or skills.sh with owner/repo metadata - if ( - (input.sourceType === "github" || input.sourceType === "skills_sh") && - owner && - repo - ) { - return `${owner}/${repo}/${slug}`; - } - - // URL source with locator - if (input.sourceType === "url") { - const locator = asString(input.sourceLocator); - if (locator) { - try { - const url = new URL(locator); - const host = normalizeSkillSlug(url.host) ?? "url"; - return `url/${host}/${hashSkillValue(locator)}/${slug}`; - } catch { - return `url/unknown/${hashSkillValue(locator)}/${slug}`; - } - } - } - - // Local path source with locator - if (input.sourceType === "local_path") { - const locator = asString(input.sourceLocator); - if (locator) { - return `local/${hashSkillValue(resolve(locator))}/${slug}`; - } - } - - // Fallback: company-scoped key - return `company/${companyId}/${slug}`; -} - -// Three-part key: org/repo/skill -const THREE_PART_KEY_RE = - /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; -// Two-part key: org/repo -const TWO_PART_KEY_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; -// skills.sh URL pattern -const SKILLS_SH_RE = - /^https?:\/\/(?:www\.)?skills\.sh\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)(?:\/([A-Za-z0-9_.-]+))?(?:[?#].*)?$/i; - -export interface ParsedSkillImportSource { - resolvedSource: string; - requestedSkillSlug: string | null; - originalSkillsShUrl: string | null; -} - -/** - * Parse a raw skill import source string and resolve it to a normalized form. - * - * Supported input formats: - * - `owner/repo/skill` -> GitHub URL with skills.sh origin tracking - * - `owner/repo` -> GitHub URL - * - `https://skills.sh/owner/repo/skill` -> GitHub URL with skills.sh origin - * - `https://github.com/owner/repo` -> pass through - * - `/local/path` -> pass through - */ -export function parseSkillImportSource( - rawInput: string, -): ParsedSkillImportSource { - const trimmed = rawInput.trim(); - - // Three-part key (org/repo/skill) -- originates from skills.sh registry - if ( - !/^https?:\/\//i.test(trimmed) && - THREE_PART_KEY_RE.test(trimmed) - ) { - const [owner, repo, skillSlugRaw] = trimmed.split("/"); - return { - resolvedSource: `https://github.com/${owner}/${repo}`, - requestedSkillSlug: normalizeSkillSlug(skillSlugRaw), - originalSkillsShUrl: `https://skills.sh/${owner}/${repo}/${skillSlugRaw}`, - }; - } - - // Two-part key (org/repo) -- resolve to GitHub - if ( - !/^https?:\/\//i.test(trimmed) && - TWO_PART_KEY_RE.test(trimmed) - ) { - return { - resolvedSource: `https://github.com/${trimmed}`, - requestedSkillSlug: null, - originalSkillsShUrl: null, - }; - } - - // skills.sh URL -> resolve to GitHub - const skillsShMatch = trimmed.match(SKILLS_SH_RE); - if (skillsShMatch) { - const [, owner, repo, skillSlugRaw] = skillsShMatch; - return { - resolvedSource: `https://github.com/${owner}/${repo}`, - requestedSkillSlug: skillSlugRaw - ? normalizeSkillSlug(skillSlugRaw) - : null, - originalSkillsShUrl: trimmed, - }; - } - - // Everything else -- pass through as resolvedSource - return { - resolvedSource: trimmed, - requestedSkillSlug: null, - originalSkillsShUrl: null, - }; -} diff --git a/src/main/skill-service.ts b/src/main/skill-service.ts deleted file mode 100644 index 55824116..00000000 --- a/src/main/skill-service.ts +++ /dev/null @@ -1 +0,0 @@ -export { createSkillService } from "./skills/index"; diff --git a/src/main/skill-types.ts b/src/main/skill-types.ts deleted file mode 100644 index b16c7642..00000000 --- a/src/main/skill-types.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Re-export shared types that were previously duplicated here. -// Canonical definitions live in @shared/types (records-core.ts & enums.ts). -export type { SkillSourceType, TrustLevel, FileInventoryEntry, SkillRecord, SkillImportResult, SkillUpdateStatus } from "@shared/types"; - -/** - * Runtime projection of a company skill, matching pi-coding-agent's progressive- - * disclosure model: only name/description/filePath/baseDir are exposed to the - * prompt. The full SKILL.md is loaded on-demand by the agent via the `read` tool. - * - * Fields mirror pi's `Skill` interface (the full Skill has sourceInfo + - * disableModelInvocation, which we don't need to forward to the prompt layer). - */ -export interface ProjectedSkill { - /** Skill name (Agent Skills spec: lowercase-kebab, matches parent dir). */ - name: string; - /** Skill description shown in the prompt manifest. */ - description: string; - /** Absolute path to the SKILL.md file. */ - filePath: string; - /** Directory containing SKILL.md (used for relative-path resolution). */ - baseDir: string; -} - -/** - * Skill-to-agent assignment record. - */ -export interface SkillAssignment { - agentId: string; - skillId: string; -} diff --git a/src/main/skills/auto-assign-on-hire.ts b/src/main/skills/auto-assign-on-hire.ts deleted file mode 100644 index 9a2b39c6..00000000 --- a/src/main/skills/auto-assign-on-hire.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DepartmentId } from "@shared/types"; - -/** - * Server-side default skill assignment at hire approval time. - * - * Before this module existed, the CEO's operating prompt was explicitly - * told to inspect every direct report every wake, fetch the skill - * catalogue, and POST /agents/{id}/skills for any unassigned role- - * relevant entry. That is business logic routed through an LLM — wasted - * tokens and an unreliable guarantee. The hire approval is the - * deterministic moment to give a fresh agent a sensible default kit; - * the CEO is still free to add or remove skills later. - * - * The mapping is department → built-in skill categories. Each seeded - * company skill carries its category in `metadata.builtinCategory` - * (see `skills/runtime.ts#seedBuiltinSkills`); we match against that - * tag so a company that imported extra skills under the same category - * inherits them too, and deletes remove the assignment pool cleanly. - */ - -const CATEGORIES_BY_DEPARTMENT: Record = { - executive: ["basic-for-all", "document-process"], - engineering: ["software-engineer", "basic-for-all"], - product: ["frontend-design", "basic-for-all", "document-process"], - design: ["frontend-design", "basic-for-all"], - marketing: ["marketing", "basic-for-all", "document-process"], - sales: ["marketing", "basic-for-all", "document-process"], - hr: ["basic-for-all", "document-process"], - finance: ["basic-for-all", "document-process"], - legal: ["basic-for-all", "document-process"], - operations: ["software-engineer", "basic-for-all", "document-process"], - customer_support: ["basic-for-all", "document-process"], - research: ["basic-for-all", "document-process"], -}; - -function readBuiltinCategory(metadata: unknown): string | null { - if (!metadata) return null; - if (typeof metadata === "string") { - try { - const parsed = JSON.parse(metadata) as Record; - const value = parsed?.builtinCategory; - return typeof value === "string" ? value : null; - } catch { - return null; - } - } - if (typeof metadata === "object") { - const value = (metadata as Record).builtinCategory; - return typeof value === "string" ? value : null; - } - return null; -} - -export interface AutoAssignSkillsInput { - agentId: string; - companyId: string; - department: DepartmentId | string | null | undefined; -} - -export interface AutoAssignSkillsResult { - assignedSkillIds: string[]; -} - -export function autoAssignSkillsForHire( - db: AppDatabase, - input: AutoAssignSkillsInput, -): AutoAssignSkillsResult { - const department = (input.department ?? "") as DepartmentId; - const categories = CATEGORIES_BY_DEPARTMENT[department]; - if (!categories || categories.length === 0) { - return { assignedSkillIds: [] }; - } - - const alreadyAssigned = new Set(db.core.skills.listAgentSkillAssignments(input.companyId, input.agentId)); - const wanted = new Set(categories); - const catalogue = db.core.skills.listCompanySkills(input.companyId); - - const assigned: string[] = []; - for (const skill of catalogue) { - if (alreadyAssigned.has(skill.id)) continue; - const category = readBuiltinCategory(skill.metadata); - if (!category || !wanted.has(category)) continue; - if (db.core.skills.assignSkillToAgent(input.companyId, input.agentId, skill.id)) { - assigned.push(skill.id); - } - } - - return { assignedSkillIds: assigned }; -} diff --git a/src/main/skills/crud.ts b/src/main/skills/crud.ts deleted file mode 100644 index e84c9b53..00000000 --- a/src/main/skills/crud.ts +++ /dev/null @@ -1,133 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DesktopResult } from "@shared/contracts"; -import type { SkillRecord, SkillUpdateStatus } from "../skill-types.js"; -import { resolveGitHubCommitSha } from "../skill-github.js"; - -interface CrudDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - cleanupSkillFiles: (companyId: string, slug: string) => Promise; - parseGitHubUrl: (url: string) => { owner: string; repo: string } | null; -} - -export function createSkillCrud({ db, logger, cleanupSkillFiles, parseGitHubUrl }: CrudDeps) { - function ok(data: T): DesktopResult { - return { ok: true, data }; - } - function fail(code: string, message: string): DesktopResult { - return { ok: false, error: { code, message } }; - } - - function listForCompany(companyId: string): SkillRecord[] { - return db.core.skills.listCompanySkills(companyId); - } - - function getDetail(companyId: string, skillId: string): DesktopResult { - const skill = db.core.skills.getCompanySkill(companyId, skillId); - if (!skill) return fail("not_found", `Skill ${skillId} not found`); - return ok(skill); - } - - async function deleteSkill( - companyId: string, - skillId: string, - ): Promise> { - const skill = db.core.skills.getCompanySkill(companyId, skillId); - if (!skill) return fail("not_found", `Skill ${skillId} not found`); - - try { - await cleanupSkillFiles(companyId, skill.slug); - db.core.skills.deleteCompanySkill(companyId, skillId); - logger.info(`Skill deleted: ${skill.key}`); - return ok(undefined); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.error("Skill deletion failed:", message); - return fail("delete_error", message); - } - } - - function assignToAgent( - companyId: string, - agentId: string, - skillId: string, - ): DesktopResult { - const skill = db.core.skills.getCompanySkill(companyId, skillId); - if (!skill) return fail("not_found", `Skill ${skillId} not found for company`); - if (!db.core.skills.assignSkillToAgent(companyId, agentId, skillId)) { - return fail("not_found", `Agent ${agentId} not found for company`); - } - return ok(undefined); - } - - function removeFromAgent( - companyId: string, - agentId: string, - skillId: string, - ): DesktopResult { - if (!db.core.skills.removeSkillFromAgent(companyId, agentId, skillId)) { - return fail("not_found", `Skill assignment not found for company`); - } - return ok(undefined); - } - - async function checkUpdateStatus( - companyId: string, - skillId: string, - ): Promise> { - const skill = db.core.skills.getCompanySkill(companyId, skillId); - if (!skill) return fail("not_found", `Skill ${skillId} not found`); - - if (skill.sourceType !== "github" && skill.sourceType !== "skills_sh") { - return ok({ - skillId: skill.id, - key: skill.key, - currentRef: skill.sourceRef, - latestRef: null, - hasUpdate: false, - }); - } - - const metadata = skill.metadata; - const owner = typeof metadata?.owner === "string" ? metadata.owner : null; - const repo = typeof metadata?.repo === "string" ? metadata.repo : null; - - if (!owner || !repo) { - const ghParsed = skill.sourceLocator ? parseGitHubUrl(skill.sourceLocator) : null; - if (!ghParsed) { - return ok({ - skillId: skill.id, - key: skill.key, - currentRef: skill.sourceRef, - latestRef: null, - hasUpdate: false, - }); - } - const latestRef = await resolveGitHubCommitSha(ghParsed.owner, ghParsed.repo, undefined, logger); - return ok({ - skillId: skill.id, - key: skill.key, - currentRef: skill.sourceRef, - latestRef, - hasUpdate: latestRef != null && latestRef !== skill.sourceRef, - }); - } - - const trackingRef = typeof metadata?.trackingRef === "string" ? metadata.trackingRef : undefined; - const latestRef = await resolveGitHubCommitSha(owner, repo, trackingRef, logger); - - return ok({ - skillId: skill.id, - key: skill.key, - currentRef: skill.sourceRef, - latestRef, - hasUpdate: latestRef != null && latestRef !== skill.sourceRef, - }); - } - - return { listForCompany, getDetail, deleteSkill, assignToAgent, removeFromAgent, checkUpdateStatus }; -} diff --git a/src/main/skills/discovery.ts b/src/main/skills/discovery.ts deleted file mode 100644 index 650c9ad6..00000000 --- a/src/main/skills/discovery.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { readdirSync, realpathSync, statSync, type Dirent } from "node:fs"; -import { join, resolve, relative } from "node:path"; -import type { FileInventoryEntry } from "../skill-types.js"; -import { classifyInventoryKind } from "../skill-format.js"; - -export const DEFAULT_SKILL_WALK_MAX_DEPTH = 8; -export const DEFAULT_SKILL_WALK_MAX_FILES = 256; - -const BLOCKED_PATH_PREFIXES_UNIX = ["/etc", "/var", "/proc", "/sys", "/dev", "/boot", "/sbin", "/usr/sbin"]; -const BLOCKED_PATH_PREFIXES_WIN = ["C:\\Windows", "C:\\Program Files", "C:\\ProgramData"]; - -export interface DiscoveryLogger { - warn: (...args: unknown[]) => void; -} - -export function assertNotSystemPath(realPath: string): void { - const normalized = realPath.replace(/\\/g, "/"); - const blocked = process.platform === "win32" ? BLOCKED_PATH_PREFIXES_WIN : BLOCKED_PATH_PREFIXES_UNIX; - for (const prefix of blocked) { - const normalizedPrefix = prefix.replace(/\\/g, "/"); - if (normalized === normalizedPrefix || normalized.startsWith(normalizedPrefix + "/")) { - throw new Error(`Importing skills from system directory is not allowed: ${realPath}`); - } - } -} - -export function findSkillMdFiles( - rootDir: string, - logger: DiscoveryLogger, - opts?: { maxDepth?: number; maxFiles?: number }, -): string[] { - const maxDepth = opts?.maxDepth ?? DEFAULT_SKILL_WALK_MAX_DEPTH; - const maxFiles = opts?.maxFiles ?? DEFAULT_SKILL_WALK_MAX_FILES; - const found: string[] = []; - const visitedRealPaths = new Set(); - let filesSeen = 0; - - function walk(dir: string, depth: number) { - if (depth > maxDepth) { - throw new Error( - `Skill directory too deep, refusing to walk beyond ${maxDepth} levels`, - ); - } - let realDir: string; - try { - realDir = realpathSync(dir); - } catch (err) { - logger.warn(`[skill-import] realpathSync failed for ${dir}:`, err instanceof Error ? err.message : String(err)); - return; - } - if (visitedRealPaths.has(realDir)) { - return; - } - visitedRealPaths.add(realDir); - - let entries: Dirent[]; - try { - entries = readdirSync(dir, { withFileTypes: true }); - } catch (err) { - logger.warn(`[skill-import] readdirSync failed for ${dir}:`, err instanceof Error ? err.message : String(err)); - return; - } - for (const entry of entries) { - filesSeen++; - if (filesSeen > maxFiles) { - throw new Error( - `Skill directory contains too many files, refusing after ${maxFiles} entries`, - ); - } - const fullPath = join(dir, entry.name); - if (entry.isDirectory()) { - walk(fullPath, depth + 1); - } else if (entry.name === "SKILL.md") { - found.push(fullPath); - } - } - } - walk(rootDir, 0); - return found; -} - -export function buildLocalInventory( - skillDir: string, - skillMdPath: string, - logger: DiscoveryLogger, - opts?: { maxDepth?: number; maxFiles?: number }, -): FileInventoryEntry[] { - const maxDepth = opts?.maxDepth ?? DEFAULT_SKILL_WALK_MAX_DEPTH; - const maxFiles = opts?.maxFiles ?? DEFAULT_SKILL_WALK_MAX_FILES; - const inventory: FileInventoryEntry[] = [ - { path: "SKILL.md", kind: "skill" }, - ]; - const visitedRealPaths = new Set(); - let filesSeen = 0; - - function walk(dir: string, depth: number) { - if (depth > maxDepth) { - throw new Error( - `Skill directory too deep, refusing to walk beyond ${maxDepth} levels`, - ); - } - let realDir: string; - try { - realDir = realpathSync(dir); - } catch (err) { - logger.warn(`[skill-import] realpathSync failed for ${dir}:`, err instanceof Error ? err.message : String(err)); - return; - } - if (visitedRealPaths.has(realDir)) { - return; - } - visitedRealPaths.add(realDir); - - let entries: Dirent[]; - try { - entries = readdirSync(dir, { withFileTypes: true }); - } catch (err) { - logger.warn(`[skill-import] readdirSync failed for ${dir}:`, err instanceof Error ? err.message : String(err)); - return; - } - for (const entry of entries) { - filesSeen++; - if (filesSeen > maxFiles) { - throw new Error( - `Skill directory contains too many files, refusing after ${maxFiles} entries`, - ); - } - const fullPath = join(dir, entry.name); - if (entry.isDirectory()) { - walk(fullPath, depth + 1); - continue; - } - if (!entry.isFile()) continue; - const resolvedPath = resolve(fullPath); - if (resolvedPath === skillMdPath) continue; - let fileStat; - try { - fileStat = statSync(resolvedPath); - } catch (err) { - logger.warn(`[skill-import] statSync failed for ${resolvedPath}:`, err instanceof Error ? err.message : String(err)); - continue; - } - if (!fileStat.isFile()) continue; - const relativePath = relative(skillDir, resolvedPath).replace(/\\/g, "/"); - inventory.push({ - path: relativePath, - kind: (fileStat.mode & 0o111) !== 0 ? "script" : classifyInventoryKind(relativePath), - }); - } - } - - try { - walk(skillDir, 0); - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - if (msg.startsWith("Skill directory too deep") || msg.startsWith("Skill directory contains too many files")) { - throw err; - } - } - return inventory; -} diff --git a/src/main/skills/import-github.ts b/src/main/skills/import-github.ts deleted file mode 100644 index cd8c3117..00000000 --- a/src/main/skills/import-github.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { basename, dirname } from "node:path"; -import type { AppDatabase } from "../database"; -import type { FileInventoryEntry, SkillImportResult, SkillSourceType } from "../skill-types.js"; -import { - parseFrontmatterMarkdown, - classifyInventoryKind, - deriveTrustLevel, -} from "../skill-format.js"; -import { - deriveCanonicalSkillKey, - normalizeSkillSlug, -} from "../skill-keys.js"; -import { - resolveGitHubCommitSha, - fetchGitHubSkills, -} from "../skill-github.js"; -import { materializeSkillFiles, type MaterializedSkillFile } from "./materialize"; - -interface GitHubImportDeps { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - skillFilesDir: (companyId: string, slug: string) => string; -} - -export function createGitHubImporter({ db, logger, skillFilesDir }: GitHubImportDeps) { - function parseGitHubUrl(url: string): { owner: string; repo: string } | null { - try { - const parsed = new URL(url); - if (parsed.hostname !== "github.com") return null; - const parts = parsed.pathname.split("/").filter(Boolean); - if (parts.length < 2) return null; - return { - owner: parts[0]!, - repo: parts[1]!.replace(/\.git$/i, ""), - }; - } catch { - return null; - } - } - - async function importFromGitHub( - companyId: string, - url: string, - requestedSlug: string | null, - originalSkillsShUrl: string | null, - ): Promise { - const ghParsed = parseGitHubUrl(url); - if (!ghParsed) { - throw new Error(`Invalid GitHub URL: ${url}`); - } - const { owner, repo } = ghParsed; - - const sha = await resolveGitHubCommitSha(owner, repo, undefined, logger); - if (!sha) { - throw new Error(`Failed to resolve commit SHA for ${owner}/${repo}`); - } - - const { skills: githubSkills, commitSha } = await fetchGitHubSkills( - owner, repo, sha, requestedSlug, logger, - ); - - if (githubSkills.length === 0) { - throw new Error(`No SKILL.md files found in ${owner}/${repo}`); - } - - const results: SkillImportResult[] = []; - const sourceType: SkillSourceType = originalSkillsShUrl ? "skills_sh" : "github"; - const nowTs = new Date().toISOString(); - - for (const ghSkill of githubSkills) { - const parsed = parseFrontmatterMarkdown(ghSkill.markdown); - const rawSlug = - normalizeSkillSlug(parsed.frontmatter.slug as string | undefined) ?? - normalizeSkillSlug( - ghSkill.skillMdPath === "SKILL.md" - ? repo - : basename(dirname(ghSkill.skillMdPath)), - ) ?? - repo; - - const skillDir = - ghSkill.skillMdPath === "SKILL.md" - ? "" - : ghSkill.skillMdPath.slice(0, ghSkill.skillMdPath.lastIndexOf("/")); - const prefix = skillDir ? `${skillDir}/` : ""; - const materializedFiles: MaterializedSkillFile[] = [ - { path: "SKILL.md", kind: "skill", content: ghSkill.markdown }, - ...ghSkill.files.map((file) => { - const relativePath = prefix ? file.path.slice(prefix.length) : file.path; - return { - path: relativePath, - kind: file.mode === "100755" ? "script" as const : classifyInventoryKind(relativePath), - content: file.content, - }; - }), - ]; - const inventory: FileInventoryEntry[] = materializedFiles.map(({ path, kind }) => ({ path, kind })); - - const metadata: Record = { - sourceKind: "github", - owner, - repo, - ref: commitSha, - trackingRef: "HEAD", - ...(originalSkillsShUrl ? { originalSkillsShUrl } : {}), - }; - - const key = deriveCanonicalSkillKey(companyId, { - slug: rawSlug, - sourceType, - sourceLocator: url, - metadata, - }); - - const trustLevel = deriveTrustLevel(inventory); - const name = - (typeof parsed.frontmatter.name === "string" ? parsed.frontmatter.name : null) ?? - rawSlug; - const description = - typeof parsed.frontmatter.description === "string" - ? parsed.frontmatter.description - : null; - - const skillId = randomUUID(); - - await materializeSkillFiles(skillFilesDir(companyId, rawSlug), materializedFiles); - - const { isUpdate } = db.core.skills.upsertCompanySkill({ - id: skillId, - companyId, - key, - slug: rawSlug, - name, - description, - sourceType, - sourceLocator: url, - sourceRef: commitSha, - trustLevel, - compatibility: "compatible", - fileInventory: JSON.stringify(inventory), - metadata: JSON.stringify(metadata), - createdAt: nowTs, - updatedAt: nowTs, - }); - - results.push({ skillId, key, name, isUpdate }); - logger.info(`Skill ${isUpdate ? "updated" : "imported"}: ${key} from ${owner}/${repo}`); - } - - return results; - } - - return { parseGitHubUrl, importFromGitHub }; -} diff --git a/src/main/skills/import-local.ts b/src/main/skills/import-local.ts deleted file mode 100644 index cfde352d..00000000 --- a/src/main/skills/import-local.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { existsSync, readFileSync, realpathSync, statSync } from "node:fs"; -import { resolve, basename, dirname, isAbsolute, relative } from "node:path"; -import type { AppDatabase } from "../database"; -import type { FileInventoryEntry, SkillImportResult } from "../skill-types.js"; -import { parseFrontmatterMarkdown, deriveTrustLevel } from "../skill-format.js"; -import { - deriveCanonicalSkillKey, - normalizeSkillSlug, - hashSkillValue, -} from "../skill-keys.js"; -import { - assertNotSystemPath, - findSkillMdFiles, - buildLocalInventory, -} from "./discovery"; -import { materializeSkillFiles, normalizeMaterializedRelativePath, type MaterializedSkillFile } from "./materialize"; -import { MAX_SKILL_BYTES, MAX_SKILL_FILE_BYTES, MAX_TOTAL_BYTES } from "../skill-github.js"; - -export interface LocalImportContext { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - skillFilesDir: (companyId: string, slug: string) => string; -} - -function assertLocalFileSize(filePath: string, size: number, maxBytes: number): void { - if (size > maxBytes) { - throw new Error(`${filePath} exceeds ${maxBytes}-byte limit`); - } -} - -function assertLocalPackageSize(totalBytes: number): void { - if (totalBytes > MAX_TOTAL_BYTES) { - throw new Error(`Skill package exceeded aggregate limit of ${MAX_TOTAL_BYTES} bytes`); - } -} - -function readLocalSkillMarkdown(skillMdPath: string): string { - const stat = statSync(skillMdPath); - if (!stat.isFile()) { - throw new Error(`Local skill path is not a file: ${skillMdPath}`); - } - assertLocalFileSize(skillMdPath, stat.size, MAX_SKILL_BYTES); - return readFileSync(skillMdPath, "utf-8"); -} - -function assertPathInsideRoot(rootDir: string, targetPath: string, relativePath: string): void { - const relativePathFromRoot = relative(rootDir, targetPath); - if (relativePathFromRoot.length === 0 || relativePathFromRoot.startsWith("..") || isAbsolute(relativePathFromRoot)) { - throw new Error(`Skill inventory path escapes source directory: ${relativePath}`); - } -} - -function buildLocalMaterializedFiles( - skillDir: string, - markdown: string, - markdownBytes: number, - inventory: FileInventoryEntry[], -): MaterializedSkillFile[] { - const realSkillDir = realpathSync(skillDir); - const files: MaterializedSkillFile[] = [ - { path: "SKILL.md", kind: "skill", content: markdown }, - ]; - let totalBytes = markdownBytes; - assertLocalPackageSize(totalBytes); - - for (const entry of inventory) { - if (entry.path === "SKILL.md") continue; - const relativePath = normalizeMaterializedRelativePath(entry.path); - const sourcePath = resolve(realSkillDir, ...relativePath.split("/")); - const realSourcePath = realpathSync(sourcePath); - assertPathInsideRoot(realSkillDir, realSourcePath, relativePath); - const stat = statSync(realSourcePath); - if (!stat.isFile()) { - throw new Error(`Skill inventory path is not a file: ${relativePath}`); - } - assertLocalFileSize(relativePath, stat.size, MAX_SKILL_FILE_BYTES); - totalBytes += stat.size; - assertLocalPackageSize(totalBytes); - files.push({ - path: relativePath, - kind: entry.kind, - content: readFileSync(realSourcePath), - }); - } - - return files; -} - -export async function importFromLocal( - ctx: LocalImportContext, - companyId: string, - localPath: string, -): Promise { - const { db, logger, skillFilesDir } = ctx; - const resolvedPath = resolve(localPath.replace(/^~/, process.env.HOME ?? process.env.USERPROFILE ?? "")); - - if (!existsSync(resolvedPath)) { - throw new Error(`Local path does not exist: ${resolvedPath}`); - } - - // Resolve symlinks to prevent traversal attacks (agent importing /tmp/evil-link → /etc/shadow) - const realPath = realpathSync(resolvedPath); - assertNotSystemPath(realPath); - - const stat = statSync(resolvedPath); - const results: SkillImportResult[] = []; - const nowTs = new Date().toISOString(); - - if (stat.isFile()) { - const markdown = readLocalSkillMarkdown(resolvedPath); - assertLocalPackageSize(Buffer.byteLength(markdown, "utf-8")); - const parsed = parseFrontmatterMarkdown(markdown); - const rawSlug = - normalizeSkillSlug(parsed.frontmatter.slug as string | undefined) ?? - normalizeSkillSlug(basename(resolvedPath, ".md")) ?? - "skill"; - const inventory: FileInventoryEntry[] = [ - { path: "SKILL.md", kind: "skill" }, - ]; - const trustLevel = deriveTrustLevel(inventory); - const contentHash = hashSkillValue(markdown); - - const key = deriveCanonicalSkillKey(companyId, { - slug: rawSlug, - sourceType: "local_path", - sourceLocator: resolvedPath, - metadata: null, - }); - - const skillId = randomUUID(); - await materializeSkillFiles(skillFilesDir(companyId, rawSlug), [ - { path: "SKILL.md", kind: "skill", content: markdown }, - ]); - - const { isUpdate } = db.core.skills.upsertCompanySkill({ - id: skillId, - companyId, - key, - slug: rawSlug, - name: (typeof parsed.frontmatter.name === "string" ? parsed.frontmatter.name : null) ?? rawSlug, - description: typeof parsed.frontmatter.description === "string" ? parsed.frontmatter.description : null, - sourceType: "local_path", - sourceLocator: resolvedPath, - sourceRef: contentHash, - trustLevel, - compatibility: "compatible", - fileInventory: JSON.stringify(inventory), - metadata: null, - createdAt: nowTs, - updatedAt: nowTs, - }); - - results.push({ skillId, key, name: rawSlug, isUpdate }); - logger.info(`Skill ${isUpdate ? "updated" : "imported"} from local file: ${key}`); - return results; - } - - // Directory: walk to find SKILL.md files - const skillMdFiles = findSkillMdFiles(resolvedPath, logger); - if (skillMdFiles.length === 0) { - throw new Error(`No SKILL.md files found in ${resolvedPath}`); - } - - for (const skillMdPath of skillMdFiles) { - const skillDir = dirname(skillMdPath); - const markdown = readLocalSkillMarkdown(skillMdPath); - const markdownBytes = Buffer.byteLength(markdown, "utf-8"); - const parsed = parseFrontmatterMarkdown(markdown); - const rawSlug = - normalizeSkillSlug(parsed.frontmatter.slug as string | undefined) ?? - normalizeSkillSlug(basename(skillDir)) ?? - "skill"; - - const inventory = buildLocalInventory(skillDir, skillMdPath, logger); - const trustLevel = deriveTrustLevel(inventory); - const contentHash = hashSkillValue(markdown); - - const key = deriveCanonicalSkillKey(companyId, { - slug: rawSlug, - sourceType: "local_path", - sourceLocator: skillDir, - metadata: null, - }); - - const skillId = randomUUID(); - await materializeSkillFiles( - skillFilesDir(companyId, rawSlug), - buildLocalMaterializedFiles(skillDir, markdown, markdownBytes, inventory), - ); - - const { isUpdate } = db.core.skills.upsertCompanySkill({ - id: skillId, - companyId, - key, - slug: rawSlug, - name: (typeof parsed.frontmatter.name === "string" ? parsed.frontmatter.name : null) ?? rawSlug, - description: typeof parsed.frontmatter.description === "string" ? parsed.frontmatter.description : null, - sourceType: "local_path", - sourceLocator: skillDir, - sourceRef: contentHash, - trustLevel, - compatibility: "compatible", - fileInventory: JSON.stringify(inventory), - metadata: null, - createdAt: nowTs, - updatedAt: nowTs, - }); - - results.push({ skillId, key, name: rawSlug, isUpdate }); - logger.info(`Skill ${isUpdate ? "updated" : "imported"} from local path: ${key}`); - } - - return results; -} diff --git a/src/main/skills/import-url.ts b/src/main/skills/import-url.ts deleted file mode 100644 index bd0d9479..00000000 --- a/src/main/skills/import-url.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { AppDatabase } from "../database"; -import type { FileInventoryEntry, SkillImportResult } from "../skill-types.js"; -import { parseFrontmatterMarkdown } from "../skill-format.js"; -import { deriveCanonicalSkillKey, normalizeSkillSlug } from "../skill-keys.js"; -import { MAX_SKILL_BYTES } from "../skill-github.js"; -import { materializeSkillFiles } from "./materialize"; -import { readResponseWithLimit } from "./read-response-with-limit.js"; - -export interface UrlImportContext { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - skillFilesDir: (companyId: string, slug: string) => string; -} - -export async function importFromUrl( - ctx: UrlImportContext, - companyId: string, - url: string, - safeFetch: (target: string) => Promise, -): Promise { - const { db, logger, skillFilesDir } = ctx; - const response = await safeFetch(url); - if (!response.ok) { - throw new Error(`Failed to fetch skill from URL: ${response.status} ${url}`); - } - const markdown = await readResponseWithLimit(response, MAX_SKILL_BYTES); - const parsed = parseFrontmatterMarkdown(markdown); - const nowTs = new Date().toISOString(); - - let urlSlug: string | null = null; - try { - const urlObj = new URL(url); - const pathParts = urlObj.pathname.split("/").filter(Boolean); - const lastPart = pathParts[pathParts.length - 1] ?? ""; - urlSlug = normalizeSkillSlug(lastPart.replace(/\.md$/i, "")); - } catch (err) { - logger.warn(`[skill-import] Unable to parse skill URL for slug derivation (${url}):`, err instanceof Error ? err.message : String(err)); - } - const rawSlug = - normalizeSkillSlug(parsed.frontmatter.slug as string | undefined) ?? - urlSlug ?? - "skill"; - - const inventory: FileInventoryEntry[] = [ - { path: "SKILL.md", kind: "skill" }, - ]; - const trustLevel = "markdown_only" as const; - - const key = deriveCanonicalSkillKey(companyId, { - slug: rawSlug, - sourceType: "url", - sourceLocator: url, - metadata: null, - }); - - const skillId = randomUUID(); - await materializeSkillFiles(skillFilesDir(companyId, rawSlug), [ - { path: "SKILL.md", kind: "skill", content: markdown }, - ]); - - const { isUpdate } = db.core.skills.upsertCompanySkill({ - id: skillId, - companyId, - key, - slug: rawSlug, - name: (typeof parsed.frontmatter.name === "string" ? parsed.frontmatter.name : null) ?? rawSlug, - description: typeof parsed.frontmatter.description === "string" ? parsed.frontmatter.description : null, - sourceType: "url", - sourceLocator: url, - sourceRef: null, - trustLevel, - compatibility: "compatible", - fileInventory: JSON.stringify(inventory), - metadata: null, - createdAt: nowTs, - updatedAt: nowTs, - }); - - const results: SkillImportResult[] = [ - { skillId, key, name: rawSlug, isUpdate }, - ]; - logger.info(`Skill ${isUpdate ? "updated" : "imported"} from URL: ${key}`); - return results; -} diff --git a/src/main/skills/import.ts b/src/main/skills/import.ts deleted file mode 100644 index 67c2254d..00000000 --- a/src/main/skills/import.ts +++ /dev/null @@ -1,132 +0,0 @@ -import type { AppDatabase } from "../database"; -import type { DesktopResult } from "@shared/contracts"; -import type { SkillImportResult } from "../skill-types.js"; -import { parseSkillImportSource } from "../skill-keys.js"; -import { createGitHubImporter } from "./import-github"; -import { - findSkillMdFiles as findSkillMdFilesImpl, - buildLocalInventory as buildLocalInventoryImpl, -} from "./discovery"; -import { cleanupSkillFilesDir } from "./materialize"; -import { importFromLocal as importFromLocalImpl } from "./import-local"; -import { importFromUrl as importFromUrlImpl } from "./import-url"; - -interface ImportDeps { - db: AppDatabase; - profileDir: string; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - skillsRoot: (companyId: string) => string; - skillFilesDir: (companyId: string, slug: string) => string; -} - -export function createSkillImporter({ db, profileDir: _profileDir, logger, skillsRoot: _skillsRoot, skillFilesDir }: ImportDeps) { - function ok(data: T): DesktopResult { - return { ok: true, data }; - } - function fail(code: string, message: string): DesktopResult { - return { ok: false, error: { code, message } }; - } - - const ghImporter = createGitHubImporter({ db, logger, skillFilesDir }); - const ctx = { db, logger, skillFilesDir }; - - async function cleanupSkillFiles(companyId: string, slug: string): Promise { - await cleanupSkillFilesDir(skillFilesDir(companyId, slug)); - } - - async function importFromLocal( - companyId: string, - localPath: string, - ): Promise { - return importFromLocalImpl(ctx, companyId, localPath); - } - - async function importFromUrl( - companyId: string, - url: string, - safeFetch: (target: string) => Promise, - ): Promise { - return importFromUrlImpl(ctx, companyId, url, safeFetch); - } - - function findSkillMdFiles( - rootDir: string, - opts?: { maxDepth?: number; maxFiles?: number }, - ): string[] { - return findSkillMdFilesImpl(rootDir, logger, opts); - } - - function buildLocalInventory( - skillDir: string, - skillMdPath: string, - opts?: { maxDepth?: number; maxFiles?: number }, - ) { - return buildLocalInventoryImpl(skillDir, skillMdPath, logger, opts); - } - - async function importFromSource( - companyId: string, - rawSource: string, - ): Promise> { - try { - const parsed = parseSkillImportSource(rawSource); - const source = parsed.resolvedSource; - - if (parsed.originalSkillsShUrl) { - const results = await ghImporter.importFromGitHub( - companyId, - source, - parsed.requestedSkillSlug, - parsed.originalSkillsShUrl, - ); - return ok(results); - } - - if (source.includes("github.com")) { - const results = await ghImporter.importFromGitHub( - companyId, - source, - parsed.requestedSkillSlug, - null, - ); - return ok(results); - } - - if ( - source.startsWith("/") || - /^[A-Za-z]:/.test(source) || - source.startsWith("~") - ) { - const results = await importFromLocal(companyId, source); - return ok(results); - } - - if (/^https?:\/\//i.test(source)) { - const { fetchWithSsrfProtection } = await import("./url-validation"); - const results = await importFromUrl(companyId, source, fetchWithSsrfProtection); - return ok(results); - } - - return fail("invalid_source", `Unrecognized skill source format: ${rawSource}`); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.error("Skill import failed:", message); - return fail("import_error", message); - } - } - - return { - importFromSource, - importFromGitHub: ghImporter.importFromGitHub, - importFromLocal, - importFromUrl, - cleanupSkillFiles, - parseGitHubUrl: ghImporter.parseGitHubUrl, - findSkillMdFiles, - buildLocalInventory, - }; -} diff --git a/src/main/skills/index.ts b/src/main/skills/index.ts deleted file mode 100644 index 982d3a6f..00000000 --- a/src/main/skills/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { join } from "node:path"; -import type { AppDatabase } from "../database"; -import { createSkillImporter } from "./import"; -import { createSkillCrud } from "./crud"; -import { createSkillRuntime } from "./runtime"; - -interface SkillServiceDependencies { - db: AppDatabase; - profileDir: string; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export function createSkillService({ db, profileDir, logger }: SkillServiceDependencies) { - function skillsRoot(companyId: string): string { - return join(profileDir, "skills", companyId); - } - - function skillFilesDir(companyId: string, slug: string): string { - return join(skillsRoot(companyId), slug); - } - - function runtimeDir(companyId: string): string { - return join(skillsRoot(companyId), "__runtime__"); - } - void runtimeDir; // used externally if needed - - const importer = createSkillImporter({ db, profileDir, logger, skillsRoot, skillFilesDir }); - const crud = createSkillCrud({ - db, - logger, - cleanupSkillFiles: importer.cleanupSkillFiles, - parseGitHubUrl: importer.parseGitHubUrl, - }); - const runtime = createSkillRuntime({ - db, - profileDir, - logger, - skillsRoot, - skillFilesDir, - importFromLocal: importer.importFromLocal, - }); - - return { - importFromSource: importer.importFromSource, - importFromGitHub: importer.importFromGitHub, - importFromLocal: importer.importFromLocal, - importFromUrl: importer.importFromUrl, - listForCompany: crud.listForCompany, - getDetail: crud.getDetail, - deleteSkill: crud.deleteSkill, - assignToAgent: crud.assignToAgent, - removeFromAgent: crud.removeFromAgent, - checkUpdateStatus: crud.checkUpdateStatus, - listRuntimeSkillEntries: runtime.listRuntimeSkillEntries, - scanWorkspaceSkills: runtime.scanWorkspaceSkills, - seedBuiltinSkills: runtime.seedBuiltinSkills, - skillFilesDir, - }; -} diff --git a/src/main/skills/materialize.ts b/src/main/skills/materialize.ts deleted file mode 100644 index 9f8b1f90..00000000 --- a/src/main/skills/materialize.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { existsSync } from "node:fs"; -import { mkdir, rename, writeFile, rm } from "node:fs/promises"; -import { randomUUID } from "node:crypto"; -import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path"; -import type { FileInventoryEntry } from "../skill-types.js"; -import { MAX_SKILL_BYTES, MAX_SKILL_FILE_BYTES, MAX_TOTAL_BYTES } from "../skill-github.js"; - -export interface MaterializedSkillFile extends FileInventoryEntry { - content: string | Uint8Array; -} - -interface PreparedSkillFile extends FileInventoryEntry { - content: Uint8Array; -} - -const MATERIALIZED_FILE_MODE = 0o600; -const MATERIALIZED_SCRIPT_MODE = 0o700; -const MATERIALIZED_DIR_MODE = 0o700; - -export function normalizeMaterializedRelativePath(filePath: string): string { - if (filePath.includes("\0")) { - throw new Error("Skill file path contains a null byte"); - } - const normalized = filePath.replace(/\\/g, "/"); - if (normalized !== filePath) { - throw new Error(`Skill file path must use POSIX separators: ${filePath}`); - } - if (normalized.length === 0 || normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized)) { - throw new Error(`Skill file path must be relative: ${filePath}`); - } - const parts = normalized.split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw new Error(`Skill file path contains traversal segments: ${filePath}`); - } - return parts.join("/"); -} - -function encodeContent(content: string | Uint8Array): Uint8Array { - if (typeof content === "string") { - return Buffer.from(content, "utf-8"); - } - return content; -} - -function ensureTargetInsideRoot(rootDir: string, targetPath: string, relativePath: string): void { - const root = resolve(rootDir); - const targetRelative = relative(root, targetPath); - if (targetRelative.length === 0 || targetRelative.startsWith("..") || isAbsolute(targetRelative)) { - throw new Error(`Skill file path escapes materialization root: ${relativePath}`); - } -} - -function prepareMaterializedFiles(files: MaterializedSkillFile[]): PreparedSkillFile[] { - const seen = new Set(); - const prepared: PreparedSkillFile[] = []; - let totalBytes = 0; - let hasRootSkill = false; - - for (const file of files) { - const path = normalizeMaterializedRelativePath(file.path); - const duplicateKey = process.platform === "win32" ? path.toLowerCase() : path; - if (seen.has(duplicateKey)) { - throw new Error(`Duplicate skill file path: ${path}`); - } - seen.add(duplicateKey); - - const content = encodeContent(file.content); - const maxBytes = path === "SKILL.md" ? MAX_SKILL_BYTES : MAX_SKILL_FILE_BYTES; - if (content.byteLength > maxBytes) { - throw new Error(`${path} exceeds ${maxBytes}-byte limit`); - } - totalBytes += content.byteLength; - if (totalBytes > MAX_TOTAL_BYTES) { - throw new Error(`Skill package exceeded aggregate limit of ${MAX_TOTAL_BYTES} bytes`); - } - if (path === "SKILL.md") { - hasRootSkill = true; - } - prepared.push({ path, kind: file.kind, content }); - } - - if (!hasRootSkill) { - throw new Error("Skill package is missing SKILL.md"); - } - return prepared; -} - -async function replaceDirectoryWithFiles(dir: string, files: PreparedSkillFile[]): Promise { - const parentDir = dirname(dir); - const dirName = basename(dir); - const stagingDir = join(parentDir, `.${dirName}.${randomUUID()}.tmp`); - let backupDir: string | null = null; - - await mkdir(parentDir, { recursive: true, mode: MATERIALIZED_DIR_MODE }); - await mkdir(stagingDir, { recursive: true, mode: MATERIALIZED_DIR_MODE }); - - try { - for (const file of files) { - const target = resolve(stagingDir, ...file.path.split("/")); - ensureTargetInsideRoot(stagingDir, target, file.path); - await mkdir(dirname(target), { recursive: true, mode: MATERIALIZED_DIR_MODE }); - await writeFile(target, file.content, { - mode: file.kind === "script" ? MATERIALIZED_SCRIPT_MODE : MATERIALIZED_FILE_MODE, - }); - } - - if (existsSync(dir)) { - backupDir = join(parentDir, `.${dirName}.${randomUUID()}.old`); - await rename(dir, backupDir); - } - - try { - await rename(stagingDir, dir); - } catch (error) { - if (backupDir && existsSync(backupDir)) { - await rename(backupDir, dir); - backupDir = null; - } - throw error; - } - - if (backupDir) { - await rm(backupDir, { recursive: true, force: true }); - backupDir = null; - } - } finally { - await rm(stagingDir, { recursive: true, force: true }); - if (backupDir) { - await rm(backupDir, { recursive: true, force: true }); - } - } -} - -export async function materializeSkillFiles( - dir: string, - files: MaterializedSkillFile[], -): Promise { - const prepared = prepareMaterializedFiles(files); - await replaceDirectoryWithFiles(dir, prepared); - return dir; -} - -export async function cleanupSkillFilesDir(dir: string): Promise { - if (existsSync(dir)) { - await rm(dir, { recursive: true, force: true }); - } -} diff --git a/src/main/skills/read-response-with-limit.ts b/src/main/skills/read-response-with-limit.ts deleted file mode 100644 index bee93ffb..00000000 --- a/src/main/skills/read-response-with-limit.ts +++ /dev/null @@ -1,72 +0,0 @@ -const encoder = new TextEncoder(); -const decoder = new TextDecoder(); - -function assertValidByteLimit(maxBytes: number): void { - if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) { - throw new Error(`Invalid response byte limit: ${maxBytes}`); - } -} - -function validateContentLength(response: Response, maxBytes: number): void { - const contentLengthHeader = response.headers.get("Content-Length"); - if (contentLengthHeader !== null) { - const contentLength = Number(contentLengthHeader); - if (!Number.isSafeInteger(contentLength) || contentLength < 0) { - throw new Error(`Invalid Content-Length header: ${contentLengthHeader}`); - } - if (contentLength > maxBytes) { - throw new Error(`Response too large: ${contentLength} bytes (max ${maxBytes})`); - } - } -} - -function assertWithinLimit(byteLength: number, maxBytes: number): void { - if (byteLength > maxBytes) { - throw new Error(`Response body exceeded ${maxBytes} bytes`); - } -} - -export async function readResponseBytesWithLimit(response: Response, maxBytes: number): Promise { - assertValidByteLimit(maxBytes); - validateContentLength(response, maxBytes); - - const reader = response.body?.getReader(); - if (!reader) { - if (typeof response.arrayBuffer === "function") { - const bytes = new Uint8Array(await response.arrayBuffer()); - assertWithinLimit(bytes.byteLength, maxBytes); - return bytes; - } - const text = await response.text(); - const bytes = encoder.encode(text); - assertWithinLimit(bytes.byteLength, maxBytes); - return bytes; - } - - const chunks: Uint8Array[] = []; - let totalBytes = 0; - - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - totalBytes += value.byteLength; - if (totalBytes > maxBytes) { - await reader.cancel(); - assertWithinLimit(totalBytes, maxBytes); - } - chunks.push(value); - } - - const body = new Uint8Array(totalBytes); - let offset = 0; - for (const chunk of chunks) { - body.set(chunk, offset); - offset += chunk.byteLength; - } - - return body; -} - -export async function readResponseWithLimit(response: Response, maxBytes: number): Promise { - return decoder.decode(await readResponseBytesWithLimit(response, maxBytes)); -} diff --git a/src/main/skills/runtime.ts b/src/main/skills/runtime.ts deleted file mode 100644 index abaf54f5..00000000 --- a/src/main/skills/runtime.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { existsSync, statSync } from "node:fs"; -import { join } from "node:path"; -import { loadSkills } from "@mariozechner/pi-coding-agent"; -import type { AppDatabase } from "../database"; -import type { SkillImportResult, ProjectedSkill } from "../skill-types.js"; -import { classifyUnknownError } from "../errors/index.js"; - -interface RuntimeDeps { - db: AppDatabase; - profileDir: string; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - skillsRoot: (companyId: string) => string; - skillFilesDir: (companyId: string, slug: string) => string; - importFromLocal: (companyId: string, localPath: string) => Promise; -} - -export function createSkillRuntime({ db, logger, skillsRoot, skillFilesDir, importFromLocal }: RuntimeDeps) { - /** - * Project the agent's assigned skills through pi-coding-agent's - * progressive-disclosure loader. Users curate skill visibility per agent - * via `agent_skill_assignments`; runtime honors that selection by only - * passing assigned SKILL.md directories to `loadSkills`. Pi returns - * descriptions for the system prompt; the agent loads full SKILL.md - * on demand via the `read` tool. - * - * connectorId is retained for signature compatibility and reserved for - * future connector-specific policy (no current use). - */ - function listRuntimeSkillEntries( - companyId: string, - agentId: string, - _connectorId: string, - ): ProjectedSkill[] { - const assignedIds = new Set(db.core.skills.listAgentSkillAssignments(companyId, agentId)); - if (assignedIds.size === 0) return []; - const companySkills = db.core.skills.listCompanySkills(companyId); - const skillPaths = companySkills - .filter((s) => assignedIds.has(s.id)) - .map((s) => skillFilesDir(companyId, s.slug)); - if (skillPaths.length === 0) return []; - const { skills, diagnostics } = loadSkills({ skillPaths, includeDefaults: false }); - - for (const diag of diagnostics) { - if (diag.type === "warning") { - logger.warn(`[skills] ${diag.message} (${diag.path})`); - } - } - - return skills.map((s) => ({ - name: s.name, - description: s.description, - filePath: s.filePath, - baseDir: s.baseDir, - })); - } - - /** - * Scan all workspace local paths for a company, looking for - * `.agentcompany/skills/` directories containing SKILL.md files. - */ - async function scanWorkspaceSkills( - companyId: string, - ): Promise { - const allResults: SkillImportResult[] = []; - - const profileSkillsDir = skillsRoot(companyId); - if (existsSync(profileSkillsDir)) { - try { - const stat = statSync(profileSkillsDir); - if (stat.isDirectory()) { - const results = await importFromLocal(companyId, profileSkillsDir); - allResults.push(...results); - logger.info(`Scanned profile skills: ${profileSkillsDir} — imported ${results.length} skill(s)`); - } - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.warn(`Failed to scan profile skills at ${profileSkillsDir}: ${message}`); - } - } - - const workspacePaths = db.core.workspaces.listWorkspaceLocalPaths(companyId); - for (const wsPath of workspacePaths) { - const agentcompanySkillsDir = join(wsPath, ".agentcompany", "skills"); - if (!existsSync(agentcompanySkillsDir)) continue; - - try { - const stat = statSync(agentcompanySkillsDir); - if (!stat.isDirectory()) continue; - - const results = await importFromLocal(companyId, agentcompanySkillsDir); - allResults.push(...results); - logger.info( - `Scanned workspace skills: ${agentcompanySkillsDir} — imported ${results.length} skill(s)`, - ); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.warn(`Failed to scan workspace skills at ${agentcompanySkillsDir}: ${message}`); - } - } - - return allResults; - } - - function getBuiltinSkillsDir(): string | null { - if (process.resourcesPath) { - const resourcesPath = join(process.resourcesPath, "builtin-skills"); - if (existsSync(resourcesPath)) return resourcesPath; - } - const cwdPath = join(process.cwd(), "builtin-skills"); - if (existsSync(cwdPath)) return cwdPath; - return null; - } - - async function seedBuiltinSkills(companyId: string): Promise { - const builtinDir = getBuiltinSkillsDir(); - if (!builtinDir) { - logger.warn("[skills] Builtin skills directory not found — skipping seed."); - return []; - } - - const allResults: SkillImportResult[] = []; - - let categories: string[]; - try { - const { readdirSync, statSync: statSyncLocal } = await import("node:fs"); - categories = readdirSync(builtinDir).filter(name => { - if (name.startsWith(".")) return false; - try { - return statSyncLocal(join(builtinDir, name)).isDirectory(); - } catch (error) { - const classified = classifyUnknownError(error, { - kind: "recoverable", - code: "skills.builtin.stat_failed", - message: `statSync failed for builtin entry ${name}`, - context: { builtinDir, entry: name }, - }); - logger.warn(`[${classified.code}] ${classified.message}: ${error instanceof Error ? error.message : String(error)}`); - return false; - } - }); - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "skills.builtin.readdir_failed", - message: `Failed to read builtin skills directory`, - context: { builtinDir }, - }); - logger.warn(`[${classified.code}] ${classified.message}: ${builtinDir}`); - return []; - } - - for (const category of categories) { - const categoryDir = join(builtinDir, category); - try { - const results = await importFromLocal(companyId, categoryDir); - for (const result of results) { - try { - const skill = db.core.skills.getCompanySkill(companyId, result.skillId); - if (skill) { - const existingMeta = skill.metadata ? JSON.parse(typeof skill.metadata === "string" ? skill.metadata : JSON.stringify(skill.metadata)) : {}; - existingMeta.builtinCategory = category; - existingMeta.sourceKind = "builtin"; - db.core.skills.updateCompanySkillMetadata(companyId, result.skillId, JSON.stringify(existingMeta)); - } - } catch (error) { - logger.warn( - `[skills] metadata update failed for skill ${result.skillId} (category ${category}): ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - allResults.push(...results); - logger.info(`[skills] Seeded ${results.length} builtin skill(s) from category: ${category}`); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - logger.warn(`[skills] Failed to seed builtin category ${category}: ${message}`); - } - } - - return allResults; - } - - return { - listRuntimeSkillEntries, - scanWorkspaceSkills, - seedBuiltinSkills, - }; -} diff --git a/src/main/skills/url-validation.ts b/src/main/skills/url-validation.ts deleted file mode 100644 index f70d6561..00000000 --- a/src/main/skills/url-validation.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { resolve4, resolve6 } from "node:dns/promises"; -import { request, type RequestOptions } from "node:https"; -import type { IncomingHttpHeaders, IncomingMessage } from "node:http"; -import type { LookupFunction } from "node:net"; - -interface ResolvedIpRecord { - address: string; - family: 4 | 6; -} - -const MAX_REDIRECT_HOPS = 5; - -function isPrivateIPv4(ip: string): boolean { - const parts = ip.split(".").map(Number); - if (parts.length !== 4 || parts.some((p) => isNaN(p) || p < 0 || p > 255)) return false; - if (parts[0] === 127) return true; - if (parts[0] === 10) return true; - if (parts[0] === 172 && parts[1]! >= 16 && parts[1]! <= 31) return true; - if (parts[0] === 192 && parts[1] === 168) return true; - if (parts[0] === 169 && parts[1] === 254) return true; - if (parts.every((p) => p === 0)) return true; - return false; -} - -function isPrivateIPv6(ip: string): boolean { - const normalized = ip.toLowerCase().replace(/[[\]]/g, ""); - if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1") return true; - if (normalized === "::" || normalized === "0:0:0:0:0:0:0:0") return true; - if (normalized.startsWith("fe80")) return true; - if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true; - const v4Mapped = normalized.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/); - if (v4Mapped && isPrivateIPv4(v4Mapped[1]!)) return true; - return false; -} - -function hasDeceptiveHostname(hostname: string): boolean { - const first = hostname.split(".")[0] ?? ""; - if (/^0\d/.test(first)) return true; - if (/^0x/i.test(first)) return true; - if (/^\d+$/.test(hostname) && !hostname.includes(".")) return true; - return false; -} - -function assertPublicIps(ips: string[]): void { - for (const ip of ips) { - if (isPrivateIPv4(ip) || isPrivateIPv6(ip)) { - throw new Error(`DNS resolved to private IP ${ip} — possible DNS rebinding attack`); - } - } -} - -export function validateSkillUrl(url: string): void { - const parsed = new URL(url); - if (parsed.protocol !== "https:") { - throw new Error("Only HTTPS URLs are allowed for skill import"); - } - const hostname = parsed.hostname; - if (hasDeceptiveHostname(hostname)) { - throw new Error("Deceptive IP format not allowed for skill import"); - } - if ( - hostname === "localhost" || - hostname === "0.0.0.0" || - isPrivateIPv4(hostname) || - isPrivateIPv6(hostname) - ) { - throw new Error("Private/reserved IP addresses are not allowed for skill import"); - } -} - -/** - * Resolve DNS and validate that all IPs are public. Returns the resolved IPv4 addresses. - */ -export async function resolveAndValidateIps(url: string): Promise { - return (await resolveAndValidateIpRecords(url)) - .filter((record) => record.family === 4) - .map((record) => record.address); -} - -async function resolveAndValidateIpRecords(url: string): Promise { - validateSkillUrl(url); - const { hostname } = new URL(url); - const v4: string[] = []; - const v6: string[] = []; - try { v4.push(...(await resolve4(hostname))); } catch { /* no A records */ } - try { v6.push(...(await resolve6(hostname))); } catch { /* no AAAA records */ } - assertPublicIps([...v4, ...v6]); - return [ - ...v4.map((address): ResolvedIpRecord => ({ address, family: 4 })), - ...v6.map((address): ResolvedIpRecord => ({ address, family: 6 })), - ]; -} - -function buildHeaders(headers: IncomingHttpHeaders): Headers { - const out = new Headers(); - for (const [key, value] of Object.entries(headers)) { - if (Array.isArray(value)) { - for (const entry of value) out.append(key, entry); - } else if (value !== undefined) { - out.set(key, value); - } - } - return out; -} - -function readBody(response: IncomingMessage): Promise { - return new Promise((resolve, reject) => { - const chunks: Buffer[] = []; - response.on("data", (chunk: Buffer | string) => { - chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); - }); - response.on("end", () => resolve(Buffer.concat(chunks))); - response.on("error", reject); - }); -} - -export function buildPinnedHttpsRequestOptions( - parsed: URL, - ip: ResolvedIpRecord, -): RequestOptions { - const lookup: LookupFunction = (_hostname, _options, callback) => { - callback(null, ip.address, ip.family); - }; - return { - method: "GET", - headers: { Host: parsed.host }, - servername: parsed.hostname, - lookup, - }; -} - -async function fetchHttpsWithResolvedIp(url: string, ip: ResolvedIpRecord): Promise { - const parsed = new URL(url); - return new Promise((resolve, reject) => { - const req = request(parsed, buildPinnedHttpsRequestOptions(parsed, ip), async (res) => { - try { - const body = await readBody(res); - const arrayBuffer = new ArrayBuffer(body.byteLength); - new Uint8Array(arrayBuffer).set(body); - resolve(new Response(arrayBuffer, { - status: res.statusCode ?? 500, - statusText: res.statusMessage, - headers: buildHeaders(res.headers), - })); - } catch (error) { - reject(error); - } - }); - req.on("error", reject); - req.end(); - }); -} - -/** - * Fetch a URL with SSRF protection: resolve DNS once, validate IPs, then keep - * the original hostname for Host/SNI while pinning the socket lookup to a - * validated IP. - */ -export async function fetchWithSsrfProtection( - url: string, - state: { visited: Set; hops: number; chain: string[] } = { - visited: new Set(), - hops: 0, - chain: [], - }, -): Promise { - if (state.visited.has(url)) { - throw new Error(`Redirect loop detected while importing skill: ${[...state.chain, url].join(" -> ")}`); - } - if (state.hops > MAX_REDIRECT_HOPS) { - throw new Error(`Too many redirects while importing skill: ${[...state.chain, url].join(" -> ")}`); - } - state.visited.add(url); - state.chain.push(url); - const resolvedIps = await resolveAndValidateIpRecords(url); - if (resolvedIps.length === 0) { - throw new Error("DNS resolution returned no usable addresses"); - } - const response = await fetchHttpsWithResolvedIp(url, resolvedIps[0]!); - // Follow redirects manually to prevent redirect-to-private-IP attacks - if (response.status >= 300 && response.status < 400) { - const location = response.headers.get("location"); - if (!location) { - throw new Error(`Redirect ${response.status} with no Location header`); - } - const redirectUrl = new URL(location, url).toString(); - return fetchWithSsrfProtection(redirectUrl, { - visited: state.visited, - hops: state.hops + 1, - chain: state.chain, - }); - } - return response; -} - -/** @deprecated Use resolveAndValidateIps or fetchWithSsrfProtection instead. */ -export async function validateSkillUrlResolved(url: string): Promise { - await resolveAndValidateIps(url); -} diff --git a/src/main/task-quality-gates.ts b/src/main/task-quality-gates.ts deleted file mode 100644 index dfeb9565..00000000 --- a/src/main/task-quality-gates.ts +++ /dev/null @@ -1,300 +0,0 @@ -/** - * Task Quality Gates — pure validation functions for task creation. - * - * Called by IPC handlers, API server, and automation service to enforce - * minimum description quality, acceptance criteria, and capability matching. - */ - -import log from "electron-log/main.js"; -import type { DesktopEvent } from "@shared/types"; -import type { AppDatabase } from "@main/database"; -import type { NotificationOptions } from "@main/notification-service"; -import type { dispatchAgentMessage } from "@main/messaging/dispatch"; -import type { resolveApprovalDecision } from "@main/approval-policy"; -import { validateTaskRubric } from "@main/task-rubrics"; - -export interface TaskValidationResult { - valid: boolean; - errors: string[]; - warnings: string[]; -} - -interface CapabilityMatchResult { - matched: boolean; - warning?: string; -} - -interface CapabilityMatchDb { - core: { - entity: { - getAgent(id: string): { name: string; capabilities: string }; - }; - skills: { - listAgentSkillAssignments(companyId: string, agentId: string): string[]; - getCompanySkill(companyId: string, skillId: string): { name: string; description: string | null; slug: string } | null; - }; - }; -} - - -const MIN_DESCRIPTION_LENGTH = 50; - -export const ACCEPTANCE_CRITERIA_KEYWORDS: readonly string[] = [ - "acceptance criteria", - "done when", - "success criteria", - "definition of done", - "requirements:", - "must:", - "should:", - "- [ ]", - "- [x]", - "deliverable:", - "expected outcome", - "exit criteria", - // Chinese equivalents so zh-locale task descriptions are not rejected - // for lacking English keywords. - "验收标准", - "完成标准", - "成功标准", - "交付物", - "交付要求", - "完成条件", - "预期结果", - "需求:", - "要求:", -]; - - -export function checkAcceptanceCriteria(description: string): { hasCriteria: boolean; suggestion: string } { - const lower = description.toLowerCase(); - const found = ACCEPTANCE_CRITERIA_KEYWORDS.some((kw) => lower.includes(kw)); - - if (found) { - return { hasCriteria: true, suggestion: "" }; - } - - return { - hasCriteria: false, - suggestion: - 'Task description should include acceptance criteria. Add a "Done when:" or "Acceptance criteria:" section, or use checkbox items (- [ ]) to define success conditions.', - }; -} - - -export function validateTaskCreation( - input: { title: string; description: string; type?: string }, -): TaskValidationResult { - const errors: string[] = []; - const warnings: string[] = []; - - // TASK-01: Minimum description length - if (input.description.length < MIN_DESCRIPTION_LENGTH) { - errors.push( - `Task description must be at least ${MIN_DESCRIPTION_LENGTH} characters (currently ${input.description.length}). Add details about what needs to be done, expected behavior, and any constraints.`, - ); - } - - // TASK-02: Acceptance criteria detection (only check if length passes) - if (input.description.length >= MIN_DESCRIPTION_LENGTH) { - const criteria = checkAcceptanceCriteria(input.description); - if (!criteria.hasCriteria) { - errors.push(criteria.suggestion); - } - } - - // TASK-03: Task-type-specific rubric warnings - if (input.type) { - const rubricResult = validateTaskRubric({ - title: input.title, - description: input.description, - type: input.type, - }); - warnings.push(...rubricResult.warnings); - } - - return { valid: errors.length === 0, errors, warnings }; -} - - -/** Tokenize text into words >3 chars, same pattern as database.ts autoAssignTask */ -function tokenize(text: string): string[] { - return text.toLowerCase().split(/\W+/).filter((w) => w.length > 3); -} - -export function checkCapabilityMatch( - db: CapabilityMatchDb, - agentId: string, - taskDescription: string, - companyId: string, -): CapabilityMatchResult { - const taskWords = tokenize(taskDescription); - - if (taskWords.length === 0) { - return { matched: true, warning: "Task description has no distinctive keywords for capability matching." }; - } - - const agent = db.core.entity.getAgent(agentId); - const capWords = tokenize(agent.capabilities); - const capabilityOverlap = taskWords.filter((w) => capWords.includes(w)).length; - - let skillOverlap = 0; - const skillIds = db.core.skills.listAgentSkillAssignments(companyId, agentId); - for (const skillId of skillIds) { - const skill = db.core.skills.getCompanySkill(companyId, skillId); - if (skill) { - const skillWords = tokenize(`${skill.name} ${skill.description ?? ""} ${skill.slug}`); - skillOverlap += taskWords.filter((w) => skillWords.includes(w)).length; - } - } - - if (capabilityOverlap > 0 || skillOverlap > 0) { - return { matched: true }; - } - - // Agent has no capabilities and no skill overlap — still allow assignment - // but surface the mismatch as a warning so the caller can decide - if (capWords.length === 0 && skillOverlap === 0) { - return { matched: false, warning: `Agent "${agent.name}" has no declared capabilities or matching skills.` }; - } - - // Agent has capabilities but no overlap — warn - return { - matched: false, - warning: `Agent "${agent.name}" may lack skills for this task. Their capabilities (${truncateAtWordBoundary(agent.capabilities, 80)}...) have no overlap with the task description. Consider reassigning.`, - }; -} - -/** Truncate `text` at or before `maxLength`, preferring the last whitespace - * boundary so the warning does not cut mid-word. Falls back to hard slice - * when a single token exceeds `maxLength`. */ -function truncateAtWordBoundary(text: string, maxLength: number): string { - if (text.length <= maxLength) return text; - const slice = text.slice(0, maxLength); - const lastSpace = slice.search(/\s\S*$/); - if (lastSpace > maxLength * 0.5) { - return slice.slice(0, lastSpace); - } - return slice; -} - - -export const REVIEW_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes (D-08) - -export interface SweepStaleReviewsDeps { - db: AppDatabase; - dispatchAgentMessage: typeof dispatchAgentMessage; - resolveApprovalDecision: typeof resolveApprovalDecision; - notify: (options: NotificationOptions) => void; - handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; - handleApprovalResolved: (approvalId: string, companyId: string, decision: string) => void; - emitEvent: (event: DesktopEvent) => void; - publishDomainChanged: () => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - getCompanyExecutionMode: (companyId: string) => string; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void }; -} - -export function sweepStaleReviews( - companyId: string, - deps: SweepStaleReviewsDeps, - now: number = Date.now(), -): number { - const isCofounderMode = deps.getCompanyExecutionMode(companyId) === "ai_cofounder"; - - let escalatedCount = 0; - const reviewTasks = deps.db.core.tasks.listReviewTasksForSweep(companyId); - - for (const task of reviewTasks) { - const reviewAge = now - new Date(task.updatedAt).getTime(); - if (reviewAge < REVIEW_TIMEOUT_MS) continue; - if (!task.assigneeAgentId) continue; - - // The reviewer is the assignee's direct manager - const reviewer = deps.db.core.agents.getManagerForAgent(task.assigneeAgentId); - if (!reviewer) continue; // No manager = CEO-assigned task, skip escalation - - // D-09: Escalate to the reviewer's manager (manager's manager) - const chain = deps.db.core.agents.getChainOfCommand(reviewer.id); - const escalationTarget = chain.length > 0 ? chain[0] : null; - - const pendingApproval = deps.db.core.approvals.findPendingApprovalForTask(companyId, task.id); - - // In ai_cofounder mode, ALL approvals require human decision — never auto-advance. - if (isCofounderMode && pendingApproval) { - deps.notify({ - title: "Your Review Required", - body: `"${task.title}" is waiting for your review. AI Co-Founder mode requires human sign-off.`, - urgency: "critical", - navigation: { section: "approvals", entityId: pendingApproval.id }, - batchKey: "cofounder_review_needed", - }); - deps.logger.info("[sweepStaleReviews] Skipping auto-approval for co-founder task", { - taskId: task.id, - approvalType: pendingApproval.type, - }); - continue; - } - - if (escalationTarget) { - deps.dispatchAgentMessage( - { - db: deps.db, - emitEvent: deps.emitEvent, - publishDomainChanged: deps.publishDomainChanged, - wakeAgentIfPossible: deps.wakeAgentIfPossible, - }, - { - companyId, - fromAgentId: reviewer.id, - toAgentId: escalationTarget.id, - channel: "direct", - subject: `Review timeout: ${task.title}`, - body: `Review by ${reviewer.name} on "${task.title}" has been pending for over 30 minutes. Auto-escalating.`, - priority: "urgent", - }, - "subtask_completed", - ); - } else { - // D-09: No higher manager (reviewer is CEO) -- notify human - deps.notify({ - title: "Review Timeout", - body: `"${task.title}" review has been pending over 30 minutes. Auto-approving.`, - urgency: "critical", - navigation: { section: "tasks", entityId: task.id }, - batchKey: "review_escalation", - }); - } - - // D-10: Auto-approve any pending approval linked to this task. - // In ai_cofounder mode, protected approval types are already handled above (continue). - if (pendingApproval) { - try { - deps.resolveApprovalDecision({ - db: deps.db, - handleApprovalResolved: deps.handleApprovalResolved, - companyId, - approvalId: pendingApproval.id, - state: "approved", - decisionNote: "Auto-approved: review timeout exceeded 30 minutes.", - detail: "Auto-approved by review timeout escalation", - actor: "system", - }); - } catch (err) { - log.warn(`[task-quality-gates] resolveApprovalDecision failed for approval ${pendingApproval.id} (likely already decided):`, err instanceof Error ? err.message : String(err)); - } - } - - // D-10: Advance task status from in_review to done - try { - deps.db.core.tasks.advanceTaskStatus(task.id, "done", "Auto-advanced: review timeout exceeded 30 minutes."); - deps.handleTaskStatusChange(task.id, companyId, "in_review", "done"); - } catch (err) { - log.warn(`[task-quality-gates] advanceTaskStatus failed for task ${task.id}:`, err instanceof Error ? err.message : String(err)); - } - - escalatedCount++; - } - - return escalatedCount; -} diff --git a/src/main/task-rubrics.ts b/src/main/task-rubrics.ts deleted file mode 100644 index 6c94a55a..00000000 --- a/src/main/task-rubrics.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Task-type-specific business rubrics for quality validation. - * - * Imported by task-quality-gates.ts to extend validateTaskCreation with - * domain-aware checks for research, content, management, and other task types. - */ - -import type { TaskType } from "@shared/types/enums"; - -export interface TaskRubric { - /** Sections the task description should contain (case-insensitive substring match). */ - requiredSections: string[]; - /** Keywords that signal the brief is grounded in quality criteria. */ - qualityKeywords: string[]; - /** Minimum description length for this task type. */ - minDescriptionLength: number; - /** Human-readable template hint shown in warnings when sections are missing. */ - briefTemplate: string; -} - -/** - * Default rubric used by task types that carry no type-specific quality - * expectations. Single source of truth so "general" and "code" cannot drift. - */ -const DEFAULT_RUBRIC: TaskRubric = { - requiredSections: [], - qualityKeywords: [], - minDescriptionLength: 50, - briefTemplate: "", -}; - -const RUBRICS: Record = { - research: { - requiredSections: ["research question", "methodology", "sources", "expected findings"], - qualityKeywords: ["data", "evidence", "analysis", "comparison", "findings"], - minDescriptionLength: 100, - briefTemplate: - "A research task brief should cover: Research Question, Methodology, Sources to consult, and Expected Findings.", - }, - content: { - requiredSections: ["target audience", "brand voice", "key messages", "format"], - qualityKeywords: ["audience", "tone", "call to action", "engagement", "headline"], - minDescriptionLength: 80, - briefTemplate: - "A content task brief should cover: Target Audience, Brand Voice, Key Messages, and Format (e.g., blog post, social copy, email).", - }, - management: { - requiredSections: ["objective", "stakeholders", "timeline", "success metrics"], - qualityKeywords: ["milestone", "deliverable", "risk", "dependency", "alignment"], - minDescriptionLength: 80, - briefTemplate: - "A management task brief should cover: Objective, Stakeholders, Timeline, and Success Metrics.", - }, - general: DEFAULT_RUBRIC, - code: DEFAULT_RUBRIC, -}; - -/** Returns the rubric for the given task type, defaulting to "general" for unknown values. */ -function getTaskTypeRubric(taskType: string): TaskRubric { - const key = taskType as TaskType; - return RUBRICS[key] ?? DEFAULT_RUBRIC; -} - -/** - * Validates a task input against the type-specific rubric. - * Returns warnings (not errors) — missing sections are advisory, - * not blockers, to avoid rejecting valid heterodox formats. - */ -export function validateTaskRubric(input: { - title: string; - description: string; - type: string; -}): { warnings: string[] } { - const rubric = getTaskTypeRubric(input.type); - const warnings: string[] = []; - - // No extra checks needed for code/general types - if (rubric.requiredSections.length === 0) { - return { warnings }; - } - - const lower = input.description.toLowerCase(); - - const missingSections = rubric.requiredSections.filter( - (section) => !lower.includes(section.toLowerCase()), - ); - - if (missingSections.length > 0) { - const listed = missingSections.map((s) => `"${s}"`).join(", "); - warnings.push( - `${capitalizeFirst(input.type)} task is missing recommended sections: ${listed}. ${rubric.briefTemplate}`, - ); - } - - return { warnings }; -} - -function capitalizeFirst(s: string): string { - return s.charAt(0).toUpperCase() + s.slice(1); -} diff --git a/src/main/task-workspace-binding.ts b/src/main/task-workspace-binding.ts deleted file mode 100644 index 73c1b500..00000000 --- a/src/main/task-workspace-binding.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { AppDatabase } from "./database"; - -type WorkspaceBindingSource = - | "explicit" - | "project" - | "assignee" - | "run" - | "creator" - | "single_company" - | "none"; - -export type TaskWorkspaceBindingResult = - | { ok: true; workspaceId: string | null; source: WorkspaceBindingSource } - | { ok: false; error: string }; - -export interface TaskWorkspaceBindingInput { - companyId: string; - requiresFilesystem: boolean; - explicitWorkspaceId?: string | null; - projectId?: string | null; - assigneeAgentId?: string | null; - creatorAgentId?: string | null; - currentRunId?: string | null; -} - -export function resolveTaskWorkspaceBinding( - db: AppDatabase, - input: TaskWorkspaceBindingInput, -): TaskWorkspaceBindingResult { - if (input.explicitWorkspaceId) { - const explicit = getCompanyWorkspace(db, input.companyId, input.explicitWorkspaceId); - if (!explicit) { - return { ok: false, error: "Selected workspace does not belong to this company." }; - } - return { ok: true, workspaceId: explicit.id, source: "explicit" }; - } - - if (!input.requiresFilesystem) { - return { - ok: true, - workspaceId: null, - source: "none", - }; - } - - const project = db.core.workspaces.getProjectPrimaryWorkspace(input.projectId ?? null, input.companyId); - if (project) return { ok: true, workspaceId: project.id, source: "project" }; - - const assignee = getAgentWorkspace(db, input.companyId, input.assigneeAgentId ?? null); - if (assignee) return { ok: true, workspaceId: assignee.id, source: "assignee" }; - - const run = getRunWorkspace(db, input.companyId, input.currentRunId ?? null); - if (run) return { ok: true, workspaceId: run.id, source: "run" }; - - const creator = getAgentWorkspace(db, input.companyId, input.creatorAgentId ?? null); - if (creator) return { ok: true, workspaceId: creator.id, source: "creator" }; - - const singleCompanyWorkspace = getSingleCompanyWorkspace(db, input.companyId); - if (singleCompanyWorkspace) { - return { ok: true, workspaceId: singleCompanyWorkspace.id, source: "single_company" }; - } - - return { - ok: false, - error: "Filesystem tasks require a workspace. Provide workspaceId, bind the project to a workspace, or bind the assignee/creator agent to a workspace.", - }; -} - -function getCompanyWorkspace(db: AppDatabase, companyId: string, workspaceId: string | null): { id: string } | null { - if (!workspaceId) return null; - const workspace = db.core.workspaces.getWorkspace(workspaceId); - return workspace && workspace.companyId === companyId ? workspace : null; -} - -function getAgentWorkspace(db: AppDatabase, companyId: string, agentId: string | null): { id: string } | null { - if (!agentId) return null; - try { - const agent = db.core.entity.getAgent(agentId); - if (agent.companyId !== companyId) return null; - return getCompanyWorkspace(db, companyId, agent.workspaceId); - } catch { - return null; - } -} - -function getRunWorkspace(db: AppDatabase, companyId: string, runId: string | null): { id: string } | null { - if (!runId) return null; - try { - const run = db.core.runs.getRun(runId); - if (run.companyId !== companyId) return null; - return getCompanyWorkspace(db, companyId, run.workspaceId); - } catch { - return null; - } -} - -function getSingleCompanyWorkspace(db: AppDatabase, companyId: string): { id: string } | null { - const workspaces = db.projection.snapshot - .listSnapshot({ companyId }) - .workspaces - .filter((workspace) => workspace.companyId === companyId); - return workspaces.length === 1 ? workspaces[0]! : null; -} diff --git a/src/main/thread-integration/index.ts b/src/main/thread-integration/index.ts deleted file mode 100644 index e2b66111..00000000 --- a/src/main/thread-integration/index.ts +++ /dev/null @@ -1,385 +0,0 @@ -/** Thread Integration — wires thread runtime into orchestration callbacks. */ - -import type { ExecutionMode } from "@shared/types"; -import { classifyUnknownError } from "../errors"; -import { - type ThreadIntegrationDeps, - findTaskThread, - ensureTaskThread, - ensureApprovalThread, - announceApprovalToBoard, - notifyThreadSubscribers, -} from "./thread-helpers"; - -export type { ThreadIntegrationDeps } from "./thread-helpers"; - -function throwThreadIntegrationError( - logger: ThreadIntegrationDeps["logger"], - operation: string, - error: unknown, - context: Record, -): never { - const classified = classifyUnknownError(error, { - kind: "upstream", - code: `thread.integration.${operation}.failed`, - message: `Thread integration ${operation} failed`, - context, - }); - logger.error(`[${classified.code}] ${classified.message}: ${error instanceof Error ? error.message : String(error)}`); - throw classified; -} - -export function createThreadIntegration({ db, logger, emitEvent, publishDomainChanged, notify }: ThreadIntegrationDeps) { - return { - /** - * Called when a new task is created. - * Creates a thread for the task and records the creation event. - */ - onTaskCreated(taskId: string, companyId: string): void { - try { - const task = db.core.entity.getTask(taskId); - if (task.companyId !== companyId) return; - - const thread = ensureTaskThread(db, taskId, companyId, task.title); - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: task.assigneeAgentId ?? "system", - actorType: task.assigneeAgentId ? "agent" : "system", - eventType: "system_note", - body: `Task created: "${task.title}"`, - metadataJson: JSON.stringify({ taskId, status: task.status, priority: task.priority }), - }); - - // Auto-enroll assignee and human as participants - if (task.assigneeAgentId) { - db.core.threads.addParticipant({ threadId: thread.id, participantId: task.assigneeAgentId, participantType: "agent", role: "owner" }); - db.core.threads.subscribe({ threadId: thread.id, subscriberId: task.assigneeAgentId, subscriberType: "agent" }); - } - db.core.threads.addParticipant({ threadId: thread.id, participantId: "user", participantType: "user", role: "observer" }); - db.core.threads.subscribe({ threadId: thread.id, subscriberId: "user", subscriberType: "user" }); - } catch (err) { - logger.error(`[thread-integration] onTaskCreated failed: ${err instanceof Error ? err.message : String(err)}`); - } - }, - - /** - * Called when a task's status changes. - * Records the transition as a thread event. - * In ai_cofounder mode, creates a wait state when task enters review. - */ - onTaskStatusChanged(taskId: string, companyId: string, previousStatus: string, newStatus: string): void { - try { - const task = db.core.entity.getTask(taskId); - if (task.companyId !== companyId) return; - - const thread = ensureTaskThread(db, taskId, companyId, task.title); - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: task.assigneeAgentId ?? "system", - actorType: task.assigneeAgentId ? "agent" : "system", - eventType: "status_change", - body: `${previousStatus} → ${newStatus}`, - metadataJson: JSON.stringify({ taskId, previousStatus, newStatus }), - }); - - // In co-founder mode, set wait state when task enters review - if (newStatus === "in_review") { - const mode = db.core.company.getCompanyExecutionMode(companyId) as ExecutionMode; - if (mode === "ai_cofounder") { - const reason = `@Board review needed: Task "${task.title}" is ready for your review.`; - db.core.threads.setThreadWaitState({ - threadId: thread.id, - companyId, - waitingFor: "user_review", - relatedApprovalId: null, - reason, - }); - notifyThreadSubscribers(db, thread.id, task.title, reason, notify); - } - } - - // Resolve wait states when task moves past review - if (previousStatus === "in_review" && (newStatus === "done" || newStatus === "in_progress")) { - const waitStates = db.core.threads.listThreadWaitStates(companyId); - for (const ws of waitStates) { - if (ws.threadId === thread.id && ws.waitingFor === "user_review") { - db.core.threads.resolveThreadWaitState(ws.id, companyId); - } - } - } - } catch (err) { - logger.error(`[thread-integration] onTaskStatusChanged failed: ${err instanceof Error ? err.message : String(err)}`); - } - }, - - /** - * Called when an approval is created (by API server or automation). - * Records the approval request in the task's thread and sets a wait state - * in ai_cofounder mode. - */ - onApprovalCreated(approvalId: string, companyId: string, taskId: string | null, approvalType: string, summary: string): void { - try { - db.withTransaction(() => { - const approval = db.core.approvals.getApprovalRecord(approvalId); - const task = taskId ? db.core.entity.getTask(taskId) : null; - const thread = task - ? ensureTaskThread(db, task.id, companyId, task.title) - : ensureApprovalThread(db, approvalId, companyId, summary || approval.payloadSummary); - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: "system", - actorType: "system", - eventType: "approval_request", - body: summary ? `@Board ${summary}` : `@Board approval required: ${approvalType}`, - metadataJson: JSON.stringify({ approvalId, approvalType }), - }); - - if (approval.requestedByAgentId) { - db.core.threads.addParticipant({ threadId: thread.id, participantId: approval.requestedByAgentId, participantType: "agent", role: "owner" }); - db.core.threads.subscribe({ threadId: thread.id, subscriberId: approval.requestedByAgentId, subscriberType: "agent" }); - } - db.core.threads.addParticipant({ threadId: thread.id, participantId: "user", participantType: "user", role: "observer" }); - db.core.threads.subscribe({ threadId: thread.id, subscriberId: "user", subscriberType: "user" }); - - // In co-founder mode, set wait state for user approval - const mode = db.core.company.getCompanyExecutionMode(companyId) as ExecutionMode; - if (mode === "ai_cofounder") { - const approvalReason = `@Board approval needed: ${approvalType}`; - db.core.threads.setThreadWaitState({ - threadId: thread.id, - companyId, - waitingFor: "user_approval", - relatedApprovalId: approvalId, - reason: approvalReason, - }); - notifyThreadSubscribers(db, thread.id, thread.title, approvalReason, notify); - } - announceApprovalToBoard(db, approval, { emitEvent, publishDomainChanged, logger }); - }); - } catch (err) { - throwThreadIntegrationError(logger, "onApprovalCreated", err, { approvalId, companyId, taskId, approvalType }); - } - }, - - /** - * Called when an approval is resolved (approved/rejected). - * Records the decision in the relevant thread and resolves wait states. - */ - onApprovalResolved(approvalId: string, companyId: string, decision: string): void { - try { - db.withTransaction(() => { - // Resolve any wait states linked to this approval - const waitStates = db.core.threads.listThreadWaitStates(companyId); - for (const ws of waitStates) { - if (ws.relatedApprovalId === approvalId) { - db.core.threads.resolveThreadWaitState(ws.id, companyId); - - // Add decision event to the thread - db.core.threads.addThreadEvent({ - threadId: ws.threadId, - actorId: "user", - actorType: "user", - eventType: "approval_decision", - body: `Approval ${decision}`, - metadataJson: JSON.stringify({ approvalId, decision }), - }); - } - } - }); - } catch (err) { - throwThreadIntegrationError(logger, "onApprovalResolved", err, { approvalId, companyId, decision }); - } - }, - - /** - * Called when a document is created or updated. - * Records in the task thread if linked to a task. - */ - onDocumentCreated(companyId: string, authorAgentId: string | null, taskId: string | null, documentTitle: string): void { - try { - if (!taskId) return; - - db.core.entity.getTask(taskId); // validates task exists and belongs to company - const thread = findTaskThread(db, taskId, companyId); - if (!thread) return; - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: authorAgentId ?? "system", - actorType: authorAgentId ? "agent" : "system", - eventType: "file_attachment", - body: `Document created: "${documentTitle}"`, - metadataJson: JSON.stringify({ taskId, authorAgentId }), - }); - } catch (err) { - logger.error(`[thread-integration] onDocumentCreated failed: ${err instanceof Error ? err.message : String(err)}`); - } - }, - - /** - * Called when a run starts for a task. - * Records the run start in the task thread. - */ - onRunStarted(runId: string, taskId: string | null, agentId: string, companyId: string): void { - if (!taskId) return; - try { - const thread = findTaskThread(db, taskId, companyId); - if (!thread) return; - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: agentId, - actorType: "agent", - eventType: "system_note", - body: "Execution started", - metadataJson: JSON.stringify({ runId, agentId }), - }); - } catch (err) { - logger.error(`[thread-integration] onRunStarted failed: ${err instanceof Error ? err.message : String(err)}`); - } - }, - - /** - * Called when a run finishes (success or failure). - * Records in the task thread. In ai_cofounder mode, creates a - * wait state for user review on successful completion. - */ - onRunFinished(runId: string, taskId: string, agentId: string, companyId: string, status: string, errorMessage: string | null): void { - try { - const thread = findTaskThread(db, taskId, companyId); - if (!thread) return; - - const body = status === "succeeded" - ? "Execution completed successfully" - : `Execution ${status}${errorMessage ? `: ${errorMessage}` : ""}`; - - db.core.threads.addThreadEvent({ - threadId: thread.id, - actorId: agentId, - actorType: "agent", - eventType: "system_note", - body, - metadataJson: JSON.stringify({ runId, status, errorMessage }), - }); - - // In co-founder mode, successful runs create a user_reply wait state - // so the heartbeat pauses until the human reviews the output - if (status === "succeeded") { - const mode = db.core.company.getCompanyExecutionMode(companyId) as ExecutionMode; - if (mode === "ai_cofounder") { - const task = db.core.entity.getTask(taskId); - const completionReason = `@Board review needed: Agent completed work on "${task.title}" — awaiting your review.`; - db.core.threads.setThreadWaitState({ - threadId: thread.id, - companyId, - waitingFor: "user_reply", - relatedApprovalId: null, - reason: completionReason, - }); - notifyThreadSubscribers(db, thread.id, task.title, completionReason, notify); - } - } - } catch (err) { - logger.error(`[thread-integration] onRunFinished failed: ${err instanceof Error ? err.message : String(err)}`); - } - }, - - /** - * Called when a human user sends a message. - * Resolves thread wait states using a precision hierarchy: - * 1. If waitStateId is provided, resolves only that exact wait state (checkpoint-precise). - * 2. Else if threadId is provided, resolves all user_* wait states for that thread. - * 3. Else if toAgentId is provided (direct message), resolves wait states for threads - * assigned to that agent. - * 4. Otherwise (company-wide broadcast), only resolves user_reply wait states. - * user_review and user_approval require scoped resolution via thread or approval UI. - */ - onHumanMessage(companyId: string, toAgentId?: string | null, threadId?: string | null, waitStateId?: string | null): void { - try { - db.withTransaction(() => { - // Most precise: resolve a single identified wait state - if (waitStateId) { - db.core.threads.resolveThreadWaitState(waitStateId, companyId); - return; - } - - // Scoped resolution: threadId or toAgentId resolve all user_* types - const SCOPED_WAIT_TYPES = new Set(["user_reply", "user_review"]); - const isScoped = Boolean(threadId || toAgentId); - - const waitStates = db.core.threads.listThreadWaitStates(companyId); - for (const ws of waitStates) { - if (isScoped) { - if (!SCOPED_WAIT_TYPES.has(ws.waitingFor)) continue; - } else { - // Company-wide fallback: only resolve user_reply to prevent - // accidental resolution of reviews/approvals from casual messages - if (ws.waitingFor !== "user_reply") continue; - } - - if (threadId) { - if (ws.threadId !== threadId) continue; - } else if (toAgentId) { - const thread = db.core.threads.getThread(ws.threadId, companyId); - if (!thread || thread.relatedEntityType !== "task" || !thread.relatedEntityId) continue; - try { - const task = db.core.entity.getTask(thread.relatedEntityId); - if (task.assigneeAgentId !== toAgentId) continue; - } catch (err) { - logger.warn(`[thread-integration] getTask failed for thread ${ws.threadId}:`, err instanceof Error ? err.message : String(err)); - continue; - } - } - - db.core.threads.resolveThreadWaitState(ws.id, companyId); - } - }); - } catch (err) { - throwThreadIntegrationError(logger, "onHumanMessage", err, { companyId, toAgentId, threadId, waitStateId }); - } - }, - - hasUnresolvedWaitStates(companyId: string): boolean { - try { - const waitStates = db.core.threads.listThreadWaitStates(companyId); - return waitStates.length > 0; - } catch (err) { - logger.warn(`[thread-integration] hasUnresolvedWaitStates query failed for company ${companyId}; treating as blocked:`, err instanceof Error ? err.message : String(err)); - return true; - } - }, - - /** - * Checks whether a specific agent has unresolved thread wait states - * across task, approval, and freeform threads. The query lives on - * `db.hasUnresolvedWaitStateForAgent` so the heartbeat scheduler and - * the pi `beforeToolCall` hook share one source of truth. - */ - hasUnresolvedWaitStatesForAgent(companyId: string, agentId: string): boolean { - try { - return db.core.threads.hasUnresolvedWaitStateForAgent(companyId, agentId); - } catch (err) { - logger.warn(`[thread-integration] hasUnresolvedWaitStatesForAgent query failed (company=${companyId} agent=${agentId}); treating as blocked:`, err instanceof Error ? err.message : String(err)); - return true; - } - }, - - /** - * Returns the count of unresolved wait states for a company. - * Used by the inbox to show "waiting on you" badge count. - */ - countUnresolvedWaitStates(companyId: string): number { - try { - return db.core.threads.listThreadWaitStates(companyId).length; - } catch (err) { - logger.warn(`[thread-integration] countUnresolvedWaitStates failed for company ${companyId}:`, err instanceof Error ? err.message : String(err)); - return 0; - } - }, - }; -} - -export type ThreadIntegrationService = ReturnType; diff --git a/src/main/thread-integration/thread-helpers.ts b/src/main/thread-integration/thread-helpers.ts deleted file mode 100644 index 6e288da7..00000000 --- a/src/main/thread-integration/thread-helpers.ts +++ /dev/null @@ -1,189 +0,0 @@ -/** Thread Integration — shared helpers and types. */ - -import type { AppDatabase } from "../database"; -import type { ThreadType } from "@shared/types"; - -export interface ThreadIntegrationDeps { - db: AppDatabase; - logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void; error: (...args: unknown[]) => void }; - emitEvent?: (event: import("@shared/types").DesktopEvent) => void; - publishDomainChanged?: () => void; - notify?: (options: { title: string; body: string }) => void; -} - -export function findTaskThread(db: AppDatabase, taskId: string, companyId: string) { - const existing = db.core.threads.listThreads({ - companyId, - type: "task" as ThreadType, - relatedEntityType: "task", - relatedEntityId: taskId, - limit: 1, - }); - return existing[0] ?? null; -} - -export function ensureTaskThread(db: AppDatabase, taskId: string, companyId: string, title: string) { - const existing = findTaskThread(db, taskId, companyId); - if (existing) return existing; - - return db.core.threads.createThread({ - companyId, - title, - type: "task" as ThreadType, - relatedEntityType: "task", - relatedEntityId: taskId, - }); -} - -export function findAgentCommunicationThread(db: AppDatabase, agentId: string, companyId: string) { - const existing = db.core.threads.listThreads({ - companyId, - type: "general" as ThreadType, - relatedEntityType: "agent", - relatedEntityId: agentId, - limit: 1, - }); - return existing[0] ?? null; -} - -/** - * Returns (or creates) the single "general" thread that accumulates an - * agent's taskless communication activity. Task runs already write into - * a task-scoped thread; taskless communication runs would otherwise drop - * their conversation events on the floor, leaving the thread view blank - * even while the agent actively replies to peers. - */ -export function ensureAgentCommunicationThread( - db: AppDatabase, - agentId: string, - companyId: string, - agentLabel: string, -) { - const existing = findAgentCommunicationThread(db, agentId, companyId); - if (existing) return existing; - - return db.core.threads.createThread({ - companyId, - title: `${agentLabel} · communication`, - type: "general" as ThreadType, - relatedEntityType: "agent", - relatedEntityId: agentId, - }); -} - -export function findApprovalThread(db: AppDatabase, approvalId: string, companyId: string) { - const existing = db.core.threads.listThreads({ - companyId, - type: "approval" as ThreadType, - relatedEntityType: "approval", - relatedEntityId: approvalId, - limit: 1, - }); - return existing[0] ?? null; -} - -export function ensureApprovalThread(db: AppDatabase, approvalId: string, companyId: string, title: string) { - const existing = findApprovalThread(db, approvalId, companyId); - if (existing) return existing; - - return db.core.threads.createThread({ - companyId, - title, - type: "approval" as ThreadType, - relatedEntityType: "approval", - relatedEntityId: approvalId, - }); -} - -function resolveApprovalAnnouncementChannel( - db: AppDatabase, - companyId: string, - taskId: string | null, - requestedByAgentId: string | null, - logger: ThreadIntegrationDeps["logger"], -): { channel: "department" | "project" | "company"; channelTargetId: string | null } | null { - if (requestedByAgentId) { - try { - const requester = db.core.entity.getAgent(requestedByAgentId); - if (requester.companyId === companyId && requester.department) { - return { channel: "department", channelTargetId: requester.department }; - } - } catch (err) { - logger.warn(`[thread-helpers] getAgent failed for requester ${requestedByAgentId}; falling through to task targeting:`, err instanceof Error ? err.message : String(err)); - } - } - - if (taskId) { - try { - const task = db.core.entity.getTask(taskId); - if (task.companyId === companyId && task.projectId) { - return { channel: "project", channelTargetId: task.projectId }; - } - } catch (err) { - logger.warn(`[thread-helpers] getTask failed for task ${taskId}; falling through to company routing:`, err instanceof Error ? err.message : String(err)); - } - } - - return { channel: "company", channelTargetId: null }; -} - -export function announceApprovalToBoard( - db: AppDatabase, - approval: { - id: string; - companyId: string; - relatedTaskId: string | null; - requestedByAgentId: string | null; - payloadSummary: string; - impactSummary: string; - }, - deps: Pick, -): void { - if (!approval.requestedByAgentId || !deps.emitEvent || !deps.publishDomainChanged) return; - - const target = resolveApprovalAnnouncementChannel( - db, - approval.companyId, - approval.relatedTaskId, - approval.requestedByAgentId, - deps.logger, - ); - if (!target) return; - - const messageId = db.core.messages.sendAgentMessage({ - companyId: approval.companyId, - fromAgentId: approval.requestedByAgentId, - channel: target.channel, - channelTargetId: target.channelTargetId, - subject: approval.payloadSummary, - body: `@Board ${approval.impactSummary || approval.payloadSummary}`, - priority: "urgent", - senderKind: "agent", - }); - const message = db.core.messages.getAgentMessage(messageId, approval.companyId); - if (message) { - deps.emitEvent({ type: "new-message", message }); - } - deps.publishDomainChanged(); -} - -/** Check subscriber notifyOn preferences and fire desktop notification. */ -export function notifyThreadSubscribers( - db: AppDatabase, - threadId: string, - threadTitle: string, - eventBody: string, - notify?: (options: { title: string; body: string }) => void, -): void { - if (!notify) return; - const subscriptions = db.core.threads.listSubscriptions(threadId); - for (const sub of subscriptions) { - if (sub.subscriberType !== "user") continue; - if (sub.notifyOn === "none") continue; - if (sub.notifyOn === "mentions") { - if (!eventBody.includes("@You") && !eventBody.includes("@user") && !eventBody.includes("@Board")) continue; - } - notify({ title: threadTitle, body: eventBody }); - break; - } -} diff --git a/src/main/updater-service.ts b/src/main/updater-service.ts deleted file mode 100644 index 665a6f86..00000000 --- a/src/main/updater-service.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { app } from "electron"; -import electronUpdater from "electron-updater"; -import type { AppDatabase } from "./database"; -import type { NotificationOptions } from "./notification-service"; -import { classifyUnknownError } from "./errors/index.js"; - -const { autoUpdater } = electronUpdater; - -interface UpdaterServiceDependencies { - db: AppDatabase; - logger: { - info: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - notify: (options: NotificationOptions) => void; -} - -type SkipUpdateReason = "updates_disabled" | "insecure_url" | "dev_without_real_url"; - -function shouldSkipUpdateCheck(input: { - isPackaged: boolean; - updatesEnabled: boolean; - updateUrl: string | undefined; - updatesDisabledEnv: boolean; -}): SkipUpdateReason | null { - if (!input.updatesEnabled || input.updatesDisabledEnv) { - return "updates_disabled"; - } - if (input.updateUrl && !input.updateUrl.startsWith("https://")) { - return "insecure_url"; - } - if (!input.isPackaged && (!input.updateUrl || input.updateUrl.includes("example.invalid"))) { - return "dev_without_real_url"; - } - return null; -} - -export function createUpdaterService({ - db, - logger, - notify, -}: UpdaterServiceDependencies) { - let listenersAttached = false; - /** - * Set by checkForUpdates({ manual: true }) from the UI. Gates the - * "Up to Date" toast so the auto-every-24h check stays silent when - * nothing happened. Cleared inside the update-not-available handler. - */ - let manualCheckPending = false; - - function attachListeners() { - if (listenersAttached) { - return; - } - listenersAttached = true; - autoUpdater.on("checking-for-update", () => { - logger.info("[updater] checking for updates"); - }); - autoUpdater.on("update-available", (info) => { - logger.info("[updater] update available", info.version); - manualCheckPending = false; - notify({ - title: "Update Available", - body: `Version ${info.version} is downloading in the background`, - urgency: "informational", - navigation: { section: "settings" }, - }); - }); - autoUpdater.on("download-progress", (progress) => { - logger.info("[updater] download progress", { - percent: progress.percent, - transferred: progress.transferred, - total: progress.total, - }); - }); - autoUpdater.on("update-downloaded", (info) => { - logger.info("[updater] update downloaded", info.version); - notify({ - title: "Update Ready", - body: `Version ${info.version} will install when AgentCompany quits`, - urgency: "informational", - navigation: { section: "settings" }, - }); - }); - autoUpdater.on("update-not-available", () => { - if (!manualCheckPending) { - return; - } - manualCheckPending = false; - notify({ - title: "Up to Date", - body: "You are running the latest version", - urgency: "informational", - navigation: { section: "settings" }, - }); - }); - autoUpdater.on("error", (error) => { - logger.error("[updater] error", error); - manualCheckPending = false; - notify({ - title: "Update Check Failed", - body: "Could not check for updates. Try again later.", - urgency: "informational", - navigation: { section: "settings" }, - }); - }); - } - - async function checkForUpdates(options: { manual?: boolean } = {}) { - const snapshot = db.projection.snapshot.listSnapshot(); - const updateUrl = process.env.AGENTCOMPANY_UPDATE_URL?.trim(); - const skipReason = shouldSkipUpdateCheck({ - isPackaged: app.isPackaged, - updatesEnabled: snapshot.updatesEnabled, - updateUrl, - updatesDisabledEnv: process.env.AGENTCOMPANY_DISABLE_UPDATES === "true", - }); - if (skipReason === "insecure_url") { - logger.error("[updater] AGENTCOMPANY_UPDATE_URL must use HTTPS — refusing insecure update source."); - return false; - } - if (skipReason === "dev_without_real_url") { - logger.info("[updater] Skipping update check because no real update URL is configured."); - return false; - } - if (skipReason) { - return false; - } - if (options.manual) { - manualCheckPending = true; - } - try { - autoUpdater.logger = { - info: (...args: unknown[]) => logger.info(...args), - warn: (...args: unknown[]) => logger.info("[warn]", ...args), - error: (...args: unknown[]) => logger.error(...args), - debug: () => undefined, - }; - autoUpdater.autoDownload = true; - autoUpdater.autoInstallOnAppQuit = true; - const result = await autoUpdater.checkForUpdates(); - return Boolean(result?.updateInfo); - } catch (error) { - const classified = classifyUnknownError(error, { - kind: "upstream", - code: "updater.check_for_updates.failed", - message: "autoUpdater.checkForUpdates() failed", - }); - logger.error(`[${classified.code}] ${classified.message}`, error); - manualCheckPending = false; - return false; - } - } - - return { - attachListeners, - checkForUpdates, - }; -} diff --git a/src/main/vault.ts b/src/main/vault.ts deleted file mode 100644 index c780fc67..00000000 --- a/src/main/vault.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto"; -import { closeSync, mkdirSync, openSync, readFileSync, writeSync } from "node:fs"; -import { join } from "node:path"; -import { safeStorage } from "electron"; - -export interface SecretVaultOptions { - /** When true, the AES-GCM file-key fallback is refused even if the env flag - * is set. Packaged main-process callers should pass `app.isPackaged`. */ - isPackaged?: boolean; -} - -export class SecretVault { - private readonly keyPath: string; - private readonly isPackaged: boolean; - - constructor(private readonly profileDir: string, options: SecretVaultOptions = {}) { - this.keyPath = join(profileDir, "vault.key"); - this.isPackaged = options.isPackaged === true; - } - - getBackendLabel(): string { - const info = this.getBackendInfo(); - switch (info.kind) { - case "safe_storage": - return info.backend ? `safe_storage:${info.backend}` : "safe_storage"; - case "vault": - return info.backend ? `vault:${info.backend}` : "vault"; - case "unavailable": - return "unavailable"; - } - } - - /** Structured view of the active backend. Prefer this over the string form - * (`getBackendLabel`) when the caller needs to branch on kind vs algorithm. */ - getBackendInfo(): { kind: "safe_storage" | "vault" | "unavailable"; backend?: string } { - if (this.canUseSafeStorage()) { - const selectedBackend = typeof safeStorage?.getSelectedStorageBackend === "function" - ? safeStorage.getSelectedStorageBackend() - : "platform"; - if (selectedBackend && selectedBackend !== "basic_text") { - return { kind: "safe_storage", backend: selectedBackend }; - } - } - if (this.allowInsecureVaultFallback()) { - return { kind: "vault", backend: "aes-256-gcm" }; - } - return { kind: "unavailable" }; - } - - encrypt(value: string): { backend: "safe_storage" | "vault"; payload: Buffer } { - if (this.canUseSafeStorage()) { - const selectedBackend = typeof safeStorage?.getSelectedStorageBackend === "function" - ? safeStorage.getSelectedStorageBackend() - : "platform"; - if (selectedBackend !== "basic_text") { - return { - backend: "safe_storage", - payload: safeStorage.encryptString(value), - }; - } - } - - if (!this.allowInsecureVaultFallback()) { - throw new Error("Secure secret storage is unavailable. AgentCompany requires OS-backed credential storage unless AGENTCOMPANY_ALLOW_INSECURE_VAULT=true is set for test-only environments."); - } - - const iv = randomBytes(12); - const key = this.ensureKey(); - const cipher = createCipheriv("aes-256-gcm", key, iv); - const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]); - const tag = cipher.getAuthTag(); - return { - backend: "vault", - payload: Buffer.concat([iv, tag, encrypted]), - }; - } - - decrypt(backend: "safe_storage" | "vault", payload: Buffer): string { - if (backend === "safe_storage") { - if (!this.canUseSafeStorage()) { - throw new Error("safeStorage backend is unavailable in the current runtime."); - } - return safeStorage.decryptString(payload); - } - const key = this.ensureKey(); - const iv = payload.subarray(0, 12); - const tag = payload.subarray(12, 28); - const encrypted = payload.subarray(28); - const decipher = createDecipheriv("aes-256-gcm", key, iv); - decipher.setAuthTag(tag); - return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8"); - } - - private ensureKey(): Buffer { - mkdirSync(this.profileDir, { recursive: true }); - try { - const fd = openSync(this.keyPath, "wx", 0o600); - const nextKey = randomBytes(32); - writeSync(fd, nextKey); - closeSync(fd); - return nextKey; - } catch (err: unknown) { - if ((err as NodeJS.ErrnoException).code === "EEXIST") { - return readFileSync(this.keyPath); - } - throw err; - } - } - - private canUseSafeStorage() { - return typeof safeStorage?.isEncryptionAvailable === "function" && safeStorage.isEncryptionAvailable(); - } - - private allowInsecureVaultFallback() { - // Hard gate: the AES-GCM fallback is a dev-only escape hatch. Packaged - // builds must refuse it regardless of the env flag. - if (this.isPackaged) return false; - return process.env.AGENTCOMPANY_ALLOW_INSECURE_VAULT === "true"; - } -} diff --git a/src/main/window-state.ts b/src/main/window-state.ts deleted file mode 100644 index eb20489b..00000000 --- a/src/main/window-state.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; -import { dirname } from "node:path"; -import type { BrowserWindow, Rectangle } from "electron"; - -interface StoredWindowState { - bounds: Rectangle; - maximized: boolean; -} - -const DEFAULT_BOUNDS: Rectangle = { - width: 1480, - height: 980, - x: 120, - y: 80, -}; - -function safeParseState(filePath: string): StoredWindowState | null { - // First-run: file absent is normal, not corruption. Return null silently. - if (!existsSync(filePath)) return null; - try { - const raw = readFileSync(filePath, "utf8"); - const parsed = JSON.parse(raw) as Partial; - if (!parsed.bounds || typeof parsed.bounds !== "object") { - - console.warn(`[window-state] ${filePath} is missing bounds; using default geometry.`); - return null; - } - const { width, height, x, y } = parsed.bounds as Partial; - if (typeof width !== "number" || !Number.isFinite(width) || typeof height !== "number" || !Number.isFinite(height)) { - - console.warn(`[window-state] ${filePath} has non-numeric bounds; using default geometry.`); - return null; - } - return { - bounds: { - width, - height, - x: typeof x === "number" && Number.isFinite(x) ? x : DEFAULT_BOUNDS.x, - y: typeof y === "number" && Number.isFinite(y) ? y : DEFAULT_BOUNDS.y, - }, - maximized: parsed.maximized === true, - }; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - - console.warn(`[window-state] ${filePath} unreadable (${message}); using default geometry.`); - return null; - } -} - -function writeState(filePath: string, state: StoredWindowState) { - mkdirSync(dirname(filePath), { recursive: true }); - writeFileSync(filePath, `${JSON.stringify(state, null, 2)}\n`, "utf8"); -} - -export function loadWindowState(filePath: string) { - return safeParseState(filePath) ?? { - bounds: DEFAULT_BOUNDS, - maximized: false, - }; -} - -export function attachWindowStatePersistence(win: BrowserWindow, filePath: string) { - let saveTimer: ReturnType | null = null; - - const persist = () => { - if (saveTimer) { - clearTimeout(saveTimer); - } - saveTimer = setTimeout(() => { - saveTimer = null; - writeState(filePath, { - bounds: win.getBounds(), - maximized: win.isMaximized(), - }); - }, 250); - }; - - win.on("resize", persist); - win.on("move", persist); - win.on("maximize", persist); - win.on("unmaximize", persist); - win.on("close", () => { - if (saveTimer) { - clearTimeout(saveTimer); - saveTimer = null; - } - writeState(filePath, { - bounds: win.getBounds(), - maximized: win.isMaximized(), - }); - }); -} diff --git a/src/main/worker-service.ts b/src/main/worker-service.ts deleted file mode 100644 index 18f1ba5f..00000000 --- a/src/main/worker-service.ts +++ /dev/null @@ -1,271 +0,0 @@ -import { app, utilityProcess } from "electron"; -import { workerMessageSchema, type WorkerServiceDependencies } from "./worker/entry/types"; -import { handleWorkerExit, requeueQueuedRunsAfterWorkerRestart } from "./worker/entry/crash-recovery"; -import { handleWorkerMessage } from "./worker/entry/message-handler"; -import { DEFAULT_MAX_CONSECUTIVE_SELF_WAKES } from "./run-attempt-policy"; - -export { workerMessageSchema } from "./worker/entry/types"; - -export function createWorkerService({ - db, - logger, - workerPath, - isQuitting, - publishDomainChanged, - emitEvent, - wakeAgentIfPossible, - dispatchRunToWorker, - processRunCompletion, - onRunStarted, - onRunCompleted, - notify, - budgetService, - sessionService, - getRuntimeBridge, - getRuntimeMessageInjector, -}: WorkerServiceDependencies) { - const MAX_RETRY_ATTEMPTS = 2; - const RETRY_COOLDOWN_MS = 30_000; // 30 seconds - const selfWakeAttemptMap = new Map(); - const MAX_CONSECUTIVE_SELF_WAKES = DEFAULT_MAX_CONSECUTIVE_SELF_WAKES; - const leaseRenewalMap = new Map(); - - let worker: ReturnType | null = null; - let destroyed = false; - let shutdownPromise: Promise | null = null; - const pendingRetryTimers = new Set>(); - - /** Crash-loop backoff state. Resets to 0 whenever a worker lives long enough - * (>HEALTHY_UPTIME_MS) between creation and exit. Past MAX_CRASH_LOOP - * consecutive fast-crashes we stop respawning and notify the user. */ - const MAX_CRASH_LOOP = 5; - const BASE_BACKOFF_MS = 1_000; - const MAX_BACKOFF_MS = 30_000; - const HEALTHY_UPTIME_MS = 60_000; - const crashLoopState = { consecutive: 0, halted: false, lastCreatedAt: 0 }; - - function scheduleWorkerRespawn(afterRespawn?: () => void) { - if (crashLoopState.halted || destroyed || isQuitting()) return; - const uptimeMs = Date.now() - crashLoopState.lastCreatedAt; - if (uptimeMs >= HEALTHY_UPTIME_MS) { - crashLoopState.consecutive = 0; - } else { - crashLoopState.consecutive += 1; - } - if (crashLoopState.consecutive > MAX_CRASH_LOOP) { - crashLoopState.halted = true; - logger.error( - `[worker-service] Worker crashed ${crashLoopState.consecutive} times within ${HEALTHY_UPTIME_MS}ms; halting respawn.`, - ); - notify({ - title: "Orchestrator Unavailable", - body: "The background worker keeps crashing. Restart AgentCompany after checking logs.", - urgency: "critical", - navigation: { section: "overview" }, - }); - return; - } - const delay = Math.min(BASE_BACKOFF_MS * 2 ** (crashLoopState.consecutive - 1), MAX_BACKOFF_MS); - logger.info(`[worker-service] Respawning worker in ${delay}ms (attempt ${crashLoopState.consecutive}/${MAX_CRASH_LOOP})`); - setTimeout(() => { - if (destroyed || isQuitting() || crashLoopState.halted) return; - createWorker(); - afterRespawn?.(); - }, delay); - } - - function getWorker() { - if (destroyed) return null; - return worker; - } - - function createWorker() { - crashLoopState.lastCreatedAt = Date.now(); - // S-01: Propagate packaged-build signal so the worker can hard-refuse - // connector bypass flags in production. - worker = utilityProcess.fork(workerPath, [], { - stdio: "pipe", - serviceName: "AgentCompany Orchestrator", - env: { - ...process.env, - AGENTCOMPANY_PACKAGED: app.isPackaged ? "true" : "false", - }, - }); - - const currentWorker = worker; - - currentWorker.stdout?.on("data", (chunk) => { - const text = String(chunk).trim(); - if (text) logger.debug(`[worker:stdout] ${text}`); - }); - currentWorker.stderr?.on("data", (chunk) => { - const text = String(chunk).trim(); - if (text) logger.warn(`[worker:stderr] ${text}`); - }); - - currentWorker.on("exit", (code) => { - if (worker === currentWorker) worker = null; - if (isQuitting() || destroyed) return; - const requeueCandidates = handleWorkerExit( - code, - { db, logger, isQuitting, publishDomainChanged, emitEvent, wakeAgentIfPossible }, - ); - scheduleWorkerRespawn( - () => requeueQueuedRunsAfterWorkerRestart( - requeueCandidates, - { db, logger, dispatchRunToWorker }, - ), - ); - }); - - currentWorker.on("message", async (message) => { - if (isShutdownReadyMessage(message)) { - try { - currentWorker.postMessage({ type: "shutdown-exit" }); - } catch (error) { - logger.debug( - `[worker-service] shutdown-exit postMessage failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - return; - } - await handleWorkerMessage( - message, - currentWorker, - { - db, - logger, - isQuitting, - emitEvent, - wakeAgentIfPossible, - processRunCompletion, - onRunStarted, - onRunCompleted, - notify, - budgetService, - sessionService, - getRuntimeBridge, - getRuntimeMessageInjector, - }, - workerMessageSchema, - destroyed, - MAX_RETRY_ATTEMPTS, - RETRY_COOLDOWN_MS, - selfWakeAttemptMap, - MAX_CONSECUTIVE_SELF_WAKES, - pendingRetryTimers, - leaseRenewalMap, - ); - }); - } - - function collectShutdownRuns(): Array<{ - id: string; - taskId: string | null; - workspaceId: string | null; - }> { - try { - const snapshot = db.projection.snapshot.listSnapshot(); - return snapshot.runs - .filter((run) => run.status === "running" || run.status === "queued") - .map((run) => ({ id: run.id, taskId: run.taskId, workspaceId: run.workspaceId })); - } catch (error) { - logger.warn( - `[worker-service] shutdown run collection failed: ${error instanceof Error ? error.message : String(error)}`, - ); - return []; - } - } - - function interruptShutdownRuns(runs: Array<{ - id: string; - taskId: string | null; - workspaceId: string | null; - }>): void { - try { - for (const run of runs) { - let status: string; - try { - status = db.core.runs.getRun(run.id).status; - } catch (error) { - logger.warn( - `[worker-service] shutdown cleanup skipped missing run ${run.id}: ${error instanceof Error ? error.message : String(error)}`, - ); - continue; - } - if (status !== "running" && status !== "queued") { - continue; - } - db.core.runs.finishRun({ - runId: run.id, - status: "interrupted", - summary: "Application shut down.", - errorMessage: null, - exitCode: null, - signal: null, - model: null, - unattributedCost: true, - }); - if (run.workspaceId) { - db.core.workspaces.releaseWorkspaceLock(run.workspaceId, run.id); - } - if (run.taskId) { - db.core.tasks.releaseTaskLock(run.taskId, run.id); - } - } - } catch (error) { - logger.warn( - `[worker-service] interrupted-run cleanup during shutdown failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - function shutdown(): Promise { - if (shutdownPromise) return shutdownPromise; - destroyed = true; - const shutdownRuns = collectShutdownRuns(); - - for (const timer of pendingRetryTimers) { - clearTimeout(timer); - } - pendingRetryTimers.clear(); - - if (!worker) { - interruptShutdownRuns(shutdownRuns); - shutdownPromise = Promise.resolve(); - return shutdownPromise; - } - - const ref = worker; - shutdownPromise = new Promise((resolve) => { - ref.once("exit", () => { - if (worker === ref) worker = null; - interruptShutdownRuns(shutdownRuns); - resolve(); - }); - try { - ref.postMessage({ type: "shutdown" }); - } catch (error) { - logger.debug( - `[worker-service] shutdown postMessage failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - }); - return shutdownPromise; - } - - function destroy() { - void shutdown(); - } - - return { - createWorker, - getWorker, - shutdown, - destroy, - }; -} - -function isShutdownReadyMessage(message: unknown): message is { type: "shutdown-ready" } { - return Boolean(message && typeof message === "object" && (message as { type?: unknown }).type === "shutdown-ready"); -} diff --git a/src/main/worker/entry/crash-recovery.ts b/src/main/worker/entry/crash-recovery.ts deleted file mode 100644 index 5c0cae21..00000000 --- a/src/main/worker/entry/crash-recovery.ts +++ /dev/null @@ -1,143 +0,0 @@ -import type { WorkerServiceDependencies } from "./types"; -import { resolveWorkspaceWithLockMode } from "../../orchestration/resolve-workspace"; - -export interface QueuedRunRecoveryCandidate { - id: string; - taskId: string | null; - agentId: string; - companyId: string; - workspaceId: string | null; - connectorId: string; -} - -export function handleWorkerExit( - code: number | null, - { - db, - logger, - isQuitting, - publishDomainChanged, - emitEvent: _emitEvent, - wakeAgentIfPossible, - }: Pick, -): QueuedRunRecoveryCandidate[] { - if (isQuitting()) return []; - - logger.warn(`[worker] Worker exited with code ${code}, recovering...`); - - const snapshot = db.projection.snapshot.listSnapshot(); - const affectedAgentIds = new Set(); - const affectedCompanyIds = new Map(); - const requeueCandidates: QueuedRunRecoveryCandidate[] = []; - - for (const run of snapshot.runs) { - if (run.status === "running") { - db.core.runs.finishRun({ - runId: run.id, - status: "interrupted", - summary: "Worker process crashed.", - errorMessage: "Worker process exited unexpectedly.", - exitCode: code, - signal: null, - model: null, - unattributedCost: true, - recoverTaskForRetry: run.taskId !== null, - }); - if (run.workspaceId) { - db.core.workspaces.releaseWorkspaceLock(run.workspaceId, run.id); - } - affectedAgentIds.add(run.agentId); - affectedCompanyIds.set(run.agentId, run.companyId); - - const chain = db.core.agents.getChainOfCommand(run.agentId); - if (chain.length > 0) { - wakeAgentIfPossible(chain[0].id, run.companyId, "report_failed"); - } - } else if (run.status === "queued") { - requeueCandidates.push({ - id: run.id, - taskId: run.taskId, - agentId: run.agentId, - companyId: run.companyId, - workspaceId: run.workspaceId, - connectorId: run.connectorId, - }); - } - } - - for (const agentId of affectedAgentIds) { - // EXEC-05: Promote deferred wakes after crash recovery - const cid = affectedCompanyIds.get(agentId) ?? ""; - const promoted = db.automation.wakeup.promoteWakeupRequests(agentId, cid); - if (promoted > 0) { - logger.info(`[worker] Promoted ${promoted} deferred wake(s) for agent ${agentId} after crash recovery`); - } - const pendingWakeTrigger = db.automation.wakeup.getPreferredWakeTrigger(agentId, cid); - wakeAgentIfPossible(agentId, cid, pendingWakeTrigger ?? "recovery"); - } - - publishDomainChanged(); - - return requeueCandidates; -} - -export function requeueQueuedRunsAfterWorkerRestart( - requeueCandidates: QueuedRunRecoveryCandidate[], - { - db, - logger, - dispatchRunToWorker, - }: Pick, -): void { - if (requeueCandidates.length === 0) return; - logger.info(`[worker] Re-enqueuing ${requeueCandidates.length} queued run(s) after worker restart.`); - const recoverySnapshot = db.projection.snapshot.listSnapshot(); - for (const candidate of requeueCandidates) { - try { - const currentRun = db.core.runs.getRun(candidate.id); - if (currentRun.status !== "queued") continue; - // The crashed run may still own a workspace lock acquired during the - // original dispatch; release it before re-dispatch so the replay - // does not self-collide with "Workspace is locked by another run". - if (candidate.workspaceId) { - db.core.workspaces.releaseWorkspaceLock(candidate.workspaceId, candidate.id); - } - const task = candidate.taskId ? db.core.entity.getTask(candidate.taskId) : null; - const agent = db.core.entity.getAgent(candidate.agentId); - const connector = db.core.connectors.getConnector(agent.connectorId); - const { workspace, lockMode, observationPath } = resolveWorkspaceWithLockMode(db, task, agent, candidate.companyId); - const recoveryCompany = recoverySnapshot.companies.find((company) => company.id === candidate.companyId); - - dispatchRunToWorker({ - runId: candidate.id, - companyId: candidate.companyId, - agent, - task, - connector, - workspace, - workspaceMode: lockMode, - observationPath, - companyName: recoveryCompany?.name ?? "Company", - companyDescription: recoveryCompany?.description ?? "", - snapshot: recoverySnapshot, - trigger: "recovery", - }); - } catch (error) { - logger.warn(`[worker] Failed to re-enqueue run ${candidate.id}: ${error instanceof Error ? error.message : String(error)}`); - db.core.runs.finishRun({ - runId: candidate.id, - status: "interrupted", - summary: "Could not re-enqueue after worker restart.", - errorMessage: error instanceof Error ? error.message : String(error), - exitCode: null, - signal: null, - model: null, - unattributedCost: true, - recoverTaskForRetry: candidate.taskId !== null, - }); - if (candidate.workspaceId) { - db.core.workspaces.releaseWorkspaceLock(candidate.workspaceId, candidate.id); - } - } - } -} diff --git a/src/main/worker/entry/index.ts b/src/main/worker/entry/index.ts deleted file mode 100644 index c453486e..00000000 --- a/src/main/worker/entry/index.ts +++ /dev/null @@ -1,183 +0,0 @@ -import type { ChildMessage, ParentMessage, RunJob } from "../runtime/helpers"; -import { WorkerRpcClient } from "./rpc"; -import { WorkerRunner } from "../runtime"; - -const parentPort = process.parentPort; - -if (!parentPort) { - throw new Error("AgentCompany worker requires process.parentPort"); -} - -interface ActiveRun { - runId: string; - agentId: string; - workspaceKey: string | null; -} - -/** - * Single source of truth for scheduling invariants: one active run per - * agent and one active run per exclusive workspace lock. Prior layout - * kept three parallel structures (`activeByAgent`, `activeByWorkspace`, - * queue) that had to be updated in lockstep. The Map-of-ActiveRun keyed - * by runId is the only authoritative record; agent/workspace busy checks - * iterate it. - */ -const active = new Map(); -const queue: RunJob[] = []; -const cancelledRuns = new Set(); -let shuttingDown = false; -let drainAckResolver: (() => void) | null = null; - -function post(message: ChildMessage) { - parentPort.postMessage(message); -} - -const rpc = new WorkerRpcClient(post); -const runner = new WorkerRunner({ - post, - rpc, - isCancelled: (runId) => cancelledRuns.has(runId), -}); - -function workspaceKey(job: RunJob): string | null { - if (job.workspaceMode !== "exclusive") return null; - return job.workspaceId ?? job.workspacePath ?? `task:${job.taskId}`; -} - -function isAgentBusy(agentId: string): boolean { - for (const run of active.values()) { - if (run.agentId === agentId) return true; - } - return false; -} - -function isWorkspaceBusy(lockKey: string): boolean { - for (const run of active.values()) { - if (run.workspaceKey === lockKey) return true; - } - return false; -} - -function enqueue(job: RunJob) { - if (shuttingDown) return; - queue.push(job); - post({ - type: "run-status", - runId: job.runId, - status: "queued", - message: "Run queued in orchestration worker.", - }); - tickQueue(); -} - -/** - * Claim-before-dispatch: for each queued job whose agent + workspace are - * free, register the claim in `active` synchronously *before* calling - * `startRun`. No async window between claim and dispatch. - */ -function tickQueue() { - if (shuttingDown) return; - let i = 0; - while (i < queue.length) { - const job = queue[i]; - if (isAgentBusy(job.agentId)) { i += 1; continue; } - const lockKey = workspaceKey(job); - if (lockKey && isWorkspaceBusy(lockKey)) { i += 1; continue; } - active.set(job.runId, { runId: job.runId, agentId: job.agentId, workspaceKey: lockKey }); - queue.splice(i, 1); - void startRun(job); - } -} - -async function startRun(job: RunJob) { - try { - await runner.run(job); - } finally { - cancelledRuns.delete(job.runId); - } -} - -function acknowledgeRunCompletion(runId: string) { - const released = active.delete(runId); - if (released) tickQueue(); - if (shuttingDown && active.size === 0 && drainAckResolver) { - drainAckResolver(); - drainAckResolver = null; - } -} - -function waitForCompletionAcks(): Promise { - if (active.size === 0) return Promise.resolve(); - return new Promise((resolve) => { - drainAckResolver = resolve; - }); -} - -function cancelRun(runId: string) { - const queuedIndex = queue.findIndex((entry) => entry.runId === runId); - if (queuedIndex >= 0) { - queue.splice(queuedIndex, 1); - post({ - type: "run-finished", - runId, - status: "cancelled", - summary: "Cancelled before execution.", - errorMessage: null, - exitCode: null, - signal: null, - model: null, - usageStatus: "aborted_before_usage", - inputTokens: null, - outputTokens: null, - }); - return; - } - - cancelledRuns.add(runId); - runner.cancel(runId); -} - -parentPort.on("message", (event) => { - const message = event.data as ParentMessage; - if (message.type === "enqueue-run") { - enqueue(message.payload); - return; - } - if (message.type === "cancel-run") { - cancelRun(message.runId); - return; - } - if (message.type === "run-completion-ack") { - acknowledgeRunCompletion(message.runId); - return; - } - if (message.type === "steer-run") { - const accepted = runner.steer(message.runId, message.message); - post({ - type: "steer-ack", - runId: message.runId, - correlationId: message.correlationId, - accepted, - }); - return; - } - if (message.type === "rpc-response") { - rpc.resolve(message.rpcId, message.response); - return; - } - if (message.type === "shutdown") { - if (shuttingDown) return; - shuttingDown = true; - void (async () => { - queue.splice(0); - await runner.cancelAll(); - await waitForCompletionAcks(); - rpc.cancelAll("Worker shutting down."); - post({ type: "shutdown-ready" }); - })(); - return; - } - if (message.type === "shutdown-exit") { - process.exit(0); - } -}); diff --git a/src/main/worker/entry/message-handler.ts b/src/main/worker/entry/message-handler.ts deleted file mode 100644 index 5c851a3a..00000000 --- a/src/main/worker/entry/message-handler.ts +++ /dev/null @@ -1,136 +0,0 @@ -import type { RuntimeBridge, RuntimeMessageInjector } from "../../agent-runtime"; -import type { workerMessageSchema } from "./types"; -import { handleRunLog } from "../handlers/run-log-handler"; -import { handleRunStatus } from "../handlers/run-status-handler"; -import { handleRunFinished } from "../handlers/run-finished-handler"; -import { releaseCompletedRunWorkspaceLock } from "../handlers/run-finished-helpers"; -import { handleContextCompaction } from "../handlers/context-compaction-handler"; -import type { HandlerContext, HandlerDeps } from "../handlers/handler-context"; -import type { RunFinishedContext } from "../handlers/run-finished-helpers"; -import type { RunResourceReleaseResult } from "../../agent-runtime/runtime-artifact-reconciler"; - -export async function handleWorkerMessage( - message: unknown, - worker: ReturnType | null, - deps: HandlerDeps & { - getRuntimeBridge?: () => RuntimeBridge | null; - getRuntimeMessageInjector?: () => RuntimeMessageInjector | null; - }, - workerMessageSchemaRef: typeof workerMessageSchema, - destroyed: boolean, - MAX_RETRY_ATTEMPTS: number, - RETRY_COOLDOWN_MS: number, - selfWakeAttemptMap: Map, - MAX_CONSECUTIVE_SELF_WAKES: number, - pendingRetryTimers: Set>, - leaseRenewalMap: Map, -) { - const parsed = workerMessageSchemaRef.safeParse(message); - if (!parsed.success) { - deps.logger.error("[worker] invalid message payload", parsed.error); - return; - } - const event = parsed.data; - - const context: HandlerContext = { - destroyed, - MAX_RETRY_ATTEMPTS, - RETRY_COOLDOWN_MS, - MAX_CONSECUTIVE_SELF_WAKES, - selfWakeAttemptMap, - pendingRetryTimers, - leaseRenewalMap, - }; - - switch (event.type) { - case "run-log": - await handleRunLog(event, deps, context); - return; - case "run-status": - handleRunStatus(event, deps, context); - return; - case "run-finished": { - let completion: RunFinishedContext | null = null; - let runtimeResourcesReleased = false; - let runtimeReleaseResult: RunResourceReleaseResult = { ok: true }; - const releaseRuntimeResources = (): RunResourceReleaseResult => { - if (runtimeResourcesReleased) return runtimeReleaseResult; - runtimeResourcesReleased = true; - runtimeReleaseResult = - deps.getRuntimeBridge?.()?.releaseRunResources(event.runId) ?? { ok: true }; - return runtimeReleaseResult; - }; - // The worker's per-run state machine releases `active[runId]` only - // after receiving run-completion-ack. Any uncaught throw between - // run-finished and posting the ack permanently leaks the agent — - // every subsequent wake then enqueues behind a queue whose - // `isAgentBusy` check refuses to start it. The ack must therefore - // be posted unconditionally. - try { - try { - completion = handleRunFinished(event, deps, context, { - beforePostCompletionAutomation: releaseRuntimeResources, - }); - } finally { - releaseRuntimeResources(); - } - releaseCompletedRunWorkspaceLock(completion, deps); - } catch (error) { - deps.logger.error( - `[worker] run-finished post-handling failed for run ${event.runId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - if (!worker) { - throw new Error(`run-completion-ack worker missing for run ${event.runId}`); - } - worker.postMessage({ type: "run-completion-ack", runId: event.runId }); - return; - } - case "agent-event": { - const bridge = deps.getRuntimeBridge?.(); - if (bridge) { - bridge.handleAgentEvent({ - runId: event.runId, - agentId: event.agentId, - companyId: event.companyId, - taskId: event.taskId, - emittedAt: event.emittedAt, - event: event.event, - }); - } - return; - } - case "context-compaction": - handleContextCompaction(event, deps, context); - return; - case "rpc-request": { - const bridge = deps.getRuntimeBridge?.(); - const response = bridge - ? await bridge.handleRpc({ - rpcId: event.rpcId, - runId: event.runId, - method: event.method, - payload: event.payload, - }) - : { ok: false as const, error: "RuntimeBridge not initialised." }; - try { - worker?.postMessage({ type: "rpc-response", rpcId: event.rpcId, response }); - } catch (error) { - deps.logger.error( - `[worker] rpc-response postMessage failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - return; - } - case "run-agent-state": { - deps.getRuntimeBridge?.()?.setRunAgentState(event.runId, event.state); - return; - } - case "steer-ack": { - deps.getRuntimeMessageInjector?.()?.handleSteerAck(event.correlationId, event.accepted); - return; - } - case "shutdown-ready": - return; - } -} diff --git a/src/main/worker/entry/rpc.ts b/src/main/worker/entry/rpc.ts deleted file mode 100644 index c7e194de..00000000 --- a/src/main/worker/entry/rpc.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { ChildMessage } from "../runtime/helpers"; - -interface PendingRpc { - resolve: (value: { ok: true; result: unknown } | { ok: false; error: string }) => void; - timer: NodeJS.Timeout; -} - -const DEFAULT_RPC_TIMEOUT_MS = 30_000; - -export class WorkerRpcClient { - private readonly pending = new Map(); - - constructor( - private readonly post: (message: ChildMessage) => void, - private readonly timeoutMs: number = DEFAULT_RPC_TIMEOUT_MS, - ) {} - - invoke( - runId: string, - method: string, - payload: unknown, - options?: { timeoutMs?: number }, - ): Promise<{ ok: true; result: unknown } | { ok: false; error: string }> { - const rpcId = randomUUID(); - const effectiveTimeoutMs = options?.timeoutMs ?? this.timeoutMs; - return new Promise((resolve) => { - const timer = setTimeout(() => { - const pending = this.pending.get(rpcId); - if (!pending) return; - this.pending.delete(rpcId); - pending.resolve({ ok: false, error: `RPC ${method} timed out after ${effectiveTimeoutMs}ms` }); - }, effectiveTimeoutMs); - this.pending.set(rpcId, { resolve, timer }); - this.post({ type: "rpc-request", rpcId, runId, method, payload }); - }); - } - - resolve(rpcId: string, response: { ok: true; result: unknown } | { ok: false; error: string }): void { - const pending = this.pending.get(rpcId); - if (!pending) return; - clearTimeout(pending.timer); - this.pending.delete(rpcId); - pending.resolve(response); - } - - cancelAll(reason: string): void { - for (const [id, pending] of this.pending) { - clearTimeout(pending.timer); - pending.resolve({ ok: false, error: reason }); - this.pending.delete(id); - } - } -} diff --git a/src/main/worker/entry/types.ts b/src/main/worker/entry/types.ts deleted file mode 100644 index d7c87177..00000000 --- a/src/main/worker/entry/types.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { z } from "zod"; -import type { AppDatabase } from "../../database"; -import { RUN_USAGE_STATUSES, type DesktopEvent, type RunRecord } from "@shared/types"; -import type { NotificationOptions } from "../../notification-service"; -import type { createBudgetEnforcementService } from "../../budget-enforcement-service"; -import type { createSessionManagementService } from "../../session-management-service"; -import type { RuntimeBridge, RuntimeMessageInjector } from "../../agent-runtime"; -import type { RunDispatchParams } from "../../orchestration/turn-context"; - -const runStatusSchema = z.enum(["queued", "running", "succeeded", "failed", "cancelled", "timed_out", "interrupted"]); -const runUsageStatusSchema = z.enum(RUN_USAGE_STATUSES); - -/** - * Single source of truth for worker → main RPC method names. - * - * This constant is consumed by both the zod validation schema in this - * file (the runtime gate at `handleWorkerMessage`) and the `RpcMethod` - * TypeScript union exported from `agent-runtime/runtime-bridge.ts` via - * `z.infer`. Adding a new internal RPC requires touching exactly one - * place — this literal list — which eliminates the C4→C5 hotfix class - * of bug where the two definitions silently drifted and the zod gate - * rejected a newly-minted method the handler had already registered. - */ -export const workerRpcMethodSchema = z.enum([ - "persistMessage", - "prepareRun", - "beforeToolCall", - "invokeInternalTool", -]); - -export type WorkerRpcMethod = z.infer; - -export const workerMessageSchema = z.union([ - z.object({ - type: z.literal("run-log"), - runId: z.string().uuid(), - stream: z.enum(["stdout", "stderr"]), - chunk: z.string(), - }), - z.object({ - type: z.literal("run-status"), - runId: z.string().uuid(), - status: runStatusSchema, - message: z.string(), - }), - z.object({ - type: z.literal("run-finished"), - runId: z.string().uuid(), - status: runStatusSchema, - summary: z.string().nullable(), - errorMessage: z.string().nullable(), - exitCode: z.number().int().nullable(), - signal: z.string().nullable(), - model: z.string().nullable(), - usageStatus: runUsageStatusSchema, - inputTokens: z.number().nullable(), - outputTokens: z.number().nullable(), - }).strict(), - z.object({ - type: z.literal("agent-event"), - runId: z.string().uuid(), - agentId: z.string(), - companyId: z.string(), - taskId: z.string().nullable(), - emittedAt: z.string(), - event: z.record(z.string(), z.unknown()).and(z.object({ type: z.string() })), - }), - z.object({ - type: z.literal("context-compaction"), - runId: z.string().uuid(), - emittedAt: z.string(), - estimatedTokens: z.number(), - originalMessageCount: z.number().int(), - compactedMessageCount: z.number().int(), - compactedOlderMessageCount: z.number().int(), - retainedRecentMessageCount: z.number().int(), - }), - z.object({ - type: z.literal("rpc-request"), - rpcId: z.string(), - runId: z.string().uuid(), - method: workerRpcMethodSchema, - payload: z.unknown(), - }), - z.object({ - type: z.literal("run-agent-state"), - runId: z.string().uuid(), - state: z.enum(["agent_active", "closing"]), - }), - z.object({ - type: z.literal("steer-ack"), - runId: z.string().uuid(), - correlationId: z.string(), - accepted: z.boolean(), - }), - z.object({ - type: z.literal("shutdown-ready"), - }), -]); - -export interface WorkerServiceDependencies { - db: AppDatabase; - logger: { - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; - workerPath: string; - isQuitting: () => boolean; - publishDomainChanged: () => void; - emitEvent: (event: DesktopEvent) => void; - wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; - dispatchRunToWorker: (params: RunDispatchParams) => void; - processRunCompletion: (run: RunRecord, event: z.infer & { type: "run-finished" }) => void; - onRunStarted?: (runId: string, taskId: string | null, agentId: string, companyId: string) => void; - onRunCompleted?: (runId: string, taskId: string | null, agentId: string, companyId: string, status: string, summary: string | null, errorMessage: string | null) => void; - notify: (options: NotificationOptions) => void; - budgetService?: ReturnType; - sessionService?: ReturnType; - /** Forwards `agent-event` from worker to renderer and routes RPC to main services. */ - getRuntimeBridge?: () => RuntimeBridge | null; - /** - * Resolves the shared runtime message injector so `steer-ack` child - * messages can commit inbox delivery or trigger a wake fallback. - */ - getRuntimeMessageInjector?: () => RuntimeMessageInjector | null; -} diff --git a/src/main/worker/handlers/context-compaction-handler.ts b/src/main/worker/handlers/context-compaction-handler.ts deleted file mode 100644 index c0dfd92e..00000000 --- a/src/main/worker/handlers/context-compaction-handler.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { persistRunEvent } from "../observability/run-event-recorder"; -import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context"; - -export function handleContextCompaction( - event: Extract, - deps: HandlerDeps, - _context: HandlerContext, -): void { - const runState = deps.db.core.runs.getRunAuthState(event.runId); - if (!runState) { - deps.logger.warn(`[context-compaction] run ${event.runId} disappeared before telemetry could be recorded.`); - return; - } - persistRunEvent(deps.db, deps.logger, { - companyId: runState.companyId, - runId: event.runId, - agentId: runState.agentId, - eventType: "context_compaction", - level: "info", - message: `Compacted ${event.compactedOlderMessageCount} older messages into a summary.`, - payload: { - emittedAt: event.emittedAt, - estimatedTokens: event.estimatedTokens, - originalMessageCount: event.originalMessageCount, - compactedMessageCount: event.compactedMessageCount, - compactedOlderMessageCount: event.compactedOlderMessageCount, - retainedRecentMessageCount: event.retainedRecentMessageCount, - }, - }); -} diff --git a/src/main/worker/handlers/handler-context.ts b/src/main/worker/handlers/handler-context.ts deleted file mode 100644 index 838c261d..00000000 --- a/src/main/worker/handlers/handler-context.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { z } from "zod"; -import type { WorkerServiceDependencies, workerMessageSchema } from "../entry/types"; - -export type WorkerMessageEvent = z.infer; - -export type HandlerDeps = Pick< - WorkerServiceDependencies, - | "db" - | "logger" - | "isQuitting" - | "emitEvent" - | "wakeAgentIfPossible" - | "processRunCompletion" - | "onRunStarted" - | "onRunCompleted" - | "notify" - | "budgetService" - | "sessionService" ->; - -export interface HandlerContext { - destroyed: boolean; - MAX_RETRY_ATTEMPTS: number; - RETRY_COOLDOWN_MS: number; - MAX_CONSECUTIVE_SELF_WAKES: number; - selfWakeAttemptMap: Map; - pendingRetryTimers: Set>; - leaseRenewalMap: Map; -} diff --git a/src/main/worker/handlers/run-finished-handler.ts b/src/main/worker/handlers/run-finished-handler.ts deleted file mode 100644 index e562e2c5..00000000 --- a/src/main/worker/handlers/run-finished-handler.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - accumulateAndRotateSession, - emitAndNotifyCompletion, - finalizeRun, - runPostCompletionAutomation, - triggerSelfWake, -} from "./run-finished-helpers"; -import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context"; -import type { RunFinishedContext } from "./run-finished-helpers"; - -export interface RunFinishedHooks { - beforePostCompletionAutomation?: (context: RunFinishedContext) => - | void - | { ok: true } - | { ok: false; errorMessage: string }; -} - -function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} - -export function handleRunFinished( - event: Extract, - deps: HandlerDeps, - context: HandlerContext, - hooks: RunFinishedHooks = {}, -): RunFinishedContext | null { - const rfCtx = finalizeRun(event, deps, context); - if (!rfCtx) return null; - - accumulateAndRotateSession(event, deps, rfCtx); - const boundaryResult = hooks.beforePostCompletionAutomation?.(rfCtx); - const effectiveEvent = - boundaryResult && !boundaryResult.ok - ? { - ...event, - status: "failed" as const, - summary: null, - errorMessage: boundaryResult.errorMessage, - usageStatus: "error_stop" as const, - } - : event; - if (boundaryResult && !boundaryResult.ok) { - try { - deps.db.core.runs.markRunCompletionFailure(event.runId, boundaryResult.errorMessage); - } catch (error) { - deps.logger.error(`[worker] markRunCompletionFailure failed for artifact boundary ${event.runId}: ${errorMessage(error)}`); - } - } - emitAndNotifyCompletion(effectiveEvent, deps, rfCtx); - const { hadDeferredWakes } = runPostCompletionAutomation(effectiveEvent, deps, context, rfCtx); - triggerSelfWake(effectiveEvent, deps, context, rfCtx, hadDeferredWakes); - return rfCtx; -} diff --git a/src/main/worker/handlers/run-finished-helpers.ts b/src/main/worker/handlers/run-finished-helpers.ts deleted file mode 100644 index 9717f8f8..00000000 --- a/src/main/worker/handlers/run-finished-helpers.ts +++ /dev/null @@ -1,453 +0,0 @@ -import type { z } from "zod"; -import { handleFailureEscalation, handleSuccessReset } from "../observability/failure-escalation"; -import { persistRunEvent } from "../observability/run-event-recorder"; -import type { workerMessageSchema } from "../entry/types"; -import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context"; -import { isUsageStatusUnattributed } from "../../run-usage-status"; -import { decideRunAttempt, runAttemptKey } from "../../run-attempt-policy"; - -type RunFinishedEvent = Extract; -type RunRecord = ReturnType; -type TaskRecord = ReturnType; - -export interface RunFinishedContext { - run: RunRecord; - task: TaskRecord | null; - runOutcome: ReturnType; -} - -function errorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} - -function runCompletionSideEffect( - logger: HandlerDeps["logger"], - label: string, - operation: () => void, -): void { - try { - operation(); - } catch (error) { - logger.error(`[worker] ${label} failed after run completion: ${errorMessage(error)}`); - } -} - -export function finalizeRun( - event: RunFinishedEvent, - deps: HandlerDeps, - context: HandlerContext, -): RunFinishedContext | null { - const { db, logger } = deps; - const { leaseRenewalMap } = context; - - let run: RunRecord; - try { - run = db.core.runs.getRun(event.runId); - } catch (error) { - logger.warn( - `[finalizeRun] getRun(${event.runId}) failed; run may have been deleted: ${error instanceof Error ? error.message : String(error)}`, - ); - return null; - } - - const unattributedCost = isUsageStatusUnattributed(event.usageStatus); - - persistRunEvent(db, logger, { - companyId: run.companyId, - runId: run.id, - agentId: run.agentId, - eventType: "run_finished", - level: event.status === "succeeded" ? "info" : "error", - message: event.summary ?? event.errorMessage ?? event.status, - payload: { - status: event.status, - summary: event.summary, - errorMessage: event.errorMessage, - exitCode: event.exitCode, - signal: event.signal, - model: event.model, - usageStatus: event.usageStatus, - unattributedCost, - inputTokens: event.inputTokens, - outputTokens: event.outputTokens, - }, - }); - - let task: TaskRecord | null = null; - if (run.taskId) { - try { - task = db.core.entity.getTask(run.taskId); - } catch (error) { - logger.warn( - `[finalizeRun] getTask(${run.taskId}) failed; task may have been deleted: ${error instanceof Error ? error.message : String(error)}`, - ); - task = null; - } - } - - leaseRenewalMap.delete(event.runId); - const runOutcome = db.core.runs.finishRun({ ...event, unattributedCost }); - runCompletionSideEffect(logger, "run activity logging", () => { - db.core.activity.addActivity({ - companyId: run.companyId, - actor: run.agentId, - action: `run.${event.status}`, - entityType: "run", - entityId: run.id, - detail: event.summary ?? event.errorMessage ?? "", - }); - }); - - return { run, task, runOutcome }; -} - -export function releaseCompletedRunWorkspaceLock( - rfCtx: RunFinishedContext | null, - deps: Pick, -): void { - const workspaceId = rfCtx?.run.workspaceId; - if (!workspaceId) return; - runCompletionSideEffect(deps.logger, "workspace lock release", () => { - deps.db.core.workspaces.releaseWorkspaceLock(workspaceId, rfCtx.run.id); - }); -} - -export function accumulateAndRotateSession( - event: RunFinishedEvent, - deps: HandlerDeps, - rfCtx: RunFinishedContext, -): void { - const { db, logger, sessionService } = deps; - const { run } = rfCtx; - - if (!sessionService) return; - - // Sessions are agent-scoped (post-v34 migration). The previous gate on - // `!task` silently dropped token accumulation and rotation for every - // heartbeat run — the exact failure mode that lets a taskless transcript - // grow past the model's context window. Resolve the session through the - // agent, never through the task. - let agentRecord: ReturnType; - try { - agentRecord = db.core.entity.getAgent(run.agentId); - } catch (error) { - logger.warn( - `[session] accumulateAndRotateSession: getAgent(${run.agentId}) failed; skipping: ${error instanceof Error ? error.message : String(error)}`, - ); - return; - } - if (!agentRecord.sessionId) return; - const session = db.core.tasks.getSessionById(agentRecord.sessionId); - if (!session) return; - - try { - sessionService.accumulateTokenUsage( - session.id, - event.inputTokens ?? 0, - event.outputTokens ?? 0, - event.runId, - ); - // Re-read after accumulation: evaluateRotation must see the counts - // that include this run, otherwise a run that just crossed the - // threshold waits a full additional cycle to rotate — the exact - // failure mode that let transcripts balloon past the context window. - const updatedSession = db.core.tasks.getSessionById(agentRecord.sessionId); - if (!updatedSession) return; - const rotationResult = sessionService.evaluateRotation(updatedSession); - if (rotationResult.shouldRotate) { - sessionService.rotateSession(updatedSession); - logger.info(`[session] Rotated session for agent ${run.agentId}: ${rotationResult.reason}`); - } - } catch (error) { - logger.error(`[session] accumulation/rotation failed for run ${run.id}: ${errorMessage(error)}`); - } -} - -export function emitAndNotifyCompletion( - event: RunFinishedEvent, - deps: HandlerDeps, - rfCtx: RunFinishedContext, -): void { - const { db, emitEvent, notify, logger } = deps; - const { run, task, runOutcome } = rfCtx; - - runCompletionSideEffect(logger, "run-updated event emission", () => { - emitEvent({ type: "run-updated", runId: run.id, action: "completed" }); - }); - runCompletionSideEffect(logger, "run-status event emission", () => { - emitEvent({ - type: "run-status", - runId: run.id, - status: event.status, - message: event.summary ?? event.errorMessage ?? event.status, - }); - }); - if ((event.status === "failed" || event.status === "timed_out" || event.status === "interrupted") && task) { - runCompletionSideEffect(logger, "task failure notification", () => { - notify({ - title: "Task Failed", - body: `${task.title} -- manual intervention needed`, - urgency: "informational", - navigation: { section: "tasks", entityId: task.id }, - batchKey: "failed_runs", - }); - }); - } - - let updatedAgent: ReturnType | null = null; - try { - updatedAgent = db.core.entity.getAgent(run.agentId); - } catch (error) { - logger.warn( - `[emitAndNotifyCompletion] getAgent(${run.agentId}) failed; skipping budget-paused notification: ${error instanceof Error ? error.message : String(error)}`, - ); - updatedAgent = null; - } - - if (updatedAgent && runOutcome.budgetHardStopped) { - runCompletionSideEffect(logger, "budget auto-pause activity logging", () => { - db.core.activity.addActivity({ - companyId: updatedAgent.companyId, - actor: "system", - action: "agent.auto_paused", - entityType: "agent", - entityId: updatedAgent.id, - detail: `Budget exhausted at ${updatedAgent.spentMonthlyUsd.toFixed(2)} / ${updatedAgent.budgetMonthlyUsd.toFixed(2)} USD.`, - }); - }); - runCompletionSideEffect(logger, "budget auto-pause notification", () => { - notify({ - title: "Agent Paused", - body: `${updatedAgent.name} paused -- budget limit reached`, - urgency: "informational", - navigation: { section: "agents", entityId: updatedAgent.id }, - batchKey: "agent_paused", - }); - }); - runCompletionSideEffect(logger, "agent-updated event emission", () => { - emitEvent({ type: "agent-updated", agentId: updatedAgent.id, action: "paused" }); - }); - } -} - -export function runPostCompletionAutomation( - event: RunFinishedEvent, - deps: HandlerDeps, - context: HandlerContext, - rfCtx: RunFinishedContext, -): { hadDeferredWakes: boolean } { - const { db, logger, isQuitting, wakeAgentIfPossible, processRunCompletion, onRunCompleted, notify, budgetService } = deps; - const { destroyed, MAX_RETRY_ATTEMPTS, RETRY_COOLDOWN_MS, pendingRetryTimers } = context; - const { run, task } = rfCtx; - let housekeepingStatus = event.status; - let housekeepingSummary = event.summary ?? null; - let housekeepingErrorMessage = event.errorMessage ?? null; - - // Policy-based incident check after run completion. Always runs once the - // run is finalized — cost is read from the cost_entries SUM inside - // finishRun/checkAndCreateIncidents, not from the worker event. - if (budgetService && event.status === "succeeded") { - try { - budgetService.checkAndCreateIncidents(run.companyId, run.agentId, task?.projectId ?? null); - } catch (error) { - logger.error(`[worker] budget incident check failed for run ${run.id}: ${errorMessage(error)}`); - } - } - - if ((event.status === "failed" || event.status === "timed_out") && !isQuitting() && !destroyed && run.taskId) { - try { - handleFailureEscalation( - { - db, - wakeAgentIfPossible, - notify: (title, body) => - notify({ title, body, urgency: "critical", navigation: { section: "tasks", entityId: run.taskId ?? "" } }), - logger, - }, - { taskId: run.taskId, agentId: run.agentId, companyId: run.companyId }, - task, - event.status, - MAX_RETRY_ATTEMPTS, - RETRY_COOLDOWN_MS, - (fn, delayMs) => { - const retryTimer = setTimeout(() => { - pendingRetryTimers.delete(retryTimer); - if (isQuitting() || destroyed) return; - fn(); - }, delayMs); - pendingRetryTimers.add(retryTimer); - }, - ); - } catch (error) { - logger.error(`[worker] failure escalation failed for run ${run.id}: ${errorMessage(error)}`); - } - } - - // EXEC-05: Promote deferred wakes after run completion - let hadDeferredWakes = false; - if (!isQuitting() && !destroyed) { - try { - const promoted = db.automation.wakeup.promoteWakeupRequests(run.agentId, run.companyId); - const pendingWakeTrigger = db.automation.wakeup.getPreferredWakeTrigger(run.agentId, run.companyId); - if (promoted > 0) { - logger.info(`[worker] Promoted ${promoted} deferred wake(s) for agent ${run.agentId}`); - } - if (pendingWakeTrigger) { - hadDeferredWakes = true; - logger.info( - `[worker] Processing pending wake(s) for agent ${run.agentId} with priority trigger "${pendingWakeTrigger}"`, - ); - wakeAgentIfPossible(run.agentId, run.companyId, pendingWakeTrigger); - } - } catch (error) { - logger.error(`[worker] deferred wake processing failed for run ${run.id}: ${errorMessage(error)}`); - } - } - - if (!isQuitting() && !destroyed) { - try { - processRunCompletion(run, event as z.infer & { type: "run-finished" }); - } catch (error) { - const message = errorMessage(error); - logger.error(`[worker] processRunCompletion failed for run ${run.id}: ${message}`); - housekeepingStatus = "failed"; - housekeepingSummary = null; - housekeepingErrorMessage = message; - try { - db.core.runs.markRunCompletionFailure(run.id, message); - } catch (markError) { - logger.error(`[worker] markRunCompletionFailure failed for run ${run.id}: ${errorMessage(markError)}`); - } - if (task?.status === "in_progress") { - try { - db.core.tasks.advanceTaskStatus( - task.id, - "blocked", - `Run completion automation failed: ${message}`, - ); - } catch (statusError) { - logger.error(`[worker] failed to block task ${task.id} after completion automation failure: ${errorMessage(statusError)}`); - } - } - } - } - - // Run housekeeping: thread events + knowledge candidates - if (!isQuitting() && !destroyed) { - try { - onRunCompleted?.( - run.id, - run.taskId, - run.agentId, - run.companyId, - housekeepingStatus, - housekeepingSummary, - housekeepingErrorMessage, - ); - } catch (err) { - logger.error(`[worker] onRunCompleted housekeeping failed: ${err instanceof Error ? err.message : String(err)}`); - } - } - - // Reset retry count on successful completion - if (housekeepingStatus === "succeeded" && run.taskId) { - handleSuccessReset(db, run.taskId, logger); - } - - return { hadDeferredWakes }; -} - -export function triggerSelfWake( - event: RunFinishedEvent, - deps: HandlerDeps, - context: HandlerContext, - rfCtx: RunFinishedContext, - hadDeferredWakes: boolean, -): void { - const { db, logger, isQuitting, wakeAgentIfPossible } = deps; - const { destroyed, selfWakeAttemptMap, MAX_CONSECUTIVE_SELF_WAKES } = context; - const { run } = rfCtx; - const attemptKey = runAttemptKey(run.agentId, run.companyId); - - // Reset self-wake attempts when a task actually progressed. - if (event.status === "succeeded") { - selfWakeAttemptMap.delete(attemptKey); - } - - // Self-wake through the shared run-attempt policy. - if (hadDeferredWakes || isQuitting() || destroyed) return; - - try { - const actionableTasks = db.core.tasks.listAgentTasks(run.agentId, run.companyId, ["todo", "in_progress"]); - const hasWorkToContinue = actionableTasks.length > 0 || hasUnfinishedTeamBuilding(db, run.agentId, run.companyId); - const consecutiveSelfWakes = selfWakeAttemptMap.get(attemptKey) ?? 0; - const decision = decideRunAttempt({ - kind: "self_wake", - hasWorkToContinue, - consecutiveSelfWakes, - maxConsecutiveSelfWakes: MAX_CONSECUTIVE_SELF_WAKES, - }); - - if (decision.action === "skip" && decision.reason === "no_work") return; - - if (decision.action === "skip") { - selfWakeAttemptMap.delete(attemptKey); - logger.warn( - `[self-wake] Run-attempt policy paused agent ${run.agentId} after ${MAX_CONSECUTIVE_SELF_WAKES} self-wakes without progress.`, - ); - // Escalate to manager since agent is stuck - try { - const chain = db.core.agents.getChainOfCommand(run.agentId); - if (chain.length > 0) { - wakeAgentIfPossible(chain[0].id, run.companyId, "report_stuck"); - } - } catch (error) { - logger.warn( - `[self-wake] chain-of-command lookup failed for agent ${run.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } else { - selfWakeAttemptMap.set(attemptKey, consecutiveSelfWakes + 1); - wakeAgentIfPossible(run.agentId, run.companyId, "task_continuation"); - } - } catch (error) { - logger.warn( - `[self-wake] self-wake evaluation failed for agent ${run.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } -} - -/** - * Returns true when a top-level agent (CEO) still has team-building work - * in flight: the company has an active goal, zero active direct reports, - * and no pending hire approvals. Each wake in that window files at most a - * handful of hire_agent POSTs, so chaining runs via self-wake instead of - * waiting for the 2-minute heartbeat timer takes bootstrap from - * 10-plus minutes down to the LLM's round-trip time. - * - * The run-attempt policy on the caller side still applies, so a CEO that - * keeps completing runs without actually creating hires gets paused - * after MAX_CONSECUTIVE_SELF_WAKES attempts. - */ -function hasUnfinishedTeamBuilding( - db: HandlerDeps["db"], - agentId: string, - companyId: string, -): boolean { - try { - const agent = db.core.entity.getAgent(agentId); - if (agent.reportsTo !== null) return false; - const activeReports = db.core.agents - .getDirectReports(agentId, companyId) - .filter((r) => r.status !== "pending_approval" && r.status !== "terminated"); - if (activeReports.length > 0) return false; - const goalCount = db.core.entity.countActiveGoalsForCompany(companyId); - if (goalCount === 0) return false; - const pendingHires = db.core.approvals - .listCompanyApprovalsByType(companyId, "hire_agent") - .filter((a) => a.state === "pending"); - return pendingHires.length === 0; - } catch { - return false; - } -} diff --git a/src/main/worker/handlers/run-log-handler.ts b/src/main/worker/handlers/run-log-handler.ts deleted file mode 100644 index 5bcc3447..00000000 --- a/src/main/worker/handlers/run-log-handler.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { filterRunLogChunk } from "../observability/run-log-filter"; -import { persistRunEvent } from "../observability/run-event-recorder"; -import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context"; -import { classifyUnknownError } from "../../errors/index.js"; - -const LEASE_RENEWAL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes - -export async function handleRunLog( - event: Extract, - deps: HandlerDeps, - context: HandlerContext, -): Promise { - const { db, logger, emitEvent } = deps; - const { leaseRenewalMap } = context; - - const filtered = filterRunLogChunk(event.stream, event.chunk); - if (filtered === null) return; - - await db.core.runs.appendRunLog(event.runId, event.stream, filtered); - const runState = db.core.runs.getRunAuthState(event.runId); - if (runState) { - persistRunEvent(db, logger, { - companyId: runState.companyId, - runId: event.runId, - agentId: runState.agentId, - eventType: "run_log", - stream: event.stream, - message: filtered, - }); - } - emitEvent({ ...event, chunk: filtered }); - - // Throttled lease renewal: keep execution lock alive for long-running tasks. - // Without this, tasks exceeding the 15-minute stale lock timeout get reclaimed. - const now = Date.now(); - const lastRenewal = leaseRenewalMap.get(event.runId) ?? 0; - if (now - lastRenewal >= LEASE_RENEWAL_INTERVAL_MS) { - try { - const run = db.core.runs.getRun(event.runId); - if (run.taskId) { - db.core.tasks.renewTaskLease(run.taskId, run.id); - } - leaseRenewalMap.set(event.runId, now); - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "worker.run_log.lease_renewal_lookup_failed", - message: `Run ${event.runId} not found during lease renewal`, - context: { runId: event.runId }, - }); - logger.warn(`[${classified.code}] ${classified.message}`); - } - } -} diff --git a/src/main/worker/handlers/run-status-handler.ts b/src/main/worker/handlers/run-status-handler.ts deleted file mode 100644 index 528585c2..00000000 --- a/src/main/worker/handlers/run-status-handler.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { persistRunEvent } from "../observability/run-event-recorder"; -import type { HandlerContext, HandlerDeps, WorkerMessageEvent } from "./handler-context"; -import { classifyUnknownError } from "../../errors/index.js"; - -export function handleRunStatus( - event: Extract, - deps: HandlerDeps, - _context: HandlerContext, -): void { - const { db, logger, emitEvent, onRunStarted } = deps; - - const runState = db.core.runs.getRunAuthState(event.runId); - db.core.runs.markRunStatus(event.runId, event.status, event.message); - if (runState) { - persistRunEvent(db, logger, { - companyId: runState.companyId, - runId: event.runId, - agentId: runState.agentId, - eventType: "run_status", - level: - event.status === "failed" || event.status === "timed_out" || event.status === "interrupted" - ? "error" - : "info", - message: event.message, - payload: { status: event.status }, - }); - } - if (event.status === "running") { - // D-02: Workspace lock is claimed authoritatively in main's - // dispatchRunToWorker before enqueue. Only lease renewal and - // run-started housekeeping run here. - try { - const run = db.core.runs.getRun(event.runId); - if (run.taskId) { - db.core.tasks.renewTaskLease(run.taskId, run.id); - } - onRunStarted?.(run.id, run.taskId, run.agentId, run.companyId); - } catch (err) { - const classified = classifyUnknownError(err, { - kind: "recoverable", - code: "worker.run_status.run_not_found", - message: `Run ${event.runId} not found during status handling`, - context: { runId: event.runId, status: event.status }, - }); - logger.warn(`[${classified.code}] ${classified.message}`); - } - } - emitEvent(event); - emitEvent({ type: "run-updated", runId: event.runId, action: "status_changed" }); -} diff --git a/src/main/worker/observability/failure-escalation.ts b/src/main/worker/observability/failure-escalation.ts deleted file mode 100644 index 56311f66..00000000 --- a/src/main/worker/observability/failure-escalation.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Retry-aware failure escalation pipeline. - * - * State machine: - * 1. Task fails with retry_count < MAX_RETRY_ATTEMPTS -> increment count, re-queue - * 2. Task fails with retry_count >= MAX_RETRY_ATTEMPTS -> escalate to manager chain - * 3. No manager in chain -> fall through to CEO - * 4. No CEO available -> notify user - * 5. Task succeeds -> reset retry count - */ - -import { decideRunAttempt } from "../../run-attempt-policy"; - -export interface EscalationDeps { - db: { - core: { - tasks: { - getTaskRetryCount: (taskId: string) => number; - incrementTaskRetryCount: (taskId: string) => void; - resetTaskRetryCount: (taskId: string) => void; - advanceTaskStatus: (taskId: string, status: string, note: string) => unknown; - }; - agents: { - getChainOfCommand: (agentId: string) => Array<{ id: string; name: string }>; - getCeoForCompany: (companyId: string) => { id: string; name: string } | null; - }; - }; - }; - wakeAgentIfPossible: (agentId: string, companyId: string, trigger: string) => unknown; - notify: (title: string, body: string) => void; - logger: { - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; - }; -} - -export interface EscalationResult { - action: "retry" | "escalated" | "user_notified" | "none"; - retryScheduled?: boolean; -} - -export function handleFailureEscalation( - deps: EscalationDeps, - run: { taskId: string; agentId: string; companyId: string }, - task: { title: string } | null, - eventStatus: "failed" | "timed_out", - maxRetryAttempts: number, - retryCooldownMs: number, - scheduleRetry: (fn: () => void, delayMs: number) => void, -): EscalationResult { - const { db, wakeAgentIfPossible, notify, logger } = deps; - const retryCount = db.core.tasks.getTaskRetryCount(run.taskId); - const retryDecision = decideRunAttempt({ - kind: "task_failure", - retryCount, - maxRetryAttempts, - }); - - if (retryDecision.action === "retry") { - db.core.tasks.incrementTaskRetryCount(run.taskId); - db.core.tasks.advanceTaskStatus( - run.taskId, - "todo", - `Run ${eventStatus} (attempt ${retryDecision.attemptNumber}/${maxRetryAttempts}). Auto-retrying after ${retryCooldownMs / 1000}s cooldown.`, - ); - logger.info( - `[escalation] Retrying task ${run.taskId} (attempt ${retryDecision.attemptNumber}/${maxRetryAttempts}) for agent ${run.agentId}`, - ); - scheduleRetry(() => { - wakeAgentIfPossible(run.agentId, run.companyId, "retry_failed"); - }, retryCooldownMs); - return { action: "retry", retryScheduled: true }; - } - - // Retry limit reached — escalate up the chain - db.core.tasks.resetTaskRetryCount(run.taskId); - logger.warn( - `[escalation] Task ${run.taskId} failed ${maxRetryAttempts} times. Escalating to manager.`, - ); - - let escalated = false; - try { - const chain = db.core.agents.getChainOfCommand(run.agentId); - if (chain.length > 0) { - wakeAgentIfPossible(chain[0].id, run.companyId, "report_failed"); - escalated = true; - logger.info( - `[escalation] Escalated task ${run.taskId} to manager ${chain[0].name} (${chain[0].id})`, - ); - } - } catch (error) { - logger.warn( - `[escalation] Chain-of-command lookup failed for agent ${run.agentId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - - if (!escalated) { - try { - const ceo = db.core.agents.getCeoForCompany(run.companyId); - if (ceo) { - wakeAgentIfPossible(ceo.id, run.companyId, "report_failed"); - escalated = true; - logger.info( - `[escalation] Escalated task ${run.taskId} to CEO ${ceo.name} (${ceo.id})`, - ); - } - } catch (error) { - logger.warn( - `[escalation] CEO lookup failed for company ${run.companyId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - if (!escalated) { - const taskTitle = task?.title ?? run.taskId; - notify( - "Task failed -- manual intervention needed", - `"${taskTitle}" failed ${maxRetryAttempts} times and no manager is available to handle it.`, - ); - logger.error( - `[escalation] Task ${run.taskId} failed with no escalation target. User notified.`, - ); - return { action: "user_notified" }; - } - - return { action: "escalated" }; -} - -export function handleSuccessReset( - db: EscalationDeps["db"], - taskId: string, - logger?: EscalationDeps["logger"], -): void { - try { - db.core.tasks.resetTaskRetryCount(taskId); - } catch (error) { - logger?.warn( - `[escalation] resetTaskRetryCount failed for task ${taskId}: ${error instanceof Error ? error.message : String(error)}`, - ); - } -} diff --git a/src/main/worker/observability/log-redactor.ts b/src/main/worker/observability/log-redactor.ts deleted file mode 100644 index f08dd298..00000000 --- a/src/main/worker/observability/log-redactor.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Pattern-based token redactor. - * - * Complements `buildRedactor` (env-value redaction) by scrubbing common - * credential shapes out of arbitrary strings before they reach the parent - * process — Bearer tokens, provider API keys, OAuth query params. - */ - -const PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [ - { pattern: /Bearer\s+[A-Za-z0-9._\-+/=]{8,}/g, replacement: "Bearer [REDACTED]" }, - { pattern: /(authorization\s*[:=]\s*)([^\s,;]{8,})/gi, replacement: "$1[REDACTED]" }, - { pattern: /(access_token=)([^&\s"']+)/gi, replacement: "$1[REDACTED]" }, - { pattern: /(refresh_token=)([^&\s"']+)/gi, replacement: "$1[REDACTED]" }, - { pattern: /(api[_-]?key\s*[:=]\s*['"]?)([A-Za-z0-9._-]{12,})/gi, replacement: "$1[REDACTED]" }, - { pattern: /sk-(?:ant-)?[A-Za-z0-9_-]{16,}/g, replacement: "sk-[REDACTED]" }, - { pattern: /ghp_[A-Za-z0-9]{16,}/g, replacement: "ghp_[REDACTED]" }, - { pattern: /gho_[A-Za-z0-9]{16,}/g, replacement: "gho_[REDACTED]" }, - { pattern: /AKIA[A-Z0-9]{16}/g, replacement: "AKIA[REDACTED]" }, -]; - -export function redactTokens(text: string): string { - let result = text; - for (const { pattern, replacement } of PATTERNS) { - result = result.replace(pattern, replacement); - } - return result; -} diff --git a/src/main/worker/observability/run-event-recorder.ts b/src/main/worker/observability/run-event-recorder.ts deleted file mode 100644 index 1f87b3d9..00000000 --- a/src/main/worker/observability/run-event-recorder.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { AppDatabase } from "../../database"; - -interface PersistInput { - companyId: string; - runId: string; - agentId: string; - eventType: string; - stream?: "stdout" | "stderr" | null; - level?: string | null; - message?: string | null; - payload?: Record | null; -} - -/** - * Best-effort `run_events` row writer used by the worker message handler. - * Failures are logged and swallowed because the run lifecycle must not be - * gated on audit-log writes. - */ -export function persistRunEvent( - db: AppDatabase, - logger: { warn: (...args: unknown[]) => void }, - input: PersistInput, -) { - try { - db.core.runs.appendRunEvent(input); - } catch (error) { - logger.warn( - `[run-events] Failed to append ${input.eventType} for ${input.runId}: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - } -} diff --git a/src/main/worker/observability/run-log-filter.ts b/src/main/worker/observability/run-log-filter.ts deleted file mode 100644 index 6eb23296..00000000 --- a/src/main/worker/observability/run-log-filter.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Run-log noise filter. - * - * CLI adapters emit stdout/stderr containing system-level JSON messages, - * hook lifecycle events, skill injection notices, and assistant internals - * (thinking/tool_use). This module strips those lines before they reach - * the user-facing run log on disk. - */ - -const RE_SKILL_INJECTION = /^\[agent-company\] Injected managed skill /; -const RE_OMC_HOOK = /^\[omc:hooks\]/; -const RE_AGENT_COMPANY_LOG = /^\[agent-company\] (?:heartbeat|hook_|system_)/; - -/** Matches system JSON except `init` subtype (which carries session metadata). */ -const RE_SYSTEM_JSON = /^\{"type"\s*:\s*"system"\s*,\s*"subtype"\s*:\s*"(?!init")/; - -/** Matches assistant thinking/tool_use JSON — internal reasoning, not user-visible output. */ -const RE_ASSISTANT_INTERNAL = - /^\{"type"\s*:\s*"assistant"\s*,\s*"subtype"\s*:\s*"(?:thinking|tool_use)"/; - -const RE_COMPACTING = /^Compacting conversation\.\.\./; - -function isNoisyLine(line: string): boolean { - const trimmed = line.trimStart(); - if (trimmed.length === 0) return false; - - return ( - RE_SKILL_INJECTION.test(trimmed) || - RE_OMC_HOOK.test(trimmed) || - RE_AGENT_COMPANY_LOG.test(trimmed) || - RE_SYSTEM_JSON.test(trimmed) || - RE_ASSISTANT_INTERNAL.test(trimmed) || - RE_COMPACTING.test(trimmed) - ); -} - -/** - * Filters a raw log chunk by removing noisy lines. - * @returns The cleaned chunk, or `null` if the entire chunk is noise. - */ -export function filterRunLogChunk( - _stream: "stdout" | "stderr", - chunk: string, -): string | null { - const lines = chunk.split("\n"); - const kept: string[] = []; - - for (const line of lines) { - if (!isNoisyLine(line)) { - kept.push(line); - } - } - - if (kept.length === 0) return null; - - const result = kept.join("\n"); - return result.length === 0 ? null : result; -} diff --git a/src/main/worker/runtime/credential-concurrency-gate.ts b/src/main/worker/runtime/credential-concurrency-gate.ts deleted file mode 100644 index 9740393b..00000000 --- a/src/main/worker/runtime/credential-concurrency-gate.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { createHash } from "node:crypto"; - -/** - * Per-credential async concurrency gate. - * - * The gate hands out a bounded number of concurrent slots per - * `(provider, apiKey)` pair. When the cap is reached, further - * `acquire` calls park until an in-flight caller releases its slot. - * - * The Boss build seeds a single Fire Pass key shared by every agent. - * Without serialization, the worker fans out three or more concurrent - * `streamSimple` calls against the personal-tier router and trips - * HTTP 429 on every burst. Holding a slot per credential prevents - * the burst at the source instead of recovering from it after the - * fact, which keeps the runtime aligned with the project's - * "let it crash" rule (no retry/backoff fallback layer is added). - * - * The gate is process-local. Only one orchestrator worker runs at a - * time, so a single gate instance correctly serializes every agent - * sharing a credential. - */ -export type ConcurrencyLimitResolver = (provider: string) => number | null; - -export interface CredentialConcurrencyGate { - acquire(provider: string, apiKey: string, signal?: AbortSignal): Promise<() => void>; -} - -interface Waiter { - notify: () => void; - cancel: (err: Error) => void; - signal?: AbortSignal; - abortListener?: () => void; -} - -interface SlotPool { - inFlight: number; - readonly limit: number; - readonly waiters: Waiter[]; -} - -const NOOP_RELEASE = () => undefined; - -function poolKey(provider: string, apiKey: string): string { - // Hash the apiKey so the Map key cannot echo a raw credential into - // heap dumps or future debug output — the gate only needs equality. - const digest = createHash("sha1").update(apiKey).digest("hex").slice(0, 16); - return `${provider}:${digest}`; -} - -function createAbortError(): Error { - const err = new Error("Aborted while waiting for credential concurrency slot."); - err.name = "AbortError"; - return err; -} - -export class InMemoryCredentialConcurrencyGate implements CredentialConcurrencyGate { - private readonly pools = new Map(); - private readonly limitFor: ConcurrencyLimitResolver; - - constructor(limitFor: ConcurrencyLimitResolver) { - this.limitFor = limitFor; - } - - async acquire(provider: string, apiKey: string, signal?: AbortSignal): Promise<() => void> { - const limit = this.limitFor(provider); - if (limit === null) return NOOP_RELEASE; - if (signal?.aborted) throw createAbortError(); - const key = poolKey(provider, apiKey); - const pool = this.getOrCreatePool(key, limit); - if (pool.inFlight < pool.limit) { - pool.inFlight += 1; - return this.makeReleaser(key); - } - await this.waitForSlot(pool, signal); - pool.inFlight += 1; - return this.makeReleaser(key); - } - - private getOrCreatePool(key: string, limit: number): SlotPool { - const existing = this.pools.get(key); - if (existing) return existing; - const pool: SlotPool = { inFlight: 0, limit, waiters: [] }; - this.pools.set(key, pool); - return pool; - } - - private waitForSlot(pool: SlotPool, signal?: AbortSignal): Promise { - return new Promise((resolve, reject) => { - const waiter: Waiter = { - notify: () => { - this.detachAbort(waiter); - resolve(); - }, - cancel: (err) => { - const idx = pool.waiters.indexOf(waiter); - if (idx >= 0) pool.waiters.splice(idx, 1); - this.detachAbort(waiter); - reject(err); - }, - signal, - }; - if (signal) { - const onAbort = () => waiter.cancel(createAbortError()); - waiter.abortListener = onAbort; - signal.addEventListener("abort", onAbort, { once: true }); - } - pool.waiters.push(waiter); - }); - } - - private detachAbort(waiter: Waiter): void { - if (waiter.abortListener && waiter.signal) { - waiter.signal.removeEventListener("abort", waiter.abortListener); - } - } - - private makeReleaser(key: string): () => void { - let released = false; - return () => { - if (released) return; - released = true; - const pool = this.pools.get(key); - if (!pool) return; - pool.inFlight = Math.max(0, pool.inFlight - 1); - const next = pool.waiters.shift(); - if (next) next.notify(); - if (pool.inFlight === 0 && pool.waiters.length === 0) { - this.pools.delete(key); - } - }; - } -} diff --git a/src/main/worker/runtime/helpers.ts b/src/main/worker/runtime/helpers.ts deleted file mode 100644 index f07fb97d..00000000 --- a/src/main/worker/runtime/helpers.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { AgentMessage } from "@mariozechner/pi-agent-core"; -import type { RunStatus, RunUsageStatus } from "@shared/types"; - -export interface RunJob { - runId: string; - companyId: string; - /** Null for heartbeat runs with no assigned task. Must stay aligned with EnqueueRunPayload. */ - taskId: string | null; - agentId: string; - agentName: string; - connectorId: string; - workspaceId: string | null; - workspacePath: string | null; - workspaceMode: "exclusive" | "shared" | "none"; - model: string | null; - thinkingEffort: string | null; - env: Record; - systemPrompt: string | null; - trigger: string | null; - taskSessionId: string; - executionMode: "ai_ceo" | "ai_cofounder"; - /** Seed user turn that kicks off the pi agent loop. Never empty. */ - initialUserTurn: string; - /** - * Internal tools (`hire_agent`, `file_approval`) to register on this - * run's agent in addition to the default coding tools. Determined on - * main side before enqueue so the worker never needs to inspect - * company/agent state. Empty array = no extra tools. - */ - internalTools: ReadonlyArray<"hire_agent" | "file_approval">; -} - -/** - * Parent → worker control-plane messages. `steer-run` is the inward half - * of pi's mid-run injection contract: the worker owns the Agent instance, - * main owns the inbox DB, so main posts the enqueued user message here and - * the worker calls `agent.steer()`. - * - * `correlationId` pairs each steer with a `steer-ack` child reply so main - * can hold the "inbox delivered" write until the worker has queued the - * message onto the live Agent. Without the ACK, a steer that lost the - * race against run teardown would be silently dropped after main already - * marked the row delivered. - */ -export type RunAgentLifecycleState = "agent_active" | "closing"; - -export type ParentMessage = - | { type: "enqueue-run"; payload: RunJob } - | { type: "cancel-run"; runId: string } - | { type: "run-completion-ack"; runId: string } - | { type: "shutdown" } - | { type: "shutdown-exit" } - | { type: "steer-run"; runId: string; correlationId: string; message: AgentMessage } - | { type: "rpc-response"; rpcId: string; response: { ok: true; result: unknown } | { ok: false; error: string } }; - -export type ChildMessage = - | { type: "run-log"; runId: string; stream: "stdout" | "stderr"; chunk: string } - | { type: "run-status"; runId: string; status: RunStatus; message: string } - | { - type: "run-finished"; - runId: string; - status: RunStatus; - summary: string | null; - errorMessage: string | null; - exitCode: number | null; - signal: string | null; - model: string | null; - usageStatus: RunUsageStatus; - inputTokens: number | null; - outputTokens: number | null; - } - | { - type: "agent-event"; - runId: string; - agentId: string; - companyId: string; - taskId: string | null; - emittedAt: string; - event: { type: string } & Record; - } - | { - type: "context-compaction"; - runId: string; - emittedAt: string; - estimatedTokens: number; - originalMessageCount: number; - compactedMessageCount: number; - compactedOlderMessageCount: number; - retainedRecentMessageCount: number; - } - | { type: "rpc-request"; rpcId: string; runId: string; method: string; payload: unknown } - | { type: "run-agent-state"; runId: string; state: RunAgentLifecycleState } - | { type: "steer-ack"; runId: string; correlationId: string; accepted: boolean } - | { type: "shutdown-ready" }; - -export function buildRedactor(env: Record): (text: string) => string { - const sensitivePatterns: string[] = []; - for (const [key, value] of Object.entries(env)) { - if (value.length < 8) continue; - if (["PATH", "HOME", "USER", "SHELL", "LANG", "TMPDIR", "TERM"].includes(key)) continue; - sensitivePatterns.push(value); - } - if (sensitivePatterns.length === 0) return (text) => text; - sensitivePatterns.sort((a, b) => b.length - a.length); - return (text: string) => { - let result = text; - for (const pattern of sensitivePatterns) { - if (result.includes(pattern)) { - result = result.replaceAll(pattern, "[REDACTED]"); - } - } - return result; - }; -} diff --git a/src/main/worker/runtime/index.ts b/src/main/worker/runtime/index.ts deleted file mode 100644 index 5458b731..00000000 --- a/src/main/worker/runtime/index.ts +++ /dev/null @@ -1,288 +0,0 @@ -import type { Agent, AgentMessage } from "@mariozechner/pi-agent-core"; -import { resolveModel, resolveExtraStreamHeaders } from "../../model-resolver"; -import type { RunStatus } from "@shared/types"; -import type { ChildMessage, RunJob } from "./helpers"; -import { buildRedactor } from "./helpers"; -import { createPiAgent, resolveThinkingLevel, type ErasedAgentTool } from "./pi-agent-factory"; -import type { WorkerRpcClient } from "../entry/rpc"; -import { createHireAgentTool, HIRE_AGENT_TOOL_NAME } from "./internal-tools/hire-agent-tool"; -import { createFileApprovalTool, FILE_APPROVAL_TOOL_NAME } from "./internal-tools/file-approval-tool"; -import { createRunScopedCodingTools, mergeRunEnvs } from "./run-tools"; -import { - classifyRunUsage, - hasAttributableAssistantUsage, - isTerminalAssistantStopReason, - type TerminalAssistantStopReason, -} from "../../run-usage-status"; - -interface PrepareRunResult { - provider: string; - apiKey: string; - extraEnv: Record; - /** OpenAI-compatible server base URL for local connectors (Ollama, LM Studio). */ - baseUrl: string | null; - priorMessages: AgentMessage[]; -} - -interface RunnerDeps { - post: (message: ChildMessage) => void; - rpc: WorkerRpcClient; - isCancelled: (runId: string) => boolean; -} - -/** - * Lifecycle owner for one-and-only-one active pi `Agent` per run. - * - * Responsibilities: - * - Calls `prepareRun` on main to materialise session + credentials. - * - Builds an `Agent` via `createPiAgent` with the full Pi contract. - * - Streams every pi `AgentEvent` into the worker → main pipe. - * - Persists each `message_end` message through `persistMessage` RPC. - * - Exposes `steer` to the worker entry so mid-run injections from - * main land on the in-process Agent instance. - * - Publishes `run-agent-state` transitions so main can tell whether - * an active run is actually ready to accept steer messages. - */ -export class WorkerRunner { - private readonly abortControllers = new Map(); - private readonly runPromises = new Map>(); - private readonly activeAgents = new Map(); - - constructor(private readonly deps: RunnerDeps) {} - - cancel(runId: string): void { - const controller = this.abortControllers.get(runId); - if (controller) controller.abort(); - } - - /** - * Enqueue a steering message onto the active Agent for this run. Returns - * true iff the Agent instance exists in `activeAgents` and the message - * was appended to its steering queue. A false return means the run has - * either not finished construction (pre-`agent_active`) or has already - * torn down (post-`closing`); callers must treat the steer as rejected - * so main can hold the inbox `delivered_at` write and fall back to the - * inbox + wake path instead. - */ - steer(runId: string, message: AgentMessage): boolean { - const agent = this.activeAgents.get(runId); - if (!agent) return false; - agent.steer(message); - return true; - } - - /** - * Aborts every in-flight run and returns a promise that resolves once - * each `run()` has settled (success, failure, or abort). Callers (the - * worker shutdown handler) must `await` this before `process.exit` so - * pending `persistMessage` RPCs and the final `run-finished` post reach - * the parent before the worker dies. - */ - async cancelAll(): Promise { - for (const controller of this.abortControllers.values()) { - controller.abort(); - } - const pending = [...this.runPromises.values()]; - this.abortControllers.clear(); - await Promise.allSettled(pending); - } - - run(job: RunJob): Promise { - const promise = this.runImpl(job).finally(() => { - this.runPromises.delete(job.runId); - }); - this.runPromises.set(job.runId, promise); - return promise; - } - - private async runImpl(job: RunJob): Promise { - const { post, rpc, isCancelled } = this.deps; - let redact = buildRedactor(job.env); - const abortController = new AbortController(); - this.abortControllers.set(job.runId, abortController); - - post({ type: "run-status", runId: job.runId, status: "running", message: `Running agent ${job.agentName}.` }); - - let resolvedModelId: string | null = job.model; - let finalUsage: { inputTokens: number | null; outputTokens: number | null } = { - inputTokens: null, - outputTokens: null, - }; - let sawAttributableUsage = false; - let terminalStopReason: TerminalAssistantStopReason | null = null; - let errorMessage: string | null = null; - - try { - if (!job.model) { - throw new Error(`Run ${job.runId} has no model selected.`); - } - - const prepareResponse = await rpc.invoke(job.runId, "prepareRun", { - connectorId: job.connectorId, - taskSessionId: job.taskSessionId, - agentId: job.agentId, - companyId: job.companyId, - taskId: job.taskId, - modelId: job.model, - workspaceId: job.workspaceId ?? null, - workspacePath: job.workspacePath ?? null, - workspaceMode: job.workspaceMode, - }); - if (!prepareResponse.ok) { - throw new Error(prepareResponse.error); - } - const prepared = prepareResponse.result as PrepareRunResult; - const runEnv = mergeRunEnvs(job.env, prepared.extraEnv); - redact = buildRedactor(runEnv); - - const model = resolveModel(prepared.provider, job.model, { - baseUrl: prepared.baseUrl ?? undefined, - }); - if (!model) { - throw new Error(`Unknown model ${job.model} for provider ${prepared.provider}.`); - } - resolvedModelId = model.id; - const extraHeaders = resolveExtraStreamHeaders(prepared.provider, prepared.apiKey); - - const cwd = job.workspacePath ?? process.cwd(); - const codingTools = createRunScopedCodingTools(cwd, runEnv); - const internalTools: ErasedAgentTool[] = []; - for (const toolName of job.internalTools ?? []) { - switch (toolName) { - case HIRE_AGENT_TOOL_NAME: - internalTools.push(createHireAgentTool(rpc, job.runId)); - break; - case FILE_APPROVAL_TOOL_NAME: - internalTools.push(createFileApprovalTool(rpc, job.runId)); - break; - default: { - // Exhaustiveness guard: a new entry in the `internalTools` - // array without a matching case should be a compile-time - // regression. - const _exhaustive: never = toolName; - throw new Error(`Unknown internal tool requested: ${String(_exhaustive)}`); - } - } - } - const tools: ErasedAgentTool[] = [...codingTools, ...internalTools]; - - const agent = createPiAgent({ - runId: job.runId, - taskSessionId: job.taskSessionId, - systemPrompt: job.systemPrompt ?? "", - model, - tools, - priorMessages: prepared.priorMessages, - thinkingLevel: resolveThinkingLevel(job.thinkingEffort), - apiKey: prepared.apiKey, - extraHeaders, - streamEnv: prepared.extraEnv, - rpc, - onContextCompaction: (telemetry) => { - post({ - type: "context-compaction", - runId: telemetry.runId, - emittedAt: telemetry.emittedAt, - estimatedTokens: telemetry.estimatedTokens, - originalMessageCount: telemetry.originalMessageCount, - compactedMessageCount: telemetry.compactedMessageCount, - compactedOlderMessageCount: telemetry.compactedOlderMessageCount, - retainedRecentMessageCount: telemetry.retainedRecentMessageCount, - }); - }, - }); - this.activeAgents.set(job.runId, agent); - post({ type: "run-agent-state", runId: job.runId, state: "agent_active" }); - - const unsubscribe = agent.subscribe(async (event) => { - const timestamp = new Date().toISOString(); - post({ - type: "agent-event", - runId: job.runId, - agentId: job.agentId, - companyId: job.companyId, - taskId: job.taskId, - emittedAt: timestamp, - event: event as { type: string } & Record, - }); - - if (event.type === "message_end" && event.message) { - const persistResponse = await rpc.invoke(job.runId, "persistMessage", { - taskSessionId: job.taskSessionId, - message: event.message, - }); - if (!persistResponse.ok) { - throw new Error(`persistMessage RPC failed: ${persistResponse.error}`); - } - const maybeAssistant = event.message as { - role?: string; - stopReason?: string; - errorMessage?: string; - usage?: { input?: number; output?: number; cost?: { total?: number } }; - }; - if (maybeAssistant.role === "assistant" && isTerminalAssistantStopReason(maybeAssistant.stopReason)) { - terminalStopReason = maybeAssistant.stopReason; - errorMessage = maybeAssistant.errorMessage ?? `Agent stopped with ${maybeAssistant.stopReason}.`; - } - if (hasAttributableAssistantUsage(maybeAssistant)) { - sawAttributableUsage = true; - finalUsage = { - inputTokens: typeof maybeAssistant.usage.input === "number" ? maybeAssistant.usage.input : finalUsage.inputTokens, - outputTokens: typeof maybeAssistant.usage.output === "number" ? maybeAssistant.usage.output : finalUsage.outputTokens, - }; - } - } - }); - - try { - const promptContent = job.initialUserTurn.trim(); - if (promptContent.length === 0) { - throw new Error(`Run ${job.runId} has an empty initial user turn.`); - } - const promptMessage: AgentMessage = { - role: "user", - content: [{ type: "text", text: promptContent }], - timestamp: Date.now(), - }; - const runPromise = agent.prompt(promptMessage); - abortController.signal.addEventListener("abort", () => agent.abort(), { once: true }); - await runPromise; - } finally { - post({ type: "run-agent-state", runId: job.runId, state: "closing" }); - unsubscribe(); - this.activeAgents.delete(job.runId); - } - } catch (error) { - errorMessage = error instanceof Error ? error.message : String(error); - post({ type: "run-log", runId: job.runId, stream: "stderr", chunk: redact(errorMessage) }); - } finally { - this.abortControllers.delete(job.runId); - } - - const status: RunStatus = isCancelled(job.runId) - ? "cancelled" - : errorMessage - ? "failed" - : "succeeded"; - const usageStatus = classifyRunUsage({ - runStatus: status, - errorMessage, - sawAttributableUsage, - terminalStopReason, - }); - - post({ - type: "run-finished", - runId: job.runId, - status, - summary: null, - errorMessage, - exitCode: null, - signal: null, - model: resolvedModelId, - usageStatus, - inputTokens: finalUsage.inputTokens, - outputTokens: finalUsage.outputTokens, - }); - } -} diff --git a/src/main/worker/runtime/internal-tools/file-approval-tool.ts b/src/main/worker/runtime/internal-tools/file-approval-tool.ts deleted file mode 100644 index 640db6e5..00000000 --- a/src/main/worker/runtime/internal-tools/file-approval-tool.ts +++ /dev/null @@ -1,139 +0,0 @@ -/** - * `file_approval` internal tool (C4 part 2/5). - * - * Collapses the `bash + node -e + fetch POST /api/companies/:id/approvals` - * chain into a single tool-call the CEO (or any agent with request - * authority) can invoke directly. The handler in main reuses the same - * `db.core.approvals.requestApproval` primitive and auto-approval policy - * the HTTP route uses, so both paths produce identical rows and the - * `approve_ceo_strategy` ordering gate fires identically. - * - * Like `hire_agent`, the worker-side `execute` is a thin RPC proxy. - * Validation failures come back as classified errors from main; pi's - * tool-error convention surfaces them to the model on the next turn. - */ - -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import { Type, type Static } from "@mariozechner/pi-ai"; -import type { WorkerRpcClient } from "../../entry/rpc"; -import type { - InvokeInternalToolRpcPayload, - InvokeInternalToolRpcResult, -} from "./internal-tool-rpc"; - -export const FILE_APPROVAL_TOOL_NAME = "file_approval"; - -/** - * TypeBox schema for `file_approval` arguments. - * - * Kept intentionally narrow (type + summaries + optional payload JSON) - * so the model sees the shape of an approval as a primitive concept - * rather than an HTTP body to marshal. `type` is an enum drawn directly - * from `shared/contracts/schemas-approvals.ts :: approvalInputSchema`; - * the handler re-validates with zod so adding a new approval type over - * there does not silently un-gate here. - */ -export const fileApprovalSchema = Type.Object({ - type: Type.Union( - [ - Type.Literal("hire_agent"), - Type.Literal("approve_ceo_strategy"), - Type.Literal("dangerous_command"), - Type.Literal("secret_access"), - Type.Literal("budget_request"), - Type.Literal("promotion"), - Type.Literal("termination"), - Type.Literal("vendor_approval"), - Type.Literal("document_review"), - Type.Literal("production_deploy"), - Type.Literal("incident_escalation"), - Type.Literal("social_post"), - Type.Literal("deliverable_review"), - Type.Literal("budget_override"), - Type.Literal("plan_review"), - Type.Literal("scope_review"), - Type.Literal("draft_review"), - Type.Literal("strategy_review"), - Type.Literal("exception_review"), - ], - { - description: - "Approval type. Use 'approve_ceo_strategy' after filing the initial hire_agent approvals to lock in the org shape.", - }, - ), - payloadSummary: Type.String({ - description: - "One-line human-readable summary of what is being approved (≤280 chars).", - minLength: 2, - maxLength: 280, - }), - impactSummary: Type.String({ - description: - "Why this approval matters / business rationale (≤400 chars).", - minLength: 2, - maxLength: 400, - }), - payloadJson: Type.Optional( - Type.String({ - description: - "Optional JSON string carrying type-specific structured payload (hire proposal, social draft, etc.). Must be valid JSON if provided. For attaching existing documents or work products, use documentIds / workProductIds — the board UI renders those directly on the first screen.", - }), - ), - documentIds: Type.Optional( - Type.Array(Type.String(), { - description: - "UUIDs of existing company documents to attach to this approval. The board inspector surfaces each attachment on the first screen of the approval modal. Prefer this over jamming {documentIds:[...]} into payloadJson.", - }), - ), - workProductIds: Type.Optional( - Type.Array(Type.String(), { - description: - "UUIDs of existing work products (files on disk, external URLs) to attach to this approval. The board inspector renders each row as a clickable link that opens in the operator's default application.", - }), - ), - relatedTaskId: Type.Optional( - Type.String({ - description: "UUID of the task this approval pertains to, if any.", - }), - ), - relatedAgentId: Type.Optional( - Type.String({ - description: "UUID of the agent this approval pertains to, if any.", - }), - ), -}); - -export type FileApprovalToolInput = Static; - -/** - * Construct the worker-side `file_approval` tool. - * - * Routes every call through the internal-tool RPC method so main owns - * the approval creation + auto-approval policy. - */ -export function createFileApprovalTool(rpc: WorkerRpcClient, runId: string): AgentTool { - return { - name: FILE_APPROVAL_TOOL_NAME, - label: "file approval", - description: - "File an approval request with the company board. Use for 'approve_ceo_strategy' after filing initial hires, or for any other decision that requires board sign-off. When the approval references existing documents or work products (e.g. deliverable_review, document_review), pass their UUIDs via documentIds / workProductIds so the board inspector can render them as clickable attachments on the first screen — do not bury IDs inside payloadJson. The request is auto-approved when the company is in hands-off mode; otherwise it waits for the human operator.", - parameters: fileApprovalSchema, - async execute(toolCallId, params, _signal?, _onUpdate?) { - const payload: InvokeInternalToolRpcPayload = { - toolName: FILE_APPROVAL_TOOL_NAME, - toolCallId, - args: params, - }; - const response = await rpc.invoke(runId, "invokeInternalTool", payload); - if (!response.ok) { - throw new Error(response.error); - } - const result = response.result as InvokeInternalToolRpcResult; - return { - content: result.content, - details: result.details, - isError: result.isError, - }; - }, - }; -} diff --git a/src/main/worker/runtime/internal-tools/hire-agent-tool.ts b/src/main/worker/runtime/internal-tools/hire-agent-tool.ts deleted file mode 100644 index cd9984be..00000000 --- a/src/main/worker/runtime/internal-tools/hire-agent-tool.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * `hire_agent` internal tool (C4 part 1/5). - * - * Replaces the pre-C4 flow where the CEO had to call the `bash` tool, - * spawn `node -e`, and POST to `/api/companies/:id/agents` on its own - * HTTP server. Every layer of that stack was an implementation detail - * leaking into the LLM prompt — if `bash` or `node` went away, the - * tool-call would silently fail. The first-class tool collapses the - * chain to a single pi tool-call whose schema the model can see and - * whose result comes back on the next turn. - * - * The tool is wire-compatible with the HTTP `POST /api/companies/:id/agents` - * endpoint (same field set, same validation order) so main's handler can - * reuse the existing `createHireRequest` DB primitive without duplicating - * the approval + auto-approval plumbing. The HTTP path stays live - * through the deprecation window documented in C4 part 5/5. - * - * Worker side: `execute` is a thin RPC proxy — no schema validation, no - * fallbacks. An invalid payload (missing field, blank string, duplicate - * name) surfaces as a `UserInputError` from main, which the RPC envelope - * converts to `{ ok: false, error }`, which the tool execute wrapper - * re-throws as an Error. Pi's loop then produces a tool-error result - * carrying the classified message — exactly what we want the CEO to see - * on its next turn so it can correct the hire. - * - * Main-side handler lives in `hire-agent-handler.ts` and is bound by the - * internal-tools router registered in `RuntimeBridge`. - */ - -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import { Type, type Static } from "@mariozechner/pi-ai"; -import type { WorkerRpcClient } from "../../entry/rpc"; -import type { - InvokeInternalToolRpcPayload, - InvokeInternalToolRpcResult, -} from "./internal-tool-rpc"; - -export const HIRE_AGENT_TOOL_NAME = "hire_agent"; - -/** - * TypeBox schema for `hire_agent` arguments. - * - * Intentionally mirrors `shared/contracts/schemas-agents.ts :: hireRequestSchema` - * on the main side — the handler re-validates with zod, so the TypeBox - * schema here is the model-facing advertisement and the zod schema is - * the boundary. Keeping both narrow (required `name/role/connectorId/model`, - * optional `department/title/reportsTo`) rejects malformed calls before - * they hit the DB layer. - * - * `department` is a free string here rather than a Union of the canonical - * set: the schemas-agents file accepts `nullable().optional()` via the - * shared `DEPARTMENT_IDS` enum, and echoing the enum in TypeBox would - * force the drift onto two schemas. The main handler validates against - * `DEPARTMENT_IDS` so an out-of-range value fails closed. - */ -export const hireAgentSchema = Type.Object({ - name: Type.String({ - description: - "Short display name for the new direct report (e.g. 'Ada Lovelace', 'CTO Claude'). Must be unique within the company and at least 2 characters.", - minLength: 2, - maxLength: 80, - }), - role: Type.String({ - description: - "Business role title (e.g. 'Chief Technology Officer', 'Head of Marketing').", - minLength: 2, - maxLength: 80, - }), - title: Type.Optional( - Type.String({ - description: "Short title displayed in UI; defaults to empty.", - maxLength: 80, - }), - ), - department: Type.Optional( - Type.String({ - description: - "Department bucket. One of: engineering, product, design, marketing, sales, hr, finance, legal, operations, customer_support, research, executive.", - }), - ), - capabilities: Type.Optional( - Type.String({ - description: - "One-paragraph description of what this hire owns. Surfaces in the hire approval and the briefing.", - }), - ), - reportsTo: Type.Optional( - Type.String({ - description: - "UUID of the manager this hire should report to. Omit to default to the requesting agent (or the department lead if applicable).", - }), - ), - connectorId: Type.String({ - description: - "Connector id drawn from the Available Connectors block in the briefing; must be in a ready state.", - }), - model: Type.String({ - description: - "Model id allowed by the connector's enabled-models list (e.g. 'claude-4-7', 'gpt-5').", - }), - budgetMonthlyUsd: Type.Optional( - Type.Number({ - description: - "Monthly USD spend cap for this hire. Defaults to 150 if omitted.", - minimum: 0, - }), - ), -}); - -export type HireAgentToolInput = Static; - -/** - * Construct the worker-side `hire_agent` tool. - * - * The returned `AgentTool` routes every call through the internal-tool - * RPC method so main owns the DB write. No retries, no fallbacks, no - * argument coercion — the schema is the contract and any deviation - * surfaces through the pi tool-error convention. - */ -export function createHireAgentTool(rpc: WorkerRpcClient, runId: string): AgentTool { - return { - name: HIRE_AGENT_TOOL_NAME, - label: "hire agent", - description: - "File a hire_agent approval to add one direct report. During CEO Team Building, call this tool 3 to 5 times to populate the initial team. Outside Team Building, use it when the CEO or another manager needs to fill one role. The approval is auto-approved for hands-off companies; otherwise it goes to the board.", - parameters: hireAgentSchema, - async execute(toolCallId, params, _signal?, _onUpdate?) { - const payload: InvokeInternalToolRpcPayload = { - toolName: HIRE_AGENT_TOOL_NAME, - toolCallId, - args: params, - }; - const response = await rpc.invoke(runId, "invokeInternalTool", payload); - if (!response.ok) { - // Propagate classified errors from main. pi wraps the throw into - // a tool-error result the model sees on the next turn. - throw new Error(response.error); - } - const result = response.result as InvokeInternalToolRpcResult; - return { - content: result.content, - details: result.details, - isError: result.isError, - }; - }, - }; -} diff --git a/src/main/worker/runtime/internal-tools/internal-tool-rpc.ts b/src/main/worker/runtime/internal-tools/internal-tool-rpc.ts deleted file mode 100644 index 27f87b57..00000000 --- a/src/main/worker/runtime/internal-tools/internal-tool-rpc.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * RPC contract for internal (main-side) agent tools. - * - * The worker constructs pi `AgentTool` instances whose `execute` method - * proxies to main via `WorkerRpcClient.invoke(runId, "invokeInternalTool", - * payload)`. Main answers from `RuntimeBridge.handleRpc` by dispatching - * to the handler registered for `toolName`. Handlers live on main because - * they need the SQLite connection, approval subsystem, and telemetry — - * none of which the worker should replicate. - * - * This mirrors the `beforeToolCall` RPC envelope in `hook-rpc.ts`: - * a minimal tool-call payload crosses the worker boundary and main owns - * the business effect. Keeping the payload shape minimal (name + JSON - * args) mirrors pi's `ToolCall` structure so adding a new internal tool - * requires no new RPC method — only a new handler entry. - */ - -export interface InvokeInternalToolRpcPayload { - toolName: string; - toolCallId: string; - args: unknown; -} - -/** - * Result envelope returned by the main-side handler. - * - * Carries the tool's textual output (what the model sees on the next - * turn) plus an `isError` discriminator. `details` is optional - * structured context the renderer can attach to the tool-call card; - * omit it when the tool's response is purely textual. - * - * A handler that wants to surface a validation failure throws a - * `UserInputError`; `RuntimeBridge` translates the throw into an - * `{ ok: false, error }` RPC envelope, and the worker-side tool wrapper - * converts that back into a pi tool-error result. That path keeps every - * internal-tool failure mode aligned with pi's own tool-error - * convention without teaching the worker about AppError classes. - */ -export interface InvokeInternalToolRpcResult { - content: { type: "text"; text: string }[]; - details: unknown; - isError: boolean; -} diff --git a/src/main/worker/runtime/pi-agent-factory.ts b/src/main/worker/runtime/pi-agent-factory.ts deleted file mode 100644 index 302edb5a..00000000 --- a/src/main/worker/runtime/pi-agent-factory.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Factory that assembles a `pi-agent-core` Agent from a prepared worker - * job. Encapsulates the full Pi contract (initial state, sessionId, - * thinkingLevel, beforeToolCall / transformContext - * hooks, streamFn) so `worker-runner` stays focused on run lifecycle. - * - * `beforeToolCall` proxies into main via the worker RPC client; main - * answers from `RuntimeBridge`. Pi's loop is tolerant of thrown hooks, - * so approval RPC failures degrade to a deterministic tool-error. The - * `transformContext` hook runs the deterministic compactor in the worker - * process and lets compaction failures fail the run explicitly. - */ - -import { - Agent, - type AgentMessage, - type AgentState, - type ThinkingLevel, -} from "@mariozechner/pi-agent-core"; -import type { Api, Model } from "@mariozechner/pi-ai"; -import { buildAgentHooks } from "@main/agent-runtime/agent-hooks"; -import type { ContextCompactionTelemetry } from "@main/agent-runtime/agent-hooks"; -import type { WorkerRpcClient } from "../entry/rpc"; -import { safeStreamSimpleWithEnv } from "./pi-safe-stream"; -// Side-effect import: drags the hook signature contract into the typecheck -// graph so any drift in pi-agent-core hook shapes breaks the build here. -import "./pi-hook-contract"; - -export type ErasedAgentTool = AgentState["tools"][number]; - -export interface PiAgentFactoryInput { - runId: string; - taskSessionId: string; - systemPrompt: string; - model: Model; - tools: ErasedAgentTool[]; - priorMessages: AgentMessage[]; - thinkingLevel: ThinkingLevel; - apiKey: string; - extraHeaders: Record | undefined; - streamEnv?: Record; - rpc: WorkerRpcClient; - onContextCompaction?: (telemetry: ContextCompactionTelemetry) => void; -} - -/** Map the UI-facing `thinkingEffort` string onto pi's `ThinkingLevel`. */ -export function resolveThinkingLevel(effort: string | null | undefined): ThinkingLevel { - switch (effort) { - case "minimal": - return "minimal"; - case "low": - return "low"; - case "medium": - return "medium"; - case "high": - return "high"; - case "xhigh": - return "xhigh"; - default: - return "off"; - } -} - -export function createPiAgent(input: PiAgentFactoryInput): Agent { - const hooks = buildAgentHooks({ - runId: input.runId, - rpc: input.rpc, - onContextCompaction: input.onContextCompaction, - }); - return new Agent({ - initialState: { - systemPrompt: input.systemPrompt, - model: input.model, - tools: input.tools, - messages: input.priorMessages, - thinkingLevel: input.thinkingLevel, - }, - sessionId: input.taskSessionId, - streamFn: (model, messages, options) => - safeStreamSimpleWithEnv( - model, - messages, - { - ...options, - apiKey: input.apiKey, - headers: { ...(options?.headers ?? {}), ...(input.extraHeaders ?? {}) }, - }, - input.streamEnv, - ), - beforeToolCall: hooks.beforeToolCall, - transformContext: hooks.transformContext, - toolExecution: "sequential", - }); -} diff --git a/src/main/worker/runtime/pi-hook-contract.ts b/src/main/worker/runtime/pi-hook-contract.ts deleted file mode 100644 index 499cfe3a..00000000 --- a/src/main/worker/runtime/pi-hook-contract.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Compile-time contract between local hook implementations and - * `pi-agent-core` callback signatures. - * - * Root `package.json` pins `@mariozechner/pi-agent-core` to 0.67.68 - * while our worker wires local hooks — `beforeToolCall` and - * `transformContext` — into the pi Agent constructor. Those hooks carry - * deep structural coupling: pi decides the context shape passed in and - * the result shape we return. A silent signature drift on upgrade would - * slip past runtime tests until a real tool call fires in production. - * - * This module re-states every hook callback type as a named alias sourced - * from pi, then pins the concrete inline callbacks from `pi-agent-factory` - * to those aliases via the `ExpectHookType` helper. If pi ever renames a - * type, drops a field, or changes an argument, `tsc` fails here — not at - * the first destructive-tool invocation on a user machine. - * - * The contract is compile-only: no runtime validator, no fallback path. - * Importing this file for side effects (see `pi-agent-factory`) is enough - * to drag it into the typecheck graph. - */ - -import type { - AgentMessage, - AgentOptions, - BeforeToolCallContext, - BeforeToolCallResult, -} from "@mariozechner/pi-agent-core"; - -/** - * Canonical hook callback types sourced directly from `AgentOptions`. - * - * Using `NonNullable` keeps a single upstream source - * of truth — if pi changes the option signature the alias fails, which - * cascades into every `satisfies` check below. - */ -export type PiBeforeToolCall = NonNullable; -export type PiTransformContext = NonNullable; - -/** - * Context/result types carried across the hook boundary. Pinned by name - * here so `hook-rpc.ts` payloads stay anchored to the pi-provided shapes - * even when the local RPC wrapper strips or re-packs fields. - */ -export type PiBeforeToolCallContext = BeforeToolCallContext; -export type PiBeforeToolCallResult = BeforeToolCallResult; -export type PiAgentMessage = AgentMessage; - -/** - * Type-level assertion: `Fn` must be assignable to the pi hook slot `Slot`. - * - * The helper produces `never` when `Fn` drifts, so any `satisfies` use - * resolves to `never` and fails to satisfy the target. That failure is - * the compile-time breakage we want — a single red squiggle pointing at - * the offending hook. - */ -type ExpectHookType = Fn; - -/** - * Callable shapes actually installed by `pi-agent-factory.createPiAgent`. - * - * These mirror the inline hook functions passed into `new Agent({...})`. - * Keeping them as standalone named types means a future refactor that - * pulls them out of the factory closure into named exports only has to - * swap the `typeof` lookup — the contract check below continues to hold. - */ -type LocalBeforeToolCallShape = ( - ctx: BeforeToolCallContext, - signal?: AbortSignal, -) => Promise; - -type LocalTransformContextShape = ( - messages: AgentMessage[], - signal?: AbortSignal, -) => Promise; - -/** - * Contract assertions — these are pure type positions; no runtime code. - * - * Each alias forces `tsc` to verify the local shape is still a valid - * substitute for the corresponding pi slot. Removing or renaming a - * field on either side breaks the build. - */ -export type BeforeToolCallContract = ExpectHookType; -export type TransformContextContract = ExpectHookType; - -/** - * Hook handler return envelopes used by `agent-runtime/hook-handlers.ts`. - * - * The handlers run inside main and ship results back to the worker over - * the RPC channel, so they do not implement the raw pi signatures. - * Pinning the mapped shapes here guarantees that any change to the - * upstream result type surfaces in the RPC payload layer too. - */ -export type BeforeToolCallHandlerResult = { - readonly block: boolean; - readonly reason: string | null; -}; - -export type TransformContextHandlerResult = { - readonly changed: boolean; - readonly messages: AgentMessage[] | null; -}; diff --git a/src/main/worker/runtime/pi-safe-stream.ts b/src/main/worker/runtime/pi-safe-stream.ts deleted file mode 100644 index 4f88f7ef..00000000 --- a/src/main/worker/runtime/pi-safe-stream.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { - createAssistantMessageEventStream, - streamSimple, - type Api, - type AssistantMessage, - type AssistantMessageEventStream, - type Context, - type Model, - type SimpleStreamOptions, - type StopReason, - type Usage, -} from "@mariozechner/pi-ai"; -import { - InMemoryCredentialConcurrencyGate, - type CredentialConcurrencyGate, -} from "./credential-concurrency-gate"; -import { getProviderConcurrencyLimit } from "./provider-rate-limits"; - -type PiStreamSource = ( - model: Model, - context: Context, - options?: SimpleStreamOptions, -) => AssistantMessageEventStream | Promise; - -type SafePiStreamSource = ( - model: Model, - context: Context, - options?: SimpleStreamOptions, -) => AssistantMessageEventStream; - -type SafePiStreamSourceWithEnv = ( - model: Model, - context: Context, - options?: SimpleStreamOptions, - envPatch?: Readonly>, -) => AssistantMessageEventStream; - -type ErrorAssistantMessage = AssistantMessage & { - stopReason: Extract; -}; - -const EMPTY_USAGE: Usage = { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 0, - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, -}; - -function formatStreamError(error: unknown): string { - if (error instanceof Error) return error.message; - return String(error); -} - -function createStreamErrorMessage(model: Model, error: unknown, signal?: AbortSignal): ErrorAssistantMessage { - const stopReason: Extract = signal?.aborted ? "aborted" : "error"; - return { - role: "assistant", - content: [{ type: "text", text: "" }], - api: model.api, - provider: model.provider, - model: model.id, - usage: EMPTY_USAGE, - stopReason, - errorMessage: formatStreamError(error), - timestamp: Date.now(), - }; -} - -function pushStreamError( - stream: AssistantMessageEventStream, - model: Model, - error: unknown, - signal?: AbortSignal, -): void { - const message = createStreamErrorMessage(model, error, signal); - stream.push({ type: "error", reason: message.stopReason, error: message }); - stream.end(message); -} - -let scopedEnvChain: Promise = Promise.resolve(); - -function hasEnvPatch(envPatch: Readonly> | undefined): envPatch is Readonly> { - return !!envPatch && Object.keys(envPatch).length > 0; -} - -async function withProcessEnvPatch( - envPatch: Readonly>, - task: () => Promise, -): Promise { - const saved = new Map(); - for (const [key, value] of Object.entries(envPatch)) { - saved.set(key, process.env[key]); - process.env[key] = value; - } - try { - await task(); - } finally { - for (const [key, previous] of saved) { - if (previous === undefined) delete process.env[key]; - else process.env[key] = previous; - } - } -} - -function runWithScopedEnv( - envPatch: Readonly> | undefined, - task: () => Promise, -): Promise { - if (!hasEnvPatch(envPatch)) return task(); - const run = scopedEnvChain.then( - () => withProcessEnvPatch(envPatch, task), - () => withProcessEnvPatch(envPatch, task), - ); - scopedEnvChain = run.then( - () => undefined, - () => undefined, - ); - return run; -} - -async function pipeSourceStream( - source: PiStreamSource, - target: AssistantMessageEventStream, - model: Model, - context: Context, - options?: SimpleStreamOptions, -): Promise { - const sourceStream = await source(model, context, options); - for await (const event of sourceStream) { - target.push(event); - } - target.end(); -} - -/** - * Build a safe stream wrapper. When `gate` is provided, every call - * acquires a slot keyed by `(model.provider, options.apiKey)` before - * the underlying source is invoked, and releases the slot once the - * stream finishes (success, error, or abort). Calls without an - * `apiKey` skip the gate — they target keyless transports such as - * local Ollama / LM Studio. - */ -export function createSafePiStream( - source: PiStreamSource, - gate?: CredentialConcurrencyGate, -): SafePiStreamSource { - const scoped = createSafePiStreamWithEnv(source, gate); - return (model, context, options) => scoped(model, context, options); -} - -export function createSafePiStreamWithEnv( - source: PiStreamSource, - gate?: CredentialConcurrencyGate, -): SafePiStreamSourceWithEnv { - return (model, context, options, envPatch) => { - const target = createAssistantMessageEventStream(); - const apiKey = typeof options?.apiKey === "string" ? options.apiKey : ""; - const acquireSlot = gate && apiKey - ? () => gate.acquire(model.provider, apiKey, options?.signal) - : () => Promise.resolve<() => void>(() => undefined); - void Promise.resolve() - .then(acquireSlot) - .then(async (release) => { - try { - await runWithScopedEnv(envPatch, () => pipeSourceStream(source, target, model, context, options)); - } finally { - release(); - } - }) - .catch((error) => { - pushStreamError(target, model, error, options?.signal); - }); - return target; - }; -} - -const defaultGate: CredentialConcurrencyGate = new InMemoryCredentialConcurrencyGate( - getProviderConcurrencyLimit, -); - -export const safeStreamSimple = createSafePiStream(streamSimple, defaultGate); -export const safeStreamSimpleWithEnv = createSafePiStreamWithEnv(streamSimple, defaultGate); diff --git a/src/main/worker/runtime/provider-rate-limits.ts b/src/main/worker/runtime/provider-rate-limits.ts deleted file mode 100644 index 4623388c..00000000 --- a/src/main/worker/runtime/provider-rate-limits.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Per-provider concurrency caps applied to outbound model calls. - * - * Each entry limits the number of in-flight `streamSimple` invocations - * that share a single credential (keyed by `provider` + `apiKey`). - * Providers absent from the map are treated as uncapped — the gate - * short-circuits and the call proceeds immediately. - * - * `fireworks-firepass` is the load-bearing entry. The Fire Pass router - * `accounts/fireworks/routers/kimi-k2p6-turbo` is a personal-tier route: - * the subscription documents zero per-token cost but the upstream - * router rejects bursts on a single key with HTTP 429. In the Boss - * build every agent shares the seeded Fire Pass key, so without a cap - * three concurrent agents trip three 429s — the exact failure mode - * captured in the overview dashboard. A cap of `1` serializes runs on - * the shared key without dropping any work. - * - * Other providers (`anthropic`, `openai`, `google`, …) advertise - * generous tier-based budgets and have no evidence of contention in - * the boss or public builds. Leaving them uncapped honours the - * project's "let it crash" stance — only providers with a known - * upstream constraint are throttled here. - */ -export const PROVIDER_CONCURRENCY_LIMITS: Readonly> = { - "fireworks-firepass": 1, -}; - -export function getProviderConcurrencyLimit(provider: string): number | null { - const value = PROVIDER_CONCURRENCY_LIMITS[provider]; - return typeof value === "number" && value > 0 ? value : null; -} diff --git a/src/main/worker/runtime/run-tools.ts b/src/main/worker/runtime/run-tools.ts deleted file mode 100644 index 111eb335..00000000 --- a/src/main/worker/runtime/run-tools.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { createCodingTools, type BashToolOptions } from "@mariozechner/pi-coding-agent"; -import type { AgentState } from "@mariozechner/pi-agent-core"; - -type ErasedAgentTool = AgentState["tools"][number]; - -export function mergeRunEnvs( - jobEnv: Record, - preparedEnv: Record, -): Record { - return { ...jobEnv, ...preparedEnv }; -} - -export function createRunScopedBashOptions( - runEnv: Record, -): BashToolOptions { - const envSnapshot = { ...runEnv }; - return { - spawnHook: (context) => ({ - ...context, - env: { - ...context.env, - ...envSnapshot, - }, - }), - }; -} - -export function createRunScopedCodingTools( - cwd: string, - runEnv: Record, -): ErasedAgentTool[] { - return createCodingTools(cwd, { - bash: createRunScopedBashOptions(runEnv), - }) as ErasedAgentTool[]; -} diff --git a/src/preload/index.ts b/src/preload/index.ts index 8c1cf30a..b2617bd1 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -1,52 +1,103 @@ import { contextBridge, ipcRenderer } from "electron"; -import { IPC_CHANNELS } from "@shared/contracts/channels"; -import type { DesktopApi } from "@shared/contracts/desktop-api"; -import { - PRELOAD_FORWARDERS, - PRELOAD_INPUT_SCHEMAS, - mapPreloadInvokeArgs, - type PreloadForwardedApi, -} from "@shared/contracts/preload-forwarders"; -import type { DesktopEvent } from "@shared/types"; +import { IPC_CHANNELS } from "../shared/ipc"; +import type { DesktopApi, RendererEvent } from "../shared/desktop-api"; -function createForwardedApi(): PreloadForwardedApi { - const forwardedEntries = PRELOAD_FORWARDERS.map(({ api, channel, payload }) => { - const schema = PRELOAD_INPUT_SCHEMAS[api]; - return [ - api, - (...args: unknown[]) => ipcRenderer.invoke( - IPC_CHANNELS[channel], - ...mapPreloadInvokeArgs(payload, args, schema), - ), - ]; - }); - - return Object.fromEntries(forwardedEntries) as PreloadForwardedApi; +function invoke(channel: string, payload?: unknown): Promise { + return ipcRenderer.invoke(channel, payload) as Promise; } const api: DesktopApi = { - ...createForwardedApi(), - subscribe: (callback: (event: DesktopEvent) => void) => { - const listener = (_event: Electron.IpcRendererEvent, payload: DesktopEvent) => callback(payload); + loadSnapshot: () => invoke(IPC_CHANNELS.loadSnapshot), + bootstrapOnboarding: (input) => invoke(IPC_CHANNELS.bootstrapOnboarding, input), + createOrganization: (input) => invoke(IPC_CHANNELS.createOrganization, input), + setActiveOrganization: (input) => invoke(IPC_CHANNELS.setActiveOrganization, input), + deleteOrganization: (input) => invoke(IPC_CHANNELS.deleteOrganization, input), + createAgent: (input) => invoke(IPC_CHANNELS.createAgent, input), + updateAgent: (input) => invoke(IPC_CHANNELS.updateAgent, input), + createTask: (input) => invoke(IPC_CHANNELS.createTask, input), + updateTask: (input) => invoke(IPC_CHANNELS.updateTask, input), + deleteTask: (input) => invoke(IPC_CHANNELS.deleteTask, input), + updateTaskStatus: (input) => invoke(IPC_CHANNELS.updateTaskStatus, input), + runTask: (input) => invoke(IPC_CHANNELS.runTask, input), + createGoal: (input) => invoke(IPC_CHANNELS.createGoal, input), + createProject: (input) => invoke(IPC_CHANNELS.createProject, input), + createWorkspace: (input) => invoke(IPC_CHANNELS.createWorkspace, input), + createDocument: (input) => invoke(IPC_CHANNELS.createDocument, input), + updateDocument: (input) => invoke(IPC_CHANNELS.updateDocument, input), + deleteDocument: (input) => invoke(IPC_CHANNELS.deleteDocument, input), + createKnowledgeEntry: (input) => invoke(IPC_CHANNELS.createKnowledgeEntry, input), + deleteKnowledgeEntry: (input) => invoke(IPC_CHANNELS.deleteKnowledgeEntry, input), + createAutomationRule: (input) => invoke(IPC_CHANNELS.createAutomationRule, input), + updateAutomationRule: (input) => invoke(IPC_CHANNELS.updateAutomationRule, input), + deleteAutomationRule: (input) => invoke(IPC_CHANNELS.deleteAutomationRule, input), + createMeeting: (input) => invoke(IPC_CHANNELS.createMeeting, input), + deleteMeeting: (input) => invoke(IPC_CHANNELS.deleteMeeting, input), + createSprint: (input) => invoke(IPC_CHANNELS.createSprint, input), + deleteSprint: (input) => invoke(IPC_CHANNELS.deleteSprint, input), + createApproval: (input) => invoke(IPC_CHANNELS.createApproval, input), + decideApproval: (input) => invoke(IPC_CHANNELS.decideApproval, input), + syncEmployeeIdentity: (input) => invoke(IPC_CHANNELS.syncEmployeeIdentity, input), + grantRole: (input) => invoke(IPC_CHANNELS.grantRole, input), + createChatSpace: (input) => invoke(IPC_CHANNELS.createChatSpace, input), + sendMessage: (input) => invoke(IPC_CHANNELS.sendMessage, input), + editMessage: (input) => invoke(IPC_CHANNELS.editMessage, input), + deleteMessage: (input) => invoke(IPC_CHANNELS.deleteMessage, input), + markChatSpaceRead: (input) => invoke(IPC_CHANNELS.markChatSpaceRead, input), + saveProviderCredential: (input) => invoke(IPC_CHANNELS.saveProviderCredential, input), + revokeProviderCredential: (input) => invoke(IPC_CHANNELS.revokeProviderCredential, input), + launchProviderSignIn: (input) => invoke(IPC_CHANNELS.launchProviderSignIn, input), + startProviderOAuth: (input) => invoke(IPC_CHANNELS.startProviderOAuth, input), + cancelProviderOAuth: (input) => invoke(IPC_CHANNELS.cancelProviderOAuth, input), + checkProviderHealth: (input) => invoke(IPC_CHANNELS.checkProviderHealth, input), + listProviderModels: (input) => invoke(IPC_CHANNELS.listProviderModels, input), + updateProviderPolicy: (input) => invoke(IPC_CHANNELS.updateProviderPolicy, input), + openExternalUrl: (url) => invoke(IPC_CHANNELS.openExternalUrl, url), + createProviderResponse: (input) => invoke(IPC_CHANNELS.createProviderResponse, input), + streamProviderResponse: (input) => invoke(IPC_CHANNELS.streamProviderResponse, input), + cancelProviderResponse: (input) => invoke(IPC_CHANNELS.cancelProviderResponse, input), + importSkillDirectory: (input) => invoke(IPC_CHANNELS.importSkillDirectory, input), + bindSkill: (input) => invoke(IPC_CHANNELS.bindSkill, input), + resolveAgentSkills: (input) => invoke(IPC_CHANNELS.resolveAgentSkills, input), + runSkillTests: (input) => invoke(IPC_CHANNELS.runSkillTests, input), + createSocialAccount: (input) => invoke(IPC_CHANNELS.createSocialAccount, input), + launchSocialLogin: (input) => invoke(IPC_CHANNELS.launchSocialLogin, input), + createScheduledPost: (input) => invoke(IPC_CHANNELS.createScheduledPost, input), + setScheduledPostState: (input) => invoke(IPC_CHANNELS.setScheduledPostState, input), + importFile: (input) => invoke(IPC_CHANNELS.importFile, input), + openFile: (input) => invoke(IPC_CHANNELS.openFile, input), + pickDirectory: () => invoke(IPC_CHANNELS.pickDirectory), + setFilePinned: (input) => invoke(IPC_CHANNELS.setFilePinned, input), + createMigrationReport: (input) => invoke(IPC_CHANNELS.createMigrationReport, input), + createRollbackSnapshot: (input) => invoke(IPC_CHANNELS.createRollbackSnapshot, input), + setRollbackSnapshotActive: (input) => invoke(IPC_CHANNELS.setRollbackSnapshotActive, input), + resolveMigrationReconciliation: (input) => invoke(IPC_CHANNELS.resolveMigrationReconciliation, input), + setFeatureFlag: (input) => invoke(IPC_CHANNELS.setFeatureFlag, input), + runChaosDrill: (input) => invoke(IPC_CHANNELS.runChaosDrill, input), + runSdlcReview: (input) => invoke(IPC_CHANNELS.runSdlcReview, input), + runEvalSuite: (input) => invoke(IPC_CHANNELS.runEvalSuite, input), + setPrBotGate: (input) => invoke(IPC_CHANNELS.setPrBotGate, input), + createComplianceExport: (input) => invoke(IPC_CHANNELS.createComplianceExport, input), + createAuditReplay: (input) => invoke(IPC_CHANNELS.createAuditReplay, input), + createLegalHold: (input) => invoke(IPC_CHANNELS.createLegalHold, input), + setLegalHoldState: (input) => invoke(IPC_CHANNELS.setLegalHoldState, input), + createRetentionFreeze: (input) => invoke(IPC_CHANNELS.createRetentionFreeze, input), + setRetentionFreezeState: (input) => invoke(IPC_CHANNELS.setRetentionFreezeState, input), + saveComposioSettings: (input) => invoke(IPC_CHANNELS.saveComposioSettings, input), + listComposioToolkits: (input) => invoke(IPC_CHANNELS.listComposioToolkits, input), + connectComposioToolkit: (input) => invoke(IPC_CHANNELS.connectComposioToolkit, input), + refreshComposioAccounts: (input) => invoke(IPC_CHANNELS.refreshComposioAccounts, input), + grantConnector: (input) => invoke(IPC_CHANNELS.grantConnector, input), + revokeConnector: (input) => invoke(IPC_CHANNELS.revokeConnector, input), + search: (input) => invoke(IPC_CHANNELS.search, input), + subscribe: (callback) => { + const listener = (_event: Electron.IpcRendererEvent, payload: RendererEvent) => callback(payload); ipcRenderer.on(IPC_CHANNELS.rendererEvent, listener); - return () => { - ipcRenderer.removeListener(IPC_CHANNELS.rendererEvent, listener); - }; - }, - platform: process.platform as "win32" | "darwin" | "linux", - windowMinimize: async () => { - await ipcRenderer.invoke(IPC_CHANNELS.windowMinimize); - }, - windowMaximize: async () => { - await ipcRenderer.invoke(IPC_CHANNELS.windowMaximize); - }, - windowClose: async () => { - await ipcRenderer.invoke(IPC_CHANNELS.windowClose); - }, - windowIsMaximized: async () => { - const result = (await ipcRenderer.invoke(IPC_CHANNELS.windowIsMaximized)) as { ok: true; data: boolean } | { ok: false }; - return result.ok ? result.data : false; + return () => ipcRenderer.removeListener(IPC_CHANNELS.rendererEvent, listener); }, + platform: process.platform as DesktopApi["platform"], + windowMinimize: () => invoke(IPC_CHANNELS.windowMinimize), + windowMaximize: () => invoke(IPC_CHANNELS.windowMaximize), + windowClose: () => invoke(IPC_CHANNELS.windowClose), }; contextBridge.exposeInMainWorld("agentCompany", api); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx deleted file mode 100644 index 2ff6c680..00000000 --- a/src/renderer/App.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { useCallback, useMemo, type ReactNode } from "react"; -import { CircleNotch } from "./components/ui/icons"; -import { LocaleContext, TranslationContext, type TranslationFn } from "./i18n"; -import type { AppLocale } from "@shared/locale"; -import { CompanyOnboarding } from "./components/company-onboarding/OnboardingWizard"; -import { OAuthPromptDialog } from "./components/settings/dialogs/OAuthPromptDialog"; -import TitleBar from "./components/TitleBar"; -import ToastContainer from "./components/Toast"; -import { SidebarView } from "./views/SidebarView"; -import { SectionContentView } from "./views/SectionContentView"; -import { CommandPaletteView } from "./views/CommandPaletteView"; -import { useAppStore } from "./state/store"; -import { useUIController } from "./hooks/useUIController"; -import { useCompanyController } from "./hooks/useCompanyController"; -import { useCommandPaletteHotkeys } from "./hooks/useCommandPaletteHotkeys"; -import { AppActionsContext, type AppActions } from "./hooks/useAppActions"; -import { SectionContext } from "./hooks/useSectionContext"; -import { createAppErrorNotice, describeDesktopError, formatDesktopResultNotice } from "./lib/desktop"; - -function Shell({ - locale, - t, - showCustomTitleBar, - className, - children, -}: { - locale: AppLocale; - t: TranslationFn; - showCustomTitleBar: boolean; - className?: string; - children: ReactNode; -}) { - return ( - - -

- - - ); -} - -export function App() { - const ui = useUIController(); - const company = useCompanyController(); - - const error = useAppStore((s) => s.error); - const setError = useAppStore((s) => s.setError); - const setSelectedRunId = useAppStore((s) => s.setSelectedRunId); - const navigateTo = useAppStore((s) => s.navigateTo); - - const showCustomTitleBar = window.agentCompany.platform !== "darwin"; - const isMac = !showCustomTitleBar; - const currentCompany = company.currentCompany; - const companyRuns = company.runs; - const refreshCompany = company.refresh; - const openPathWithFeedback = company.openPathWithFeedback; - - const startRun = useCallback(async (taskId: string) => { - if (!currentCompany) { - setError(createAppErrorNotice( - "Select a company before starting a run.", - "COMPANY_REQUIRED", - "Select a company in the sidebar, then start the run.", - )); - return; - } - const result = await window.agentCompany.startTaskRun({ companyId: currentCompany.id, taskId }); - if (!result.ok) { setError(formatDesktopResultNotice(result.error)); return; } - setSelectedRunId(result.data); - await refreshCompany(); - }, [currentCompany, refreshCompany, setError, setSelectedRunId]); - - const cancelRun = useCallback(async (runId: string) => { - try { - const run = companyRuns.find((entry) => entry.id === runId); - if (!run) throw new Error("Selected run is no longer available."); - const result = await window.agentCompany.cancelRun({ companyId: run.companyId, runId }); - if (!result.ok) { setError(formatDesktopResultNotice(result.error)); return; } - await refreshCompany(); - setError(null); - } catch (err) { setError(describeDesktopError(err)); } - }, [companyRuns, refreshCompany, setError]); - - const { filteredNavItems, matchedAgents, matchedTasks, matchedRuns, matchedGoals, matchedProjects, hasEntityResults } = - useMemo(() => ui.buildPaletteResults( - ui.navItems, - company.companyAgents, - company.tasks, - company.runs, - company.companyGoals, - company.companyProjects, - ), [ - ui, - company.companyAgents, - company.tasks, - company.runs, - company.companyGoals, - company.companyProjects, - ]); - - const paletteActions = useMemo( - () => ui.buildPaletteActions(filteredNavItems, matchedAgents, matchedTasks, matchedRuns, matchedGoals, matchedProjects), - [ui, filteredNavItems, matchedAgents, matchedTasks, matchedRuns, matchedGoals, matchedProjects], - ); - - const paletteActionIndex = useMemo( - () => new Map(paletteActions.map((action, index) => [action.key, index])), - [paletteActions], - ); - - useCommandPaletteHotkeys({ - commandPaletteOpen: ui.commandPaletteOpen, - setCommandPaletteOpen: ui.setCommandPaletteOpen, - setCommandPaletteSearch: ui.setCommandPaletteSearch, - setSelectedPaletteIndex: ui.setSelectedPaletteIndex, - paletteActions, - navigateTo, - commandPaletteSearch: ui.commandPaletteSearch, - }); - - const appActions = useMemo(() => ({ - refresh: refreshCompany, - setError, - openPathWithFeedback, - startRun, - cancelRun, - }), [refreshCompany, openPathWithFeedback, startRun, cancelRun, setError]); - - if (!company.snapshot) { - return ( - -
- - {ui.t("app.loading")} -
-
- ); - } - - if (company.snapshot.companies.length === 0 || ui.showOnboarding || ui.initialOnboardingLocked) { - return ( - -
- 0 && !ui.initialOnboardingLocked} - onCancel={() => { - ui.setShowOnboarding(false); - ui.setInitialOnboardingLocked(false); - setError(null); - }} - currentLocale={ui.locale} - onLocaleChange={ui.handleLocaleChange} - isFirstLaunch={company.snapshot.companies.length === 0} - /> -
- {/* Mount here so onboarding OAuth flows that need a prompt (e.g. */} - {/* GitHub Copilot's enterprise-domain step) can surface a modal. */} - -
- ); - } - - return ( - - - - -
- {showCustomTitleBar && } -
- - - -
-
-
-

- {ui.navItems.find((item) => item.id === ui.section)?.label ?? ui.t(`nav.${ui.section}`)} -

-
-
- - -
- - - - - {/* App-root mount so any section that kicks off an OAuth login — */} - {/* not just Settings — sees prompt/manual-code events. */} - -
-
-
-
-
-
- ); -} - -export default App; diff --git a/src/renderer/components/TitleBar.tsx b/src/renderer/components/TitleBar.tsx deleted file mode 100644 index f151c3c1..00000000 --- a/src/renderer/components/TitleBar.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { Copy, Minus, Square, X } from "./ui/icons"; -import { useT } from "../i18n"; - -export default function TitleBar() { - const t = useT(); - const [maximized, setMaximized] = useState(false); - - const refreshMaximized = useCallback(() => { - void window.agentCompany.windowIsMaximized().then(setMaximized); - }, []); - - useEffect(() => { - refreshMaximized(); - const onResize = () => refreshMaximized(); - window.addEventListener("resize", onResize); - return () => window.removeEventListener("resize", onResize); - }, [refreshMaximized]); - - return ( -
-
- - AgentCompany - -
- -
- - - -
-
- ); -} diff --git a/src/renderer/components/Toast.tsx b/src/renderer/components/Toast.tsx deleted file mode 100644 index f891061a..00000000 --- a/src/renderer/components/Toast.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { AnimatePresence, motion } from "framer-motion" -import { CheckCircle, Warning, X, XCircle } from "./ui/icons" -import { useAppStore } from "../state/store" -import { useReducedMotion } from "./ui" -import type { Toast } from "../state/slices/ui" - -const TONE_CONFIG = { - success: { icon: CheckCircle, className: "bg-success-muted border-success text-success" }, - danger: { icon: XCircle, className: "bg-destructive-muted border-destructive text-destructive" }, - warn: { icon: Warning, className: "bg-warning-muted border-warning text-warning" }, -} as const - -export default function ToastContainer() { - const toasts = useAppStore((s) => s.toasts) - const dismiss = useAppStore((s) => s.dismissToast) - const reduced = useReducedMotion() - - if (toasts.length === 0) return null - - return ( -
- - {toasts.map((toast) => { - const cfg = TONE_CONFIG[toast.tone] - const Icon = cfg.icon - return ( - - - - - - ) - })} - -
- ) -} - -function ToastMessage({ message }: { message: Toast["message"] }) { - if (typeof message === "string") { - return ( - - {message} - - ) - } - - return ( -
-
- - {message.code} - - {message.actionHint} -
-
{message.message}
-
- ) -} diff --git a/src/renderer/components/TwoPaneLayout.tsx b/src/renderer/components/TwoPaneLayout.tsx deleted file mode 100644 index 8775313c..00000000 --- a/src/renderer/components/TwoPaneLayout.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import type { ReactNode } from "react"; -import { Eyebrow } from "./ui"; - -/** - * Two-pane layout with an optional section header. - * - `split="vertical"` (default): stacks primary over secondary with rhythmic whitespace. - * - `split="horizontal"`: primary (register) on the left, secondary (focus) on the right. - * Use horizontal when the two panes share a single focus — selecting a row on the - * left updates the inspector on the right, and the page should present one idea. - * - * `action` docks a single control (e.g. a primary "+ Add" button) to the right of the - * header row. When a title/eyebrow is present the action sits on the header's baseline; - * when the header is absent, the action sits in its own right-aligned row above the body. - * Keep it to one element — this slot exists so the control has a home, not a stage. - * - * Use `Panel` (from ui/) for single-slot sections. Use this when rendering a primary + secondary pane. - */ -export function TwoPaneLayout({ - title, - eyebrow, - primary, - secondary, - split = "vertical", - action, -}: { - title?: string; - eyebrow?: string; - primary: ReactNode; - secondary: ReactNode; - split?: "vertical" | "horizontal"; - action?: ReactNode; -}) { - const hasHeader = Boolean(title || eyebrow); - const body = - split === "horizontal" ? ( -
-
{primary}
-
{secondary}
-
- ) : ( -
{primary}{secondary}
- ); - return ( -
- {hasHeader ? ( -
-
- {eyebrow ? {eyebrow} : null} - {title ?

{title}

: null} -
- {action ?
{action}
: null} -
- ) : action ? ( -
{action}
- ) : null} - {body} -
- ); -} diff --git a/src/renderer/components/automation/AutomationPanel.tsx b/src/renderer/components/automation/AutomationPanel.tsx deleted file mode 100644 index c77b242a..00000000 --- a/src/renderer/components/automation/AutomationPanel.tsx +++ /dev/null @@ -1,312 +0,0 @@ -import { useCallback, useEffect, useMemo, useState } from "react" -import { AnimatePresence, motion } from "framer-motion" -import { ArrowRight, ArrowsClockwise, Lightning, Plus, Robot, X } from "../ui/icons" -import type { AutomationAction, AutomationRuleRecord, AutomationStatus, AutomationTrigger, WorkflowPipelineRecord } from "@shared/types" -import { ActionButton, ConfirmDialog, Card, Eyebrow } from "../ui" -import { useT, type TranslationFn } from "../../i18n" -import { triggerConfig, actionConfig, type AutomationLogEntry } from "./automation-config" -import { timeAgo } from "../../lib/formatters" -import { RuleCard } from "./RuleCard" -import { RuleFormModal } from "./RuleEditor" -import { WorkflowCard } from "./WorkflowList" -import { WorkflowFormModal } from "./WorkflowEditor" - -function AutomationActivityLog({ entries, t }: { entries: AutomationLogEntry[]; t: TranslationFn }) { - if (entries.length === 0) { - return
{t("auto.activity.noActivity")}
- } - return ( -
- {entries.map((entry, idx) => { - const ti = triggerConfig[entry.trigger as AutomationTrigger] - const ai = actionConfig[entry.action as AutomationAction] - const TIcon = ti?.icon ?? Lightning - return ( - - -
-
- {entry.ruleName} -
-
- {ti?.label ?? entry.trigger} - - {ai?.label ?? entry.action} -
-
- {timeAgo(entry.executedAt)} -
- ) - })} -
- ) -} - -function RulesPanel({ rules, companyId, onRefresh, t }: { rules: AutomationRuleRecord[]; companyId: string; onRefresh: () => void; t: TranslationFn }) { - const [showCreate, setShowCreate] = useState(false); const [editRule, setEditRule] = useState(null); const [delTarget, setDelTarget] = useState(null) - const [actLog, setActLog] = useState([]); const [activeTab, setActiveTab] = useState<"rules"|"activity">("rules"); const [filterStatus, setFilterStatus] = useState("all") - const [actionError, setActionError] = useState(null) - - useEffect(() => { void window.agentCompany.getAutomationLog(companyId).then((r) => { if (r.ok) setActLog(r.data) }) }, [companyId, rules]) - const filtered = useMemo(() => filterStatus === "all" ? rules : rules.filter((r) => r.status === filterStatus), [rules, filterStatus]) - const counts = useMemo(() => { let active = 0, paused = 0, error = 0; for (const r of rules) { if (r.status === "active") active++; else if (r.status === "paused") paused++; else if (r.status === "error") error++; } return { total: rules.length, active, paused, error } }, [rules]) - const handleToggle = useCallback(async (rule: AutomationRuleRecord) => { setActionError(null); try { const r = await window.agentCompany.toggleAutomationRule({ id: rule.id, companyId, status: (rule.status === "active" ? "paused" : "active") as "active"|"paused" }); if (!r.ok) { setActionError(r.error.message); return }; onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : t("auto.failedAction")) } }, [companyId, onRefresh, t]) - const handleDelete = useCallback(async () => { if (!delTarget) return; setActionError(null); try { const r = await window.agentCompany.deleteAutomationRule({ id: delTarget.id, companyId }); if (!r.ok) { setActionError(r.error.message); setDelTarget(null); return }; setDelTarget(null); onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : t("auto.failedAction")); setDelTarget(null) } }, [delTarget, companyId, onRefresh, t]) - - return ( -
- {actionError ? ( -
- {actionError} - -
- ) : null} -
-
-
- -
-
-

{t("auto.rules.title")}

-

- {t("auto.rules.summaryActive").replace("{n}", String(counts.active))},{t("auto.rules.summaryPaused").replace("{n}", String(counts.paused))}{counts.error > 0 ? `,${t("auto.rules.summaryErrored").replace("{n}", String(counts.error))}` : ""} -

-
-
- setShowCreate(true)} icon={Plus} tone="accent" /> -
- {rules.length > 0 ? ( -
- {[ - { l: t("auto.rules.totalRules"), v: counts.total, accent: false }, - { l: t("auto.rules.totalExecutions"), v: rules.reduce((s, r) => s + r.executionCount, 0), accent: true }, - { l: t("auto.rules.recentActivity"), v: actLog.length, accent: true }, - ].map((s) => ( - - {s.l} -
{s.v}
-
- ))} -
- ) : null} -
- - -
- {activeTab === "rules" ? ( - <> - {rules.length > 0 ? ( -
- {(["all", "active", "paused", "error"] as const).map((s) => { - const filterLabel = s === "all" ? t("auto.rules.filterAll") - : s === "active" ? t("auto.rules.filterActive") - : s === "paused" ? t("auto.rules.filterPaused") - : t("auto.rules.filterError"); - return ( - - ); - })} -
- ) : null} - {filtered.length === 0 && rules.length === 0 ? ( -
- -
{t("auto.rules.noRules")}
-
- setShowCreate(true)} icon={Lightning} tone="accent" /> -
-
- ) : filtered.length === 0 ? ( -
{t("auto.rules.noRulesFilter")}
- ) : ( -
- - {filtered.map((r) => ( - void handleToggle(r)} - onDelete={() => setDelTarget(r)} - onEdit={() => setEditRule(r)} - /> - ))} - -
- )} - - ) : ( - - )} - - {showCreate ? ( - setShowCreate(false)} onSaved={onRefresh} /> - ) : null} - {editRule ? ( - setEditRule(null)} onSaved={onRefresh} /> - ) : null} - - void handleDelete()} - onCancel={() => setDelTarget(null)} - /> -
- ) -} - -function WorkflowsPanel({ workflows, companyId, onRefresh, t }: { workflows: WorkflowPipelineRecord[]; companyId: string; onRefresh: () => void; t: TranslationFn }) { - const [showCreate, setShowCreate] = useState(false); const [editWf, setEditWf] = useState(null); const [delTarget, setDelTarget] = useState(null) - const [actionError, setActionError] = useState(null); const [runningId, setRunningId] = useState(null) - const handleDelete = useCallback(async () => { if (!delTarget) return; setActionError(null); try { const r = await window.agentCompany.deleteWorkflow({ id: delTarget.id, companyId }); if (!r.ok) { setActionError(r.error.message); setDelTarget(null); return }; setDelTarget(null); onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : t("auto.failedAction")); setDelTarget(null) } }, [delTarget, companyId, onRefresh, t]) - const handleRun = useCallback(async (wf: WorkflowPipelineRecord) => { setActionError(null); setRunningId(wf.id); try { const r = await window.agentCompany.runWorkflow({ id: wf.id, companyId }); if (!r.ok) { setActionError(r.error.message); return }; onRefresh() } catch (e) { setActionError(e instanceof Error ? e.message : t("auto.failedAction")) } finally { setRunningId(null) } }, [companyId, onRefresh, t]) - const counts = useMemo(() => ({ total: workflows.length, active: workflows.filter((w) => w.status === "active").length, draft: workflows.filter((w) => w.status === "draft").length }), [workflows]) - return ( -
- {actionError ? ( -
- {actionError} - -
- ) : null} -
-
-
- -
-
-

{t("auto.workflows.title")}

-

- {t("auto.workflows.summaryActive").replace("{n}", String(counts.active))},{t("auto.workflows.summaryDraft").replace("{n}", String(counts.draft))} - {counts.total > counts.active + counts.draft ? `,${t("auto.workflows.summaryOther").replace("{n}", String(counts.total - counts.active - counts.draft))}` : ""} -

-
-
- setShowCreate(true)} icon={Plus} tone="accent" /> -
- {workflows.length === 0 ? ( -
- -
{t("auto.workflows.noWorkflows")}
-
- setShowCreate(true)} icon={ArrowsClockwise} tone="accent" /> -
-
- ) : ( -
- - {workflows.map((wf) => ( - setDelTarget(wf)} - onEdit={() => setEditWf(wf)} - onRun={() => void handleRun(wf)} - /> - ))} - -
- )} - - {showCreate ? ( - setShowCreate(false)} onSaved={onRefresh} /> - ) : null} - {editWf ? ( - setEditWf(null)} onSaved={onRefresh} /> - ) : null} - - void handleDelete()} - onCancel={() => setDelTarget(null)} - /> -
- ) -} - -export function AutomationPanel({ rules, workflows, companyId, onRefresh }: { rules: AutomationRuleRecord[]; workflows: WorkflowPipelineRecord[]; companyId: string; onRefresh: () => void }) { - const t = useT(); const [activeSection, setActiveSection] = useState<"rules"|"workflows">("rules") - return ( -
-
-
-
- -
-
-
{t("auto.automationEngine")}
-
- {t("auto.engineDescription")} -
-
-
-
-
- - -
- - - {activeSection === "rules" ? ( - - ) : ( - - )} - - -
- ) -} diff --git a/src/renderer/components/automation/RuleCard.tsx b/src/renderer/components/automation/RuleCard.tsx deleted file mode 100644 index 237c62a9..00000000 --- a/src/renderer/components/automation/RuleCard.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { motion } from "framer-motion" -import { ArrowRight, CaretRight, Gear, Lightning, Pause, Play, Trash } from "../ui/icons" -import type { AutomationRuleRecord } from "@shared/types" -import { timeAgo } from "../../lib/formatters" -import { triggerConfig, actionConfig, statusColors } from "./automation-config" - -export function RuleCard({ rule, onToggle, onDelete, onEdit }: { rule: AutomationRuleRecord; onToggle: () => void; onDelete: () => void; onEdit: () => void }) { - const triggerInfo = triggerConfig[rule.trigger]; const actionInfo = actionConfig[rule.action] - const TriggerIcon = triggerInfo?.icon ?? Lightning; const colors = statusColors[rule.status] - - return ( - -
-
- -
- - -
-
-
- ) -} diff --git a/src/renderer/components/automation/RuleEditor.tsx b/src/renderer/components/automation/RuleEditor.tsx deleted file mode 100644 index 9f94c8b5..00000000 --- a/src/renderer/components/automation/RuleEditor.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useCallback, useEffect, useState } from "react" -import { Gear, Lightning } from "../ui/icons" -import type { AutomationAction, AutomationRuleRecord, AutomationTrigger, DepartmentId } from "@shared/types" -import { ActionButton, Modal, Select } from "../ui" -import { triggerConfig, actionConfig, departmentOptions, safeJsonStringify } from "./automation-config" -import { useT } from "../../i18n" - -interface RuleFormState { name: string; description: string; trigger: AutomationTrigger; conditionsJson: string; action: AutomationAction; actionConfigJson: string; sourceDepartment: string; targetDepartment: string; priority: number } -const defaultRuleForm: RuleFormState = { name: "", description: "", trigger: "task_status_changed", conditionsJson: "{}", action: "assign_task", actionConfigJson: "{}", sourceDepartment: "", targetDepartment: "", priority: 50 } -function ruleToFormState(rule: AutomationRuleRecord): RuleFormState { return { name: rule.name, description: rule.description, trigger: rule.trigger, conditionsJson: safeJsonStringify(rule.conditionsJson), action: rule.action, actionConfigJson: safeJsonStringify(rule.actionConfigJson), sourceDepartment: rule.sourceDepartment ?? "", targetDepartment: rule.targetDepartment ?? "", priority: rule.priority } } - -export function RuleFormModal({ open, editingRule, companyId, onClose, onSaved }: { open: boolean; editingRule: AutomationRuleRecord | null; companyId: string; onClose: () => void; onSaved: () => void }) { - const t = useT() - const isEditing = editingRule !== null; const [form, setForm] = useState(defaultRuleForm); const [saving, setSaving] = useState(false); const [error, setError] = useState(null) - useEffect(() => { if (open) { setForm(editingRule ? ruleToFormState(editingRule) : defaultRuleForm); setError(null) } }, [open, editingRule]) - const updateField = useCallback((key: K, value: RuleFormState[K]) => { setForm((prev) => ({ ...prev, [key]: value })) }, []) - const handleSave = useCallback(async () => { - if (!form.name.trim()) { setError(t("automation.ruleEditor.errNameRequired")); return } - try { JSON.parse(form.conditionsJson) } catch { setError(t("automation.ruleEditor.errConditionsJson")); return } - try { JSON.parse(form.actionConfigJson) } catch { setError(t("automation.ruleEditor.errActionConfigJson")); return } - setSaving(true); setError(null) - try { const result = await window.agentCompany.saveAutomationRule({ id: editingRule?.id ?? null, companyId, name: form.name.trim(), description: form.description.trim(), trigger: form.trigger, conditionsJson: form.conditionsJson, action: form.action, actionConfigJson: form.actionConfigJson, sourceDepartment: (form.sourceDepartment || null) as DepartmentId | null, targetDepartment: (form.targetDepartment || null) as DepartmentId | null, priority: form.priority, status: editingRule?.status ?? "active" }); if (!result.ok) { setError(result.error.message); return }; onSaved(); onClose() } catch (err) { setError(err instanceof Error ? err.message : t("automation.ruleEditor.errSaveFailed")) } finally { setSaving(false) } - }, [form, editingRule, companyId, onSaved, onClose, t]) - const triggerOptions = Object.entries(triggerConfig).map(([key, c]) => ({ value: key, label: c.label })); const actionOptions = Object.entries(actionConfig).map(([key, c]) => ({ value: key, label: c.label })) - const selectedTriggerInfo = triggerConfig[form.trigger]; const selectedActionInfo = actionConfig[form.action] - return ( - -
- {error ?
{error}
: null} -
updateField("name", e.target.value)} placeholder={t("automation.ruleEditor.namePlaceholder")} className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 w-full rounded-lg border border-border bg-card px-3.5 py-2.5 text-[14px] text-foreground placeholder:text-muted-foreground" />
-

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%0Ac6vtQOaK_e6)%P?pOCQYmaIzL9-Z6R? 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�_ec6X99=Feju)6-x1mzDLj|y?Ka<5i4Q#79 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≶eFmh7 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

#F=B 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 -qg%#)yalNYW$Mzy-hv3RsiYT9Inz9T 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½qXmaMATpvu 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≈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�S&J-W~R`rZ5zI-nmHJ+sVpq;ai5`qP83F1PA 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 z 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