ccjk 14.2.2 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +58 -341
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/detect.js +15 -0
- package/dist/commands/detect.js.map +1 -0
- package/dist/commands/doctor.js +68 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/git-install.js +50 -0
- package/dist/commands/git-install.js.map +1 -0
- package/dist/commands/init.js +102 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.js +66 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/menu.js +33 -0
- package/dist/commands/menu.js.map +1 -0
- package/dist/core/detect.js +24 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/lint.js +49 -0
- package/dist/core/lint.js.map +1 -0
- package/dist/core/mcp.js +41 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/paths.js +9 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/providers.js +53 -0
- package/dist/core/providers.js.map +1 -0
- package/dist/core/settings.js +31 -0
- package/dist/core/settings.js.map +1 -0
- package/dist/core/slash-templates.js +56 -0
- package/dist/core/slash-templates.js.map +1 -0
- package/dist/core/tools.js +27 -0
- package/dist/core/tools.js.map +1 -0
- package/package.json +43 -164
- package/README.HONEST.md +0 -176
- package/README.en.md +0 -67
- package/README.ja.md +0 -67
- package/README.ko.md +0 -67
- package/README.zh-CN.md +0 -86
- package/bin/ccjk.mjs +0 -5
- package/bin/ccjk.ts +0 -222
- package/dist/chunks/agent-teams.mjs +0 -145
- package/dist/chunks/agent.mjs +0 -1439
- package/dist/chunks/agents.mjs +0 -3783
- package/dist/chunks/api-cli.mjs +0 -135
- package/dist/chunks/api-config-selector.mjs +0 -159
- package/dist/chunks/api-providers.mjs +0 -144
- package/dist/chunks/api.mjs +0 -115
- package/dist/chunks/auto-bootstrap.mjs +0 -358
- package/dist/chunks/auto-fixer.mjs +0 -95
- package/dist/chunks/auto-updater.mjs +0 -507
- package/dist/chunks/banner.mjs +0 -173
- package/dist/chunks/bash.mjs +0 -187
- package/dist/chunks/boost.mjs +0 -474
- package/dist/chunks/brain-config.mjs +0 -75
- package/dist/chunks/brain-status.mjs +0 -89
- package/dist/chunks/ccjk-agents.mjs +0 -416
- package/dist/chunks/ccjk-all.mjs +0 -1046
- package/dist/chunks/ccjk-config.mjs +0 -445
- package/dist/chunks/ccjk-hooks.mjs +0 -1074
- package/dist/chunks/ccjk-mcp.mjs +0 -763
- package/dist/chunks/ccjk-setup.mjs +0 -765
- package/dist/chunks/ccjk-skills.mjs +0 -518
- package/dist/chunks/ccr.mjs +0 -109
- package/dist/chunks/ccu.mjs +0 -40
- package/dist/chunks/check-updates.mjs +0 -117
- package/dist/chunks/claude-code-incremental-manager.mjs +0 -761
- package/dist/chunks/claude-config.mjs +0 -606
- package/dist/chunks/claude-config2.mjs +0 -62
- package/dist/chunks/claude-wrapper.mjs +0 -85
- package/dist/chunks/clavue-config.mjs +0 -1454
- package/dist/chunks/cleanup-migration.mjs +0 -20
- package/dist/chunks/cli-hook.mjs +0 -4096
- package/dist/chunks/cloud-sync.mjs +0 -29
- package/dist/chunks/code-type-resolver.mjs +0 -880
- package/dist/chunks/codex-config-switch.mjs +0 -452
- package/dist/chunks/codex-provider-manager.mjs +0 -238
- package/dist/chunks/codex-uninstaller.mjs +0 -404
- package/dist/chunks/codex.mjs +0 -2141
- package/dist/chunks/commands.mjs +0 -108
- package/dist/chunks/commands2.mjs +0 -421
- package/dist/chunks/commit.mjs +0 -140
- package/dist/chunks/completion.mjs +0 -517
- package/dist/chunks/config-consolidator.mjs +0 -172
- package/dist/chunks/config-switch.mjs +0 -334
- package/dist/chunks/config.mjs +0 -558
- package/dist/chunks/config2.mjs +0 -484
- package/dist/chunks/config3.mjs +0 -486
- package/dist/chunks/constants.mjs +0 -323
- package/dist/chunks/context-opt.mjs +0 -444
- package/dist/chunks/context.mjs +0 -974
- package/dist/chunks/dashboard.mjs +0 -481
- package/dist/chunks/doctor.mjs +0 -1301
- package/dist/chunks/eval.mjs +0 -502
- package/dist/chunks/evolution.mjs +0 -322
- package/dist/chunks/features.mjs +0 -715
- package/dist/chunks/fish.mjs +0 -181
- package/dist/chunks/fs-operations.mjs +0 -180
- package/dist/chunks/health-alerts.mjs +0 -830
- package/dist/chunks/help.mjs +0 -341
- package/dist/chunks/hook-installer.mjs +0 -48
- package/dist/chunks/impact.mjs +0 -651
- package/dist/chunks/index.mjs +0 -23
- package/dist/chunks/index10.mjs +0 -19
- package/dist/chunks/index11.mjs +0 -1171
- package/dist/chunks/index12.mjs +0 -218
- package/dist/chunks/index13.mjs +0 -679
- package/dist/chunks/index14.mjs +0 -1009
- package/dist/chunks/index15.mjs +0 -194
- package/dist/chunks/index2.mjs +0 -7637
- package/dist/chunks/index3.mjs +0 -171
- package/dist/chunks/index4.mjs +0 -26
- package/dist/chunks/index5.mjs +0 -19
- package/dist/chunks/index6.mjs +0 -19092
- package/dist/chunks/index7.mjs +0 -616
- package/dist/chunks/index8.mjs +0 -1602
- package/dist/chunks/index9.mjs +0 -5384
- package/dist/chunks/init.mjs +0 -1911
- package/dist/chunks/installer.mjs +0 -757
- package/dist/chunks/installer2.mjs +0 -103
- package/dist/chunks/interview.mjs +0 -2927
- package/dist/chunks/json-config.mjs +0 -60
- package/dist/chunks/linux.mjs +0 -3863
- package/dist/chunks/macos.mjs +0 -69
- package/dist/chunks/main.mjs +0 -635
- package/dist/chunks/manager.mjs +0 -1048
- package/dist/chunks/marketplace.mjs +0 -265
- package/dist/chunks/mcp-cli.mjs +0 -205
- package/dist/chunks/mcp-performance.mjs +0 -187
- package/dist/chunks/mcp.mjs +0 -667
- package/dist/chunks/memory-check.mjs +0 -2973
- package/dist/chunks/memory-paths.mjs +0 -259
- package/dist/chunks/memory-sync.mjs +0 -209
- package/dist/chunks/memory.mjs +0 -354
- package/dist/chunks/metrics-display.mjs +0 -153
- package/dist/chunks/monitor.mjs +0 -1856
- package/dist/chunks/notification.mjs +0 -1864
- package/dist/chunks/onboarding.mjs +0 -386
- package/dist/chunks/package.mjs +0 -3
- package/dist/chunks/paradigm.mjs +0 -74
- package/dist/chunks/permission-manager.mjs +0 -250
- package/dist/chunks/permissions.mjs +0 -265
- package/dist/chunks/persistence-manager.mjs +0 -801
- package/dist/chunks/persistence.mjs +0 -707
- package/dist/chunks/platform.mjs +0 -395
- package/dist/chunks/plugin.mjs +0 -1936
- package/dist/chunks/powershell.mjs +0 -213
- package/dist/chunks/prompts.mjs +0 -244
- package/dist/chunks/providers.mjs +0 -263
- package/dist/chunks/quick-actions.mjs +0 -335
- package/dist/chunks/quick-provider.mjs +0 -755
- package/dist/chunks/quick-setup.mjs +0 -421
- package/dist/chunks/remote.mjs +0 -497
- package/dist/chunks/research.mjs +0 -1904
- package/dist/chunks/rollback.mjs +0 -38
- package/dist/chunks/session-manager.mjs +0 -1371
- package/dist/chunks/session.mjs +0 -878
- package/dist/chunks/sessions.mjs +0 -106
- package/dist/chunks/silent-updater.mjs +0 -396
- package/dist/chunks/simple-config.mjs +0 -122
- package/dist/chunks/skill.mjs +0 -117
- package/dist/chunks/skill2.mjs +0 -9052
- package/dist/chunks/skills-sync.mjs +0 -1343
- package/dist/chunks/skills.mjs +0 -577
- package/dist/chunks/slash-commands.mjs +0 -208
- package/dist/chunks/smart-guide.mjs +0 -247
- package/dist/chunks/snapshot.mjs +0 -58
- package/dist/chunks/startup.mjs +0 -487
- package/dist/chunks/stats.mjs +0 -191
- package/dist/chunks/status.mjs +0 -471
- package/dist/chunks/team.mjs +0 -63
- package/dist/chunks/thinking.mjs +0 -626
- package/dist/chunks/trace.mjs +0 -57
- package/dist/chunks/uninstall.mjs +0 -852
- package/dist/chunks/update.mjs +0 -174
- package/dist/chunks/upgrade-manager.mjs +0 -204
- package/dist/chunks/upgrade.mjs +0 -133
- package/dist/chunks/version-checker.mjs +0 -891
- package/dist/chunks/vim.mjs +0 -903
- package/dist/chunks/windows.mjs +0 -14
- package/dist/chunks/workflows.mjs +0 -633
- package/dist/chunks/wsl.mjs +0 -129
- package/dist/chunks/zero-config.mjs +0 -871
- package/dist/chunks/zsh.mjs +0 -182
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +0 -2684
- package/dist/i18n/locales/en/agent-teams.json +0 -18
- package/dist/i18n/locales/en/agentBrowser.json +0 -80
- package/dist/i18n/locales/en/agents.json +0 -135
- package/dist/i18n/locales/en/api.json +0 -63
- package/dist/i18n/locales/en/ccjk-agents.json +0 -33
- package/dist/i18n/locales/en/ccjk-all.json +0 -23
- package/dist/i18n/locales/en/ccjk-skills.json +0 -22
- package/dist/i18n/locales/en/ccjk.json +0 -276
- package/dist/i18n/locales/en/ccr.json +0 -65
- package/dist/i18n/locales/en/claude-md.json +0 -73
- package/dist/i18n/locales/en/cli.json +0 -148
- package/dist/i18n/locales/en/cloud-setup.json +0 -31
- package/dist/i18n/locales/en/cloud-sync.json +0 -147
- package/dist/i18n/locales/en/cloud.json +0 -40
- package/dist/i18n/locales/en/cloudPlugins.json +0 -118
- package/dist/i18n/locales/en/codex.json +0 -184
- package/dist/i18n/locales/en/cometix.json +0 -29
- package/dist/i18n/locales/en/common.json +0 -68
- package/dist/i18n/locales/en/config.json +0 -108
- package/dist/i18n/locales/en/configuration.json +0 -236
- package/dist/i18n/locales/en/context.json +0 -85
- package/dist/i18n/locales/en/dashboard.json +0 -78
- package/dist/i18n/locales/en/errors.json +0 -26
- package/dist/i18n/locales/en/evolution.json +0 -54
- package/dist/i18n/locales/en/hooks.json +0 -74
- package/dist/i18n/locales/en/hooksSync.json +0 -133
- package/dist/i18n/locales/en/installation.json +0 -83
- package/dist/i18n/locales/en/interview.json +0 -104
- package/dist/i18n/locales/en/language.json +0 -19
- package/dist/i18n/locales/en/lsp.json +0 -78
- package/dist/i18n/locales/en/marketplace.json +0 -116
- package/dist/i18n/locales/en/mcp.json +0 -180
- package/dist/i18n/locales/en/memory.json +0 -23
- package/dist/i18n/locales/en/menu.json +0 -299
- package/dist/i18n/locales/en/multi-config.json +0 -79
- package/dist/i18n/locales/en/notification.json +0 -307
- package/dist/i18n/locales/en/permissions.json +0 -95
- package/dist/i18n/locales/en/persistence.json +0 -127
- package/dist/i18n/locales/en/plugins.json +0 -146
- package/dist/i18n/locales/en/quick-actions.json +0 -78
- package/dist/i18n/locales/en/registry.json +0 -54
- package/dist/i18n/locales/en/remote.json +0 -93
- package/dist/i18n/locales/en/sandbox.json +0 -44
- package/dist/i18n/locales/en/setup.json +0 -44
- package/dist/i18n/locales/en/shencha.json +0 -14
- package/dist/i18n/locales/en/skills.json +0 -100
- package/dist/i18n/locales/en/skillsSync.json +0 -74
- package/dist/i18n/locales/en/smartGuide.json +0 -49
- package/dist/i18n/locales/en/stats.json +0 -20
- package/dist/i18n/locales/en/subagent.json +0 -69
- package/dist/i18n/locales/en/superpowers.json +0 -117
- package/dist/i18n/locales/en/team.json +0 -7
- package/dist/i18n/locales/en/thinking.json +0 -65
- package/dist/i18n/locales/en/tools.json +0 -42
- package/dist/i18n/locales/en/uninstall.json +0 -56
- package/dist/i18n/locales/en/updater.json +0 -29
- package/dist/i18n/locales/en/vim.json +0 -169
- package/dist/i18n/locales/en/workflow.json +0 -55
- package/dist/i18n/locales/en/workspace.json +0 -108
- package/dist/i18n/locales/zh-CN/agent-teams.json +0 -18
- package/dist/i18n/locales/zh-CN/agentBrowser.json +0 -80
- package/dist/i18n/locales/zh-CN/agents.json +0 -135
- package/dist/i18n/locales/zh-CN/api.json +0 -63
- package/dist/i18n/locales/zh-CN/ccjk-agents.json +0 -33
- package/dist/i18n/locales/zh-CN/ccjk-all.json +0 -23
- package/dist/i18n/locales/zh-CN/ccjk-skills.json +0 -22
- package/dist/i18n/locales/zh-CN/ccjk.json +0 -276
- package/dist/i18n/locales/zh-CN/ccr.json +0 -65
- package/dist/i18n/locales/zh-CN/claude-md.json +0 -73
- package/dist/i18n/locales/zh-CN/cli.json +0 -148
- package/dist/i18n/locales/zh-CN/cloud-setup.json +0 -31
- package/dist/i18n/locales/zh-CN/cloud-sync.json +0 -147
- package/dist/i18n/locales/zh-CN/cloud.json +0 -40
- package/dist/i18n/locales/zh-CN/cloudPlugins.json +0 -118
- package/dist/i18n/locales/zh-CN/codex.json +0 -184
- package/dist/i18n/locales/zh-CN/cometix.json +0 -29
- package/dist/i18n/locales/zh-CN/common.json +0 -68
- package/dist/i18n/locales/zh-CN/config.json +0 -108
- package/dist/i18n/locales/zh-CN/configuration.json +0 -234
- package/dist/i18n/locales/zh-CN/context.json +0 -85
- package/dist/i18n/locales/zh-CN/dashboard.json +0 -78
- package/dist/i18n/locales/zh-CN/errors.json +0 -26
- package/dist/i18n/locales/zh-CN/evolution.json +0 -54
- package/dist/i18n/locales/zh-CN/hooks.json +0 -74
- package/dist/i18n/locales/zh-CN/hooksSync.json +0 -133
- package/dist/i18n/locales/zh-CN/installation.json +0 -83
- package/dist/i18n/locales/zh-CN/interview.json +0 -104
- package/dist/i18n/locales/zh-CN/language.json +0 -19
- package/dist/i18n/locales/zh-CN/lsp.json +0 -78
- package/dist/i18n/locales/zh-CN/marketplace.json +0 -116
- package/dist/i18n/locales/zh-CN/mcp.json +0 -180
- package/dist/i18n/locales/zh-CN/memory.json +0 -23
- package/dist/i18n/locales/zh-CN/menu.json +0 -299
- package/dist/i18n/locales/zh-CN/multi-config.json +0 -79
- package/dist/i18n/locales/zh-CN/notification.json +0 -307
- package/dist/i18n/locales/zh-CN/permissions.json +0 -95
- package/dist/i18n/locales/zh-CN/persistence.json +0 -127
- package/dist/i18n/locales/zh-CN/plugins.json +0 -146
- package/dist/i18n/locales/zh-CN/quick-actions.json +0 -78
- package/dist/i18n/locales/zh-CN/registry.json +0 -54
- package/dist/i18n/locales/zh-CN/remote.json +0 -93
- package/dist/i18n/locales/zh-CN/sandbox.json +0 -44
- package/dist/i18n/locales/zh-CN/setup.json +0 -44
- package/dist/i18n/locales/zh-CN/shencha.json +0 -14
- package/dist/i18n/locales/zh-CN/skills.json +0 -100
- package/dist/i18n/locales/zh-CN/skillsSync.json +0 -74
- package/dist/i18n/locales/zh-CN/smartGuide.json +0 -49
- package/dist/i18n/locales/zh-CN/stats.json +0 -20
- package/dist/i18n/locales/zh-CN/subagent.json +0 -69
- package/dist/i18n/locales/zh-CN/superpowers.json +0 -117
- package/dist/i18n/locales/zh-CN/team.json +0 -7
- package/dist/i18n/locales/zh-CN/thinking.json +0 -65
- package/dist/i18n/locales/zh-CN/tools.json +0 -42
- package/dist/i18n/locales/zh-CN/uninstall.json +0 -56
- package/dist/i18n/locales/zh-CN/updater.json +0 -29
- package/dist/i18n/locales/zh-CN/vim.json +0 -169
- package/dist/i18n/locales/zh-CN/workflow.json +0 -55
- package/dist/i18n/locales/zh-CN/workspace.json +0 -108
- package/dist/index.d.mts +0 -5658
- package/dist/index.d.ts +0 -5658
- package/dist/index.mjs +0 -3732
- package/dist/shared/ccjk.5bEolFrk.mjs +0 -254
- package/dist/shared/ccjk.8oaxX4iR.mjs +0 -90
- package/dist/shared/ccjk.B2U7DsPy.mjs +0 -31
- package/dist/shared/ccjk.B2f-cwUP.mjs +0 -468
- package/dist/shared/ccjk.BAGoDD49.mjs +0 -36
- package/dist/shared/ccjk.BBtCGd_g.mjs +0 -899
- package/dist/shared/ccjk.BFQ7yr5S.mjs +0 -16
- package/dist/shared/ccjk.BLsIiTqO.mjs +0 -449
- package/dist/shared/ccjk.BXv8aYs1.mjs +0 -170
- package/dist/shared/ccjk.BnsY5WxD.mjs +0 -171
- package/dist/shared/ccjk.BoApaI4j.mjs +0 -28
- package/dist/shared/ccjk.Bq8TqZG_.mjs +0 -189
- package/dist/shared/ccjk.BtrioX1Z.mjs +0 -25
- package/dist/shared/ccjk.Bx_rmYfN.mjs +0 -69
- package/dist/shared/ccjk.BzPbSEP2.mjs +0 -115
- package/dist/shared/ccjk.C0WLUnFV.mjs +0 -293
- package/dist/shared/ccjk.C1hANZTu.mjs +0 -19
- package/dist/shared/ccjk.C2jHOZVP.mjs +0 -52
- package/dist/shared/ccjk.CNhnT6uQ.mjs +0 -636
- package/dist/shared/ccjk.COweQ1RR.mjs +0 -5
- package/dist/shared/ccjk.CfKKcvWy.mjs +0 -126
- package/dist/shared/ccjk.Cjgrln_h.mjs +0 -297
- package/dist/shared/ccjk.CoCHVXl3.mjs +0 -3951
- package/dist/shared/ccjk.CwGZSTAK.mjs +0 -319
- package/dist/shared/ccjk.CxpGa6MC.mjs +0 -2724
- package/dist/shared/ccjk.D-magaEx.mjs +0 -763
- package/dist/shared/ccjk.D0g2ABGg.mjs +0 -171
- package/dist/shared/ccjk.D6ycHbak.mjs +0 -270
- package/dist/shared/ccjk.D75wivnp.mjs +0 -142
- package/dist/shared/ccjk.DDL-4C-k.mjs +0 -100
- package/dist/shared/ccjk.DFRPtmK_.mjs +0 -75
- package/dist/shared/ccjk.DMV3x5Sd.mjs +0 -299
- package/dist/shared/ccjk.DZ2LLOa-.mjs +0 -2195
- package/dist/shared/ccjk.DbigonEQ.mjs +0 -698
- package/dist/shared/ccjk.DcMvE7lf.mjs +0 -618
- package/dist/shared/ccjk.DeWpAShp.mjs +0 -1828
- package/dist/shared/ccjk.DhJ1kyDR.mjs +0 -30
- package/dist/shared/ccjk.DlTXS9rP.mjs +0 -224
- package/dist/shared/ccjk.DopKzo3z.mjs +0 -305
- package/dist/shared/ccjk.DsZsc4LR.mjs +0 -1280
- package/dist/shared/ccjk.DuzJZlgj.mjs +0 -418
- package/dist/shared/ccjk.Dxgd2vjc.mjs +0 -444
- package/dist/shared/ccjk.J8YiPsOw.mjs +0 -259
- package/dist/shared/ccjk.KfSWcGlE.mjs +0 -38
- package/dist/shared/ccjk.L7yC58_i.mjs +0 -225
- package/dist/shared/ccjk.MwtjAULc.mjs +0 -1447
- package/dist/shared/ccjk.OJKHVSOb.mjs +0 -2005
- package/dist/shared/ccjk.OTnevPNE.mjs +0 -225
- package/dist/shared/ccjk.RyizuzOI.mjs +0 -21
- package/dist/shared/ccjk.T_cX87dY.mjs +0 -15
- package/dist/shared/ccjk.bQ7Dh1g4.mjs +0 -249
- package/dist/shared/ccjk.gDEDGD_t.mjs +0 -38
- package/dist/shared/ccjk.hoqrwWdN.mjs +0 -333
- package/dist/shared/ccjk.i_vn-9C3.mjs +0 -317
- package/dist/shared/ccjk.lG3ccFjm.mjs +0 -885
- package/dist/shared/ccjk.wLJHO0Af.mjs +0 -244
- package/dist/shared/ccjk.y-a_1vK4.mjs +0 -5127
- package/dist/templates/agents/README.md +0 -78
- package/dist/templates/agents/fullstack-developer.json +0 -70
- package/dist/templates/agents/go-expert.json +0 -69
- package/dist/templates/agents/index.json +0 -64
- package/dist/templates/agents/python-expert.json +0 -69
- package/dist/templates/agents/react-specialist.json +0 -69
- package/dist/templates/agents/testing-automation-expert.json +0 -70
- package/dist/templates/agents/typescript-architect.json +0 -69
- package/dist/templates/claude-code/common/settings.json +0 -109
- package/dist/templates/common/error-prevention.md +0 -267
- package/dist/templates/common/karpathy-baseline.md +0 -83
- package/dist/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
- package/dist/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
- package/dist/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
- package/dist/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
- package/dist/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
- package/dist/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
- package/dist/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
- package/dist/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
- package/dist/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
- package/dist/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
- package/dist/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
- package/dist/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
- package/dist/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
- package/dist/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
- package/dist/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
- package/dist/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
- package/dist/templates/common/workflow/essential/en/feat.md +0 -92
- package/dist/templates/common/workflow/essential/en/goal.md +0 -147
- package/dist/templates/common/workflow/essential/en/init-project.md +0 -53
- package/dist/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
- package/dist/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
- package/dist/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
- package/dist/templates/common/workflow/essential/zh-CN/feat.md +0 -315
- package/dist/templates/common/workflow/essential/zh-CN/goal.md +0 -146
- package/dist/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
- package/dist/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
- package/dist/templates/common/workflow/git/en/git-commit.md +0 -205
- package/dist/templates/common/workflow/git/en/git-rollback.md +0 -90
- package/dist/templates/common/workflow/git/en/git-worktree.md +0 -276
- package/dist/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
- package/dist/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
- package/dist/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
- package/dist/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
- package/dist/templates/common/workflow/interview/en/interview.md +0 -67
- package/dist/templates/common/workflow/interview/zh-CN/interview.md +0 -67
- package/dist/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
- package/dist/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
- package/dist/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
- package/dist/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
- package/dist/templates/common/workflow/sixStep/en/workflow.md +0 -83
- package/dist/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
- package/dist/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
- package/dist/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
- package/dist/templates/hooks/README.md +0 -212
- package/dist/templates/hooks/git-workflow-hooks.md +0 -551
- package/dist/templates/hooks/post-test/coverage.json +0 -21
- package/dist/templates/hooks/post-test/summary.json +0 -21
- package/dist/templates/hooks/post-test-coverage.md +0 -434
- package/dist/templates/hooks/pre-commit/eslint.json +0 -22
- package/dist/templates/hooks/pre-commit/prettier.json +0 -22
- package/dist/templates/hooks/pre-commit-black.md +0 -274
- package/dist/templates/hooks/pre-commit-eslint.md +0 -153
- package/dist/templates/hooks/pre-commit-gofmt.md +0 -284
- package/dist/templates/hooks/pre-commit-prettier.md +0 -212
- package/dist/templates/hooks/pre-commit-type-check.md +0 -377
- package/dist/templates/skills/ccjk-init.md +0 -154
- package/dist/templates/skills/ccjk-mcp-setup.md +0 -205
- package/dist/templates/skills/ccjk-troubleshoot.md +0 -228
- package/dist/templates/skills/django-patterns.md +0 -1016
- package/dist/templates/skills/git-workflow.md +0 -748
- package/dist/templates/skills/go-idioms.md +0 -963
- package/dist/templates/skills/index.json +0 -132
- package/dist/templates/skills/nextjs-optimization.md +0 -694
- package/dist/templates/skills/python-pep8.md +0 -852
- package/dist/templates/skills/react-patterns.md +0 -686
- package/dist/templates/skills/rust-patterns.md +0 -1057
- package/dist/templates/skills/security-best-practices.md +0 -1413
- package/dist/templates/skills/testing-best-practices.md +0 -1315
- package/dist/templates/skills/ts-best-practices.md +0 -354
- package/templates/agents/README.md +0 -78
- package/templates/agents/fullstack-developer.json +0 -70
- package/templates/agents/go-expert.json +0 -69
- package/templates/agents/index.json +0 -64
- package/templates/agents/python-expert.json +0 -69
- package/templates/agents/react-specialist.json +0 -69
- package/templates/agents/testing-automation-expert.json +0 -70
- package/templates/agents/typescript-architect.json +0 -69
- package/templates/claude-code/common/settings.json +0 -109
- package/templates/common/error-prevention.md +0 -267
- package/templates/common/karpathy-baseline.md +0 -83
- package/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
- package/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
- package/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
- package/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
- package/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
- package/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
- package/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
- package/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
- package/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
- package/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
- package/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
- package/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
- package/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
- package/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
- package/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
- package/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
- package/templates/common/workflow/essential/en/feat.md +0 -92
- package/templates/common/workflow/essential/en/goal.md +0 -147
- package/templates/common/workflow/essential/en/init-project.md +0 -53
- package/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
- package/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
- package/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
- package/templates/common/workflow/essential/zh-CN/feat.md +0 -315
- package/templates/common/workflow/essential/zh-CN/goal.md +0 -146
- package/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
- package/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
- package/templates/common/workflow/git/en/git-commit.md +0 -205
- package/templates/common/workflow/git/en/git-rollback.md +0 -90
- package/templates/common/workflow/git/en/git-worktree.md +0 -276
- package/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
- package/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
- package/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
- package/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
- package/templates/common/workflow/interview/en/interview.md +0 -67
- package/templates/common/workflow/interview/zh-CN/interview.md +0 -67
- package/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
- package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
- package/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
- package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
- package/templates/common/workflow/sixStep/en/workflow.md +0 -83
- package/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
- package/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
- package/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
- package/templates/hooks/README.md +0 -212
- package/templates/hooks/git-workflow-hooks.md +0 -551
- package/templates/hooks/post-test/coverage.json +0 -21
- package/templates/hooks/post-test/summary.json +0 -21
- package/templates/hooks/post-test-coverage.md +0 -434
- package/templates/hooks/pre-commit/eslint.json +0 -22
- package/templates/hooks/pre-commit/prettier.json +0 -22
- package/templates/hooks/pre-commit-black.md +0 -274
- package/templates/hooks/pre-commit-eslint.md +0 -153
- package/templates/hooks/pre-commit-gofmt.md +0 -284
- package/templates/hooks/pre-commit-prettier.md +0 -212
- package/templates/hooks/pre-commit-type-check.md +0 -377
- package/templates/skills/basic.hbs +0 -72
- package/templates/skills/ccjk-init.md +0 -154
- package/templates/skills/ccjk-mcp-setup.md +0 -205
- package/templates/skills/ccjk-troubleshoot.md +0 -228
- package/templates/skills/code-refactor.hbs +0 -133
- package/templates/skills/code-review.hbs +0 -141
- package/templates/skills/django-patterns.md +0 -1016
- package/templates/skills/git-workflow.md +0 -748
- package/templates/skills/go-idioms.md +0 -963
- package/templates/skills/index.json +0 -132
- package/templates/skills/nextjs-optimization.md +0 -694
- package/templates/skills/python-pep8.md +0 -852
- package/templates/skills/react-patterns.md +0 -686
- package/templates/skills/rust-patterns.md +0 -1057
- package/templates/skills/security-best-practices.md +0 -1413
- package/templates/skills/testing-best-practices.md +0 -1315
- package/templates/skills/ts-best-practices.md +0 -354
- package/templates/skills/type-fix.hbs +0 -132
package/dist/chunks/cli-hook.mjs
DELETED
|
@@ -1,4096 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { DEFAULT_CODE_TOOL_TYPE, isCodeToolType, getCodeToolNativeSlashCommands } from './constants.mjs';
|
|
3
|
-
import { readZcfConfig } from './ccjk-config.mjs';
|
|
4
|
-
import { a as getGlobalStateManager, g as getGlobalConvoyManager, c as contextLoader, S as SessionIntelligence } from './session-manager.mjs';
|
|
5
|
-
import { l as logger } from '../shared/ccjk.8oaxX4iR.mjs';
|
|
6
|
-
import { Buffer } from 'node:buffer';
|
|
7
|
-
import { randomUUID } from 'node:crypto';
|
|
8
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
9
|
-
import { d as dirname, j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
10
|
-
import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
|
|
11
|
-
import process__default from 'node:process';
|
|
12
|
-
import 'node:os';
|
|
13
|
-
import './index2.mjs';
|
|
14
|
-
import 'node:url';
|
|
15
|
-
import '../shared/ccjk.BBtCGd_g.mjs';
|
|
16
|
-
import './index3.mjs';
|
|
17
|
-
import './fs-operations.mjs';
|
|
18
|
-
import 'node:fs/promises';
|
|
19
|
-
import './json-config.mjs';
|
|
20
|
-
import '../shared/ccjk.RyizuzOI.mjs';
|
|
21
|
-
import '../shared/ccjk.BAGoDD49.mjs';
|
|
22
|
-
import './main.mjs';
|
|
23
|
-
import 'module';
|
|
24
|
-
import 'node:child_process';
|
|
25
|
-
import 'node:path';
|
|
26
|
-
import 'node:stream';
|
|
27
|
-
import 'node:readline';
|
|
28
|
-
import 'tinyglobby';
|
|
29
|
-
import '../shared/ccjk.DlTXS9rP.mjs';
|
|
30
|
-
import './index5.mjs';
|
|
31
|
-
import '../shared/ccjk.wLJHO0Af.mjs';
|
|
32
|
-
|
|
33
|
-
class HookRegistry {
|
|
34
|
-
hooks = /* @__PURE__ */ new Map();
|
|
35
|
-
/**
|
|
36
|
-
* Register a hook for an event
|
|
37
|
-
*/
|
|
38
|
-
register(event, hook) {
|
|
39
|
-
const hooks = this.hooks.get(event) || [];
|
|
40
|
-
hooks.push(hook);
|
|
41
|
-
hooks.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
42
|
-
this.hooks.set(event, hooks);
|
|
43
|
-
logger.debug(`Registered hook "${hook.name}" for event "${event}"`);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Unregister a hook
|
|
47
|
-
*/
|
|
48
|
-
unregister(event, hookName) {
|
|
49
|
-
const hooks = this.hooks.get(event);
|
|
50
|
-
if (!hooks)
|
|
51
|
-
return;
|
|
52
|
-
const filtered = hooks.filter((h) => h.name !== hookName);
|
|
53
|
-
this.hooks.set(event, filtered);
|
|
54
|
-
logger.debug(`Unregistered hook "${hookName}" for event "${event}"`);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Execute all hooks for an event
|
|
58
|
-
* Returns false if any hook returns continue: false
|
|
59
|
-
*/
|
|
60
|
-
async execute(context) {
|
|
61
|
-
const hooks = this.hooks.get(context.event) || [];
|
|
62
|
-
const enabledHooks = hooks.filter((h) => h.enabled !== false);
|
|
63
|
-
if (enabledHooks.length === 0) {
|
|
64
|
-
return { continue: true };
|
|
65
|
-
}
|
|
66
|
-
let currentContext = context;
|
|
67
|
-
let aggregatedData = {};
|
|
68
|
-
for (const hook of enabledHooks) {
|
|
69
|
-
try {
|
|
70
|
-
const result = await hook.fn(currentContext);
|
|
71
|
-
if (result.data) {
|
|
72
|
-
aggregatedData = { ...aggregatedData, ...result.data };
|
|
73
|
-
}
|
|
74
|
-
if (!result.continue) {
|
|
75
|
-
return {
|
|
76
|
-
continue: false,
|
|
77
|
-
data: aggregatedData,
|
|
78
|
-
error: result.error
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
currentContext = {
|
|
82
|
-
...currentContext,
|
|
83
|
-
data: { ...currentContext.data, ...aggregatedData }
|
|
84
|
-
};
|
|
85
|
-
} catch (error) {
|
|
86
|
-
logger.error(`Hook "${hook.name}" failed:`, error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
continue: true,
|
|
91
|
-
data: aggregatedData
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Get all registered hooks for an event
|
|
96
|
-
*/
|
|
97
|
-
getHooks(event) {
|
|
98
|
-
return this.hooks.get(event) || [];
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Clear all hooks
|
|
102
|
-
*/
|
|
103
|
-
clear() {
|
|
104
|
-
this.hooks.clear();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
const hookRegistry = new HookRegistry();
|
|
108
|
-
|
|
109
|
-
async function emitCommandHookEvent(event, data, sessionId) {
|
|
110
|
-
try {
|
|
111
|
-
const context = {
|
|
112
|
-
event,
|
|
113
|
-
sessionId,
|
|
114
|
-
data,
|
|
115
|
-
timestamp: Date.now(),
|
|
116
|
-
metadata: {
|
|
117
|
-
source: "brain-router"
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
await hookRegistry.execute(context);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
logger.debug(`Command hook bridge skipped for "${event}": ${String(error)}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const DEFAULT_CONFIG = {
|
|
127
|
-
enablePersistence: false,
|
|
128
|
-
maxHistorySize: 1e3,
|
|
129
|
-
messageRetentionTime: 24 * 60 * 60 * 1e3,
|
|
130
|
-
// 24 hours
|
|
131
|
-
enableLogging: true,
|
|
132
|
-
logLevel: "info",
|
|
133
|
-
enableValidation: true,
|
|
134
|
-
maxMessageSize: 1024 * 1024,
|
|
135
|
-
// 1MB
|
|
136
|
-
enableDeadLetterQueue: true
|
|
137
|
-
};
|
|
138
|
-
class FileMessageStorage {
|
|
139
|
-
filePath;
|
|
140
|
-
constructor(filePath) {
|
|
141
|
-
this.filePath = filePath;
|
|
142
|
-
this.ensureDirectory();
|
|
143
|
-
}
|
|
144
|
-
ensureDirectory() {
|
|
145
|
-
const dir = dirname(this.filePath);
|
|
146
|
-
if (!existsSync(dir)) {
|
|
147
|
-
mkdirSync(dir, { recursive: true });
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
async save(message) {
|
|
151
|
-
try {
|
|
152
|
-
const messages = await this.load();
|
|
153
|
-
messages.push(message);
|
|
154
|
-
writeFileSync(this.filePath, JSON.stringify(messages, null, 2), "utf-8");
|
|
155
|
-
} catch (error) {
|
|
156
|
-
console.error("Failed to save message:", error);
|
|
157
|
-
throw error;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
async load(filter) {
|
|
161
|
-
try {
|
|
162
|
-
if (!existsSync(this.filePath)) {
|
|
163
|
-
return [];
|
|
164
|
-
}
|
|
165
|
-
const content = readFileSync(this.filePath, "utf-8");
|
|
166
|
-
const messages = JSON.parse(content);
|
|
167
|
-
if (filter) {
|
|
168
|
-
return messages.filter(filter);
|
|
169
|
-
}
|
|
170
|
-
return messages;
|
|
171
|
-
} catch (error) {
|
|
172
|
-
console.error("Failed to load messages:", error);
|
|
173
|
-
return [];
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
async delete(messageId) {
|
|
177
|
-
try {
|
|
178
|
-
const messages = await this.load();
|
|
179
|
-
const filtered = messages.filter((msg) => msg.id !== messageId);
|
|
180
|
-
writeFileSync(this.filePath, JSON.stringify(filtered, null, 2), "utf-8");
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.error("Failed to delete message:", error);
|
|
183
|
-
throw error;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
async clear() {
|
|
187
|
-
try {
|
|
188
|
-
writeFileSync(this.filePath, JSON.stringify([], null, 2), "utf-8");
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.error("Failed to clear messages:", error);
|
|
191
|
-
throw error;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async getStats() {
|
|
195
|
-
try {
|
|
196
|
-
if (!existsSync(this.filePath)) {
|
|
197
|
-
return { count: 0, size: 0 };
|
|
198
|
-
}
|
|
199
|
-
const messages = await this.load();
|
|
200
|
-
const content = readFileSync(this.filePath, "utf-8");
|
|
201
|
-
return {
|
|
202
|
-
count: messages.length,
|
|
203
|
-
size: Buffer.byteLength(content, "utf-8")
|
|
204
|
-
};
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.error("Failed to get storage stats:", error);
|
|
207
|
-
return { count: 0, size: 0 };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
class MessageBus {
|
|
212
|
-
config;
|
|
213
|
-
subscriptions;
|
|
214
|
-
messageHistory;
|
|
215
|
-
deadLetterQueue;
|
|
216
|
-
storage;
|
|
217
|
-
stats;
|
|
218
|
-
constructor(config = {}) {
|
|
219
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
220
|
-
this.subscriptions = /* @__PURE__ */ new Map();
|
|
221
|
-
this.messageHistory = [];
|
|
222
|
-
this.deadLetterQueue = [];
|
|
223
|
-
if (this.config.enablePersistence && this.config.persistencePath) {
|
|
224
|
-
this.storage = new FileMessageStorage(this.config.persistencePath);
|
|
225
|
-
this.loadPersistedMessages();
|
|
226
|
-
}
|
|
227
|
-
this.stats = {
|
|
228
|
-
totalMessages: 0,
|
|
229
|
-
messagesByType: {},
|
|
230
|
-
messagesByStatus: {},
|
|
231
|
-
activeSubscriptions: 0,
|
|
232
|
-
historySize: 0,
|
|
233
|
-
deadLetterQueueSize: 0,
|
|
234
|
-
avgProcessingTime: 0
|
|
235
|
-
};
|
|
236
|
-
this.startCleanupInterval();
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Publish a message to the bus
|
|
240
|
-
*/
|
|
241
|
-
async publish(type, from, to, subject, payload, options = {}) {
|
|
242
|
-
const message = {
|
|
243
|
-
id: randomUUID(),
|
|
244
|
-
type,
|
|
245
|
-
from,
|
|
246
|
-
to,
|
|
247
|
-
subject,
|
|
248
|
-
payload,
|
|
249
|
-
priority: options.priority || "normal",
|
|
250
|
-
status: "pending",
|
|
251
|
-
timestamp: Date.now(),
|
|
252
|
-
correlationId: options.correlationId,
|
|
253
|
-
replyTo: options.replyTo,
|
|
254
|
-
metadata: options.metadata
|
|
255
|
-
};
|
|
256
|
-
if (this.config.enableValidation) {
|
|
257
|
-
this.validateMessage(message);
|
|
258
|
-
}
|
|
259
|
-
this.logMessage("publish", message);
|
|
260
|
-
this.updateStats(message);
|
|
261
|
-
this.addToHistory(message);
|
|
262
|
-
if (this.storage) {
|
|
263
|
-
await this.storage.save(message);
|
|
264
|
-
}
|
|
265
|
-
await this.routeMessage(message);
|
|
266
|
-
return message.id;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Subscribe to messages
|
|
270
|
-
*/
|
|
271
|
-
subscribe(subscriber, handler, options = {}) {
|
|
272
|
-
const subscription = {
|
|
273
|
-
id: randomUUID(),
|
|
274
|
-
subscriber,
|
|
275
|
-
options,
|
|
276
|
-
handler,
|
|
277
|
-
createdAt: Date.now(),
|
|
278
|
-
unsubscribe: () => this.unsubscribe(subscription.id)
|
|
279
|
-
};
|
|
280
|
-
this.subscriptions.set(subscription.id, subscription);
|
|
281
|
-
this.stats.activeSubscriptions = this.subscriptions.size;
|
|
282
|
-
this.log("info", `Agent ${subscriber} subscribed with ID ${subscription.id}`);
|
|
283
|
-
return subscription;
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Unsubscribe from messages
|
|
287
|
-
*/
|
|
288
|
-
unsubscribe(subscriptionId) {
|
|
289
|
-
const subscription = this.subscriptions.get(subscriptionId);
|
|
290
|
-
if (subscription) {
|
|
291
|
-
this.subscriptions.delete(subscriptionId);
|
|
292
|
-
this.stats.activeSubscriptions = this.subscriptions.size;
|
|
293
|
-
this.log("info", `Subscription ${subscriptionId} removed`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Get message by ID
|
|
298
|
-
*/
|
|
299
|
-
getMessage(messageId) {
|
|
300
|
-
return this.messageHistory.find((msg) => msg.id === messageId);
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Get messages by filter
|
|
304
|
-
*/
|
|
305
|
-
getMessages(filter) {
|
|
306
|
-
return this.messageHistory.filter(filter);
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Update message status
|
|
310
|
-
*/
|
|
311
|
-
async updateMessageStatus(messageId, status, error) {
|
|
312
|
-
const message = this.getMessage(messageId);
|
|
313
|
-
if (message) {
|
|
314
|
-
message.status = status;
|
|
315
|
-
if (error) {
|
|
316
|
-
message.error = error;
|
|
317
|
-
}
|
|
318
|
-
if (status === "failed" && this.config.enableDeadLetterQueue) {
|
|
319
|
-
this.deadLetterQueue.push(message);
|
|
320
|
-
this.stats.deadLetterQueueSize = this.deadLetterQueue.length;
|
|
321
|
-
}
|
|
322
|
-
this.stats.messagesByStatus[status] = (this.stats.messagesByStatus[status] || 0) + 1;
|
|
323
|
-
if (this.storage) {
|
|
324
|
-
await this.storage.save(message);
|
|
325
|
-
}
|
|
326
|
-
this.log("debug", `Message ${messageId} status updated to ${status}`);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Get message bus statistics
|
|
331
|
-
*/
|
|
332
|
-
getStats() {
|
|
333
|
-
return { ...this.stats };
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Clear message history
|
|
337
|
-
*/
|
|
338
|
-
async clearHistory() {
|
|
339
|
-
this.messageHistory = [];
|
|
340
|
-
this.stats.historySize = 0;
|
|
341
|
-
if (this.storage) {
|
|
342
|
-
await this.storage.clear();
|
|
343
|
-
}
|
|
344
|
-
this.log("info", "Message history cleared");
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Clear dead letter queue
|
|
348
|
-
*/
|
|
349
|
-
clearDeadLetterQueue() {
|
|
350
|
-
this.deadLetterQueue = [];
|
|
351
|
-
this.stats.deadLetterQueueSize = 0;
|
|
352
|
-
this.log("info", "Dead letter queue cleared");
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Get dead letter queue messages
|
|
356
|
-
*/
|
|
357
|
-
getDeadLetterQueue() {
|
|
358
|
-
return [...this.deadLetterQueue];
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Shutdown message bus
|
|
362
|
-
*/
|
|
363
|
-
async shutdown() {
|
|
364
|
-
this.log("info", "Shutting down message bus");
|
|
365
|
-
this.subscriptions.clear();
|
|
366
|
-
this.stats.activeSubscriptions = 0;
|
|
367
|
-
if (this.storage && this.messageHistory.length > 0) {
|
|
368
|
-
for (const message of this.messageHistory) {
|
|
369
|
-
await this.storage.save(message);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
this.log("info", "Message bus shutdown complete");
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Route message to subscribers
|
|
376
|
-
*/
|
|
377
|
-
async routeMessage(message) {
|
|
378
|
-
const startTime = Date.now();
|
|
379
|
-
const matchingSubscriptions = this.findMatchingSubscriptions(message);
|
|
380
|
-
this.log("debug", `Routing message ${message.id} to ${matchingSubscriptions.length} subscribers`);
|
|
381
|
-
for (const subscription of matchingSubscriptions) {
|
|
382
|
-
try {
|
|
383
|
-
message.status = "processing";
|
|
384
|
-
if (subscription.options.async) {
|
|
385
|
-
await subscription.handler(message);
|
|
386
|
-
} else {
|
|
387
|
-
subscription.handler(message);
|
|
388
|
-
}
|
|
389
|
-
message.status = "completed";
|
|
390
|
-
} catch (error) {
|
|
391
|
-
this.log("error", `Error handling message ${message.id} in subscription ${subscription.id}:`, error);
|
|
392
|
-
await this.updateMessageStatus(message.id, "failed", {
|
|
393
|
-
code: "HANDLER_ERROR",
|
|
394
|
-
message: error instanceof Error ? error.message : String(error),
|
|
395
|
-
stack: error instanceof Error ? error.stack : void 0
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
const processingTime = Date.now() - startTime;
|
|
400
|
-
this.stats.avgProcessingTime = (this.stats.avgProcessingTime + processingTime) / 2;
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Find subscriptions matching the message
|
|
404
|
-
*/
|
|
405
|
-
findMatchingSubscriptions(message) {
|
|
406
|
-
const matching = [];
|
|
407
|
-
const subscriptions = Array.from(this.subscriptions.values());
|
|
408
|
-
for (const subscription of subscriptions) {
|
|
409
|
-
const isAddressed = message.to === "all" || message.to === subscription.subscriber || Array.isArray(message.to) && message.to.includes(subscription.subscriber);
|
|
410
|
-
if (!isAddressed) {
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
if (!this.matchesSubscriptionFilters(message, subscription.options)) {
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
416
|
-
matching.push(subscription);
|
|
417
|
-
}
|
|
418
|
-
return matching;
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Check if message matches subscription filters
|
|
422
|
-
*/
|
|
423
|
-
matchesSubscriptionFilters(message, options) {
|
|
424
|
-
if (options.type) {
|
|
425
|
-
const types = Array.isArray(options.type) ? options.type : [options.type];
|
|
426
|
-
if (!types.includes(message.type)) {
|
|
427
|
-
return false;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
if (options.from) {
|
|
431
|
-
const senders = Array.isArray(options.from) ? options.from : [options.from];
|
|
432
|
-
if (!senders.includes(message.from)) {
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if (options.priority) {
|
|
437
|
-
const priorities = Array.isArray(options.priority) ? options.priority : [options.priority];
|
|
438
|
-
if (!priorities.includes(message.priority)) {
|
|
439
|
-
return false;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (options.filter && !options.filter(message)) {
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
return true;
|
|
446
|
-
}
|
|
447
|
-
/**
|
|
448
|
-
* Validate message
|
|
449
|
-
*/
|
|
450
|
-
validateMessage(message) {
|
|
451
|
-
if (!message.id) {
|
|
452
|
-
throw new Error("Message ID is required");
|
|
453
|
-
}
|
|
454
|
-
if (!message.type) {
|
|
455
|
-
throw new Error("Message type is required");
|
|
456
|
-
}
|
|
457
|
-
if (!message.from) {
|
|
458
|
-
throw new Error("Message sender is required");
|
|
459
|
-
}
|
|
460
|
-
if (!message.to) {
|
|
461
|
-
throw new Error("Message recipient is required");
|
|
462
|
-
}
|
|
463
|
-
if (!message.subject) {
|
|
464
|
-
throw new Error("Message subject is required");
|
|
465
|
-
}
|
|
466
|
-
if (this.config.maxMessageSize) {
|
|
467
|
-
const messageSize = Buffer.byteLength(JSON.stringify(message), "utf-8");
|
|
468
|
-
if (messageSize > this.config.maxMessageSize) {
|
|
469
|
-
throw new Error(`Message size ${messageSize} exceeds maximum ${this.config.maxMessageSize}`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Add message to history
|
|
475
|
-
*/
|
|
476
|
-
addToHistory(message) {
|
|
477
|
-
this.messageHistory.push(message);
|
|
478
|
-
this.stats.historySize = this.messageHistory.length;
|
|
479
|
-
const maxHistorySize = this.config.maxHistorySize ?? 1e3;
|
|
480
|
-
if (this.messageHistory.length > maxHistorySize) {
|
|
481
|
-
this.messageHistory.shift();
|
|
482
|
-
this.stats.historySize = this.messageHistory.length;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* Update statistics
|
|
487
|
-
*/
|
|
488
|
-
updateStats(message) {
|
|
489
|
-
this.stats.totalMessages++;
|
|
490
|
-
this.stats.messagesByType[message.type] = (this.stats.messagesByType[message.type] || 0) + 1;
|
|
491
|
-
this.stats.messagesByStatus[message.status] = (this.stats.messagesByStatus[message.status] || 0) + 1;
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Load persisted messages
|
|
495
|
-
*/
|
|
496
|
-
async loadPersistedMessages() {
|
|
497
|
-
if (!this.storage) {
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
try {
|
|
501
|
-
const messages = await this.storage.load();
|
|
502
|
-
this.messageHistory = messages;
|
|
503
|
-
this.stats.historySize = messages.length;
|
|
504
|
-
this.log("info", `Loaded ${messages.length} persisted messages`);
|
|
505
|
-
} catch (error) {
|
|
506
|
-
this.log("error", "Failed to load persisted messages:", error);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Start cleanup interval for old messages
|
|
511
|
-
*/
|
|
512
|
-
startCleanupInterval() {
|
|
513
|
-
setInterval(() => {
|
|
514
|
-
const now = Date.now();
|
|
515
|
-
const retentionTime = this.config.messageRetentionTime ?? 864e5;
|
|
516
|
-
this.messageHistory = this.messageHistory.filter(
|
|
517
|
-
(msg) => now - msg.timestamp < retentionTime
|
|
518
|
-
);
|
|
519
|
-
this.stats.historySize = this.messageHistory.length;
|
|
520
|
-
this.deadLetterQueue = this.deadLetterQueue.filter(
|
|
521
|
-
(msg) => now - msg.timestamp < retentionTime
|
|
522
|
-
);
|
|
523
|
-
this.stats.deadLetterQueueSize = this.deadLetterQueue.length;
|
|
524
|
-
this.log("debug", "Cleanup completed");
|
|
525
|
-
}, 60 * 60 * 1e3);
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* Log message
|
|
529
|
-
*/
|
|
530
|
-
logMessage(action, message) {
|
|
531
|
-
if (!this.config.enableLogging) {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
const logLevel = this.config.logLevel;
|
|
535
|
-
const shouldLog = logLevel === "debug" || logLevel === "info" && ["publish", "subscribe"].includes(action) || logLevel === "warn" && message.priority === "high" || logLevel === "error" && message.status === "failed";
|
|
536
|
-
if (shouldLog) {
|
|
537
|
-
this.log("debug", `[${action}] ${message.type} from ${message.from} to ${message.to}: ${message.subject}`);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Internal logging
|
|
542
|
-
*/
|
|
543
|
-
log(level, message, ...args) {
|
|
544
|
-
if (!this.config.enableLogging) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const levels = ["debug", "info", "warn", "error"];
|
|
548
|
-
const configLevel = levels.indexOf(this.config.logLevel ?? "info");
|
|
549
|
-
const messageLevel = levels.indexOf(level);
|
|
550
|
-
if (messageLevel >= configLevel) {
|
|
551
|
-
console[level](`[MessageBus] ${message}`, ...args);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
let globalMessageBus = null;
|
|
556
|
-
function getMessageBus(config) {
|
|
557
|
-
if (!globalMessageBus) {
|
|
558
|
-
globalMessageBus = new MessageBus(config);
|
|
559
|
-
}
|
|
560
|
-
return globalMessageBus;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
class SkillRegistry extends EventEmitter {
|
|
564
|
-
skills;
|
|
565
|
-
filePathIndex;
|
|
566
|
-
triggerIndex;
|
|
567
|
-
messageBus = getMessageBus();
|
|
568
|
-
constructor() {
|
|
569
|
-
super();
|
|
570
|
-
this.skills = /* @__PURE__ */ new Map();
|
|
571
|
-
this.filePathIndex = /* @__PURE__ */ new Map();
|
|
572
|
-
this.triggerIndex = /* @__PURE__ */ new Map();
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Register a skill
|
|
576
|
-
*
|
|
577
|
-
* @param skill - Parsed skill file
|
|
578
|
-
* @param source - Skill source type
|
|
579
|
-
* @returns Registered entry
|
|
580
|
-
*/
|
|
581
|
-
register(skill, source = "user") {
|
|
582
|
-
const id = skill.metadata.name;
|
|
583
|
-
const existing = this.skills.get(id);
|
|
584
|
-
const dependencies = this.extractDependencies(skill.metadata);
|
|
585
|
-
const entry = {
|
|
586
|
-
id,
|
|
587
|
-
metadata: skill.metadata,
|
|
588
|
-
content: skill.content,
|
|
589
|
-
filePath: skill.filePath,
|
|
590
|
-
enabled: existing?.enabled ?? true,
|
|
591
|
-
source,
|
|
592
|
-
registeredAt: existing?.registeredAt ?? Date.now(),
|
|
593
|
-
modifiedAt: skill.modifiedAt?.getTime() ?? Date.now(),
|
|
594
|
-
estimatedTokens: this.estimateTokens(skill),
|
|
595
|
-
dependencies,
|
|
596
|
-
dependents: existing?.dependents || /* @__PURE__ */ new Set()
|
|
597
|
-
};
|
|
598
|
-
this.skills.set(id, entry);
|
|
599
|
-
this.filePathIndex.set(skill.filePath, id);
|
|
600
|
-
this.updateTriggerIndex(id, entry.metadata.triggers);
|
|
601
|
-
this.updateDependencyGraph(id, dependencies);
|
|
602
|
-
if (existing) {
|
|
603
|
-
this.emit("skill:updated", existing, entry);
|
|
604
|
-
this.publishMessage("skill:updated", { oldSkill: existing, newSkill: entry });
|
|
605
|
-
} else {
|
|
606
|
-
this.emit("skill:registered", entry);
|
|
607
|
-
this.publishMessage("skill:registered", entry);
|
|
608
|
-
}
|
|
609
|
-
return entry;
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* Unregister a skill by ID
|
|
613
|
-
*
|
|
614
|
-
* @param id - Skill ID
|
|
615
|
-
* @returns True if skill was unregistered
|
|
616
|
-
*/
|
|
617
|
-
unregister(id) {
|
|
618
|
-
const entry = this.skills.get(id);
|
|
619
|
-
if (!entry)
|
|
620
|
-
return false;
|
|
621
|
-
if (entry.dependents.size > 0) {
|
|
622
|
-
const dependentList = Array.from(entry.dependents).join(", ");
|
|
623
|
-
throw new Error(`Cannot unregister skill "${id}": depended upon by: ${dependentList}`);
|
|
624
|
-
}
|
|
625
|
-
this.skills.delete(id);
|
|
626
|
-
this.filePathIndex.delete(entry.filePath);
|
|
627
|
-
for (const trigger of entry.metadata.triggers) {
|
|
628
|
-
const skills = this.triggerIndex.get(trigger);
|
|
629
|
-
if (skills) {
|
|
630
|
-
skills.delete(id);
|
|
631
|
-
if (skills.size === 0)
|
|
632
|
-
this.triggerIndex.delete(trigger);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
for (const dep of entry.dependencies) {
|
|
636
|
-
const depEntry = this.skills.get(dep);
|
|
637
|
-
if (depEntry)
|
|
638
|
-
depEntry.dependents.delete(id);
|
|
639
|
-
}
|
|
640
|
-
this.emit("skill:unregistered", entry);
|
|
641
|
-
this.publishMessage("skill:unregistered", entry);
|
|
642
|
-
return true;
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Unregister a skill by file path
|
|
646
|
-
*
|
|
647
|
-
* @param filePath - File path
|
|
648
|
-
* @returns True if skill was unregistered
|
|
649
|
-
*/
|
|
650
|
-
unregisterByPath(filePath) {
|
|
651
|
-
const id = this.filePathIndex.get(filePath);
|
|
652
|
-
return id ? this.unregister(id) : false;
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Get a skill by ID
|
|
656
|
-
*
|
|
657
|
-
* @param id - Skill ID
|
|
658
|
-
* @returns Skill entry or undefined
|
|
659
|
-
*/
|
|
660
|
-
getById(id) {
|
|
661
|
-
return this.skills.get(id);
|
|
662
|
-
}
|
|
663
|
-
/**
|
|
664
|
-
* Get a skill by file path
|
|
665
|
-
*
|
|
666
|
-
* @param filePath - File path
|
|
667
|
-
* @returns Skill entry or undefined
|
|
668
|
-
*/
|
|
669
|
-
getByPath(filePath) {
|
|
670
|
-
const id = this.filePathIndex.get(filePath);
|
|
671
|
-
return id ? this.skills.get(id) : void 0;
|
|
672
|
-
}
|
|
673
|
-
/**
|
|
674
|
-
* Get skills by trigger
|
|
675
|
-
*
|
|
676
|
-
* @param trigger - Trigger string (e.g., '/commit')
|
|
677
|
-
* @returns Array of matching skills
|
|
678
|
-
*/
|
|
679
|
-
getByTrigger(trigger) {
|
|
680
|
-
const ids = this.triggerIndex.get(trigger);
|
|
681
|
-
if (!ids)
|
|
682
|
-
return [];
|
|
683
|
-
return Array.from(ids).map((id) => this.skills.get(id)).filter((e) => e !== void 0 && e.enabled);
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Lookup skills with filters
|
|
687
|
-
*
|
|
688
|
-
* @param options - Lookup options
|
|
689
|
-
* @returns Array of matching skills
|
|
690
|
-
*/
|
|
691
|
-
lookup(options = {}) {
|
|
692
|
-
let results = Array.from(this.skills.values());
|
|
693
|
-
if (options.enabled !== void 0) {
|
|
694
|
-
results = results.filter((e) => e.enabled === options.enabled);
|
|
695
|
-
}
|
|
696
|
-
if (options.category) {
|
|
697
|
-
results = results.filter((e) => e.metadata.category === options.category);
|
|
698
|
-
}
|
|
699
|
-
if (options.source) {
|
|
700
|
-
results = results.filter((e) => e.source === options.source);
|
|
701
|
-
}
|
|
702
|
-
if (options.userInvocable !== void 0) {
|
|
703
|
-
results = results.filter(
|
|
704
|
-
(e) => (e.metadata.user_invocable ?? true) === options.userInvocable
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
if (options.autoActivate !== void 0) {
|
|
708
|
-
results = results.filter(
|
|
709
|
-
(e) => (e.metadata.auto_activate ?? false) === options.autoActivate
|
|
710
|
-
);
|
|
711
|
-
}
|
|
712
|
-
if (options.agent) {
|
|
713
|
-
results = results.filter(
|
|
714
|
-
(e) => e.metadata.agent === options.agent || e.metadata.agents?.includes(options.agent)
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
if (options.search) {
|
|
718
|
-
const query = options.search.toLowerCase();
|
|
719
|
-
results = results.filter(
|
|
720
|
-
(e) => e.id.toLowerCase().includes(query) || e.metadata.description.toLowerCase().includes(query) || e.metadata.tags?.some((t) => t.toLowerCase().includes(query))
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
if (options.sortBy) {
|
|
724
|
-
const dir = options.sortDir === "desc" ? -1 : 1;
|
|
725
|
-
results.sort((a, b) => {
|
|
726
|
-
switch (options.sortBy) {
|
|
727
|
-
case "name":
|
|
728
|
-
return a.id.localeCompare(b.id) * dir;
|
|
729
|
-
case "priority":
|
|
730
|
-
return ((a.metadata.priority ?? 5) - (b.metadata.priority ?? 5)) * dir;
|
|
731
|
-
case "registeredAt":
|
|
732
|
-
return (a.registeredAt - b.registeredAt) * dir;
|
|
733
|
-
case "modifiedAt":
|
|
734
|
-
return (a.modifiedAt - b.modifiedAt) * dir;
|
|
735
|
-
default:
|
|
736
|
-
return 0;
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
if (options.limit) {
|
|
741
|
-
results = results.slice(0, options.limit);
|
|
742
|
-
}
|
|
743
|
-
return results;
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Enable a skill
|
|
747
|
-
*
|
|
748
|
-
* @param id - Skill ID
|
|
749
|
-
* @returns True if enabled
|
|
750
|
-
*/
|
|
751
|
-
enable(id) {
|
|
752
|
-
const entry = this.skills.get(id);
|
|
753
|
-
if (!entry || entry.enabled)
|
|
754
|
-
return false;
|
|
755
|
-
entry.enabled = true;
|
|
756
|
-
this.emit("skill:enabled", entry);
|
|
757
|
-
this.publishMessage("skill:enabled", entry);
|
|
758
|
-
return true;
|
|
759
|
-
}
|
|
760
|
-
/**
|
|
761
|
-
* Disable a skill
|
|
762
|
-
*
|
|
763
|
-
* @param id - Skill ID
|
|
764
|
-
* @returns True if disabled
|
|
765
|
-
*/
|
|
766
|
-
disable(id) {
|
|
767
|
-
const entry = this.skills.get(id);
|
|
768
|
-
if (!entry || !entry.enabled)
|
|
769
|
-
return false;
|
|
770
|
-
entry.enabled = false;
|
|
771
|
-
this.emit("skill:disabled", entry);
|
|
772
|
-
this.publishMessage("skill:disabled", entry);
|
|
773
|
-
return true;
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Toggle skill enabled state
|
|
777
|
-
*
|
|
778
|
-
* @param id - Skill ID
|
|
779
|
-
* @returns New enabled state
|
|
780
|
-
*/
|
|
781
|
-
toggle(id) {
|
|
782
|
-
const entry = this.skills.get(id);
|
|
783
|
-
if (!entry)
|
|
784
|
-
return false;
|
|
785
|
-
entry.enabled = !entry.enabled;
|
|
786
|
-
const event = entry.enabled ? "skill:enabled" : "skill:disabled";
|
|
787
|
-
this.emit(event, entry);
|
|
788
|
-
this.publishMessage(event, entry);
|
|
789
|
-
return entry.enabled;
|
|
790
|
-
}
|
|
791
|
-
/**
|
|
792
|
-
* Check if a skill exists
|
|
793
|
-
*
|
|
794
|
-
* @param id - Skill ID
|
|
795
|
-
* @returns True if skill exists
|
|
796
|
-
*/
|
|
797
|
-
has(id) {
|
|
798
|
-
return this.skills.has(id);
|
|
799
|
-
}
|
|
800
|
-
/**
|
|
801
|
-
* Check if a skill is enabled
|
|
802
|
-
*
|
|
803
|
-
* @param id - Skill ID
|
|
804
|
-
* @returns True if enabled, false if disabled or not found
|
|
805
|
-
*/
|
|
806
|
-
isEnabled(id) {
|
|
807
|
-
return this.skills.get(id)?.enabled ?? false;
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Get all skill IDs
|
|
811
|
-
*
|
|
812
|
-
* @returns Array of skill IDs
|
|
813
|
-
*/
|
|
814
|
-
getIds() {
|
|
815
|
-
return Array.from(this.skills.keys());
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Get all entries
|
|
819
|
-
*
|
|
820
|
-
* @returns Array of all entries
|
|
821
|
-
*/
|
|
822
|
-
getAll() {
|
|
823
|
-
return Array.from(this.skills.values());
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
* Get enabled entries
|
|
827
|
-
*
|
|
828
|
-
* @returns Array of enabled entries
|
|
829
|
-
*/
|
|
830
|
-
getEnabled() {
|
|
831
|
-
return this.lookup({ enabled: true });
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Get registry statistics
|
|
835
|
-
*
|
|
836
|
-
* @returns Registry statistics
|
|
837
|
-
*/
|
|
838
|
-
getStats() {
|
|
839
|
-
const all = this.getAll();
|
|
840
|
-
const enabled = this.getEnabled();
|
|
841
|
-
const byCategory = {
|
|
842
|
-
dev: 0,
|
|
843
|
-
git: 0,
|
|
844
|
-
review: 0,
|
|
845
|
-
testing: 0,
|
|
846
|
-
docs: 0,
|
|
847
|
-
devops: 0,
|
|
848
|
-
planning: 0,
|
|
849
|
-
debugging: 0,
|
|
850
|
-
custom: 0
|
|
851
|
-
};
|
|
852
|
-
const bySource = { builtin: 0, user: 0, marketplace: 0 };
|
|
853
|
-
let totalTokens = 0;
|
|
854
|
-
let lastRegistered = 0;
|
|
855
|
-
let lastModified = 0;
|
|
856
|
-
for (const entry of all) {
|
|
857
|
-
byCategory[entry.metadata.category]++;
|
|
858
|
-
bySource[entry.source]++;
|
|
859
|
-
totalTokens += entry.estimatedTokens;
|
|
860
|
-
if (entry.registeredAt > lastRegistered)
|
|
861
|
-
lastRegistered = entry.registeredAt;
|
|
862
|
-
if (entry.modifiedAt > lastModified)
|
|
863
|
-
lastModified = entry.modifiedAt;
|
|
864
|
-
}
|
|
865
|
-
return {
|
|
866
|
-
totalSkills: all.length,
|
|
867
|
-
enabledSkills: enabled.length,
|
|
868
|
-
disabledSkills: all.length - enabled.length,
|
|
869
|
-
byCategory,
|
|
870
|
-
bySource,
|
|
871
|
-
totalTokens,
|
|
872
|
-
lastRegistered: lastRegistered > 0 ? this.getById(this.getEntriesSortedBy("registeredAt")[0]?.id || "")?.id : void 0,
|
|
873
|
-
lastModified: lastModified > 0 ? this.getById(this.getEntriesSortedBy("modifiedAt")[0]?.id || "")?.id : void 0
|
|
874
|
-
};
|
|
875
|
-
}
|
|
876
|
-
/**
|
|
877
|
-
* Get dependent skills
|
|
878
|
-
*
|
|
879
|
-
* @param id - Skill ID
|
|
880
|
-
* @returns Array of dependent skill IDs
|
|
881
|
-
*/
|
|
882
|
-
getDependents(id) {
|
|
883
|
-
return Array.from(this.skills.get(id)?.dependents || []);
|
|
884
|
-
}
|
|
885
|
-
/**
|
|
886
|
-
* Get skill dependencies
|
|
887
|
-
*
|
|
888
|
-
* @param id - Skill ID
|
|
889
|
-
* @returns Array of dependency IDs
|
|
890
|
-
*/
|
|
891
|
-
getDependencies(id) {
|
|
892
|
-
return this.skills.get(id)?.dependencies || [];
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Check for missing dependencies
|
|
896
|
-
*
|
|
897
|
-
* @param id - Skill ID
|
|
898
|
-
* @returns Array of missing dependency IDs
|
|
899
|
-
*/
|
|
900
|
-
getMissingDependencies(id) {
|
|
901
|
-
const deps = this.getDependencies(id);
|
|
902
|
-
return deps.filter((dep) => !this.has(dep));
|
|
903
|
-
}
|
|
904
|
-
/**
|
|
905
|
-
* Validate all dependencies
|
|
906
|
-
*
|
|
907
|
-
* @returns Map of skill ID to missing dependencies
|
|
908
|
-
*/
|
|
909
|
-
validateDependencies() {
|
|
910
|
-
const missing = /* @__PURE__ */ new Map();
|
|
911
|
-
Array.from(this.skills.entries()).forEach(([id, entry]) => {
|
|
912
|
-
const missingDeps = entry.dependencies.filter((dep) => !this.has(dep));
|
|
913
|
-
if (missingDeps.length > 0) {
|
|
914
|
-
missing.set(id, missingDeps);
|
|
915
|
-
}
|
|
916
|
-
});
|
|
917
|
-
return missing;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Clear all skills from registry
|
|
921
|
-
*/
|
|
922
|
-
clear() {
|
|
923
|
-
this.skills.clear();
|
|
924
|
-
this.filePathIndex.clear();
|
|
925
|
-
this.triggerIndex.clear();
|
|
926
|
-
this.emit("registry:cleared");
|
|
927
|
-
this.publishMessage("registry:cleared", {});
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Get the size of the registry
|
|
931
|
-
*
|
|
932
|
-
* @returns Number of registered skills
|
|
933
|
-
*/
|
|
934
|
-
size() {
|
|
935
|
-
return this.skills.size;
|
|
936
|
-
}
|
|
937
|
-
// ==========================================================================
|
|
938
|
-
// Private Methods
|
|
939
|
-
// ==========================================================================
|
|
940
|
-
/**
|
|
941
|
-
* Extract dependencies from skill metadata
|
|
942
|
-
*/
|
|
943
|
-
extractDependencies(metadata) {
|
|
944
|
-
const deps = [];
|
|
945
|
-
if (metadata.agents) {
|
|
946
|
-
deps.push(...metadata.agents);
|
|
947
|
-
}
|
|
948
|
-
if (metadata.related_skills) {
|
|
949
|
-
deps.push(...metadata.related_skills);
|
|
950
|
-
}
|
|
951
|
-
return deps;
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* Update trigger index
|
|
955
|
-
*/
|
|
956
|
-
updateTriggerIndex(id, triggers) {
|
|
957
|
-
Array.from(this.triggerIndex.entries()).forEach(([trigger, skillIds]) => {
|
|
958
|
-
skillIds.delete(id);
|
|
959
|
-
if (skillIds.size === 0)
|
|
960
|
-
this.triggerIndex.delete(trigger);
|
|
961
|
-
});
|
|
962
|
-
for (const trigger of triggers) {
|
|
963
|
-
if (!this.triggerIndex.has(trigger)) {
|
|
964
|
-
this.triggerIndex.set(trigger, /* @__PURE__ */ new Set());
|
|
965
|
-
}
|
|
966
|
-
this.triggerIndex.get(trigger).add(id);
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Update dependency graph
|
|
971
|
-
*/
|
|
972
|
-
updateDependencyGraph(id, dependencies) {
|
|
973
|
-
Array.from(this.skills.entries()).forEach(([_depId, entry]) => {
|
|
974
|
-
if (entry.dependencies.includes(id)) {
|
|
975
|
-
entry.dependents.delete(id);
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
for (const dep of dependencies) {
|
|
979
|
-
const depEntry = this.skills.get(dep);
|
|
980
|
-
if (depEntry) {
|
|
981
|
-
depEntry.dependents.add(id);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
/**
|
|
986
|
-
* Estimate token count for a skill
|
|
987
|
-
*/
|
|
988
|
-
estimateTokens(skill) {
|
|
989
|
-
const contentTokens = Math.ceil(skill.content.length / 4);
|
|
990
|
-
const metadataTokens = Math.ceil(JSON.stringify(skill.metadata).length / 4);
|
|
991
|
-
return contentTokens + metadataTokens;
|
|
992
|
-
}
|
|
993
|
-
/**
|
|
994
|
-
* Get entries sorted by a field
|
|
995
|
-
*/
|
|
996
|
-
getEntriesSortedBy(field) {
|
|
997
|
-
return Array.from(this.skills.values()).sort((a, b) => b[field] - a[field]);
|
|
998
|
-
}
|
|
999
|
-
/**
|
|
1000
|
-
* Publish message to event bus
|
|
1001
|
-
*/
|
|
1002
|
-
publishMessage(type, payload) {
|
|
1003
|
-
this.messageBus.publish(
|
|
1004
|
-
type,
|
|
1005
|
-
"coordinator",
|
|
1006
|
-
"all",
|
|
1007
|
-
`Skill registry event: ${type}`,
|
|
1008
|
-
payload,
|
|
1009
|
-
{ priority: "normal" }
|
|
1010
|
-
).catch(console.error);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
let registryInstance = null;
|
|
1014
|
-
function getSkillRegistry() {
|
|
1015
|
-
if (!registryInstance) {
|
|
1016
|
-
registryInstance = new SkillRegistry();
|
|
1017
|
-
}
|
|
1018
|
-
return registryInstance;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
class ProgressTracker extends EventEmitter {
|
|
1022
|
-
config;
|
|
1023
|
-
convoyManager;
|
|
1024
|
-
trackedConvoys = /* @__PURE__ */ new Map();
|
|
1025
|
-
taskStartTimes = /* @__PURE__ */ new Map();
|
|
1026
|
-
taskDurations = /* @__PURE__ */ new Map();
|
|
1027
|
-
constructor(convoyManager, config = {}) {
|
|
1028
|
-
super();
|
|
1029
|
-
this.convoyManager = convoyManager;
|
|
1030
|
-
this.config = {
|
|
1031
|
-
updateInterval: config.updateInterval ?? 1e3,
|
|
1032
|
-
consoleOutput: config.consoleOutput ?? false,
|
|
1033
|
-
progressBarWidth: config.progressBarWidth ?? 40
|
|
1034
|
-
};
|
|
1035
|
-
this.setupEventListeners();
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
|
-
* Start tracking a convoy
|
|
1039
|
-
*/
|
|
1040
|
-
track(convoyId) {
|
|
1041
|
-
if (this.trackedConvoys.has(convoyId)) {
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
const interval = setInterval(() => {
|
|
1045
|
-
this.emitProgress(convoyId);
|
|
1046
|
-
}, this.config.updateInterval);
|
|
1047
|
-
this.trackedConvoys.set(convoyId, interval);
|
|
1048
|
-
this.taskDurations.set(convoyId, []);
|
|
1049
|
-
this.emitProgress(convoyId);
|
|
1050
|
-
}
|
|
1051
|
-
/**
|
|
1052
|
-
* Stop tracking a convoy
|
|
1053
|
-
*/
|
|
1054
|
-
untrack(convoyId) {
|
|
1055
|
-
const interval = this.trackedConvoys.get(convoyId);
|
|
1056
|
-
if (interval) {
|
|
1057
|
-
clearInterval(interval);
|
|
1058
|
-
this.trackedConvoys.delete(convoyId);
|
|
1059
|
-
}
|
|
1060
|
-
this.taskDurations.delete(convoyId);
|
|
1061
|
-
}
|
|
1062
|
-
/**
|
|
1063
|
-
* Get current progress for a convoy
|
|
1064
|
-
*/
|
|
1065
|
-
getProgress(convoyId) {
|
|
1066
|
-
const convoy = this.convoyManager.get(convoyId);
|
|
1067
|
-
if (!convoy)
|
|
1068
|
-
return null;
|
|
1069
|
-
return this.buildProgressUpdate(convoy);
|
|
1070
|
-
}
|
|
1071
|
-
/**
|
|
1072
|
-
* Get progress bar string
|
|
1073
|
-
*/
|
|
1074
|
-
getProgressBar(convoyId) {
|
|
1075
|
-
const convoy = this.convoyManager.get(convoyId);
|
|
1076
|
-
if (!convoy)
|
|
1077
|
-
return "";
|
|
1078
|
-
return this.buildProgressBar(convoy.progress);
|
|
1079
|
-
}
|
|
1080
|
-
/**
|
|
1081
|
-
* Get formatted progress string
|
|
1082
|
-
*/
|
|
1083
|
-
getFormattedProgress(convoyId) {
|
|
1084
|
-
const update = this.getProgress(convoyId);
|
|
1085
|
-
if (!update)
|
|
1086
|
-
return "Convoy not found";
|
|
1087
|
-
const lines = [
|
|
1088
|
-
`${update.convoyName} [${update.convoyId}]`,
|
|
1089
|
-
this.buildProgressBar(update.progress),
|
|
1090
|
-
`Status: ${this.formatStatus(update.status)}`,
|
|
1091
|
-
`Progress: ${update.progress}% (${update.completedTasks}/${update.totalTasks})`
|
|
1092
|
-
];
|
|
1093
|
-
if (update.inProgressTasks > 0) {
|
|
1094
|
-
lines.push(`In Progress: ${update.inProgressTasks}`);
|
|
1095
|
-
}
|
|
1096
|
-
if (update.failedTasks > 0) {
|
|
1097
|
-
lines.push(`Failed: ${update.failedTasks}`);
|
|
1098
|
-
}
|
|
1099
|
-
if (update.currentTasks.length > 0) {
|
|
1100
|
-
lines.push("\nCurrent Tasks:");
|
|
1101
|
-
for (const task of update.currentTasks) {
|
|
1102
|
-
lines.push(` - ${task.title} (${task.assignedTo ?? "unassigned"})`);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
if (update.estimatedCompletion) {
|
|
1106
|
-
lines.push(`
|
|
1107
|
-
ETA: ${this.formatTime(update.estimatedCompletion.getTime() - Date.now())}`);
|
|
1108
|
-
}
|
|
1109
|
-
lines.push(`Elapsed: ${this.formatTime(update.elapsedTime)}`);
|
|
1110
|
-
return lines.join("\n");
|
|
1111
|
-
}
|
|
1112
|
-
/**
|
|
1113
|
-
* Stop all tracking
|
|
1114
|
-
*/
|
|
1115
|
-
stopAll() {
|
|
1116
|
-
const convoyIds = Array.from(this.trackedConvoys.keys());
|
|
1117
|
-
for (const convoyId of convoyIds) {
|
|
1118
|
-
this.untrack(convoyId);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
* Destroy tracker
|
|
1123
|
-
*/
|
|
1124
|
-
destroy() {
|
|
1125
|
-
this.stopAll();
|
|
1126
|
-
this.removeAllListeners();
|
|
1127
|
-
}
|
|
1128
|
-
// ========================================================================
|
|
1129
|
-
// Private Methods
|
|
1130
|
-
// ========================================================================
|
|
1131
|
-
setupEventListeners() {
|
|
1132
|
-
this.convoyManager.on("task:started", (convoy, task) => {
|
|
1133
|
-
this.taskStartTimes.set(task.id, Date.now());
|
|
1134
|
-
});
|
|
1135
|
-
this.convoyManager.on("task:completed", (convoy, task) => {
|
|
1136
|
-
const startTime = this.taskStartTimes.get(task.id);
|
|
1137
|
-
if (startTime) {
|
|
1138
|
-
const duration = Date.now() - startTime;
|
|
1139
|
-
const durations = this.taskDurations.get(convoy.id) ?? [];
|
|
1140
|
-
durations.push(duration);
|
|
1141
|
-
this.taskDurations.set(convoy.id, durations);
|
|
1142
|
-
this.taskStartTimes.delete(task.id);
|
|
1143
|
-
}
|
|
1144
|
-
});
|
|
1145
|
-
this.convoyManager.on("convoy:completed", (convoy) => {
|
|
1146
|
-
this.untrack(convoy.id);
|
|
1147
|
-
});
|
|
1148
|
-
this.convoyManager.on("convoy:failed", (convoy) => {
|
|
1149
|
-
this.untrack(convoy.id);
|
|
1150
|
-
});
|
|
1151
|
-
this.convoyManager.on("convoy:cancelled", (convoy) => {
|
|
1152
|
-
this.untrack(convoy.id);
|
|
1153
|
-
});
|
|
1154
|
-
}
|
|
1155
|
-
emitProgress(convoyId) {
|
|
1156
|
-
const update = this.getProgress(convoyId);
|
|
1157
|
-
if (update) {
|
|
1158
|
-
this.emit("progress", update);
|
|
1159
|
-
if (this.config.consoleOutput) {
|
|
1160
|
-
console.log(this.getFormattedProgress(convoyId));
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
buildProgressUpdate(convoy) {
|
|
1165
|
-
const inProgressTasks = convoy.tasks.filter((t) => t.status === "in_progress").length;
|
|
1166
|
-
const pendingTasks = convoy.tasks.filter((t) => t.status === "pending").length;
|
|
1167
|
-
const currentTasks = convoy.tasks.filter((t) => t.status === "in_progress");
|
|
1168
|
-
const durations = this.taskDurations.get(convoy.id) ?? [];
|
|
1169
|
-
const averageTaskTime = durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0;
|
|
1170
|
-
const elapsedTime = convoy.startedAt ? Date.now() - new Date(convoy.startedAt).getTime() : 0;
|
|
1171
|
-
let estimatedCompletion;
|
|
1172
|
-
if (averageTaskTime > 0 && pendingTasks > 0) {
|
|
1173
|
-
const remainingTime = (pendingTasks + inProgressTasks) * averageTaskTime;
|
|
1174
|
-
estimatedCompletion = new Date(Date.now() + remainingTime);
|
|
1175
|
-
}
|
|
1176
|
-
return {
|
|
1177
|
-
convoyId: convoy.id,
|
|
1178
|
-
convoyName: convoy.name,
|
|
1179
|
-
progress: convoy.progress,
|
|
1180
|
-
status: convoy.status,
|
|
1181
|
-
totalTasks: convoy.totalTasks,
|
|
1182
|
-
completedTasks: convoy.completedTasks,
|
|
1183
|
-
failedTasks: convoy.failedTasks,
|
|
1184
|
-
inProgressTasks,
|
|
1185
|
-
pendingTasks,
|
|
1186
|
-
currentTasks,
|
|
1187
|
-
estimatedCompletion,
|
|
1188
|
-
elapsedTime,
|
|
1189
|
-
averageTaskTime
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
|
-
buildProgressBar(progress) {
|
|
1193
|
-
const width = this.config.progressBarWidth;
|
|
1194
|
-
const filled = Math.round(progress / 100 * width);
|
|
1195
|
-
const empty = width - filled;
|
|
1196
|
-
const filledChar = "\u2588";
|
|
1197
|
-
const emptyChar = "\u2591";
|
|
1198
|
-
return `[${filledChar.repeat(filled)}${emptyChar.repeat(empty)}] ${progress}%`;
|
|
1199
|
-
}
|
|
1200
|
-
formatStatus(status) {
|
|
1201
|
-
const statusMap = {
|
|
1202
|
-
pending: "\u23F3 Pending",
|
|
1203
|
-
in_progress: "\u{1F504} In Progress",
|
|
1204
|
-
completed: "\u2705 Completed",
|
|
1205
|
-
failed: "\u274C Failed",
|
|
1206
|
-
cancelled: "\u{1F6AB} Cancelled",
|
|
1207
|
-
paused: "\u23F8\uFE0F Paused"
|
|
1208
|
-
};
|
|
1209
|
-
return statusMap[status] ?? status;
|
|
1210
|
-
}
|
|
1211
|
-
formatTime(ms) {
|
|
1212
|
-
if (ms < 0)
|
|
1213
|
-
return "0s";
|
|
1214
|
-
const seconds = Math.floor(ms / 1e3);
|
|
1215
|
-
const minutes = Math.floor(seconds / 60);
|
|
1216
|
-
const hours = Math.floor(minutes / 60);
|
|
1217
|
-
if (hours > 0) {
|
|
1218
|
-
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
1219
|
-
}
|
|
1220
|
-
if (minutes > 0) {
|
|
1221
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
1222
|
-
}
|
|
1223
|
-
return `${seconds}s`;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
class PersistentMailboxManager extends EventEmitter {
|
|
1228
|
-
stateManager;
|
|
1229
|
-
mailboxes = /* @__PURE__ */ new Map();
|
|
1230
|
-
expirationCheckInterval = null;
|
|
1231
|
-
initialized = false;
|
|
1232
|
-
constructor(stateManager) {
|
|
1233
|
-
super();
|
|
1234
|
-
this.stateManager = stateManager ?? getGlobalStateManager();
|
|
1235
|
-
this.expirationCheckInterval = setInterval(() => {
|
|
1236
|
-
this.checkExpiredMessages();
|
|
1237
|
-
}, 6e4);
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* Initialize mailbox manager
|
|
1241
|
-
*/
|
|
1242
|
-
async initialize() {
|
|
1243
|
-
if (this.initialized)
|
|
1244
|
-
return;
|
|
1245
|
-
await this.stateManager.initialize();
|
|
1246
|
-
for (const agentId of this.stateManager.getAgentIds()) {
|
|
1247
|
-
await this.loadMailbox(agentId);
|
|
1248
|
-
}
|
|
1249
|
-
this.initialized = true;
|
|
1250
|
-
}
|
|
1251
|
-
/**
|
|
1252
|
-
* Create mailbox for agent
|
|
1253
|
-
*/
|
|
1254
|
-
async createMailbox(agentId) {
|
|
1255
|
-
await this.ensureInitialized();
|
|
1256
|
-
if (this.mailboxes.has(agentId)) {
|
|
1257
|
-
return this.mailboxes.get(agentId);
|
|
1258
|
-
}
|
|
1259
|
-
const mailbox = {
|
|
1260
|
-
agentId,
|
|
1261
|
-
inbox: [],
|
|
1262
|
-
outbox: [],
|
|
1263
|
-
archive: [],
|
|
1264
|
-
updatedAt: Date.now()
|
|
1265
|
-
};
|
|
1266
|
-
this.mailboxes.set(agentId, mailbox);
|
|
1267
|
-
await this.persistMailbox(agentId);
|
|
1268
|
-
this.emit("mailbox:created", agentId);
|
|
1269
|
-
return mailbox;
|
|
1270
|
-
}
|
|
1271
|
-
/**
|
|
1272
|
-
* Get mailbox for agent
|
|
1273
|
-
*/
|
|
1274
|
-
async getMailbox(agentId) {
|
|
1275
|
-
await this.ensureInitialized();
|
|
1276
|
-
if (!this.mailboxes.has(agentId)) {
|
|
1277
|
-
return this.createMailbox(agentId);
|
|
1278
|
-
}
|
|
1279
|
-
return this.mailboxes.get(agentId);
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Send message to agent
|
|
1283
|
-
*/
|
|
1284
|
-
async send(from, to, subject, body, options = {}) {
|
|
1285
|
-
await this.ensureInitialized();
|
|
1286
|
-
const message = {
|
|
1287
|
-
id: nanoid(),
|
|
1288
|
-
from,
|
|
1289
|
-
to,
|
|
1290
|
-
subject,
|
|
1291
|
-
body,
|
|
1292
|
-
priority: options.priority ?? "normal",
|
|
1293
|
-
timestamp: Date.now(),
|
|
1294
|
-
read: false,
|
|
1295
|
-
archived: false,
|
|
1296
|
-
correlationId: options.correlationId,
|
|
1297
|
-
replyTo: options.replyTo,
|
|
1298
|
-
expiresAt: options.expiresIn ? Date.now() + options.expiresIn : void 0,
|
|
1299
|
-
metadata: options.metadata
|
|
1300
|
-
};
|
|
1301
|
-
const senderMailbox = await this.getMailbox(from);
|
|
1302
|
-
senderMailbox.outbox.push(message);
|
|
1303
|
-
senderMailbox.updatedAt = Date.now();
|
|
1304
|
-
await this.persistMailbox(from);
|
|
1305
|
-
const recipientMailbox = await this.getMailbox(to);
|
|
1306
|
-
recipientMailbox.inbox.push(message);
|
|
1307
|
-
recipientMailbox.updatedAt = Date.now();
|
|
1308
|
-
await this.persistMailbox(to);
|
|
1309
|
-
this.emit("message:sent", message);
|
|
1310
|
-
this.emit("message:received", message);
|
|
1311
|
-
return message;
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* Reply to a message
|
|
1315
|
-
*/
|
|
1316
|
-
async reply(originalMessage, from, body, options = {}) {
|
|
1317
|
-
return this.send(
|
|
1318
|
-
from,
|
|
1319
|
-
originalMessage.replyTo ?? originalMessage.from,
|
|
1320
|
-
`Re: ${originalMessage.subject}`,
|
|
1321
|
-
body,
|
|
1322
|
-
{
|
|
1323
|
-
...options,
|
|
1324
|
-
correlationId: originalMessage.id
|
|
1325
|
-
}
|
|
1326
|
-
);
|
|
1327
|
-
}
|
|
1328
|
-
/**
|
|
1329
|
-
* Broadcast message to multiple agents
|
|
1330
|
-
*/
|
|
1331
|
-
async broadcast(from, toAgents, subject, body, options = {}) {
|
|
1332
|
-
const messages = [];
|
|
1333
|
-
for (const to of toAgents) {
|
|
1334
|
-
const message = await this.send(from, to, subject, body, options);
|
|
1335
|
-
messages.push(message);
|
|
1336
|
-
}
|
|
1337
|
-
return messages;
|
|
1338
|
-
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Check inbox for unread messages
|
|
1341
|
-
*/
|
|
1342
|
-
async checkInbox(agentId) {
|
|
1343
|
-
await this.ensureInitialized();
|
|
1344
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1345
|
-
return mailbox.inbox.filter((m) => !m.read && !m.archived);
|
|
1346
|
-
}
|
|
1347
|
-
/**
|
|
1348
|
-
* Get unread message count
|
|
1349
|
-
*/
|
|
1350
|
-
async getUnreadCount(agentId) {
|
|
1351
|
-
const unread = await this.checkInbox(agentId);
|
|
1352
|
-
return unread.length;
|
|
1353
|
-
}
|
|
1354
|
-
/**
|
|
1355
|
-
* Get messages by priority
|
|
1356
|
-
*/
|
|
1357
|
-
async getByPriority(agentId, priority) {
|
|
1358
|
-
await this.ensureInitialized();
|
|
1359
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1360
|
-
return mailbox.inbox.filter((m) => m.priority === priority && !m.archived);
|
|
1361
|
-
}
|
|
1362
|
-
/**
|
|
1363
|
-
* Get messages by correlation ID
|
|
1364
|
-
*/
|
|
1365
|
-
async getByCorrelationId(agentId, correlationId) {
|
|
1366
|
-
await this.ensureInitialized();
|
|
1367
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1368
|
-
return [
|
|
1369
|
-
...mailbox.inbox.filter((m) => m.correlationId === correlationId),
|
|
1370
|
-
...mailbox.outbox.filter((m) => m.correlationId === correlationId)
|
|
1371
|
-
];
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Mark message as read
|
|
1375
|
-
*/
|
|
1376
|
-
async markAsRead(agentId, messageId) {
|
|
1377
|
-
await this.ensureInitialized();
|
|
1378
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1379
|
-
const message = mailbox.inbox.find((m) => m.id === messageId);
|
|
1380
|
-
if (message && !message.read) {
|
|
1381
|
-
message.read = true;
|
|
1382
|
-
mailbox.updatedAt = Date.now();
|
|
1383
|
-
await this.persistMailbox(agentId);
|
|
1384
|
-
this.emit("message:read", messageId, agentId);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
/**
|
|
1388
|
-
* Mark all messages as read
|
|
1389
|
-
*/
|
|
1390
|
-
async markAllAsRead(agentId) {
|
|
1391
|
-
await this.ensureInitialized();
|
|
1392
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1393
|
-
let count = 0;
|
|
1394
|
-
for (const message of mailbox.inbox) {
|
|
1395
|
-
if (!message.read) {
|
|
1396
|
-
message.read = true;
|
|
1397
|
-
count++;
|
|
1398
|
-
this.emit("message:read", message.id, agentId);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
if (count > 0) {
|
|
1402
|
-
mailbox.updatedAt = Date.now();
|
|
1403
|
-
await this.persistMailbox(agentId);
|
|
1404
|
-
}
|
|
1405
|
-
return count;
|
|
1406
|
-
}
|
|
1407
|
-
/**
|
|
1408
|
-
* Archive message
|
|
1409
|
-
*/
|
|
1410
|
-
async archive(agentId, messageId) {
|
|
1411
|
-
await this.ensureInitialized();
|
|
1412
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1413
|
-
const inboxIndex = mailbox.inbox.findIndex((m) => m.id === messageId);
|
|
1414
|
-
if (inboxIndex !== -1) {
|
|
1415
|
-
const [message] = mailbox.inbox.splice(inboxIndex, 1);
|
|
1416
|
-
message.archived = true;
|
|
1417
|
-
mailbox.archive.push(message);
|
|
1418
|
-
mailbox.updatedAt = Date.now();
|
|
1419
|
-
await this.persistMailbox(agentId);
|
|
1420
|
-
this.emit("message:archived", messageId, agentId);
|
|
1421
|
-
return;
|
|
1422
|
-
}
|
|
1423
|
-
const outboxIndex = mailbox.outbox.findIndex((m) => m.id === messageId);
|
|
1424
|
-
if (outboxIndex !== -1) {
|
|
1425
|
-
const [message] = mailbox.outbox.splice(outboxIndex, 1);
|
|
1426
|
-
message.archived = true;
|
|
1427
|
-
mailbox.archive.push(message);
|
|
1428
|
-
mailbox.updatedAt = Date.now();
|
|
1429
|
-
await this.persistMailbox(agentId);
|
|
1430
|
-
this.emit("message:archived", messageId, agentId);
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
/**
|
|
1434
|
-
* Delete message permanently
|
|
1435
|
-
*/
|
|
1436
|
-
async delete(agentId, messageId) {
|
|
1437
|
-
await this.ensureInitialized();
|
|
1438
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1439
|
-
let deleted = false;
|
|
1440
|
-
for (const arr of [mailbox.inbox, mailbox.outbox, mailbox.archive]) {
|
|
1441
|
-
const index = arr.findIndex((m) => m.id === messageId);
|
|
1442
|
-
if (index !== -1) {
|
|
1443
|
-
arr.splice(index, 1);
|
|
1444
|
-
deleted = true;
|
|
1445
|
-
break;
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
if (deleted) {
|
|
1449
|
-
mailbox.updatedAt = Date.now();
|
|
1450
|
-
await this.persistMailbox(agentId);
|
|
1451
|
-
}
|
|
1452
|
-
return deleted;
|
|
1453
|
-
}
|
|
1454
|
-
/**
|
|
1455
|
-
* Search messages
|
|
1456
|
-
*/
|
|
1457
|
-
async search(agentId, query) {
|
|
1458
|
-
await this.ensureInitialized();
|
|
1459
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1460
|
-
const allMessages = [...mailbox.inbox, ...mailbox.outbox, ...mailbox.archive];
|
|
1461
|
-
return allMessages.filter((m) => {
|
|
1462
|
-
if (query.subject && !m.subject.toLowerCase().includes(query.subject.toLowerCase())) {
|
|
1463
|
-
return false;
|
|
1464
|
-
}
|
|
1465
|
-
if (query.from && m.from !== query.from) {
|
|
1466
|
-
return false;
|
|
1467
|
-
}
|
|
1468
|
-
if (query.to && m.to !== query.to) {
|
|
1469
|
-
return false;
|
|
1470
|
-
}
|
|
1471
|
-
if (query.read !== void 0 && m.read !== query.read) {
|
|
1472
|
-
return false;
|
|
1473
|
-
}
|
|
1474
|
-
if (query.priority && m.priority !== query.priority) {
|
|
1475
|
-
return false;
|
|
1476
|
-
}
|
|
1477
|
-
if (query.after && m.timestamp < query.after) {
|
|
1478
|
-
return false;
|
|
1479
|
-
}
|
|
1480
|
-
if (query.before && m.timestamp > query.before) {
|
|
1481
|
-
return false;
|
|
1482
|
-
}
|
|
1483
|
-
return true;
|
|
1484
|
-
});
|
|
1485
|
-
}
|
|
1486
|
-
/**
|
|
1487
|
-
* Get mailbox statistics
|
|
1488
|
-
*/
|
|
1489
|
-
async getStats(agentId) {
|
|
1490
|
-
await this.ensureInitialized();
|
|
1491
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1492
|
-
const unread = mailbox.inbox.filter((m) => !m.read);
|
|
1493
|
-
return {
|
|
1494
|
-
inboxCount: mailbox.inbox.length,
|
|
1495
|
-
outboxCount: mailbox.outbox.length,
|
|
1496
|
-
archiveCount: mailbox.archive.length,
|
|
1497
|
-
unreadCount: unread.length,
|
|
1498
|
-
oldestUnread: unread.length > 0 ? Math.min(...unread.map((m) => m.timestamp)) : null
|
|
1499
|
-
};
|
|
1500
|
-
}
|
|
1501
|
-
/**
|
|
1502
|
-
* Cleanup old archived messages
|
|
1503
|
-
*/
|
|
1504
|
-
async cleanupArchive(agentId, olderThanMs) {
|
|
1505
|
-
await this.ensureInitialized();
|
|
1506
|
-
const mailbox = await this.getMailbox(agentId);
|
|
1507
|
-
const cutoff = Date.now() - olderThanMs;
|
|
1508
|
-
const originalLength = mailbox.archive.length;
|
|
1509
|
-
mailbox.archive = mailbox.archive.filter((m) => m.timestamp > cutoff);
|
|
1510
|
-
const removed = originalLength - mailbox.archive.length;
|
|
1511
|
-
if (removed > 0) {
|
|
1512
|
-
mailbox.updatedAt = Date.now();
|
|
1513
|
-
await this.persistMailbox(agentId);
|
|
1514
|
-
}
|
|
1515
|
-
return removed;
|
|
1516
|
-
}
|
|
1517
|
-
/**
|
|
1518
|
-
* Destroy mailbox manager
|
|
1519
|
-
*/
|
|
1520
|
-
destroy() {
|
|
1521
|
-
if (this.expirationCheckInterval) {
|
|
1522
|
-
clearInterval(this.expirationCheckInterval);
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
// ========================================================================
|
|
1526
|
-
// Private Methods
|
|
1527
|
-
// ========================================================================
|
|
1528
|
-
async ensureInitialized() {
|
|
1529
|
-
if (!this.initialized) {
|
|
1530
|
-
await this.initialize();
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
async loadMailbox(agentId) {
|
|
1534
|
-
const agentPath = this.stateManager.getAgentPath(agentId);
|
|
1535
|
-
if (!agentPath)
|
|
1536
|
-
return;
|
|
1537
|
-
const mailboxFile = join(agentPath, "mailbox.json");
|
|
1538
|
-
if (!existsSync(mailboxFile))
|
|
1539
|
-
return;
|
|
1540
|
-
try {
|
|
1541
|
-
const data = JSON.parse(readFileSync(mailboxFile, "utf-8"));
|
|
1542
|
-
this.mailboxes.set(agentId, {
|
|
1543
|
-
agentId,
|
|
1544
|
-
inbox: data.inbox ?? [],
|
|
1545
|
-
outbox: data.outbox ?? [],
|
|
1546
|
-
archive: data.archive ?? [],
|
|
1547
|
-
updatedAt: data.updatedAt ?? Date.now()
|
|
1548
|
-
});
|
|
1549
|
-
} catch {
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
async persistMailbox(agentId) {
|
|
1553
|
-
const mailbox = this.mailboxes.get(agentId);
|
|
1554
|
-
if (!mailbox)
|
|
1555
|
-
return;
|
|
1556
|
-
await this.stateManager.createAgentWorktree(agentId);
|
|
1557
|
-
const agentPath = this.stateManager.getAgentPath(agentId);
|
|
1558
|
-
if (!agentPath)
|
|
1559
|
-
return;
|
|
1560
|
-
const mailboxFile = join(agentPath, "mailbox.json");
|
|
1561
|
-
writeFileSync(mailboxFile, JSON.stringify(mailbox, null, 2));
|
|
1562
|
-
}
|
|
1563
|
-
async checkExpiredMessages() {
|
|
1564
|
-
const now = Date.now();
|
|
1565
|
-
const entries = Array.from(this.mailboxes.entries());
|
|
1566
|
-
for (const [agentId, mailbox] of entries) {
|
|
1567
|
-
let changed = false;
|
|
1568
|
-
for (const message of mailbox.inbox) {
|
|
1569
|
-
if (message.expiresAt && message.expiresAt < now && !message.archived) {
|
|
1570
|
-
message.archived = true;
|
|
1571
|
-
mailbox.archive.push(message);
|
|
1572
|
-
changed = true;
|
|
1573
|
-
this.emit("message:expired", message.id);
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
mailbox.inbox = mailbox.inbox.filter((m) => !m.archived);
|
|
1577
|
-
if (changed) {
|
|
1578
|
-
mailbox.updatedAt = now;
|
|
1579
|
-
await this.persistMailbox(agentId);
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
let globalMailboxManager = null;
|
|
1585
|
-
function getGlobalMailboxManager() {
|
|
1586
|
-
if (!globalMailboxManager) {
|
|
1587
|
-
globalMailboxManager = new PersistentMailboxManager();
|
|
1588
|
-
}
|
|
1589
|
-
return globalMailboxManager;
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
const persistentMailbox = {
|
|
1593
|
-
__proto__: null,
|
|
1594
|
-
PersistentMailboxManager: PersistentMailboxManager,
|
|
1595
|
-
getGlobalMailboxManager: getGlobalMailboxManager
|
|
1596
|
-
};
|
|
1597
|
-
|
|
1598
|
-
class MayorAgent extends EventEmitter {
|
|
1599
|
-
id;
|
|
1600
|
-
config;
|
|
1601
|
-
convoyManager;
|
|
1602
|
-
mailboxManager;
|
|
1603
|
-
progressTrackers = /* @__PURE__ */ new Map();
|
|
1604
|
-
activeConvoys = /* @__PURE__ */ new Set();
|
|
1605
|
-
constructor(config = {}) {
|
|
1606
|
-
super();
|
|
1607
|
-
this.id = `mayor-${nanoid(6)}`;
|
|
1608
|
-
this.config = {
|
|
1609
|
-
autoCreateConvoy: config.autoCreateConvoy ?? true,
|
|
1610
|
-
autoSpawnWorkers: config.autoSpawnWorkers ?? true,
|
|
1611
|
-
monitorProgress: config.monitorProgress ?? true,
|
|
1612
|
-
progressInterval: config.progressInterval ?? 5e3,
|
|
1613
|
-
notifyHuman: config.notifyHuman ?? true,
|
|
1614
|
-
maxConcurrentWorkers: config.maxConcurrentWorkers ?? 5
|
|
1615
|
-
};
|
|
1616
|
-
this.convoyManager = getGlobalConvoyManager();
|
|
1617
|
-
this.mailboxManager = getGlobalMailboxManager();
|
|
1618
|
-
this.setupEventListeners();
|
|
1619
|
-
}
|
|
1620
|
-
/**
|
|
1621
|
-
* Process user request - main entry point
|
|
1622
|
-
*/
|
|
1623
|
-
async processRequest(input) {
|
|
1624
|
-
try {
|
|
1625
|
-
const intent = await this.analyzeIntent(input);
|
|
1626
|
-
this.emit("intent:analyzed", intent);
|
|
1627
|
-
const plan = await this.createTaskPlan(intent);
|
|
1628
|
-
this.emit("plan:created", plan);
|
|
1629
|
-
let convoy = null;
|
|
1630
|
-
if (this.config.autoCreateConvoy) {
|
|
1631
|
-
convoy = await this.createConvoy(plan);
|
|
1632
|
-
this.emit("convoy:created", convoy);
|
|
1633
|
-
}
|
|
1634
|
-
let workerCount = 0;
|
|
1635
|
-
if (this.config.autoSpawnWorkers && convoy) {
|
|
1636
|
-
workerCount = await this.spawnWorkers(convoy, plan);
|
|
1637
|
-
this.emit("workers:spawned", workerCount);
|
|
1638
|
-
}
|
|
1639
|
-
if (this.config.monitorProgress && convoy) {
|
|
1640
|
-
this.startMonitoring(convoy.id);
|
|
1641
|
-
}
|
|
1642
|
-
return {
|
|
1643
|
-
id: nanoid(),
|
|
1644
|
-
convoyId: convoy?.id ?? "",
|
|
1645
|
-
plan,
|
|
1646
|
-
workerCount,
|
|
1647
|
-
message: this.buildResponseMessage(plan, convoy, workerCount),
|
|
1648
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1649
|
-
};
|
|
1650
|
-
} catch (error) {
|
|
1651
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1652
|
-
this.emit("error", err);
|
|
1653
|
-
throw err;
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
/**
|
|
1657
|
-
* Analyze user intent from natural language
|
|
1658
|
-
*/
|
|
1659
|
-
async analyzeIntent(input) {
|
|
1660
|
-
const lowerInput = input.toLowerCase();
|
|
1661
|
-
let type = "other";
|
|
1662
|
-
if (lowerInput.includes("add") || lowerInput.includes("implement") || lowerInput.includes("create")) {
|
|
1663
|
-
type = "feature";
|
|
1664
|
-
} else if (lowerInput.includes("fix") || lowerInput.includes("bug") || lowerInput.includes("error")) {
|
|
1665
|
-
type = "bugfix";
|
|
1666
|
-
} else if (lowerInput.includes("refactor") || lowerInput.includes("clean") || lowerInput.includes("improve")) {
|
|
1667
|
-
type = "refactor";
|
|
1668
|
-
} else if (lowerInput.includes("research") || lowerInput.includes("investigate")) {
|
|
1669
|
-
type = "research";
|
|
1670
|
-
} else if (lowerInput.includes("document") || lowerInput.includes("docs")) {
|
|
1671
|
-
type = "documentation";
|
|
1672
|
-
} else if (lowerInput.includes("test") || lowerInput.includes("spec")) {
|
|
1673
|
-
type = "testing";
|
|
1674
|
-
} else if (lowerInput.includes("deploy") || lowerInput.includes("release")) {
|
|
1675
|
-
type = "deployment";
|
|
1676
|
-
}
|
|
1677
|
-
const entities = {
|
|
1678
|
-
files: this.extractFiles(input),
|
|
1679
|
-
functions: this.extractFunctions(input),
|
|
1680
|
-
components: this.extractComponents(input),
|
|
1681
|
-
technologies: this.extractTechnologies(input),
|
|
1682
|
-
keywords: this.extractKeywords(input)
|
|
1683
|
-
};
|
|
1684
|
-
const complexity = this.estimateComplexity(input, entities);
|
|
1685
|
-
const requiredRoles = this.determineRequiredRoles(type, entities);
|
|
1686
|
-
return {
|
|
1687
|
-
id: nanoid(),
|
|
1688
|
-
originalInput: input,
|
|
1689
|
-
type,
|
|
1690
|
-
summary: this.generateSummary(input, type),
|
|
1691
|
-
entities,
|
|
1692
|
-
confidence: 0.8,
|
|
1693
|
-
approach: this.suggestApproach(type, complexity),
|
|
1694
|
-
complexity,
|
|
1695
|
-
requiredRoles
|
|
1696
|
-
};
|
|
1697
|
-
}
|
|
1698
|
-
/**
|
|
1699
|
-
* Create task plan from intent
|
|
1700
|
-
*/
|
|
1701
|
-
async createTaskPlan(intent) {
|
|
1702
|
-
const tasks = [];
|
|
1703
|
-
switch (intent.type) {
|
|
1704
|
-
case "feature":
|
|
1705
|
-
tasks.push(
|
|
1706
|
-
{ title: "Analyze requirements", description: `Understand: ${intent.summary}`, role: "researcher", dependsOn: [], estimatedEffort: "small" },
|
|
1707
|
-
{ title: "Design implementation", description: "Create design and identify files", role: "architect", dependsOn: ["task-0"], estimatedEffort: "medium" },
|
|
1708
|
-
{ title: "Implement feature", description: "Write the code", role: "coder", dependsOn: ["task-1"], estimatedEffort: "large" },
|
|
1709
|
-
{ title: "Write tests", description: "Create tests", role: "tester", dependsOn: ["task-2"], estimatedEffort: "medium" },
|
|
1710
|
-
{ title: "Review", description: "Code review", role: "reviewer", dependsOn: ["task-3"], estimatedEffort: "small" }
|
|
1711
|
-
);
|
|
1712
|
-
break;
|
|
1713
|
-
case "bugfix":
|
|
1714
|
-
tasks.push(
|
|
1715
|
-
{ title: "Reproduce issue", description: "Understand the bug", role: "researcher", dependsOn: [], estimatedEffort: "small" },
|
|
1716
|
-
{ title: "Find root cause", description: "Debug and find cause", role: "debugger", dependsOn: ["task-0"], estimatedEffort: "medium" },
|
|
1717
|
-
{ title: "Implement fix", description: "Write the fix", role: "coder", dependsOn: ["task-1"], estimatedEffort: "medium" },
|
|
1718
|
-
{ title: "Add regression test", description: "Prevent regression", role: "tester", dependsOn: ["task-2"], estimatedEffort: "small" }
|
|
1719
|
-
);
|
|
1720
|
-
break;
|
|
1721
|
-
case "refactor":
|
|
1722
|
-
tasks.push(
|
|
1723
|
-
{ title: "Analyze code", description: "Understand current implementation", role: "researcher", dependsOn: [], estimatedEffort: "medium" },
|
|
1724
|
-
{ title: "Plan refactoring", description: "Design approach", role: "architect", dependsOn: ["task-0"], estimatedEffort: "medium" },
|
|
1725
|
-
{ title: "Execute refactoring", description: "Perform refactoring", role: "coder", dependsOn: ["task-1"], estimatedEffort: "large" },
|
|
1726
|
-
{ title: "Verify tests", description: "Ensure tests pass", role: "tester", dependsOn: ["task-2"], estimatedEffort: "small" }
|
|
1727
|
-
);
|
|
1728
|
-
break;
|
|
1729
|
-
default:
|
|
1730
|
-
tasks.push(
|
|
1731
|
-
{ title: "Analyze request", description: `Understand: ${intent.summary}`, role: "researcher", dependsOn: [], estimatedEffort: "small" },
|
|
1732
|
-
{ title: "Execute task", description: "Perform the work", role: "coder", dependsOn: ["task-0"], estimatedEffort: "medium" }
|
|
1733
|
-
);
|
|
1734
|
-
}
|
|
1735
|
-
return {
|
|
1736
|
-
id: nanoid(),
|
|
1737
|
-
name: intent.summary,
|
|
1738
|
-
description: `Task plan for: ${intent.originalInput}`,
|
|
1739
|
-
tasks,
|
|
1740
|
-
totalEffort: this.calculateTotalEffort(tasks),
|
|
1741
|
-
risks: this.identifyRisks(intent),
|
|
1742
|
-
successCriteria: this.defineSuccessCriteria(intent)
|
|
1743
|
-
};
|
|
1744
|
-
}
|
|
1745
|
-
/**
|
|
1746
|
-
* Create convoy from task plan
|
|
1747
|
-
*/
|
|
1748
|
-
async createConvoy(plan) {
|
|
1749
|
-
const convoy = await this.convoyManager.create(plan.name, {
|
|
1750
|
-
description: plan.description,
|
|
1751
|
-
createdBy: this.id,
|
|
1752
|
-
notifyOnComplete: this.config.notifyHuman,
|
|
1753
|
-
notifyOnFailure: true,
|
|
1754
|
-
notifyOnProgress: true,
|
|
1755
|
-
metadata: { planId: plan.id, totalEffort: plan.totalEffort }
|
|
1756
|
-
});
|
|
1757
|
-
const taskIdMap = /* @__PURE__ */ new Map();
|
|
1758
|
-
for (let i = 0; i < plan.tasks.length; i++) {
|
|
1759
|
-
const planTask = plan.tasks[i];
|
|
1760
|
-
const dependsOn = planTask.dependsOn.map((dep) => taskIdMap.get(dep)).filter((id) => id !== void 0);
|
|
1761
|
-
const task = await this.convoyManager.addTask(convoy.id, planTask.title, {
|
|
1762
|
-
description: planTask.description,
|
|
1763
|
-
dependsOn,
|
|
1764
|
-
metadata: { role: planTask.role, estimatedEffort: planTask.estimatedEffort }
|
|
1765
|
-
});
|
|
1766
|
-
taskIdMap.set(`task-${i}`, task.id);
|
|
1767
|
-
}
|
|
1768
|
-
this.activeConvoys.add(convoy.id);
|
|
1769
|
-
return this.convoyManager.get(convoy.id);
|
|
1770
|
-
}
|
|
1771
|
-
/**
|
|
1772
|
-
* Spawn worker agents for convoy
|
|
1773
|
-
*/
|
|
1774
|
-
async spawnWorkers(convoy, plan) {
|
|
1775
|
-
const uniqueRoles = new Set(plan.tasks.map((t) => t.role));
|
|
1776
|
-
const workerCount = Math.min(uniqueRoles.size, this.config.maxConcurrentWorkers);
|
|
1777
|
-
await this.convoyManager.start(convoy.id);
|
|
1778
|
-
return workerCount;
|
|
1779
|
-
}
|
|
1780
|
-
/**
|
|
1781
|
-
* Start monitoring convoy progress
|
|
1782
|
-
*/
|
|
1783
|
-
startMonitoring(convoyId) {
|
|
1784
|
-
if (this.progressTrackers.has(convoyId))
|
|
1785
|
-
return;
|
|
1786
|
-
const tracker = new ProgressTracker(this.convoyManager, {
|
|
1787
|
-
updateInterval: this.config.progressInterval
|
|
1788
|
-
});
|
|
1789
|
-
tracker.on("progress", (update) => {
|
|
1790
|
-
this.emit("progress:update", update);
|
|
1791
|
-
});
|
|
1792
|
-
tracker.track(convoyId);
|
|
1793
|
-
this.progressTrackers.set(convoyId, tracker);
|
|
1794
|
-
}
|
|
1795
|
-
/**
|
|
1796
|
-
* Stop monitoring convoy
|
|
1797
|
-
*/
|
|
1798
|
-
stopMonitoring(convoyId) {
|
|
1799
|
-
const tracker = this.progressTrackers.get(convoyId);
|
|
1800
|
-
if (tracker) {
|
|
1801
|
-
tracker.destroy();
|
|
1802
|
-
this.progressTrackers.delete(convoyId);
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
/**
|
|
1806
|
-
* Get convoy status
|
|
1807
|
-
*/
|
|
1808
|
-
getConvoyStatus(convoyId) {
|
|
1809
|
-
return this.convoyManager.getSummary(convoyId);
|
|
1810
|
-
}
|
|
1811
|
-
/**
|
|
1812
|
-
* Get all active convoys
|
|
1813
|
-
*/
|
|
1814
|
-
getActiveConvoys() {
|
|
1815
|
-
return Array.from(this.activeConvoys).map((id) => this.convoyManager.get(id)).filter((c) => c !== void 0);
|
|
1816
|
-
}
|
|
1817
|
-
/**
|
|
1818
|
-
* Destroy mayor agent
|
|
1819
|
-
*/
|
|
1820
|
-
destroy() {
|
|
1821
|
-
const trackers = Array.from(this.progressTrackers.values());
|
|
1822
|
-
for (const tracker of trackers) {
|
|
1823
|
-
tracker.destroy();
|
|
1824
|
-
}
|
|
1825
|
-
this.progressTrackers.clear();
|
|
1826
|
-
this.activeConvoys.clear();
|
|
1827
|
-
this.removeAllListeners();
|
|
1828
|
-
}
|
|
1829
|
-
// ========================================================================
|
|
1830
|
-
// Private Methods
|
|
1831
|
-
// ========================================================================
|
|
1832
|
-
setupEventListeners() {
|
|
1833
|
-
this.convoyManager.on("convoy:completed", (convoy) => {
|
|
1834
|
-
if (this.activeConvoys.has(convoy.id)) {
|
|
1835
|
-
this.activeConvoys.delete(convoy.id);
|
|
1836
|
-
this.stopMonitoring(convoy.id);
|
|
1837
|
-
this.emit("convoy:completed", convoy, this.convoyManager.getSummary(convoy.id));
|
|
1838
|
-
}
|
|
1839
|
-
});
|
|
1840
|
-
this.convoyManager.on("convoy:failed", (convoy) => {
|
|
1841
|
-
if (this.activeConvoys.has(convoy.id)) {
|
|
1842
|
-
this.activeConvoys.delete(convoy.id);
|
|
1843
|
-
this.stopMonitoring(convoy.id);
|
|
1844
|
-
this.emit("convoy:failed", convoy, "Convoy failed");
|
|
1845
|
-
}
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
extractFiles(input) {
|
|
1849
|
-
const filePattern = /[\w-]+\.(ts|js|tsx|jsx|json|md|yaml|yml|toml)/gi;
|
|
1850
|
-
return input.match(filePattern) ?? [];
|
|
1851
|
-
}
|
|
1852
|
-
extractFunctions(input) {
|
|
1853
|
-
const funcPattern = /\b(\w+)\s*\(/g;
|
|
1854
|
-
const matches = [];
|
|
1855
|
-
let match;
|
|
1856
|
-
while ((match = funcPattern.exec(input)) !== null) {
|
|
1857
|
-
if (!["if", "for", "while", "switch", "catch"].includes(match[1])) {
|
|
1858
|
-
matches.push(match[1]);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
return matches;
|
|
1862
|
-
}
|
|
1863
|
-
extractComponents(input) {
|
|
1864
|
-
const componentPattern = /\b([A-Z][a-zA-Z]+)\b/g;
|
|
1865
|
-
return input.match(componentPattern) ?? [];
|
|
1866
|
-
}
|
|
1867
|
-
extractTechnologies(input) {
|
|
1868
|
-
const techs = ["react", "vue", "angular", "node", "typescript", "javascript", "python", "rust", "go", "docker", "kubernetes", "aws", "gcp", "azure"];
|
|
1869
|
-
const lowerInput = input.toLowerCase();
|
|
1870
|
-
return techs.filter((tech) => lowerInput.includes(tech));
|
|
1871
|
-
}
|
|
1872
|
-
extractKeywords(input) {
|
|
1873
|
-
const words = input.toLowerCase().split(/\s+/);
|
|
1874
|
-
const stopWords = /* @__PURE__ */ new Set(["the", "a", "an", "is", "are", "was", "were", "be", "been", "being", "have", "has", "had", "do", "does", "did", "will", "would", "could", "should", "may", "might", "must", "shall", "can", "need", "dare", "ought", "used", "to", "of", "in", "for", "on", "with", "at", "by", "from", "as", "into", "through", "during", "before", "after", "above", "below", "between", "under", "again", "further", "then", "once", "here", "there", "when", "where", "why", "how", "all", "each", "few", "more", "most", "other", "some", "such", "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "and", "but", "if", "or", "because", "until", "while", "although", "though", "after", "before", "when", "whenever", "where", "wherever", "whether", "which", "who", "whom", "whose", "what", "whatever", "whichever", "whoever", "whomever", "this", "that", "these", "those", "i", "me", "my", "myself", "we", "our", "ours", "ourselves", "you", "your", "yours", "yourself", "yourselves", "he", "him", "his", "himself", "she", "her", "hers", "herself", "it", "its", "itself", "they", "them", "their", "theirs", "themselves"]);
|
|
1875
|
-
return words.filter((w) => w.length > 2 && !stopWords.has(w));
|
|
1876
|
-
}
|
|
1877
|
-
estimateComplexity(input, entities) {
|
|
1878
|
-
const fileCount = entities.files?.length ?? 0;
|
|
1879
|
-
const componentCount = entities.components?.length ?? 0;
|
|
1880
|
-
const wordCount = input.split(/\s+/).length;
|
|
1881
|
-
if (wordCount < 10 && fileCount <= 1)
|
|
1882
|
-
return "trivial";
|
|
1883
|
-
if (wordCount < 20 && fileCount <= 2)
|
|
1884
|
-
return "simple";
|
|
1885
|
-
if (wordCount < 50 && fileCount <= 5)
|
|
1886
|
-
return "moderate";
|
|
1887
|
-
if (wordCount < 100 || componentCount > 3)
|
|
1888
|
-
return "complex";
|
|
1889
|
-
return "very_complex";
|
|
1890
|
-
}
|
|
1891
|
-
determineRequiredRoles(type, _entities) {
|
|
1892
|
-
const roles = ["researcher"];
|
|
1893
|
-
switch (type) {
|
|
1894
|
-
case "feature":
|
|
1895
|
-
roles.push("architect", "coder", "tester", "reviewer");
|
|
1896
|
-
break;
|
|
1897
|
-
case "bugfix":
|
|
1898
|
-
roles.push("debugger", "coder", "tester");
|
|
1899
|
-
break;
|
|
1900
|
-
case "refactor":
|
|
1901
|
-
roles.push("architect", "coder", "tester");
|
|
1902
|
-
break;
|
|
1903
|
-
case "testing":
|
|
1904
|
-
roles.push("tester");
|
|
1905
|
-
break;
|
|
1906
|
-
case "documentation":
|
|
1907
|
-
roles.push("writer");
|
|
1908
|
-
break;
|
|
1909
|
-
default:
|
|
1910
|
-
roles.push("coder");
|
|
1911
|
-
}
|
|
1912
|
-
return roles;
|
|
1913
|
-
}
|
|
1914
|
-
generateSummary(input, type) {
|
|
1915
|
-
const words = input.split(/\s+/).slice(0, 10).join(" ");
|
|
1916
|
-
const typeLabel = type.charAt(0).toUpperCase() + type.slice(1);
|
|
1917
|
-
return `${typeLabel}: ${words}${input.split(/\s+/).length > 10 ? "..." : ""}`;
|
|
1918
|
-
}
|
|
1919
|
-
suggestApproach(type, _complexity) {
|
|
1920
|
-
const approaches = {
|
|
1921
|
-
feature: "Design-first approach with incremental implementation",
|
|
1922
|
-
bugfix: "Reproduce, isolate, fix, and verify",
|
|
1923
|
-
refactor: "Ensure test coverage, then refactor incrementally",
|
|
1924
|
-
research: "Gather information, analyze, and document findings",
|
|
1925
|
-
documentation: "Review code, document API and usage patterns",
|
|
1926
|
-
testing: "Identify test cases, implement, and verify coverage",
|
|
1927
|
-
deployment: "Prepare, validate, deploy, and monitor",
|
|
1928
|
-
other: "Analyze requirements and implement solution"
|
|
1929
|
-
};
|
|
1930
|
-
return approaches[type];
|
|
1931
|
-
}
|
|
1932
|
-
calculateTotalEffort(tasks) {
|
|
1933
|
-
const effortMap = { minimal: 1, small: 2, medium: 4, large: 8 };
|
|
1934
|
-
const total = tasks.reduce((sum, t) => sum + effortMap[t.estimatedEffort], 0);
|
|
1935
|
-
if (total <= 4)
|
|
1936
|
-
return "Small";
|
|
1937
|
-
if (total <= 10)
|
|
1938
|
-
return "Medium";
|
|
1939
|
-
if (total <= 20)
|
|
1940
|
-
return "Large";
|
|
1941
|
-
return "Very Large";
|
|
1942
|
-
}
|
|
1943
|
-
identifyRisks(intent) {
|
|
1944
|
-
const risks = [];
|
|
1945
|
-
if (intent.complexity === "complex" || intent.complexity === "very_complex") {
|
|
1946
|
-
risks.push("High complexity may require multiple iterations");
|
|
1947
|
-
}
|
|
1948
|
-
if (intent.type === "refactor") {
|
|
1949
|
-
risks.push("Refactoring may introduce regressions");
|
|
1950
|
-
}
|
|
1951
|
-
if (intent.entities.files && intent.entities.files.length > 5) {
|
|
1952
|
-
risks.push("Multiple files affected - careful coordination needed");
|
|
1953
|
-
}
|
|
1954
|
-
if (risks.length === 0) {
|
|
1955
|
-
risks.push("No significant risks identified");
|
|
1956
|
-
}
|
|
1957
|
-
return risks;
|
|
1958
|
-
}
|
|
1959
|
-
defineSuccessCriteria(intent) {
|
|
1960
|
-
const criteria = [];
|
|
1961
|
-
switch (intent.type) {
|
|
1962
|
-
case "feature":
|
|
1963
|
-
criteria.push("Feature implemented as specified", "Tests pass", "Code reviewed");
|
|
1964
|
-
break;
|
|
1965
|
-
case "bugfix":
|
|
1966
|
-
criteria.push("Bug no longer reproducible", "Regression test added", "No new issues introduced");
|
|
1967
|
-
break;
|
|
1968
|
-
case "refactor":
|
|
1969
|
-
criteria.push("All existing tests pass", "Code quality improved", "No functional changes");
|
|
1970
|
-
break;
|
|
1971
|
-
default:
|
|
1972
|
-
criteria.push("Task completed successfully", "Results documented");
|
|
1973
|
-
}
|
|
1974
|
-
return criteria;
|
|
1975
|
-
}
|
|
1976
|
-
buildResponseMessage(plan, convoy, workerCount) {
|
|
1977
|
-
const lines = [
|
|
1978
|
-
`Created plan: ${plan.name}`,
|
|
1979
|
-
`Tasks: ${plan.tasks.length}`,
|
|
1980
|
-
`Estimated effort: ${plan.totalEffort}`
|
|
1981
|
-
];
|
|
1982
|
-
if (convoy) {
|
|
1983
|
-
lines.push(`Convoy: ${convoy.id}`);
|
|
1984
|
-
}
|
|
1985
|
-
if (workerCount > 0) {
|
|
1986
|
-
lines.push(`Workers: ${workerCount}`);
|
|
1987
|
-
}
|
|
1988
|
-
return lines.join("\n");
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
let globalMayorAgent = null;
|
|
1992
|
-
function getGlobalMayorAgent(config) {
|
|
1993
|
-
if (!globalMayorAgent) {
|
|
1994
|
-
globalMayorAgent = new MayorAgent(config);
|
|
1995
|
-
}
|
|
1996
|
-
return globalMayorAgent;
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
class MetricsCollector {
|
|
2000
|
-
metrics = /* @__PURE__ */ new Map();
|
|
2001
|
-
taskMetrics = /* @__PURE__ */ new Map();
|
|
2002
|
-
performanceMetrics = /* @__PURE__ */ new Map();
|
|
2003
|
-
maxRecords;
|
|
2004
|
-
retentionPeriod;
|
|
2005
|
-
constructor(options = {}) {
|
|
2006
|
-
this.maxRecords = options.maxRecords ?? 1e3;
|
|
2007
|
-
this.retentionPeriod = options.retentionPeriod ?? 36e5;
|
|
2008
|
-
}
|
|
2009
|
-
/**
|
|
2010
|
-
* Record a metric value
|
|
2011
|
-
*/
|
|
2012
|
-
recordMetric(agentId, metricName, value, metadata) {
|
|
2013
|
-
if (!this.metrics.has(agentId)) {
|
|
2014
|
-
this.metrics.set(agentId, /* @__PURE__ */ new Map());
|
|
2015
|
-
}
|
|
2016
|
-
const agentMetrics = this.metrics.get(agentId);
|
|
2017
|
-
if (!agentMetrics.has(metricName)) {
|
|
2018
|
-
agentMetrics.set(metricName, []);
|
|
2019
|
-
}
|
|
2020
|
-
const records = agentMetrics.get(metricName);
|
|
2021
|
-
records.push({
|
|
2022
|
-
timestamp: Date.now(),
|
|
2023
|
-
value,
|
|
2024
|
-
metadata
|
|
2025
|
-
});
|
|
2026
|
-
this.trimRecords(records);
|
|
2027
|
-
}
|
|
2028
|
-
/**
|
|
2029
|
-
* Record CPU usage
|
|
2030
|
-
*/
|
|
2031
|
-
recordCpuUsage(agentId, usage) {
|
|
2032
|
-
this.recordMetric(agentId, "cpu_usage", usage);
|
|
2033
|
-
this.updatePerformanceMetrics(agentId, { cpuUsage: usage });
|
|
2034
|
-
}
|
|
2035
|
-
/**
|
|
2036
|
-
* Record memory usage
|
|
2037
|
-
*/
|
|
2038
|
-
recordMemoryUsage(agentId, usage) {
|
|
2039
|
-
this.recordMetric(agentId, "memory_usage", usage);
|
|
2040
|
-
this.updatePerformanceMetrics(agentId, { memoryUsage: usage });
|
|
2041
|
-
}
|
|
2042
|
-
/**
|
|
2043
|
-
* Record response time
|
|
2044
|
-
*/
|
|
2045
|
-
recordResponseTime(agentId, responseTime) {
|
|
2046
|
-
this.recordMetric(agentId, "response_time", responseTime);
|
|
2047
|
-
this.updatePerformanceMetrics(agentId, { responseTime });
|
|
2048
|
-
}
|
|
2049
|
-
/**
|
|
2050
|
-
* Record task completion
|
|
2051
|
-
*/
|
|
2052
|
-
recordTaskCompletion(agentId, success, duration) {
|
|
2053
|
-
if (!this.taskMetrics.has(agentId)) {
|
|
2054
|
-
this.taskMetrics.set(agentId, {
|
|
2055
|
-
totalTasks: 0,
|
|
2056
|
-
completedTasks: 0,
|
|
2057
|
-
failedTasks: 0,
|
|
2058
|
-
avgDuration: 0,
|
|
2059
|
-
successRate: 0
|
|
2060
|
-
});
|
|
2061
|
-
}
|
|
2062
|
-
const metrics = this.taskMetrics.get(agentId);
|
|
2063
|
-
metrics.totalTasks++;
|
|
2064
|
-
if (success) {
|
|
2065
|
-
metrics.completedTasks++;
|
|
2066
|
-
} else {
|
|
2067
|
-
metrics.failedTasks++;
|
|
2068
|
-
}
|
|
2069
|
-
metrics.avgDuration = (metrics.avgDuration * (metrics.totalTasks - 1) + duration) / metrics.totalTasks;
|
|
2070
|
-
metrics.successRate = metrics.completedTasks / metrics.totalTasks;
|
|
2071
|
-
this.recordMetric(agentId, "task_duration", duration, { success });
|
|
2072
|
-
}
|
|
2073
|
-
/**
|
|
2074
|
-
* Record error
|
|
2075
|
-
*/
|
|
2076
|
-
recordError(agentId, errorType, errorMessage) {
|
|
2077
|
-
this.recordMetric(agentId, "error", 1, { errorType, errorMessage });
|
|
2078
|
-
this.updatePerformanceMetrics(agentId, { errorCount: 1 });
|
|
2079
|
-
}
|
|
2080
|
-
/**
|
|
2081
|
-
* Get agent metrics
|
|
2082
|
-
*/
|
|
2083
|
-
getAgentMetrics(agentId) {
|
|
2084
|
-
const taskMetrics = this.taskMetrics.get(agentId);
|
|
2085
|
-
const cpuRecords = this.getMetricRecords(agentId, "cpu_usage");
|
|
2086
|
-
const memoryRecords = this.getMetricRecords(agentId, "memory_usage");
|
|
2087
|
-
const responseTimeRecords = this.getMetricRecords(agentId, "response_time");
|
|
2088
|
-
const cpuUsage = cpuRecords.length > 0 ? cpuRecords[cpuRecords.length - 1].value : 0;
|
|
2089
|
-
const memoryUsage = memoryRecords.length > 0 ? memoryRecords[memoryRecords.length - 1].value : 0;
|
|
2090
|
-
this.calculateAverage(responseTimeRecords.map((r) => r.value));
|
|
2091
|
-
taskMetrics ? taskMetrics.failedTasks / taskMetrics.totalTasks : 0;
|
|
2092
|
-
return {
|
|
2093
|
-
tasksExecuted: taskMetrics?.totalTasks ?? 0,
|
|
2094
|
-
tasksSucceeded: taskMetrics?.completedTasks ?? 0,
|
|
2095
|
-
tasksFailed: taskMetrics?.failedTasks ?? 0,
|
|
2096
|
-
avgTaskDuration: taskMetrics?.avgDuration ?? 0,
|
|
2097
|
-
successRate: taskMetrics?.successRate ?? 0,
|
|
2098
|
-
totalExecutionTime: taskMetrics?.avgDuration ?? 0,
|
|
2099
|
-
avgConfidence: 0.8,
|
|
2100
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2101
|
-
cpuUsage,
|
|
2102
|
-
memoryUsage
|
|
2103
|
-
};
|
|
2104
|
-
}
|
|
2105
|
-
/**
|
|
2106
|
-
* Get metric snapshot
|
|
2107
|
-
*/
|
|
2108
|
-
getMetricSnapshot(agentId, metricName, timeRange) {
|
|
2109
|
-
const records = this.getMetricRecords(agentId, metricName, timeRange);
|
|
2110
|
-
const values = records.map((r) => r.value);
|
|
2111
|
-
if (values.length === 0) {
|
|
2112
|
-
return {
|
|
2113
|
-
metricName,
|
|
2114
|
-
agentId,
|
|
2115
|
-
timestamp: Date.now(),
|
|
2116
|
-
current: 0,
|
|
2117
|
-
min: 0,
|
|
2118
|
-
max: 0,
|
|
2119
|
-
avg: 0,
|
|
2120
|
-
count: 0
|
|
2121
|
-
};
|
|
2122
|
-
}
|
|
2123
|
-
return {
|
|
2124
|
-
metricName,
|
|
2125
|
-
agentId,
|
|
2126
|
-
timestamp: Date.now(),
|
|
2127
|
-
current: values[values.length - 1],
|
|
2128
|
-
min: Math.min(...values),
|
|
2129
|
-
max: Math.max(...values),
|
|
2130
|
-
avg: this.calculateAverage(values),
|
|
2131
|
-
count: values.length
|
|
2132
|
-
};
|
|
2133
|
-
}
|
|
2134
|
-
/**
|
|
2135
|
-
* Get aggregated metrics
|
|
2136
|
-
*/
|
|
2137
|
-
getAggregatedMetrics(agentId, metricName, timeRange) {
|
|
2138
|
-
const records = this.getMetricRecords(agentId, metricName, timeRange);
|
|
2139
|
-
const values = records.map((r) => r.value).sort((a, b) => a - b);
|
|
2140
|
-
if (values.length === 0) {
|
|
2141
|
-
return {
|
|
2142
|
-
min: 0,
|
|
2143
|
-
max: 0,
|
|
2144
|
-
avg: 0,
|
|
2145
|
-
median: 0,
|
|
2146
|
-
p95: 0,
|
|
2147
|
-
p99: 0,
|
|
2148
|
-
count: 0
|
|
2149
|
-
};
|
|
2150
|
-
}
|
|
2151
|
-
return {
|
|
2152
|
-
min: values[0],
|
|
2153
|
-
max: values[values.length - 1],
|
|
2154
|
-
avg: this.calculateAverage(values),
|
|
2155
|
-
median: this.calculatePercentile(values, 50),
|
|
2156
|
-
p95: this.calculatePercentile(values, 95),
|
|
2157
|
-
p99: this.calculatePercentile(values, 99),
|
|
2158
|
-
count: values.length
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
/**
|
|
2162
|
-
* Get task metrics
|
|
2163
|
-
*/
|
|
2164
|
-
getTaskMetrics(agentId) {
|
|
2165
|
-
return this.taskMetrics.get(agentId);
|
|
2166
|
-
}
|
|
2167
|
-
/**
|
|
2168
|
-
* Get performance metrics
|
|
2169
|
-
*/
|
|
2170
|
-
getPerformanceMetrics(agentId) {
|
|
2171
|
-
return this.performanceMetrics.get(agentId);
|
|
2172
|
-
}
|
|
2173
|
-
/**
|
|
2174
|
-
* Get all agents with metrics
|
|
2175
|
-
*/
|
|
2176
|
-
getAllAgents() {
|
|
2177
|
-
return Array.from(this.metrics.keys());
|
|
2178
|
-
}
|
|
2179
|
-
/**
|
|
2180
|
-
* Clear metrics for an agent
|
|
2181
|
-
*/
|
|
2182
|
-
clearAgentMetrics(agentId) {
|
|
2183
|
-
this.metrics.delete(agentId);
|
|
2184
|
-
this.taskMetrics.delete(agentId);
|
|
2185
|
-
this.performanceMetrics.delete(agentId);
|
|
2186
|
-
}
|
|
2187
|
-
/**
|
|
2188
|
-
* Clear all metrics
|
|
2189
|
-
*/
|
|
2190
|
-
clearAll() {
|
|
2191
|
-
this.metrics.clear();
|
|
2192
|
-
this.taskMetrics.clear();
|
|
2193
|
-
this.performanceMetrics.clear();
|
|
2194
|
-
}
|
|
2195
|
-
/**
|
|
2196
|
-
* Export metrics to JSON
|
|
2197
|
-
*/
|
|
2198
|
-
exportMetrics(agentId) {
|
|
2199
|
-
if (agentId) {
|
|
2200
|
-
return {
|
|
2201
|
-
agentId,
|
|
2202
|
-
metrics: this.getAgentMetrics(agentId),
|
|
2203
|
-
taskMetrics: this.getTaskMetrics(agentId),
|
|
2204
|
-
performanceMetrics: this.getPerformanceMetrics(agentId),
|
|
2205
|
-
timestamp: Date.now()
|
|
2206
|
-
};
|
|
2207
|
-
}
|
|
2208
|
-
const allMetrics = {};
|
|
2209
|
-
for (const id of this.getAllAgents()) {
|
|
2210
|
-
allMetrics[id] = {
|
|
2211
|
-
metrics: this.getAgentMetrics(id),
|
|
2212
|
-
taskMetrics: this.getTaskMetrics(id),
|
|
2213
|
-
performanceMetrics: this.getPerformanceMetrics(id)
|
|
2214
|
-
};
|
|
2215
|
-
}
|
|
2216
|
-
return {
|
|
2217
|
-
agents: allMetrics,
|
|
2218
|
-
timestamp: Date.now()
|
|
2219
|
-
};
|
|
2220
|
-
}
|
|
2221
|
-
/**
|
|
2222
|
-
* Get metric records
|
|
2223
|
-
*/
|
|
2224
|
-
getMetricRecords(agentId, metricName, timeRange) {
|
|
2225
|
-
const agentMetrics = this.metrics.get(agentId);
|
|
2226
|
-
if (!agentMetrics) {
|
|
2227
|
-
return [];
|
|
2228
|
-
}
|
|
2229
|
-
const records = agentMetrics.get(metricName) ?? [];
|
|
2230
|
-
if (timeRange) {
|
|
2231
|
-
const cutoff = Date.now() - timeRange;
|
|
2232
|
-
return records.filter((r) => r.timestamp >= cutoff);
|
|
2233
|
-
}
|
|
2234
|
-
return records;
|
|
2235
|
-
}
|
|
2236
|
-
/**
|
|
2237
|
-
* Update performance metrics
|
|
2238
|
-
*/
|
|
2239
|
-
updatePerformanceMetrics(agentId, update) {
|
|
2240
|
-
if (!this.performanceMetrics.has(agentId)) {
|
|
2241
|
-
this.performanceMetrics.set(agentId, {
|
|
2242
|
-
cpuUsage: 0,
|
|
2243
|
-
memoryUsage: 0,
|
|
2244
|
-
responseTime: 0,
|
|
2245
|
-
errorCount: 0,
|
|
2246
|
-
requestCount: 0,
|
|
2247
|
-
timestamp: Date.now()
|
|
2248
|
-
});
|
|
2249
|
-
}
|
|
2250
|
-
const metrics = this.performanceMetrics.get(agentId);
|
|
2251
|
-
if (update.cpuUsage !== void 0) {
|
|
2252
|
-
metrics.cpuUsage = update.cpuUsage;
|
|
2253
|
-
}
|
|
2254
|
-
if (update.memoryUsage !== void 0) {
|
|
2255
|
-
metrics.memoryUsage = update.memoryUsage;
|
|
2256
|
-
}
|
|
2257
|
-
if (update.responseTime !== void 0) {
|
|
2258
|
-
metrics.requestCount++;
|
|
2259
|
-
metrics.responseTime = (metrics.responseTime * (metrics.requestCount - 1) + update.responseTime) / metrics.requestCount;
|
|
2260
|
-
}
|
|
2261
|
-
if (update.errorCount !== void 0) {
|
|
2262
|
-
metrics.errorCount += update.errorCount;
|
|
2263
|
-
}
|
|
2264
|
-
metrics.timestamp = Date.now();
|
|
2265
|
-
}
|
|
2266
|
-
/**
|
|
2267
|
-
* Trim old records
|
|
2268
|
-
*/
|
|
2269
|
-
trimRecords(records) {
|
|
2270
|
-
const cutoff = Date.now() - this.retentionPeriod;
|
|
2271
|
-
while (records.length > 0 && records[0].timestamp < cutoff) {
|
|
2272
|
-
records.shift();
|
|
2273
|
-
}
|
|
2274
|
-
while (records.length > this.maxRecords) {
|
|
2275
|
-
records.shift();
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
/**
|
|
2279
|
-
* Calculate average
|
|
2280
|
-
*/
|
|
2281
|
-
calculateAverage(values) {
|
|
2282
|
-
if (values.length === 0) {
|
|
2283
|
-
return 0;
|
|
2284
|
-
}
|
|
2285
|
-
return values.reduce((sum, val) => sum + val, 0) / values.length;
|
|
2286
|
-
}
|
|
2287
|
-
/**
|
|
2288
|
-
* Calculate percentile
|
|
2289
|
-
*/
|
|
2290
|
-
calculatePercentile(sortedValues, percentile) {
|
|
2291
|
-
if (sortedValues.length === 0) {
|
|
2292
|
-
return 0;
|
|
2293
|
-
}
|
|
2294
|
-
const index = Math.ceil(percentile / 100 * sortedValues.length) - 1;
|
|
2295
|
-
return sortedValues[Math.max(0, index)];
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
|
-
let globalMetricsCollector;
|
|
2299
|
-
function getMetricsCollector(options) {
|
|
2300
|
-
if (!globalMetricsCollector) {
|
|
2301
|
-
globalMetricsCollector = new MetricsCollector(options);
|
|
2302
|
-
}
|
|
2303
|
-
return globalMetricsCollector;
|
|
2304
|
-
}
|
|
2305
|
-
|
|
2306
|
-
const promptUserQuestion = async (question) => {
|
|
2307
|
-
if (!process__default.stdin.isTTY || !process__default.stdout.isTTY) {
|
|
2308
|
-
return null;
|
|
2309
|
-
}
|
|
2310
|
-
try {
|
|
2311
|
-
const inquirer = (await import('./index6.mjs').then(function (n) { return n.c; })).default;
|
|
2312
|
-
const choices = question.options.map((option) => ({
|
|
2313
|
-
name: option.description ? `${option.label} \u2014 ${option.description}` : option.label,
|
|
2314
|
-
value: option.value
|
|
2315
|
-
}));
|
|
2316
|
-
const defaultIndex = typeof question.defaultValue === "string" ? Math.max(0, choices.findIndex((choice) => choice.value === question.defaultValue)) : 0;
|
|
2317
|
-
const { selected } = await inquirer.prompt([
|
|
2318
|
-
{
|
|
2319
|
-
type: "list",
|
|
2320
|
-
name: "selected",
|
|
2321
|
-
message: question.prompt,
|
|
2322
|
-
choices,
|
|
2323
|
-
default: defaultIndex
|
|
2324
|
-
}
|
|
2325
|
-
]);
|
|
2326
|
-
return {
|
|
2327
|
-
value: selected,
|
|
2328
|
-
source: "option"
|
|
2329
|
-
};
|
|
2330
|
-
} catch {
|
|
2331
|
-
return null;
|
|
2332
|
-
}
|
|
2333
|
-
};
|
|
2334
|
-
|
|
2335
|
-
const DEFAULT_PHASE_SUMMARY = {
|
|
2336
|
-
calls: 0,
|
|
2337
|
-
failures: 0,
|
|
2338
|
-
successRate: 0,
|
|
2339
|
-
avgDurationMs: 0
|
|
2340
|
-
};
|
|
2341
|
-
class ExecutionTelemetry {
|
|
2342
|
-
constructor(maxEvents = 2e3) {
|
|
2343
|
-
this.maxEvents = maxEvents;
|
|
2344
|
-
}
|
|
2345
|
-
events = [];
|
|
2346
|
-
record(event) {
|
|
2347
|
-
const entry = {
|
|
2348
|
-
id: `te-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
2349
|
-
timestamp: Date.now(),
|
|
2350
|
-
...event
|
|
2351
|
-
};
|
|
2352
|
-
this.events.push(entry);
|
|
2353
|
-
if (this.events.length > this.maxEvents) {
|
|
2354
|
-
this.events.shift();
|
|
2355
|
-
}
|
|
2356
|
-
return entry;
|
|
2357
|
-
}
|
|
2358
|
-
getRecent(limit = 50) {
|
|
2359
|
-
if (limit <= 0) {
|
|
2360
|
-
return [];
|
|
2361
|
-
}
|
|
2362
|
-
return this.events.slice(-limit);
|
|
2363
|
-
}
|
|
2364
|
-
summarize() {
|
|
2365
|
-
const phaseStats = {
|
|
2366
|
-
execution: { ...DEFAULT_PHASE_SUMMARY },
|
|
2367
|
-
intent: { ...DEFAULT_PHASE_SUMMARY },
|
|
2368
|
-
elicitation: { ...DEFAULT_PHASE_SUMMARY },
|
|
2369
|
-
skill: { ...DEFAULT_PHASE_SUMMARY },
|
|
2370
|
-
agent: { ...DEFAULT_PHASE_SUMMARY },
|
|
2371
|
-
mcp: { ...DEFAULT_PHASE_SUMMARY },
|
|
2372
|
-
route: { ...DEFAULT_PHASE_SUMMARY }
|
|
2373
|
-
};
|
|
2374
|
-
let totalSuccess = 0;
|
|
2375
|
-
let durationCount = 0;
|
|
2376
|
-
let durationTotal = 0;
|
|
2377
|
-
for (const event of this.events) {
|
|
2378
|
-
const summary = phaseStats[event.phase];
|
|
2379
|
-
summary.calls++;
|
|
2380
|
-
if (!event.success) {
|
|
2381
|
-
summary.failures++;
|
|
2382
|
-
} else {
|
|
2383
|
-
totalSuccess++;
|
|
2384
|
-
}
|
|
2385
|
-
if (typeof event.durationMs === "number") {
|
|
2386
|
-
durationTotal += event.durationMs;
|
|
2387
|
-
durationCount++;
|
|
2388
|
-
summary.avgDurationMs = (summary.avgDurationMs * (summary.calls - 1) + event.durationMs) / summary.calls;
|
|
2389
|
-
}
|
|
2390
|
-
summary.successRate = summary.calls === 0 ? 0 : (summary.calls - summary.failures) / summary.calls;
|
|
2391
|
-
}
|
|
2392
|
-
return {
|
|
2393
|
-
totalEvents: this.events.length,
|
|
2394
|
-
overallSuccessRate: this.events.length === 0 ? 0 : totalSuccess / this.events.length,
|
|
2395
|
-
avgDurationMs: durationCount === 0 ? 0 : durationTotal / durationCount,
|
|
2396
|
-
phaseStats
|
|
2397
|
-
};
|
|
2398
|
-
}
|
|
2399
|
-
clear() {
|
|
2400
|
-
this.events = [];
|
|
2401
|
-
}
|
|
2402
|
-
}
|
|
2403
|
-
let globalExecutionTelemetry = null;
|
|
2404
|
-
function getGlobalExecutionTelemetry() {
|
|
2405
|
-
if (!globalExecutionTelemetry) {
|
|
2406
|
-
globalExecutionTelemetry = new ExecutionTelemetry();
|
|
2407
|
-
}
|
|
2408
|
-
return globalExecutionTelemetry;
|
|
2409
|
-
}
|
|
2410
|
-
|
|
2411
|
-
class IntentRouter extends EventEmitter {
|
|
2412
|
-
config;
|
|
2413
|
-
// Keywords for intent detection
|
|
2414
|
-
mayorKeywords = [
|
|
2415
|
-
"implement",
|
|
2416
|
-
"build",
|
|
2417
|
-
"create",
|
|
2418
|
-
"add",
|
|
2419
|
-
"develop",
|
|
2420
|
-
"integrate",
|
|
2421
|
-
"system",
|
|
2422
|
-
"architecture",
|
|
2423
|
-
"multiple",
|
|
2424
|
-
"complex",
|
|
2425
|
-
"full",
|
|
2426
|
-
"authentication",
|
|
2427
|
-
"authorization",
|
|
2428
|
-
"api",
|
|
2429
|
-
"database",
|
|
2430
|
-
"backend",
|
|
2431
|
-
"frontend",
|
|
2432
|
-
"ui",
|
|
2433
|
-
"ux",
|
|
2434
|
-
"design",
|
|
2435
|
-
"workflow"
|
|
2436
|
-
];
|
|
2437
|
-
planKeywords = [
|
|
2438
|
-
"plan",
|
|
2439
|
-
"design",
|
|
2440
|
-
"architect",
|
|
2441
|
-
"structure",
|
|
2442
|
-
"organize",
|
|
2443
|
-
"refactor",
|
|
2444
|
-
"restructure",
|
|
2445
|
-
"reorganize",
|
|
2446
|
-
"improve",
|
|
2447
|
-
"how to",
|
|
2448
|
-
"approach",
|
|
2449
|
-
"strategy",
|
|
2450
|
-
"best way"
|
|
2451
|
-
];
|
|
2452
|
-
featureKeywords = [
|
|
2453
|
-
"add",
|
|
2454
|
-
"create",
|
|
2455
|
-
"implement",
|
|
2456
|
-
"build",
|
|
2457
|
-
"make",
|
|
2458
|
-
"feature",
|
|
2459
|
-
"function",
|
|
2460
|
-
"component",
|
|
2461
|
-
"module",
|
|
2462
|
-
"button",
|
|
2463
|
-
"form",
|
|
2464
|
-
"page",
|
|
2465
|
-
"endpoint",
|
|
2466
|
-
"route"
|
|
2467
|
-
];
|
|
2468
|
-
bugFixKeywords = [
|
|
2469
|
-
"fix",
|
|
2470
|
-
"bug",
|
|
2471
|
-
"error",
|
|
2472
|
-
"issue",
|
|
2473
|
-
"problem",
|
|
2474
|
-
"broken",
|
|
2475
|
-
"not working",
|
|
2476
|
-
"crash",
|
|
2477
|
-
"fail",
|
|
2478
|
-
"debug",
|
|
2479
|
-
"resolve",
|
|
2480
|
-
"solve"
|
|
2481
|
-
];
|
|
2482
|
-
questionKeywords = [
|
|
2483
|
-
"what",
|
|
2484
|
-
"how",
|
|
2485
|
-
"why",
|
|
2486
|
-
"when",
|
|
2487
|
-
"where",
|
|
2488
|
-
"which",
|
|
2489
|
-
"explain",
|
|
2490
|
-
"tell me",
|
|
2491
|
-
"show me",
|
|
2492
|
-
"help",
|
|
2493
|
-
"can you",
|
|
2494
|
-
"could you",
|
|
2495
|
-
"would you"
|
|
2496
|
-
];
|
|
2497
|
-
constructor(config = {}) {
|
|
2498
|
-
super();
|
|
2499
|
-
this.config = {
|
|
2500
|
-
mayorComplexityThreshold: config.mayorComplexityThreshold || "complex",
|
|
2501
|
-
planComplexityThreshold: config.planComplexityThreshold || "moderate",
|
|
2502
|
-
autoRoute: config.autoRoute !== void 0 ? config.autoRoute : true,
|
|
2503
|
-
askConfirmation: config.askConfirmation !== void 0 ? config.askConfirmation : false,
|
|
2504
|
-
verbose: config.verbose !== void 0 ? config.verbose : false
|
|
2505
|
-
};
|
|
2506
|
-
}
|
|
2507
|
-
/**
|
|
2508
|
-
* Analyze user input and determine intent
|
|
2509
|
-
*/
|
|
2510
|
-
async analyze(input) {
|
|
2511
|
-
const normalized = input.toLowerCase().trim();
|
|
2512
|
-
const complexity = this.calculateComplexity(normalized);
|
|
2513
|
-
const type = this.detectIntentType(normalized);
|
|
2514
|
-
const keywords = this.extractKeywords(normalized);
|
|
2515
|
-
const requiresPlanning = this.needsPlanning(normalized, complexity);
|
|
2516
|
-
const requiresMultipleAgents = this.needsMultipleAgents(normalized, complexity);
|
|
2517
|
-
const estimatedSteps = this.estimateSteps(normalized, complexity);
|
|
2518
|
-
const confidence = this.calculateConfidence(type, complexity, keywords);
|
|
2519
|
-
const suggestedRoute = this.determineSuggestedRoute(
|
|
2520
|
-
type,
|
|
2521
|
-
complexity,
|
|
2522
|
-
requiresPlanning,
|
|
2523
|
-
requiresMultipleAgents
|
|
2524
|
-
);
|
|
2525
|
-
const reasoning = this.generateReasoning(
|
|
2526
|
-
type,
|
|
2527
|
-
complexity,
|
|
2528
|
-
suggestedRoute,
|
|
2529
|
-
requiresPlanning,
|
|
2530
|
-
requiresMultipleAgents,
|
|
2531
|
-
estimatedSteps
|
|
2532
|
-
);
|
|
2533
|
-
const intent = {
|
|
2534
|
-
type,
|
|
2535
|
-
complexity,
|
|
2536
|
-
confidence,
|
|
2537
|
-
reasoning,
|
|
2538
|
-
suggestedRoute,
|
|
2539
|
-
keywords,
|
|
2540
|
-
requiresPlanning,
|
|
2541
|
-
requiresMultipleAgents,
|
|
2542
|
-
estimatedSteps
|
|
2543
|
-
};
|
|
2544
|
-
this.emit("intent:analyzed", intent);
|
|
2545
|
-
return intent;
|
|
2546
|
-
}
|
|
2547
|
-
/**
|
|
2548
|
-
* Route user input to appropriate system
|
|
2549
|
-
*/
|
|
2550
|
-
async route(input) {
|
|
2551
|
-
const intent = await this.analyze(input);
|
|
2552
|
-
let shouldExecute = this.config.autoRoute;
|
|
2553
|
-
if (this.config.askConfirmation && intent.complexity === "very_complex") {
|
|
2554
|
-
shouldExecute = false;
|
|
2555
|
-
}
|
|
2556
|
-
const message = this.generateRouteMessage(intent);
|
|
2557
|
-
this.emit("route:determined", {
|
|
2558
|
-
route: intent.suggestedRoute,
|
|
2559
|
-
intent,
|
|
2560
|
-
shouldExecute
|
|
2561
|
-
});
|
|
2562
|
-
return {
|
|
2563
|
-
route: intent.suggestedRoute,
|
|
2564
|
-
intent,
|
|
2565
|
-
shouldExecute,
|
|
2566
|
-
message
|
|
2567
|
-
};
|
|
2568
|
-
}
|
|
2569
|
-
/**
|
|
2570
|
-
* Calculate complexity level
|
|
2571
|
-
*/
|
|
2572
|
-
calculateComplexity(input) {
|
|
2573
|
-
let score = 0;
|
|
2574
|
-
const words = input.split(/\s+/).length;
|
|
2575
|
-
if (words > 50)
|
|
2576
|
-
score += 3;
|
|
2577
|
-
else if (words > 30)
|
|
2578
|
-
score += 2;
|
|
2579
|
-
else if (words > 15)
|
|
2580
|
-
score += 1;
|
|
2581
|
-
const components = ["frontend", "backend", "database", "api", "ui", "auth", "test"];
|
|
2582
|
-
const mentionedComponents = components.filter((c) => input.includes(c)).length;
|
|
2583
|
-
score += mentionedComponents;
|
|
2584
|
-
const actions = ["create", "update", "delete", "implement", "integrate", "test", "deploy"];
|
|
2585
|
-
const mentionedActions = actions.filter((a) => input.includes(a)).length;
|
|
2586
|
-
score += mentionedActions;
|
|
2587
|
-
const technicalTerms = [
|
|
2588
|
-
"authentication",
|
|
2589
|
-
"authorization",
|
|
2590
|
-
"middleware",
|
|
2591
|
-
"validation",
|
|
2592
|
-
"encryption",
|
|
2593
|
-
"jwt",
|
|
2594
|
-
"oauth",
|
|
2595
|
-
"websocket",
|
|
2596
|
-
"graphql",
|
|
2597
|
-
"rest",
|
|
2598
|
-
"microservice",
|
|
2599
|
-
"docker",
|
|
2600
|
-
"kubernetes",
|
|
2601
|
-
"ci/cd"
|
|
2602
|
-
];
|
|
2603
|
-
const mentionedTerms = technicalTerms.filter((t) => input.includes(t)).length;
|
|
2604
|
-
score += mentionedTerms * 2;
|
|
2605
|
-
if (input.match(/\band\b/gi)?.length || 0 > 2)
|
|
2606
|
-
score += 2;
|
|
2607
|
-
if (score >= 10)
|
|
2608
|
-
return "very_complex";
|
|
2609
|
-
if (score >= 7)
|
|
2610
|
-
return "complex";
|
|
2611
|
-
if (score >= 4)
|
|
2612
|
-
return "moderate";
|
|
2613
|
-
if (score >= 2)
|
|
2614
|
-
return "simple";
|
|
2615
|
-
return "trivial";
|
|
2616
|
-
}
|
|
2617
|
-
/**
|
|
2618
|
-
* Detect intent type from input
|
|
2619
|
-
*/
|
|
2620
|
-
detectIntentType(input) {
|
|
2621
|
-
if (this.matchesKeywords(input, this.questionKeywords)) {
|
|
2622
|
-
return "question";
|
|
2623
|
-
}
|
|
2624
|
-
if (this.matchesKeywords(input, this.bugFixKeywords)) {
|
|
2625
|
-
return "bug_fix";
|
|
2626
|
-
}
|
|
2627
|
-
if (this.matchesKeywords(input, this.planKeywords)) {
|
|
2628
|
-
return "plan";
|
|
2629
|
-
}
|
|
2630
|
-
if (this.matchesKeywords(input, this.featureKeywords)) {
|
|
2631
|
-
return "feature";
|
|
2632
|
-
}
|
|
2633
|
-
if (input.includes("refactor") || input.includes("improve") || input.includes("optimize")) {
|
|
2634
|
-
return "refactor";
|
|
2635
|
-
}
|
|
2636
|
-
if (this.matchesKeywords(input, this.mayorKeywords)) {
|
|
2637
|
-
return "mayor";
|
|
2638
|
-
}
|
|
2639
|
-
return "direct";
|
|
2640
|
-
}
|
|
2641
|
-
/**
|
|
2642
|
-
* Check if input matches keywords
|
|
2643
|
-
*/
|
|
2644
|
-
matchesKeywords(input, keywords) {
|
|
2645
|
-
return keywords.some((keyword) => input.includes(keyword));
|
|
2646
|
-
}
|
|
2647
|
-
/**
|
|
2648
|
-
* Extract relevant keywords
|
|
2649
|
-
*/
|
|
2650
|
-
extractKeywords(input) {
|
|
2651
|
-
const allKeywords = [
|
|
2652
|
-
...this.mayorKeywords,
|
|
2653
|
-
...this.planKeywords,
|
|
2654
|
-
...this.featureKeywords,
|
|
2655
|
-
...this.bugFixKeywords,
|
|
2656
|
-
...this.questionKeywords
|
|
2657
|
-
];
|
|
2658
|
-
return allKeywords.filter((keyword) => input.includes(keyword));
|
|
2659
|
-
}
|
|
2660
|
-
/**
|
|
2661
|
-
* Determine if planning is needed
|
|
2662
|
-
*/
|
|
2663
|
-
needsPlanning(input, complexity) {
|
|
2664
|
-
if (complexity === "very_complex")
|
|
2665
|
-
return true;
|
|
2666
|
-
if (this.matchesKeywords(input, this.planKeywords))
|
|
2667
|
-
return true;
|
|
2668
|
-
const architecturalKeywords = [
|
|
2669
|
-
"architecture",
|
|
2670
|
-
"structure",
|
|
2671
|
-
"design",
|
|
2672
|
-
"refactor",
|
|
2673
|
-
"reorganize",
|
|
2674
|
-
"restructure",
|
|
2675
|
-
"system"
|
|
2676
|
-
];
|
|
2677
|
-
if (this.matchesKeywords(input, architecturalKeywords))
|
|
2678
|
-
return true;
|
|
2679
|
-
if (complexity === "complex" || complexity === "moderate") {
|
|
2680
|
-
const components = ["frontend", "backend", "database", "api"];
|
|
2681
|
-
const mentionedComponents = components.filter((c) => input.includes(c)).length;
|
|
2682
|
-
if (mentionedComponents >= 2)
|
|
2683
|
-
return true;
|
|
2684
|
-
}
|
|
2685
|
-
return false;
|
|
2686
|
-
}
|
|
2687
|
-
/**
|
|
2688
|
-
* Determine if multiple agents are needed
|
|
2689
|
-
*/
|
|
2690
|
-
needsMultipleAgents(input, complexity) {
|
|
2691
|
-
if (complexity === "very_complex")
|
|
2692
|
-
return true;
|
|
2693
|
-
if (complexity === "complex")
|
|
2694
|
-
return true;
|
|
2695
|
-
const components = ["frontend", "backend", "database", "api", "test", "deploy"];
|
|
2696
|
-
const mentionedComponents = components.filter((c) => input.includes(c)).length;
|
|
2697
|
-
if (mentionedComponents >= 2)
|
|
2698
|
-
return true;
|
|
2699
|
-
const actions = ["create", "update", "delete", "test", "deploy", "integrate"];
|
|
2700
|
-
const mentionedActions = actions.filter((a) => input.includes(a)).length;
|
|
2701
|
-
if (mentionedActions >= 3)
|
|
2702
|
-
return true;
|
|
2703
|
-
return false;
|
|
2704
|
-
}
|
|
2705
|
-
/**
|
|
2706
|
-
* Estimate number of steps
|
|
2707
|
-
*/
|
|
2708
|
-
estimateSteps(input, complexity) {
|
|
2709
|
-
const baseSteps = {
|
|
2710
|
-
trivial: 1,
|
|
2711
|
-
simple: 2,
|
|
2712
|
-
moderate: 4,
|
|
2713
|
-
complex: 8,
|
|
2714
|
-
very_complex: 15
|
|
2715
|
-
};
|
|
2716
|
-
let steps = baseSteps[complexity];
|
|
2717
|
-
const components = ["frontend", "backend", "database", "api", "test", "deploy"];
|
|
2718
|
-
const mentionedComponents = components.filter((c) => input.includes(c)).length;
|
|
2719
|
-
steps += mentionedComponents * 2;
|
|
2720
|
-
const actions = ["create", "update", "delete", "integrate", "test", "deploy"];
|
|
2721
|
-
const mentionedActions = actions.filter((a) => input.includes(a)).length;
|
|
2722
|
-
steps += mentionedActions;
|
|
2723
|
-
return Math.min(steps, 30);
|
|
2724
|
-
}
|
|
2725
|
-
/**
|
|
2726
|
-
* Calculate confidence score
|
|
2727
|
-
*/
|
|
2728
|
-
calculateConfidence(type, complexity, keywords) {
|
|
2729
|
-
let confidence = 0.5;
|
|
2730
|
-
confidence += Math.min(keywords.length * 0.05, 0.3);
|
|
2731
|
-
if (type !== "direct") {
|
|
2732
|
-
confidence += 0.2;
|
|
2733
|
-
}
|
|
2734
|
-
return Math.min(confidence, 1);
|
|
2735
|
-
}
|
|
2736
|
-
/**
|
|
2737
|
-
* Determine suggested route
|
|
2738
|
-
*/
|
|
2739
|
-
determineSuggestedRoute(type, complexity, requiresPlanning, requiresMultipleAgents) {
|
|
2740
|
-
if (type === "question") {
|
|
2741
|
-
return "direct";
|
|
2742
|
-
}
|
|
2743
|
-
if (complexity === "very_complex" || requiresMultipleAgents) {
|
|
2744
|
-
return "mayor";
|
|
2745
|
-
}
|
|
2746
|
-
if (complexity === "complex" && requiresPlanning) {
|
|
2747
|
-
return "mayor";
|
|
2748
|
-
}
|
|
2749
|
-
if (type === "plan" || requiresPlanning) {
|
|
2750
|
-
return "plan";
|
|
2751
|
-
}
|
|
2752
|
-
if (complexity === "moderate" && (type === "feature" || type === "bug_fix")) {
|
|
2753
|
-
return "feature";
|
|
2754
|
-
}
|
|
2755
|
-
if (complexity === "simple" || complexity === "trivial") {
|
|
2756
|
-
return "direct";
|
|
2757
|
-
}
|
|
2758
|
-
return "feature";
|
|
2759
|
-
}
|
|
2760
|
-
/**
|
|
2761
|
-
* Generate reasoning explanation
|
|
2762
|
-
*/
|
|
2763
|
-
generateReasoning(type, complexity, route, requiresPlanning, requiresMultipleAgents, estimatedSteps) {
|
|
2764
|
-
const reasons = [];
|
|
2765
|
-
reasons.push(`Complexity: ${complexity}`);
|
|
2766
|
-
reasons.push(`Intent: ${type}`);
|
|
2767
|
-
if (requiresPlanning) {
|
|
2768
|
-
reasons.push("Requires architectural planning");
|
|
2769
|
-
}
|
|
2770
|
-
if (requiresMultipleAgents) {
|
|
2771
|
-
reasons.push("Requires multiple specialized agents");
|
|
2772
|
-
}
|
|
2773
|
-
reasons.push(`Estimated ${estimatedSteps} steps`);
|
|
2774
|
-
const routeReasons = {
|
|
2775
|
-
mayor: "Using Mayor Agent for orchestration",
|
|
2776
|
-
plan: "Using Plan Mode for architectural design",
|
|
2777
|
-
feature: "Using Feature Mode for implementation",
|
|
2778
|
-
direct: "Direct execution"
|
|
2779
|
-
};
|
|
2780
|
-
reasons.push(routeReasons[route]);
|
|
2781
|
-
return reasons.join(" \u2022 ");
|
|
2782
|
-
}
|
|
2783
|
-
/**
|
|
2784
|
-
* Generate user-friendly route message
|
|
2785
|
-
*/
|
|
2786
|
-
generateRouteMessage(intent) {
|
|
2787
|
-
const messages = {
|
|
2788
|
-
mayor: `\u{1F9E0} Mayor Agent will orchestrate this ${intent.complexity} task with ${intent.estimatedSteps} steps`,
|
|
2789
|
-
plan: `\u{1F4CB} Creating architectural plan for this ${intent.complexity} task`,
|
|
2790
|
-
feature: `\u26A1 Implementing feature directly (${intent.complexity} complexity)`,
|
|
2791
|
-
direct: `\u{1F680} Executing directly`
|
|
2792
|
-
};
|
|
2793
|
-
return messages[intent.suggestedRoute];
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2796
|
-
let globalRouter$1 = null;
|
|
2797
|
-
function getGlobalIntentRouter(config) {
|
|
2798
|
-
if (!globalRouter$1) {
|
|
2799
|
-
globalRouter$1 = new IntentRouter(config);
|
|
2800
|
-
}
|
|
2801
|
-
return globalRouter$1;
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
const MCP_TOOL_PROFILES = [
|
|
2805
|
-
{
|
|
2806
|
-
tool: "filesystem",
|
|
2807
|
-
keywords: ["file", "directory", "folder", "workspace", "path", "read", "write"],
|
|
2808
|
-
basePriority: 5,
|
|
2809
|
-
intentBoost: {
|
|
2810
|
-
feature: 2,
|
|
2811
|
-
refactor: 2,
|
|
2812
|
-
bug_fix: 2
|
|
2813
|
-
}
|
|
2814
|
-
},
|
|
2815
|
-
{
|
|
2816
|
-
tool: "github",
|
|
2817
|
-
keywords: ["github", "repository", "repo", "pr", "pull request", "issue", "commit"],
|
|
2818
|
-
basePriority: 4,
|
|
2819
|
-
intentBoost: {
|
|
2820
|
-
feature: 1,
|
|
2821
|
-
bug_fix: 1
|
|
2822
|
-
}
|
|
2823
|
-
},
|
|
2824
|
-
{
|
|
2825
|
-
tool: "web-search",
|
|
2826
|
-
keywords: ["search", "research", "web", "documentation", "docs", "latest", "reference"],
|
|
2827
|
-
basePriority: 3,
|
|
2828
|
-
intentBoost: {
|
|
2829
|
-
question: 2,
|
|
2830
|
-
plan: 1
|
|
2831
|
-
}
|
|
2832
|
-
},
|
|
2833
|
-
{
|
|
2834
|
-
tool: "context7",
|
|
2835
|
-
keywords: ["library", "framework", "package", "sdk", "api docs", "best practice"],
|
|
2836
|
-
basePriority: 4,
|
|
2837
|
-
intentBoost: {
|
|
2838
|
-
feature: 2,
|
|
2839
|
-
plan: 2,
|
|
2840
|
-
question: 1
|
|
2841
|
-
}
|
|
2842
|
-
},
|
|
2843
|
-
{
|
|
2844
|
-
tool: "ide",
|
|
2845
|
-
keywords: ["diagnostic", "error", "lint", "typecheck", "compile", "warning"],
|
|
2846
|
-
basePriority: 3,
|
|
2847
|
-
intentBoost: {
|
|
2848
|
-
bug_fix: 2,
|
|
2849
|
-
refactor: 1
|
|
2850
|
-
}
|
|
2851
|
-
},
|
|
2852
|
-
{
|
|
2853
|
-
tool: "playwright",
|
|
2854
|
-
keywords: ["browser", "webpage", "e2e", "ui test", "automation", "screenshot"],
|
|
2855
|
-
basePriority: 2,
|
|
2856
|
-
intentBoost: {
|
|
2857
|
-
feature: 1,
|
|
2858
|
-
bug_fix: 1
|
|
2859
|
-
}
|
|
2860
|
-
}
|
|
2861
|
-
];
|
|
2862
|
-
class AutoExecutor extends EventEmitter {
|
|
2863
|
-
config;
|
|
2864
|
-
metricsCollector = getMetricsCollector();
|
|
2865
|
-
constructor(config = {}) {
|
|
2866
|
-
super();
|
|
2867
|
-
this.config = {
|
|
2868
|
-
autoCreateSkills: config.autoCreateSkills !== void 0 ? config.autoCreateSkills : true,
|
|
2869
|
-
autoCreateAgents: config.autoCreateAgents !== void 0 ? config.autoCreateAgents : true,
|
|
2870
|
-
autoSelectMcp: config.autoSelectMcp !== void 0 ? config.autoSelectMcp : true,
|
|
2871
|
-
enableElicitation: config.enableElicitation !== void 0 ? config.enableElicitation : true,
|
|
2872
|
-
maxMcpTools: config.maxMcpTools !== void 0 ? Math.max(1, config.maxMcpTools) : 3,
|
|
2873
|
-
askUserQuestion: config.askUserQuestion || promptUserQuestion,
|
|
2874
|
-
intentRouter: config.intentRouter || getGlobalIntentRouter(),
|
|
2875
|
-
telemetry: config.telemetry || getGlobalExecutionTelemetry(),
|
|
2876
|
-
verbose: config.verbose !== void 0 ? config.verbose : false
|
|
2877
|
-
};
|
|
2878
|
-
}
|
|
2879
|
-
/**
|
|
2880
|
-
* Execute a user request after a router has selected this executor.
|
|
2881
|
-
*/
|
|
2882
|
-
async execute(userInput) {
|
|
2883
|
-
const executionId = `exec-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2884
|
-
const startedAt = Date.now();
|
|
2885
|
-
this.emit("execution:started", { input: userInput });
|
|
2886
|
-
this.emitCommandHook("command-start", {
|
|
2887
|
-
executionId,
|
|
2888
|
-
inputLength: userInput.length,
|
|
2889
|
-
source: "auto-executor"
|
|
2890
|
-
});
|
|
2891
|
-
this.config.telemetry.record({
|
|
2892
|
-
executionId,
|
|
2893
|
-
phase: "execution",
|
|
2894
|
-
action: "start",
|
|
2895
|
-
success: true,
|
|
2896
|
-
metadata: {
|
|
2897
|
-
inputLength: userInput.length
|
|
2898
|
-
}
|
|
2899
|
-
});
|
|
2900
|
-
try {
|
|
2901
|
-
const routeStart = Date.now();
|
|
2902
|
-
const routeResult = await this.config.intentRouter.route(userInput);
|
|
2903
|
-
this.config.telemetry.record({
|
|
2904
|
-
executionId,
|
|
2905
|
-
phase: "intent",
|
|
2906
|
-
action: "route",
|
|
2907
|
-
success: true,
|
|
2908
|
-
durationMs: Date.now() - routeStart,
|
|
2909
|
-
metadata: {
|
|
2910
|
-
initialRoute: routeResult.route,
|
|
2911
|
-
confidence: routeResult.intent.confidence,
|
|
2912
|
-
intentType: routeResult.intent.type,
|
|
2913
|
-
complexity: routeResult.intent.complexity
|
|
2914
|
-
}
|
|
2915
|
-
});
|
|
2916
|
-
this.emitCommandHook("command-telemetry", {
|
|
2917
|
-
executionId,
|
|
2918
|
-
phase: "intent",
|
|
2919
|
-
action: "route",
|
|
2920
|
-
route: routeResult.route,
|
|
2921
|
-
confidence: routeResult.intent.confidence
|
|
2922
|
-
});
|
|
2923
|
-
const elicitationResult = await this.resolveRouteWithElicitation(
|
|
2924
|
-
routeResult.route,
|
|
2925
|
-
routeResult.intent,
|
|
2926
|
-
executionId
|
|
2927
|
-
);
|
|
2928
|
-
const route = elicitationResult.route;
|
|
2929
|
-
const intent = elicitationResult.intent;
|
|
2930
|
-
this.log(`Intent analyzed: ${intent.type} (${intent.complexity})`);
|
|
2931
|
-
this.log(`Suggested route: ${route}`);
|
|
2932
|
-
const skillDetectStart = Date.now();
|
|
2933
|
-
const skillReq = await this.detectSkillRequirement(userInput, intent);
|
|
2934
|
-
this.config.telemetry.record({
|
|
2935
|
-
executionId,
|
|
2936
|
-
phase: "skill",
|
|
2937
|
-
action: "detect",
|
|
2938
|
-
success: true,
|
|
2939
|
-
durationMs: Date.now() - skillDetectStart,
|
|
2940
|
-
metadata: {
|
|
2941
|
-
needed: skillReq.needed,
|
|
2942
|
-
reason: skillReq.reason
|
|
2943
|
-
}
|
|
2944
|
-
});
|
|
2945
|
-
const agentDetectStart = Date.now();
|
|
2946
|
-
const agentReq = await this.detectAgentRequirement(userInput, intent);
|
|
2947
|
-
this.config.telemetry.record({
|
|
2948
|
-
executionId,
|
|
2949
|
-
phase: "agent",
|
|
2950
|
-
action: "detect",
|
|
2951
|
-
success: true,
|
|
2952
|
-
durationMs: Date.now() - agentDetectStart,
|
|
2953
|
-
metadata: {
|
|
2954
|
-
needed: agentReq.needed,
|
|
2955
|
-
reason: agentReq.reason
|
|
2956
|
-
}
|
|
2957
|
-
});
|
|
2958
|
-
const mcpDetectStart = Date.now();
|
|
2959
|
-
const mcpReq = await this.detectMcpRequirement(userInput, intent);
|
|
2960
|
-
this.config.telemetry.record({
|
|
2961
|
-
executionId,
|
|
2962
|
-
phase: "mcp",
|
|
2963
|
-
action: "detect",
|
|
2964
|
-
success: true,
|
|
2965
|
-
durationMs: Date.now() - mcpDetectStart,
|
|
2966
|
-
metadata: {
|
|
2967
|
-
needed: mcpReq.needed,
|
|
2968
|
-
selectedTools: mcpReq.tools,
|
|
2969
|
-
candidates: mcpReq.candidates,
|
|
2970
|
-
reason: mcpReq.reason
|
|
2971
|
-
}
|
|
2972
|
-
});
|
|
2973
|
-
const agentsCreated = [];
|
|
2974
|
-
const skillsCreated = [];
|
|
2975
|
-
const mcpToolsUsed = [];
|
|
2976
|
-
if (this.config.autoCreateSkills && skillReq.needed) {
|
|
2977
|
-
this.log(`Auto-creating skill: ${skillReq.skillName}`);
|
|
2978
|
-
const skillCreateStart = Date.now();
|
|
2979
|
-
const skillId = await this.autoCreateSkill(skillReq);
|
|
2980
|
-
skillsCreated.push(skillId);
|
|
2981
|
-
this.config.telemetry.record({
|
|
2982
|
-
executionId,
|
|
2983
|
-
phase: "skill",
|
|
2984
|
-
action: "create",
|
|
2985
|
-
success: true,
|
|
2986
|
-
durationMs: Date.now() - skillCreateStart,
|
|
2987
|
-
metadata: {
|
|
2988
|
-
skillId,
|
|
2989
|
-
skillName: skillReq.skillName
|
|
2990
|
-
}
|
|
2991
|
-
});
|
|
2992
|
-
this.emit("skill:created", { skillId, skillReq });
|
|
2993
|
-
}
|
|
2994
|
-
if (this.config.autoCreateAgents && agentReq.needed) {
|
|
2995
|
-
this.log(`Auto-creating agent: ${agentReq.domain}`);
|
|
2996
|
-
const agentCreateStart = Date.now();
|
|
2997
|
-
const agentId = await this.autoCreateAgent(agentReq);
|
|
2998
|
-
agentsCreated.push(agentId);
|
|
2999
|
-
this.config.telemetry.record({
|
|
3000
|
-
executionId,
|
|
3001
|
-
phase: "agent",
|
|
3002
|
-
action: "create",
|
|
3003
|
-
success: true,
|
|
3004
|
-
durationMs: Date.now() - agentCreateStart,
|
|
3005
|
-
metadata: {
|
|
3006
|
-
agentId,
|
|
3007
|
-
agentType: agentReq.agentType,
|
|
3008
|
-
domain: agentReq.domain
|
|
3009
|
-
}
|
|
3010
|
-
});
|
|
3011
|
-
this.emit("agent:created", { agentId, agentReq });
|
|
3012
|
-
}
|
|
3013
|
-
if (this.config.autoSelectMcp && mcpReq.needed) {
|
|
3014
|
-
this.log(`Auto-selecting MCP tools: ${mcpReq.tools.join(", ")}`);
|
|
3015
|
-
mcpToolsUsed.push(...mcpReq.tools);
|
|
3016
|
-
this.config.telemetry.record({
|
|
3017
|
-
executionId,
|
|
3018
|
-
phase: "mcp",
|
|
3019
|
-
action: "select",
|
|
3020
|
-
success: true,
|
|
3021
|
-
metadata: {
|
|
3022
|
-
tools: mcpReq.tools,
|
|
3023
|
-
candidates: mcpReq.candidates
|
|
3024
|
-
}
|
|
3025
|
-
});
|
|
3026
|
-
this.emit("mcp:selected", { tools: mcpReq.tools, mcpReq });
|
|
3027
|
-
}
|
|
3028
|
-
let result;
|
|
3029
|
-
const routeExecutionStart = Date.now();
|
|
3030
|
-
switch (route) {
|
|
3031
|
-
case "mayor":
|
|
3032
|
-
result = await this.executeMayor(userInput, intent, agentsCreated, skillsCreated, mcpToolsUsed);
|
|
3033
|
-
break;
|
|
3034
|
-
case "plan":
|
|
3035
|
-
result = await this.executePlan(userInput, intent, agentsCreated, skillsCreated, mcpToolsUsed);
|
|
3036
|
-
break;
|
|
3037
|
-
case "feature":
|
|
3038
|
-
result = await this.executeFeature(userInput, intent, agentsCreated, skillsCreated, mcpToolsUsed);
|
|
3039
|
-
break;
|
|
3040
|
-
case "direct":
|
|
3041
|
-
result = await this.executeDirect(userInput, intent, agentsCreated, skillsCreated, mcpToolsUsed);
|
|
3042
|
-
break;
|
|
3043
|
-
default:
|
|
3044
|
-
throw new Error(`Unknown route: ${route}`);
|
|
3045
|
-
}
|
|
3046
|
-
const routeDuration = Date.now() - routeExecutionStart;
|
|
3047
|
-
this.config.telemetry.record({
|
|
3048
|
-
executionId,
|
|
3049
|
-
phase: "route",
|
|
3050
|
-
action: route,
|
|
3051
|
-
success: true,
|
|
3052
|
-
durationMs: routeDuration,
|
|
3053
|
-
metadata: {
|
|
3054
|
-
intentType: intent.type,
|
|
3055
|
-
complexity: intent.complexity
|
|
3056
|
-
}
|
|
3057
|
-
});
|
|
3058
|
-
this.emitCommandHook("command-telemetry", {
|
|
3059
|
-
executionId,
|
|
3060
|
-
phase: "route",
|
|
3061
|
-
action: route,
|
|
3062
|
-
durationMs: routeDuration
|
|
3063
|
-
});
|
|
3064
|
-
const totalDuration = Date.now() - startedAt;
|
|
3065
|
-
this.metricsCollector.recordResponseTime("auto-executor", totalDuration);
|
|
3066
|
-
this.metricsCollector.recordTaskCompletion("auto-executor", true, totalDuration);
|
|
3067
|
-
this.config.telemetry.record({
|
|
3068
|
-
executionId,
|
|
3069
|
-
phase: "execution",
|
|
3070
|
-
action: "complete",
|
|
3071
|
-
success: true,
|
|
3072
|
-
durationMs: totalDuration,
|
|
3073
|
-
metadata: {
|
|
3074
|
-
route,
|
|
3075
|
-
agentsCreated: agentsCreated.length,
|
|
3076
|
-
skillsCreated: skillsCreated.length,
|
|
3077
|
-
mcpToolsUsed: mcpToolsUsed.length
|
|
3078
|
-
}
|
|
3079
|
-
});
|
|
3080
|
-
this.emitCommandHook("command-complete", {
|
|
3081
|
-
executionId,
|
|
3082
|
-
success: true,
|
|
3083
|
-
route,
|
|
3084
|
-
durationMs: totalDuration,
|
|
3085
|
-
mcpToolsUsed: mcpToolsUsed.length
|
|
3086
|
-
});
|
|
3087
|
-
result.insights = this.buildExecutionInsights({
|
|
3088
|
-
initialRoute: routeResult.route,
|
|
3089
|
-
resolvedRoute: route,
|
|
3090
|
-
elicitationAsked: elicitationResult.elicitationAsked,
|
|
3091
|
-
userSelectedRoute: elicitationResult.userSelectedRoute,
|
|
3092
|
-
mcpReq,
|
|
3093
|
-
totalDurationMs: totalDuration,
|
|
3094
|
-
executionId
|
|
3095
|
-
});
|
|
3096
|
-
this.emit("execution:completed", result);
|
|
3097
|
-
return result;
|
|
3098
|
-
} catch (error) {
|
|
3099
|
-
const totalDuration = Date.now() - startedAt;
|
|
3100
|
-
const errorMessage = this.getErrorMessage(error);
|
|
3101
|
-
this.metricsCollector.recordResponseTime("auto-executor", totalDuration);
|
|
3102
|
-
this.metricsCollector.recordTaskCompletion("auto-executor", false, totalDuration);
|
|
3103
|
-
this.metricsCollector.recordError("auto-executor", "execution_error", errorMessage);
|
|
3104
|
-
this.config.telemetry.record({
|
|
3105
|
-
executionId,
|
|
3106
|
-
phase: "execution",
|
|
3107
|
-
action: "complete",
|
|
3108
|
-
success: false,
|
|
3109
|
-
durationMs: totalDuration,
|
|
3110
|
-
metadata: {
|
|
3111
|
-
error: errorMessage
|
|
3112
|
-
}
|
|
3113
|
-
});
|
|
3114
|
-
this.emitCommandHook("command-complete", {
|
|
3115
|
-
executionId,
|
|
3116
|
-
success: false,
|
|
3117
|
-
durationMs: totalDuration,
|
|
3118
|
-
error: errorMessage
|
|
3119
|
-
});
|
|
3120
|
-
this.emit("execution:failed", { error, input: userInput });
|
|
3121
|
-
throw error;
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
/**
|
|
3125
|
-
* Resolve route with optional structured elicitation.
|
|
3126
|
-
* This keeps model autonomy but lets users disambiguate complex intent.
|
|
3127
|
-
*/
|
|
3128
|
-
async resolveRouteWithElicitation(suggestedRoute, intent, executionId) {
|
|
3129
|
-
if (!this.config.enableElicitation || !this.shouldAskRouteQuestion(intent)) {
|
|
3130
|
-
return {
|
|
3131
|
-
route: suggestedRoute,
|
|
3132
|
-
intent,
|
|
3133
|
-
elicitationAsked: false,
|
|
3134
|
-
userSelectedRoute: false
|
|
3135
|
-
};
|
|
3136
|
-
}
|
|
3137
|
-
const question = this.buildRouteQuestion(suggestedRoute, intent);
|
|
3138
|
-
const askStart = Date.now();
|
|
3139
|
-
const answer = await this.config.askUserQuestion(question);
|
|
3140
|
-
this.config.telemetry.record({
|
|
3141
|
-
executionId,
|
|
3142
|
-
phase: "elicitation",
|
|
3143
|
-
action: "route-choice",
|
|
3144
|
-
success: true,
|
|
3145
|
-
durationMs: Date.now() - askStart,
|
|
3146
|
-
metadata: {
|
|
3147
|
-
asked: true,
|
|
3148
|
-
suggestedRoute,
|
|
3149
|
-
answered: Boolean(answer),
|
|
3150
|
-
selected: answer?.value
|
|
3151
|
-
}
|
|
3152
|
-
});
|
|
3153
|
-
if (!answer) {
|
|
3154
|
-
return {
|
|
3155
|
-
route: suggestedRoute,
|
|
3156
|
-
intent,
|
|
3157
|
-
elicitationAsked: true,
|
|
3158
|
-
userSelectedRoute: false
|
|
3159
|
-
};
|
|
3160
|
-
}
|
|
3161
|
-
return this.applyRouteAnswer(suggestedRoute, intent, answer);
|
|
3162
|
-
}
|
|
3163
|
-
shouldAskRouteQuestion(intent) {
|
|
3164
|
-
if (intent.complexity === "trivial" || intent.complexity === "simple") {
|
|
3165
|
-
return false;
|
|
3166
|
-
}
|
|
3167
|
-
const lowConfidence = intent.confidence < 0.65;
|
|
3168
|
-
const multiRouteIndicators = intent.requiresPlanning && intent.requiresMultipleAgents;
|
|
3169
|
-
return lowConfidence || multiRouteIndicators;
|
|
3170
|
-
}
|
|
3171
|
-
buildRouteQuestion(suggestedRoute, intent) {
|
|
3172
|
-
const routeLabels = {
|
|
3173
|
-
direct: "Direct execution",
|
|
3174
|
-
feature: "Feature implementation",
|
|
3175
|
-
plan: "Plan first",
|
|
3176
|
-
mayor: "Multi-agent orchestration"
|
|
3177
|
-
};
|
|
3178
|
-
const options = [
|
|
3179
|
-
{
|
|
3180
|
-
value: suggestedRoute,
|
|
3181
|
-
label: `Use recommended: ${routeLabels[suggestedRoute]}`,
|
|
3182
|
-
description: `Best guess from intent analysis (confidence ${Math.round(intent.confidence * 100)}%)`
|
|
3183
|
-
},
|
|
3184
|
-
{
|
|
3185
|
-
value: "plan",
|
|
3186
|
-
label: routeLabels.plan,
|
|
3187
|
-
description: "Start with architecture and implementation plan"
|
|
3188
|
-
},
|
|
3189
|
-
{
|
|
3190
|
-
value: "feature",
|
|
3191
|
-
label: routeLabels.feature,
|
|
3192
|
-
description: "Implement directly with focused feature workflow"
|
|
3193
|
-
},
|
|
3194
|
-
{
|
|
3195
|
-
value: "direct",
|
|
3196
|
-
label: routeLabels.direct,
|
|
3197
|
-
description: "Run quickly without extra orchestration"
|
|
3198
|
-
},
|
|
3199
|
-
{
|
|
3200
|
-
value: "mayor",
|
|
3201
|
-
label: routeLabels.mayor,
|
|
3202
|
-
description: "Use specialized agents for decomposition and coordination"
|
|
3203
|
-
}
|
|
3204
|
-
].filter((option, index, arr) => arr.findIndex((x) => x.value === option.value) === index);
|
|
3205
|
-
return {
|
|
3206
|
-
id: "execution-route-choice",
|
|
3207
|
-
prompt: "How should I execute this request?",
|
|
3208
|
-
options,
|
|
3209
|
-
defaultValue: suggestedRoute
|
|
3210
|
-
};
|
|
3211
|
-
}
|
|
3212
|
-
applyRouteAnswer(suggestedRoute, intent, answer) {
|
|
3213
|
-
const selectedRoute = ["direct", "feature", "plan", "mayor"].includes(answer.value) ? answer.value : suggestedRoute;
|
|
3214
|
-
if (selectedRoute === suggestedRoute) {
|
|
3215
|
-
return {
|
|
3216
|
-
route: suggestedRoute,
|
|
3217
|
-
intent,
|
|
3218
|
-
elicitationAsked: true,
|
|
3219
|
-
userSelectedRoute: false
|
|
3220
|
-
};
|
|
3221
|
-
}
|
|
3222
|
-
return {
|
|
3223
|
-
route: selectedRoute,
|
|
3224
|
-
intent: {
|
|
3225
|
-
...intent,
|
|
3226
|
-
suggestedRoute: selectedRoute,
|
|
3227
|
-
reasoning: `${intent.reasoning} \u2022 User selected route: ${selectedRoute}`
|
|
3228
|
-
},
|
|
3229
|
-
elicitationAsked: true,
|
|
3230
|
-
userSelectedRoute: true
|
|
3231
|
-
};
|
|
3232
|
-
}
|
|
3233
|
-
/**
|
|
3234
|
-
* Detect if a new skill is needed
|
|
3235
|
-
*/
|
|
3236
|
-
async detectSkillRequirement(input, intent) {
|
|
3237
|
-
const normalized = input.toLowerCase();
|
|
3238
|
-
const technologies = [
|
|
3239
|
-
{ name: "react", type: "code" },
|
|
3240
|
-
{ name: "vue", type: "code" },
|
|
3241
|
-
{ name: "angular", type: "code" },
|
|
3242
|
-
{ name: "docker", type: "deployment" },
|
|
3243
|
-
{ name: "kubernetes", type: "deployment" },
|
|
3244
|
-
{ name: "graphql", type: "integration" },
|
|
3245
|
-
{ name: "websocket", type: "integration" },
|
|
3246
|
-
{ name: "oauth", type: "integration" },
|
|
3247
|
-
{ name: "jwt", type: "integration" }
|
|
3248
|
-
];
|
|
3249
|
-
for (const tech of technologies) {
|
|
3250
|
-
if (normalized.includes(tech.name)) {
|
|
3251
|
-
return {
|
|
3252
|
-
needed: true,
|
|
3253
|
-
skillName: `${tech.name}-specialist`,
|
|
3254
|
-
skillType: tech.type,
|
|
3255
|
-
reason: `Detected ${tech.name} technology requirement`
|
|
3256
|
-
};
|
|
3257
|
-
}
|
|
3258
|
-
}
|
|
3259
|
-
if (normalized.includes("authentication") || normalized.includes("auth")) {
|
|
3260
|
-
return {
|
|
3261
|
-
needed: true,
|
|
3262
|
-
skillName: "authentication-specialist",
|
|
3263
|
-
skillType: "integration",
|
|
3264
|
-
reason: "Authentication system requires specialized skill"
|
|
3265
|
-
};
|
|
3266
|
-
}
|
|
3267
|
-
if (normalized.includes("database") || normalized.includes("sql")) {
|
|
3268
|
-
return {
|
|
3269
|
-
needed: true,
|
|
3270
|
-
skillName: "database-specialist",
|
|
3271
|
-
skillType: "code",
|
|
3272
|
-
reason: "Database operations require specialized skill"
|
|
3273
|
-
};
|
|
3274
|
-
}
|
|
3275
|
-
if (normalized.includes("api") && normalized.includes("design")) {
|
|
3276
|
-
return {
|
|
3277
|
-
needed: true,
|
|
3278
|
-
skillName: "api-architect",
|
|
3279
|
-
skillType: "analysis",
|
|
3280
|
-
reason: "API design requires architectural skill"
|
|
3281
|
-
};
|
|
3282
|
-
}
|
|
3283
|
-
if (intent.complexity === "very_complex" || intent.complexity === "complex") {
|
|
3284
|
-
return {
|
|
3285
|
-
needed: true,
|
|
3286
|
-
skillName: `custom-${intent.type}-specialist`,
|
|
3287
|
-
skillType: "code",
|
|
3288
|
-
reason: `Complex ${intent.type} task requires specialized skill`
|
|
3289
|
-
};
|
|
3290
|
-
}
|
|
3291
|
-
return {
|
|
3292
|
-
needed: false,
|
|
3293
|
-
skillName: "",
|
|
3294
|
-
skillType: "code",
|
|
3295
|
-
reason: "No specialized skill needed"
|
|
3296
|
-
};
|
|
3297
|
-
}
|
|
3298
|
-
/**
|
|
3299
|
-
* Detect if a new agent is needed
|
|
3300
|
-
*/
|
|
3301
|
-
async detectAgentRequirement(input, intent) {
|
|
3302
|
-
const normalized = input.toLowerCase();
|
|
3303
|
-
if (normalized.includes("architecture") || normalized.includes("design system")) {
|
|
3304
|
-
return {
|
|
3305
|
-
needed: true,
|
|
3306
|
-
agentType: "architect",
|
|
3307
|
-
domain: "System Architecture",
|
|
3308
|
-
reason: "Architectural design requires architect agent"
|
|
3309
|
-
};
|
|
3310
|
-
}
|
|
3311
|
-
if (normalized.includes("deploy") || normalized.includes("ci/cd") || normalized.includes("docker")) {
|
|
3312
|
-
return {
|
|
3313
|
-
needed: true,
|
|
3314
|
-
agentType: "devops",
|
|
3315
|
-
domain: "DevOps & Deployment",
|
|
3316
|
-
reason: "Deployment tasks require DevOps agent"
|
|
3317
|
-
};
|
|
3318
|
-
}
|
|
3319
|
-
const specializations = [
|
|
3320
|
-
{ keywords: ["security", "encryption", "auth"], domain: "Security" },
|
|
3321
|
-
{ keywords: ["performance", "optimize", "cache"], domain: "Performance" },
|
|
3322
|
-
{ keywords: ["test", "testing", "qa"], domain: "Testing" },
|
|
3323
|
-
{ keywords: ["ui", "ux", "design", "frontend"], domain: "Frontend" },
|
|
3324
|
-
{ keywords: ["api", "backend", "server"], domain: "Backend" },
|
|
3325
|
-
{ keywords: ["database", "sql", "query"], domain: "Database" }
|
|
3326
|
-
];
|
|
3327
|
-
for (const spec of specializations) {
|
|
3328
|
-
if (spec.keywords.some((kw) => normalized.includes(kw))) {
|
|
3329
|
-
return {
|
|
3330
|
-
needed: true,
|
|
3331
|
-
agentType: "specialist",
|
|
3332
|
-
domain: spec.domain,
|
|
3333
|
-
reason: `${spec.domain} tasks require specialized agent`
|
|
3334
|
-
};
|
|
3335
|
-
}
|
|
3336
|
-
}
|
|
3337
|
-
if (intent.estimatedSteps > 5) {
|
|
3338
|
-
return {
|
|
3339
|
-
needed: true,
|
|
3340
|
-
agentType: "engineer",
|
|
3341
|
-
domain: "Implementation",
|
|
3342
|
-
reason: "Multi-step implementation requires engineer agent"
|
|
3343
|
-
};
|
|
3344
|
-
}
|
|
3345
|
-
return {
|
|
3346
|
-
needed: false,
|
|
3347
|
-
agentType: "engineer",
|
|
3348
|
-
domain: "",
|
|
3349
|
-
reason: "Existing agents can handle this task"
|
|
3350
|
-
};
|
|
3351
|
-
}
|
|
3352
|
-
/**
|
|
3353
|
-
* Detect which MCP tools are needed
|
|
3354
|
-
*/
|
|
3355
|
-
async detectMcpRequirement(input, intent) {
|
|
3356
|
-
const normalized = input.toLowerCase();
|
|
3357
|
-
const scoredTools = MCP_TOOL_PROFILES.map((profile) => {
|
|
3358
|
-
const matchedKeywords = profile.keywords.filter((keyword) => normalized.includes(keyword));
|
|
3359
|
-
if (matchedKeywords.length === 0) {
|
|
3360
|
-
return null;
|
|
3361
|
-
}
|
|
3362
|
-
const intentBoost = profile.intentBoost?.[intent.type] ?? 0;
|
|
3363
|
-
const complexityBoost = intent.complexity === "complex" || intent.complexity === "very_complex" ? 1 : 0;
|
|
3364
|
-
const score = profile.basePriority + matchedKeywords.length * 2 + intentBoost + complexityBoost;
|
|
3365
|
-
return {
|
|
3366
|
-
tool: profile.tool,
|
|
3367
|
-
score
|
|
3368
|
-
};
|
|
3369
|
-
}).filter((item) => item !== null).sort((a, b) => b.score - a.score);
|
|
3370
|
-
const candidates = scoredTools.map((item) => item.tool);
|
|
3371
|
-
const tools = scoredTools.slice(0, this.config.maxMcpTools).map((item) => item.tool);
|
|
3372
|
-
return {
|
|
3373
|
-
needed: tools.length > 0,
|
|
3374
|
-
tools,
|
|
3375
|
-
candidates,
|
|
3376
|
-
reason: tools.length > 0 ? candidates.length > tools.length ? `Selected top ${tools.length}/${candidates.length} MCP tools by capability score: ${tools.join(", ")}` : `Requires MCP tools: ${tools.join(", ")}` : "No MCP tools needed"
|
|
3377
|
-
};
|
|
3378
|
-
}
|
|
3379
|
-
/**
|
|
3380
|
-
* Auto-create a skill
|
|
3381
|
-
*/
|
|
3382
|
-
async autoCreateSkill(req) {
|
|
3383
|
-
const skillId = `skill-${req.skillName}-${Date.now()}`;
|
|
3384
|
-
const skillDefinition = {
|
|
3385
|
-
id: skillId,
|
|
3386
|
-
name: req.skillName,
|
|
3387
|
-
type: req.skillType,
|
|
3388
|
-
description: `Auto-generated skill for ${req.reason}`,
|
|
3389
|
-
capabilities: this.generateSkillCapabilities(req),
|
|
3390
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3391
|
-
autoGenerated: true
|
|
3392
|
-
};
|
|
3393
|
-
const stateManager = getGlobalStateManager();
|
|
3394
|
-
await stateManager.initialize();
|
|
3395
|
-
await stateManager.createAgentWorktree(skillId);
|
|
3396
|
-
await stateManager.saveState(skillId, {
|
|
3397
|
-
agentId: skillId,
|
|
3398
|
-
status: "active",
|
|
3399
|
-
currentTask: "Ready",
|
|
3400
|
-
memory: { skillDefinition }
|
|
3401
|
-
});
|
|
3402
|
-
this.log(`Skill created: ${skillId}`);
|
|
3403
|
-
return skillId;
|
|
3404
|
-
}
|
|
3405
|
-
/**
|
|
3406
|
-
* Generate skill capabilities based on requirement
|
|
3407
|
-
*/
|
|
3408
|
-
generateSkillCapabilities(req) {
|
|
3409
|
-
const capabilitiesMap = {
|
|
3410
|
-
code: ["write_code", "review_code", "refactor_code", "debug_code"],
|
|
3411
|
-
analysis: ["analyze_requirements", "design_architecture", "create_diagrams", "document_design"],
|
|
3412
|
-
integration: ["integrate_apis", "configure_services", "test_integration", "handle_auth"],
|
|
3413
|
-
deployment: ["deploy_application", "configure_infrastructure", "setup_ci_cd", "monitor_services"]
|
|
3414
|
-
};
|
|
3415
|
-
return capabilitiesMap[req.skillType] || ["general_task"];
|
|
3416
|
-
}
|
|
3417
|
-
/**
|
|
3418
|
-
* Auto-create an agent
|
|
3419
|
-
*/
|
|
3420
|
-
async autoCreateAgent(req) {
|
|
3421
|
-
const agentId = `agent-${req.agentType}-${Date.now()}`;
|
|
3422
|
-
const agentDefinition = {
|
|
3423
|
-
id: agentId,
|
|
3424
|
-
name: `${req.domain} ${req.agentType}`,
|
|
3425
|
-
type: req.agentType,
|
|
3426
|
-
domain: req.domain,
|
|
3427
|
-
status: "active",
|
|
3428
|
-
model: req.agentType === "architect" ? "opus" : "sonnet",
|
|
3429
|
-
capabilities: this.generateAgentCapabilities(req),
|
|
3430
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3431
|
-
autoGenerated: true
|
|
3432
|
-
};
|
|
3433
|
-
const stateManager = getGlobalStateManager();
|
|
3434
|
-
await stateManager.initialize();
|
|
3435
|
-
await stateManager.createAgentWorktree(agentId);
|
|
3436
|
-
await stateManager.saveState(agentId, {
|
|
3437
|
-
agentId,
|
|
3438
|
-
status: "active",
|
|
3439
|
-
currentTask: "Ready",
|
|
3440
|
-
memory: { agentDefinition }
|
|
3441
|
-
});
|
|
3442
|
-
const mailboxManager = getGlobalMailboxManager();
|
|
3443
|
-
await mailboxManager.initialize();
|
|
3444
|
-
await mailboxManager.createMailbox(agentId);
|
|
3445
|
-
this.log(`Agent created: ${agentId}`);
|
|
3446
|
-
return agentId;
|
|
3447
|
-
}
|
|
3448
|
-
/**
|
|
3449
|
-
* Generate agent capabilities based on requirement
|
|
3450
|
-
*/
|
|
3451
|
-
generateAgentCapabilities(req) {
|
|
3452
|
-
const capabilitiesMap = {
|
|
3453
|
-
architect: ["design_architecture", "create_plans", "review_design", "make_decisions"],
|
|
3454
|
-
specialist: ["deep_expertise", "solve_complex_problems", "optimize_solutions", "provide_guidance"],
|
|
3455
|
-
engineer: ["implement_features", "write_code", "test_code", "fix_bugs"],
|
|
3456
|
-
devops: ["deploy_applications", "manage_infrastructure", "setup_pipelines", "monitor_systems"]
|
|
3457
|
-
};
|
|
3458
|
-
return capabilitiesMap[req.agentType] || ["general_task"];
|
|
3459
|
-
}
|
|
3460
|
-
/**
|
|
3461
|
-
* Execute via Mayor Agent
|
|
3462
|
-
*/
|
|
3463
|
-
async executeMayor(input, intent, agentsCreated, skillsCreated, mcpToolsUsed) {
|
|
3464
|
-
this.log("Executing via Mayor Agent");
|
|
3465
|
-
const mayor = getGlobalMayorAgent({
|
|
3466
|
-
autoCreateConvoy: true,
|
|
3467
|
-
autoSpawnWorkers: true,
|
|
3468
|
-
monitorProgress: true,
|
|
3469
|
-
notifyHuman: true
|
|
3470
|
-
});
|
|
3471
|
-
const response = await mayor.processRequest(input);
|
|
3472
|
-
return {
|
|
3473
|
-
success: true,
|
|
3474
|
-
route: "mayor",
|
|
3475
|
-
intent,
|
|
3476
|
-
convoyId: response.convoyId,
|
|
3477
|
-
agentsCreated,
|
|
3478
|
-
skillsCreated,
|
|
3479
|
-
mcpToolsUsed,
|
|
3480
|
-
message: response.message,
|
|
3481
|
-
details: response
|
|
3482
|
-
};
|
|
3483
|
-
}
|
|
3484
|
-
/**
|
|
3485
|
-
* Execute via Plan Mode
|
|
3486
|
-
*/
|
|
3487
|
-
async executePlan(input, intent, agentsCreated, skillsCreated, mcpToolsUsed) {
|
|
3488
|
-
this.log("Executing via Plan Mode");
|
|
3489
|
-
const convoyManager = getGlobalConvoyManager();
|
|
3490
|
-
await convoyManager.initialize();
|
|
3491
|
-
const convoy = await convoyManager.create(`Plan: ${input.substring(0, 50)}`, {
|
|
3492
|
-
description: input,
|
|
3493
|
-
createdBy: "auto-executor"
|
|
3494
|
-
});
|
|
3495
|
-
await convoyManager.addTask(convoy.id, "Analyze requirements");
|
|
3496
|
-
await convoyManager.addTask(convoy.id, "Design architecture");
|
|
3497
|
-
await convoyManager.addTask(convoy.id, "Create implementation plan");
|
|
3498
|
-
await convoyManager.start(convoy.id);
|
|
3499
|
-
return {
|
|
3500
|
-
success: true,
|
|
3501
|
-
route: "plan",
|
|
3502
|
-
intent,
|
|
3503
|
-
convoyId: convoy.id,
|
|
3504
|
-
agentsCreated,
|
|
3505
|
-
skillsCreated,
|
|
3506
|
-
mcpToolsUsed,
|
|
3507
|
-
message: `Planning convoy created: ${convoy.id}`,
|
|
3508
|
-
details: { convoy }
|
|
3509
|
-
};
|
|
3510
|
-
}
|
|
3511
|
-
/**
|
|
3512
|
-
* Execute via Feature Mode
|
|
3513
|
-
*/
|
|
3514
|
-
async executeFeature(input, intent, agentsCreated, skillsCreated, mcpToolsUsed) {
|
|
3515
|
-
this.log("Executing via Feature Mode");
|
|
3516
|
-
const convoyManager = getGlobalConvoyManager();
|
|
3517
|
-
await convoyManager.initialize();
|
|
3518
|
-
const convoy = await convoyManager.create(`Feature: ${input.substring(0, 50)}`, {
|
|
3519
|
-
description: input,
|
|
3520
|
-
createdBy: "auto-executor"
|
|
3521
|
-
});
|
|
3522
|
-
await convoyManager.addTask(convoy.id, "Implement feature");
|
|
3523
|
-
await convoyManager.addTask(convoy.id, "Write tests");
|
|
3524
|
-
await convoyManager.addTask(convoy.id, "Update documentation");
|
|
3525
|
-
await convoyManager.start(convoy.id);
|
|
3526
|
-
return {
|
|
3527
|
-
success: true,
|
|
3528
|
-
route: "feature",
|
|
3529
|
-
intent,
|
|
3530
|
-
convoyId: convoy.id,
|
|
3531
|
-
agentsCreated,
|
|
3532
|
-
skillsCreated,
|
|
3533
|
-
mcpToolsUsed,
|
|
3534
|
-
message: `Feature convoy created: ${convoy.id}`,
|
|
3535
|
-
details: { convoy }
|
|
3536
|
-
};
|
|
3537
|
-
}
|
|
3538
|
-
/**
|
|
3539
|
-
* Execute directly
|
|
3540
|
-
*/
|
|
3541
|
-
async executeDirect(input, intent, agentsCreated, skillsCreated, mcpToolsUsed) {
|
|
3542
|
-
this.log("Executing directly");
|
|
3543
|
-
return {
|
|
3544
|
-
success: true,
|
|
3545
|
-
route: "direct",
|
|
3546
|
-
intent,
|
|
3547
|
-
agentsCreated,
|
|
3548
|
-
skillsCreated,
|
|
3549
|
-
mcpToolsUsed,
|
|
3550
|
-
message: `Direct execution: ${input}`,
|
|
3551
|
-
details: { input }
|
|
3552
|
-
};
|
|
3553
|
-
}
|
|
3554
|
-
buildExecutionInsights(options) {
|
|
3555
|
-
return {
|
|
3556
|
-
decisionProfile: options.userSelectedRoute ? "user_guided" : "automatic",
|
|
3557
|
-
routeDecision: {
|
|
3558
|
-
initial: options.initialRoute,
|
|
3559
|
-
final: options.resolvedRoute,
|
|
3560
|
-
elicitationAsked: options.elicitationAsked,
|
|
3561
|
-
userSelectedRoute: options.userSelectedRoute
|
|
3562
|
-
},
|
|
3563
|
-
mcpSelection: {
|
|
3564
|
-
selected: options.mcpReq.tools,
|
|
3565
|
-
candidates: options.mcpReq.candidates,
|
|
3566
|
-
truncated: options.mcpReq.candidates.length > options.mcpReq.tools.length,
|
|
3567
|
-
reason: options.mcpReq.reason
|
|
3568
|
-
},
|
|
3569
|
-
telemetry: {
|
|
3570
|
-
totalDurationMs: options.totalDurationMs,
|
|
3571
|
-
eventCount: this.getExecutionTelemetryEventCount(options.executionId)
|
|
3572
|
-
}
|
|
3573
|
-
};
|
|
3574
|
-
}
|
|
3575
|
-
getExecutionTelemetryEventCount(executionId) {
|
|
3576
|
-
return this.config.telemetry.getRecent(500).filter((event) => event.executionId === executionId).length;
|
|
3577
|
-
}
|
|
3578
|
-
/**
|
|
3579
|
-
* Get aggregated execution telemetry.
|
|
3580
|
-
*/
|
|
3581
|
-
getTelemetrySummary() {
|
|
3582
|
-
return this.config.telemetry.summarize();
|
|
3583
|
-
}
|
|
3584
|
-
/**
|
|
3585
|
-
* Get recent execution telemetry events.
|
|
3586
|
-
*/
|
|
3587
|
-
getTelemetryEvents(limit = 50) {
|
|
3588
|
-
return this.config.telemetry.getRecent(limit);
|
|
3589
|
-
}
|
|
3590
|
-
clearTelemetry() {
|
|
3591
|
-
this.config.telemetry.clear();
|
|
3592
|
-
}
|
|
3593
|
-
getErrorMessage(error) {
|
|
3594
|
-
if (error instanceof Error) {
|
|
3595
|
-
return error.message;
|
|
3596
|
-
}
|
|
3597
|
-
return String(error);
|
|
3598
|
-
}
|
|
3599
|
-
/**
|
|
3600
|
-
* Log message if verbose
|
|
3601
|
-
*/
|
|
3602
|
-
log(message) {
|
|
3603
|
-
if (this.config.verbose) {
|
|
3604
|
-
console.log(`[AutoExecutor] ${message}`);
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
emitCommandHook(event, data) {
|
|
3608
|
-
void emitCommandHookEvent(event, data);
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
let globalExecutor = null;
|
|
3612
|
-
function getGlobalAutoExecutor(config) {
|
|
3613
|
-
if (!globalExecutor) {
|
|
3614
|
-
globalExecutor = new AutoExecutor(config);
|
|
3615
|
-
}
|
|
3616
|
-
return globalExecutor;
|
|
3617
|
-
}
|
|
3618
|
-
|
|
3619
|
-
class CliInterceptor extends EventEmitter {
|
|
3620
|
-
config;
|
|
3621
|
-
autoExecutor = getGlobalAutoExecutor({
|
|
3622
|
-
autoCreateSkills: true,
|
|
3623
|
-
autoCreateAgents: true,
|
|
3624
|
-
autoSelectMcp: true,
|
|
3625
|
-
verbose: false
|
|
3626
|
-
});
|
|
3627
|
-
getActiveCodeTool() {
|
|
3628
|
-
const codeToolType = readZcfConfig()?.codeToolType;
|
|
3629
|
-
return isCodeToolType(codeToolType) ? codeToolType : DEFAULT_CODE_TOOL_TYPE;
|
|
3630
|
-
}
|
|
3631
|
-
getSystemCommands() {
|
|
3632
|
-
return getCodeToolNativeSlashCommands(this.getActiveCodeTool());
|
|
3633
|
-
}
|
|
3634
|
-
// Simple queries that don't need interception
|
|
3635
|
-
simpleQueryPatterns = [
|
|
3636
|
-
/^what is/i,
|
|
3637
|
-
/^who is/i,
|
|
3638
|
-
/^when was/i,
|
|
3639
|
-
/^where is/i,
|
|
3640
|
-
/^how do i/i,
|
|
3641
|
-
/^can you explain/i,
|
|
3642
|
-
/^tell me about/i
|
|
3643
|
-
];
|
|
3644
|
-
constructor(config = {}) {
|
|
3645
|
-
super();
|
|
3646
|
-
this.config = {
|
|
3647
|
-
enabled: config.enabled !== void 0 ? config.enabled : true,
|
|
3648
|
-
autoExecute: config.autoExecute !== void 0 ? config.autoExecute : true,
|
|
3649
|
-
showIntent: config.showIntent !== void 0 ? config.showIntent : true,
|
|
3650
|
-
bypassKeywords: config.bypassKeywords || [],
|
|
3651
|
-
ccjkOwnedSlashPrefixes: config.ccjkOwnedSlashPrefixes || ["/ccjk", "/ccjk:", "/plugin", "/plugins", "/skill"],
|
|
3652
|
-
verbose: config.verbose !== void 0 ? config.verbose : false
|
|
3653
|
-
};
|
|
3654
|
-
}
|
|
3655
|
-
/**
|
|
3656
|
-
* Intercept user input when this component is explicitly integrated.
|
|
3657
|
-
*/
|
|
3658
|
-
async intercept(userInput) {
|
|
3659
|
-
if (!this.config.enabled) {
|
|
3660
|
-
return {
|
|
3661
|
-
intercepted: false,
|
|
3662
|
-
reason: "Interceptor disabled"
|
|
3663
|
-
};
|
|
3664
|
-
}
|
|
3665
|
-
this.emit("intercept:started", { input: userInput });
|
|
3666
|
-
const bypassCheck = this.shouldBypass(userInput);
|
|
3667
|
-
if (bypassCheck.bypass) {
|
|
3668
|
-
await this.handleBypassedCommand(userInput, bypassCheck.reason);
|
|
3669
|
-
this.emit("intercept:bypassed", { input: userInput, reason: bypassCheck.reason });
|
|
3670
|
-
return {
|
|
3671
|
-
intercepted: false,
|
|
3672
|
-
reason: "Bypassed",
|
|
3673
|
-
bypassed: true,
|
|
3674
|
-
bypassReason: bypassCheck.reason
|
|
3675
|
-
};
|
|
3676
|
-
}
|
|
3677
|
-
try {
|
|
3678
|
-
this.log(`Intercepting: ${userInput.substring(0, 50)}...`);
|
|
3679
|
-
if (this.config.showIntent) {
|
|
3680
|
-
this.showIntentMessage(userInput);
|
|
3681
|
-
}
|
|
3682
|
-
const executionResult = await this.autoExecutor.execute(userInput);
|
|
3683
|
-
this.emit("intercept:completed", { input: userInput, result: executionResult });
|
|
3684
|
-
return {
|
|
3685
|
-
intercepted: true,
|
|
3686
|
-
reason: "Automatically routed and executed",
|
|
3687
|
-
executionResult
|
|
3688
|
-
};
|
|
3689
|
-
} catch (error) {
|
|
3690
|
-
this.emit("intercept:failed", { input: userInput, error });
|
|
3691
|
-
throw error;
|
|
3692
|
-
}
|
|
3693
|
-
}
|
|
3694
|
-
/**
|
|
3695
|
-
* Check if input should bypass interception
|
|
3696
|
-
*/
|
|
3697
|
-
shouldBypass(input) {
|
|
3698
|
-
const normalized = input.trim().toLowerCase();
|
|
3699
|
-
const systemCommands = this.getSystemCommands();
|
|
3700
|
-
if (normalized.startsWith("/")) {
|
|
3701
|
-
const isCcjkOwned = this.config.ccjkOwnedSlashPrefixes.some((prefix) => normalized.startsWith(prefix));
|
|
3702
|
-
if (!isCcjkOwned && systemCommands.some((cmd) => normalized.startsWith(cmd))) {
|
|
3703
|
-
return { bypass: true, reason: "Native slash command passthrough" };
|
|
3704
|
-
}
|
|
3705
|
-
}
|
|
3706
|
-
if (systemCommands.some((cmd) => normalized.startsWith(cmd))) {
|
|
3707
|
-
return { bypass: true, reason: "System command" };
|
|
3708
|
-
}
|
|
3709
|
-
if (this.config.bypassKeywords.some((kw) => normalized.includes(kw.toLowerCase()))) {
|
|
3710
|
-
return { bypass: true, reason: "Custom bypass keyword" };
|
|
3711
|
-
}
|
|
3712
|
-
if (this.simpleQueryPatterns.some((pattern) => pattern.test(input))) {
|
|
3713
|
-
return { bypass: true, reason: "Simple informational query" };
|
|
3714
|
-
}
|
|
3715
|
-
if (input.split(/\s+/).length <= 3) {
|
|
3716
|
-
return { bypass: true, reason: "Too short - likely a simple question" };
|
|
3717
|
-
}
|
|
3718
|
-
return { bypass: false, reason: "" };
|
|
3719
|
-
}
|
|
3720
|
-
/**
|
|
3721
|
-
* Show intent message to user
|
|
3722
|
-
*/
|
|
3723
|
-
showIntentMessage(_input) {
|
|
3724
|
-
console.log("\n\u{1F9E0} Brain router is handling this request...");
|
|
3725
|
-
console.log(" It may use skills, agents, and MCP tools based on the active routing config.\n");
|
|
3726
|
-
}
|
|
3727
|
-
async handleBypassedCommand(input, reason) {
|
|
3728
|
-
const normalized = input.trim().toLowerCase();
|
|
3729
|
-
const command = this.extractCommandName(normalized);
|
|
3730
|
-
if (normalized.startsWith("/clear")) {
|
|
3731
|
-
this.autoExecutor.clearTelemetry();
|
|
3732
|
-
contextLoader.clearCache();
|
|
3733
|
-
getSkillRegistry().clear();
|
|
3734
|
-
await emitCommandHookEvent("command-clear", {
|
|
3735
|
-
command,
|
|
3736
|
-
cleared: ["telemetry", "context-cache", "skill-registry"]
|
|
3737
|
-
});
|
|
3738
|
-
}
|
|
3739
|
-
if (normalized.startsWith("/")) {
|
|
3740
|
-
await emitCommandHookEvent("command-bypass", {
|
|
3741
|
-
command,
|
|
3742
|
-
reason
|
|
3743
|
-
});
|
|
3744
|
-
}
|
|
3745
|
-
}
|
|
3746
|
-
extractCommandName(input) {
|
|
3747
|
-
if (!input.startsWith("/")) {
|
|
3748
|
-
return "";
|
|
3749
|
-
}
|
|
3750
|
-
return input.split(/\s+/)[0];
|
|
3751
|
-
}
|
|
3752
|
-
/**
|
|
3753
|
-
* Enable interceptor
|
|
3754
|
-
*/
|
|
3755
|
-
enable() {
|
|
3756
|
-
this.config.enabled = true;
|
|
3757
|
-
this.emit("interceptor:enabled");
|
|
3758
|
-
}
|
|
3759
|
-
/**
|
|
3760
|
-
* Disable interceptor
|
|
3761
|
-
*/
|
|
3762
|
-
disable() {
|
|
3763
|
-
this.config.enabled = false;
|
|
3764
|
-
this.emit("interceptor:disabled");
|
|
3765
|
-
}
|
|
3766
|
-
/**
|
|
3767
|
-
* Check if interceptor is enabled
|
|
3768
|
-
*/
|
|
3769
|
-
isEnabled() {
|
|
3770
|
-
return this.config.enabled;
|
|
3771
|
-
}
|
|
3772
|
-
/**
|
|
3773
|
-
* Log message if verbose
|
|
3774
|
-
*/
|
|
3775
|
-
log(message) {
|
|
3776
|
-
if (this.config.verbose) {
|
|
3777
|
-
console.log(`[CliInterceptor] ${message}`);
|
|
3778
|
-
}
|
|
3779
|
-
}
|
|
3780
|
-
}
|
|
3781
|
-
let globalInterceptor = null;
|
|
3782
|
-
function getGlobalCliInterceptor(config) {
|
|
3783
|
-
if (!globalInterceptor) {
|
|
3784
|
-
globalInterceptor = new CliInterceptor(config);
|
|
3785
|
-
}
|
|
3786
|
-
return globalInterceptor;
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
class BrainRouter extends EventEmitter {
|
|
3790
|
-
interceptor = getGlobalCliInterceptor({
|
|
3791
|
-
enabled: true,
|
|
3792
|
-
autoExecute: true,
|
|
3793
|
-
showIntent: true,
|
|
3794
|
-
verbose: false
|
|
3795
|
-
});
|
|
3796
|
-
constructor() {
|
|
3797
|
-
super();
|
|
3798
|
-
this.interceptor.on("intercept:started", (data) => {
|
|
3799
|
-
this.emit("router:started", data);
|
|
3800
|
-
});
|
|
3801
|
-
this.interceptor.on("intercept:completed", (data) => {
|
|
3802
|
-
this.emit("router:completed", data);
|
|
3803
|
-
});
|
|
3804
|
-
this.interceptor.on("intercept:failed", (data) => {
|
|
3805
|
-
this.emit("router:failed", data);
|
|
3806
|
-
});
|
|
3807
|
-
this.interceptor.on("intercept:bypassed", (data) => {
|
|
3808
|
-
this.emit("router:bypassed", data);
|
|
3809
|
-
});
|
|
3810
|
-
}
|
|
3811
|
-
/**
|
|
3812
|
-
* Process user input - main entry point
|
|
3813
|
-
*
|
|
3814
|
-
* This is the ONLY function users/CLI need to call.
|
|
3815
|
-
* Everything else is automatic.
|
|
3816
|
-
*/
|
|
3817
|
-
async process(userInput) {
|
|
3818
|
-
try {
|
|
3819
|
-
const interceptionResult = await this.interceptor.intercept(userInput);
|
|
3820
|
-
if (interceptionResult.bypassed) {
|
|
3821
|
-
return {
|
|
3822
|
-
handled: false,
|
|
3823
|
-
passthrough: true,
|
|
3824
|
-
message: `Passing through to Claude Code: ${interceptionResult.bypassReason}`
|
|
3825
|
-
};
|
|
3826
|
-
}
|
|
3827
|
-
if (interceptionResult.intercepted && interceptionResult.executionResult) {
|
|
3828
|
-
return {
|
|
3829
|
-
handled: true,
|
|
3830
|
-
result: interceptionResult.executionResult,
|
|
3831
|
-
message: interceptionResult.executionResult.message
|
|
3832
|
-
};
|
|
3833
|
-
}
|
|
3834
|
-
return {
|
|
3835
|
-
handled: false,
|
|
3836
|
-
passthrough: true,
|
|
3837
|
-
message: "No interception needed"
|
|
3838
|
-
};
|
|
3839
|
-
} catch (error) {
|
|
3840
|
-
this.emit("router:error", { error, input: userInput });
|
|
3841
|
-
throw error;
|
|
3842
|
-
}
|
|
3843
|
-
}
|
|
3844
|
-
/**
|
|
3845
|
-
* Enable automatic routing
|
|
3846
|
-
*/
|
|
3847
|
-
enable() {
|
|
3848
|
-
this.interceptor.enable();
|
|
3849
|
-
this.emit("router:enabled");
|
|
3850
|
-
}
|
|
3851
|
-
/**
|
|
3852
|
-
* Disable automatic routing
|
|
3853
|
-
*/
|
|
3854
|
-
disable() {
|
|
3855
|
-
this.interceptor.disable();
|
|
3856
|
-
this.emit("router:disabled");
|
|
3857
|
-
}
|
|
3858
|
-
/**
|
|
3859
|
-
* Check if router is enabled
|
|
3860
|
-
*/
|
|
3861
|
-
isEnabled() {
|
|
3862
|
-
return this.interceptor.isEnabled();
|
|
3863
|
-
}
|
|
3864
|
-
}
|
|
3865
|
-
let globalRouter = null;
|
|
3866
|
-
function getGlobalBrainRouter() {
|
|
3867
|
-
if (!globalRouter) {
|
|
3868
|
-
globalRouter = new BrainRouter();
|
|
3869
|
-
}
|
|
3870
|
-
return globalRouter;
|
|
3871
|
-
}
|
|
3872
|
-
async function processUserInput(userInput) {
|
|
3873
|
-
const router = getGlobalBrainRouter();
|
|
3874
|
-
return await router.process(userInput);
|
|
3875
|
-
}
|
|
3876
|
-
|
|
3877
|
-
class BrainCliHook extends EventEmitter {
|
|
3878
|
-
config;
|
|
3879
|
-
initialized = false;
|
|
3880
|
-
constructor(config = {}) {
|
|
3881
|
-
super();
|
|
3882
|
-
this.config = {
|
|
3883
|
-
enabled: config.enabled !== void 0 ? config.enabled : true,
|
|
3884
|
-
silent: config.silent !== void 0 ? config.silent : false,
|
|
3885
|
-
fallbackToClaudeCode: config.fallbackToClaudeCode !== void 0 ? config.fallbackToClaudeCode : true
|
|
3886
|
-
};
|
|
3887
|
-
}
|
|
3888
|
-
/**
|
|
3889
|
-
* Initialize the hook
|
|
3890
|
-
*/
|
|
3891
|
-
async initialize() {
|
|
3892
|
-
if (this.initialized) {
|
|
3893
|
-
return;
|
|
3894
|
-
}
|
|
3895
|
-
const { getGlobalStateManager } = await import('./session-manager.mjs').then(function (n) { return n.b; });
|
|
3896
|
-
const { getGlobalMailboxManager } = await Promise.resolve().then(function () { return persistentMailbox; });
|
|
3897
|
-
const { getGlobalConvoyManager } = await import('./session-manager.mjs').then(function (n) { return n.d; });
|
|
3898
|
-
const stateManager = getGlobalStateManager();
|
|
3899
|
-
const mailboxManager = getGlobalMailboxManager();
|
|
3900
|
-
const convoyManager = getGlobalConvoyManager();
|
|
3901
|
-
await stateManager.initialize();
|
|
3902
|
-
await mailboxManager.initialize();
|
|
3903
|
-
await convoyManager.initialize();
|
|
3904
|
-
this.initialized = true;
|
|
3905
|
-
this.emit("hook:initialized");
|
|
3906
|
-
if (!this.config.silent) {
|
|
3907
|
-
console.log("\u{1F9E0} Brain system initialized - automatic routing enabled");
|
|
3908
|
-
}
|
|
3909
|
-
}
|
|
3910
|
-
/**
|
|
3911
|
-
* Process user input through the hook
|
|
3912
|
-
*/
|
|
3913
|
-
async processInput(userInput) {
|
|
3914
|
-
if (!this.config.enabled) {
|
|
3915
|
-
return {
|
|
3916
|
-
intercepted: false,
|
|
3917
|
-
handled: false,
|
|
3918
|
-
shouldContinue: true,
|
|
3919
|
-
message: "Hook disabled"
|
|
3920
|
-
};
|
|
3921
|
-
}
|
|
3922
|
-
if (!this.initialized) {
|
|
3923
|
-
await this.initialize();
|
|
3924
|
-
}
|
|
3925
|
-
try {
|
|
3926
|
-
SessionIntelligence.getInstance().recordMessage("user", userInput);
|
|
3927
|
-
const result = await processUserInput(userInput);
|
|
3928
|
-
if (result.handled && result.result) {
|
|
3929
|
-
this.emit("hook:handled", { input: userInput, result: result.result });
|
|
3930
|
-
if (!this.config.silent) {
|
|
3931
|
-
this.displayResult(result.result);
|
|
3932
|
-
}
|
|
3933
|
-
return {
|
|
3934
|
-
intercepted: true,
|
|
3935
|
-
handled: true,
|
|
3936
|
-
executionResult: result.result,
|
|
3937
|
-
shouldContinue: false,
|
|
3938
|
-
// Don't pass to Claude Code
|
|
3939
|
-
message: result.message
|
|
3940
|
-
};
|
|
3941
|
-
}
|
|
3942
|
-
if (result.passthrough) {
|
|
3943
|
-
this.emit("hook:passthrough", { input: userInput, reason: result.message });
|
|
3944
|
-
const additionalContext = this.config.silent ? void 0 : await this.buildAdditionalContext();
|
|
3945
|
-
return {
|
|
3946
|
-
intercepted: true,
|
|
3947
|
-
handled: false,
|
|
3948
|
-
shouldContinue: true,
|
|
3949
|
-
// Pass to Claude Code
|
|
3950
|
-
message: result.message,
|
|
3951
|
-
additionalContext
|
|
3952
|
-
};
|
|
3953
|
-
}
|
|
3954
|
-
return {
|
|
3955
|
-
intercepted: false,
|
|
3956
|
-
handled: false,
|
|
3957
|
-
shouldContinue: this.config.fallbackToClaudeCode,
|
|
3958
|
-
message: "No interception"
|
|
3959
|
-
};
|
|
3960
|
-
} catch (error) {
|
|
3961
|
-
this.emit("hook:error", { error, input: userInput });
|
|
3962
|
-
if (this.config.fallbackToClaudeCode) {
|
|
3963
|
-
console.error("Brain system error, falling back to Claude Code:", error);
|
|
3964
|
-
return {
|
|
3965
|
-
intercepted: true,
|
|
3966
|
-
handled: false,
|
|
3967
|
-
shouldContinue: true,
|
|
3968
|
-
message: "Error - falling back to Claude Code"
|
|
3969
|
-
};
|
|
3970
|
-
}
|
|
3971
|
-
throw error;
|
|
3972
|
-
}
|
|
3973
|
-
}
|
|
3974
|
-
/**
|
|
3975
|
-
* Display execution result to user
|
|
3976
|
-
*/
|
|
3977
|
-
displayResult(result) {
|
|
3978
|
-
console.log(`
|
|
3979
|
-
${"=".repeat(60)}`);
|
|
3980
|
-
console.log("\u{1F9E0} Brain System Result");
|
|
3981
|
-
console.log("=".repeat(60));
|
|
3982
|
-
console.log();
|
|
3983
|
-
const routeEmoji = {
|
|
3984
|
-
mayor: "\u{1F454}",
|
|
3985
|
-
plan: "\u{1F4CB}",
|
|
3986
|
-
feature: "\u26A1",
|
|
3987
|
-
direct: "\u{1F680}"
|
|
3988
|
-
};
|
|
3989
|
-
console.log(`${routeEmoji[result.route]} Route: ${result.route.toUpperCase()}`);
|
|
3990
|
-
console.log(`\u{1F4CA} Complexity: ${result.intent.complexity}`);
|
|
3991
|
-
console.log(`\u{1F3AF} Intent: ${result.intent.type}`);
|
|
3992
|
-
console.log();
|
|
3993
|
-
if (result.agentsCreated.length > 0) {
|
|
3994
|
-
console.log("\u{1F916} Agents Created:");
|
|
3995
|
-
for (const agent of result.agentsCreated) {
|
|
3996
|
-
console.log(` \u2713 ${agent}`);
|
|
3997
|
-
}
|
|
3998
|
-
console.log();
|
|
3999
|
-
}
|
|
4000
|
-
if (result.skillsCreated.length > 0) {
|
|
4001
|
-
console.log("\u{1F393} Skills Created:");
|
|
4002
|
-
for (const skill of result.skillsCreated) {
|
|
4003
|
-
console.log(` \u2713 ${skill}`);
|
|
4004
|
-
}
|
|
4005
|
-
console.log();
|
|
4006
|
-
}
|
|
4007
|
-
if (result.mcpToolsUsed.length > 0) {
|
|
4008
|
-
console.log("\u{1F527} MCP Tools Selected:");
|
|
4009
|
-
for (const tool of result.mcpToolsUsed) {
|
|
4010
|
-
console.log(` \u2713 ${tool}`);
|
|
4011
|
-
}
|
|
4012
|
-
console.log();
|
|
4013
|
-
}
|
|
4014
|
-
if (result.insights) {
|
|
4015
|
-
console.log("\u2728 Smart Upgrade Signals:");
|
|
4016
|
-
console.log(` Route decision: ${result.insights.routeDecision.initial} \u2192 ${result.insights.routeDecision.final}`);
|
|
4017
|
-
if (result.insights.routeDecision.userSelectedRoute) {
|
|
4018
|
-
console.log(" Mode: User-guided route disambiguation");
|
|
4019
|
-
} else if (result.insights.routeDecision.elicitationAsked) {
|
|
4020
|
-
console.log(" Mode: Asked for route preference (kept recommended)");
|
|
4021
|
-
} else {
|
|
4022
|
-
console.log(" Mode: Fully automatic route decision");
|
|
4023
|
-
}
|
|
4024
|
-
if (result.insights.mcpSelection.selected.length > 0) {
|
|
4025
|
-
if (result.insights.mcpSelection.truncated) {
|
|
4026
|
-
console.log(` MCP ranking: selected ${result.insights.mcpSelection.selected.length} of ${result.insights.mcpSelection.candidates.length} candidates`);
|
|
4027
|
-
}
|
|
4028
|
-
console.log(` MCP reason: ${result.insights.mcpSelection.reason}`);
|
|
4029
|
-
} else {
|
|
4030
|
-
console.log(" MCP reason: no external tools needed");
|
|
4031
|
-
}
|
|
4032
|
-
console.log(` Telemetry: ${result.insights.telemetry.eventCount} events, ${result.insights.telemetry.totalDurationMs}ms`);
|
|
4033
|
-
console.log();
|
|
4034
|
-
}
|
|
4035
|
-
if (result.convoyId) {
|
|
4036
|
-
console.log(`\u{1F4E6} Convoy: ${result.convoyId}`);
|
|
4037
|
-
console.log();
|
|
4038
|
-
}
|
|
4039
|
-
console.log("\u{1F4AC} Message:");
|
|
4040
|
-
console.log(` ${result.message}`);
|
|
4041
|
-
console.log();
|
|
4042
|
-
console.log("=".repeat(60));
|
|
4043
|
-
console.log();
|
|
4044
|
-
}
|
|
4045
|
-
/**
|
|
4046
|
-
* Build additional context string for PreToolUse hook injection.
|
|
4047
|
-
* Provides brain insights (task state, session context) to the model
|
|
4048
|
-
* without blocking tool execution. Claude Code 2.1+ feature.
|
|
4049
|
-
*/
|
|
4050
|
-
async buildAdditionalContext() {
|
|
4051
|
-
try {
|
|
4052
|
-
const { loadContextAtDepth } = await import('./session-manager.mjs').then(function (n) { return n.e; });
|
|
4053
|
-
const ctx = await loadContextAtDepth("L0");
|
|
4054
|
-
if (ctx.totalTokens > 0) {
|
|
4055
|
-
return `[Brain Context: ${ctx.layers.size} layers, ~${ctx.totalTokens} tokens, depth=${ctx.depth}]`;
|
|
4056
|
-
}
|
|
4057
|
-
return void 0;
|
|
4058
|
-
} catch {
|
|
4059
|
-
return void 0;
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
|
-
/**
|
|
4063
|
-
* Enable the hook
|
|
4064
|
-
*/
|
|
4065
|
-
enable() {
|
|
4066
|
-
this.config.enabled = true;
|
|
4067
|
-
this.emit("hook:enabled");
|
|
4068
|
-
}
|
|
4069
|
-
/**
|
|
4070
|
-
* Disable the hook
|
|
4071
|
-
*/
|
|
4072
|
-
disable() {
|
|
4073
|
-
this.config.enabled = false;
|
|
4074
|
-
this.emit("hook:disabled");
|
|
4075
|
-
}
|
|
4076
|
-
/**
|
|
4077
|
-
* Check if hook is enabled
|
|
4078
|
-
*/
|
|
4079
|
-
isEnabled() {
|
|
4080
|
-
return this.config.enabled;
|
|
4081
|
-
}
|
|
4082
|
-
}
|
|
4083
|
-
let globalHook = null;
|
|
4084
|
-
function getGlobalBrainHook(config) {
|
|
4085
|
-
if (!globalHook) {
|
|
4086
|
-
globalHook = new BrainCliHook(config);
|
|
4087
|
-
}
|
|
4088
|
-
return globalHook;
|
|
4089
|
-
}
|
|
4090
|
-
async function setupBrainHook(config) {
|
|
4091
|
-
const hook = getGlobalBrainHook(config);
|
|
4092
|
-
await hook.initialize();
|
|
4093
|
-
return hook;
|
|
4094
|
-
}
|
|
4095
|
-
|
|
4096
|
-
export { BrainCliHook, getGlobalBrainHook, setupBrainHook };
|