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/research.mjs
DELETED
|
@@ -1,1904 +0,0 @@
|
|
|
1
|
-
import a from './index5.mjs';
|
|
2
|
-
import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
|
|
3
|
-
import { T as TaskPersistence } from '../shared/ccjk.CNhnT6uQ.mjs';
|
|
4
|
-
import { m as matter } from '../shared/ccjk.y-a_1vK4.mjs';
|
|
5
|
-
import { writeFile, readFile } from './fs-operations.mjs';
|
|
6
|
-
import { j as join, d as dirname } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
7
|
-
import { existsSync, readFileSync, appendFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
8
|
-
import { homedir } from 'node:os';
|
|
9
|
-
import { e as executeCommand } from '../shared/ccjk.BnsY5WxD.mjs';
|
|
10
|
-
import '../shared/ccjk.BAGoDD49.mjs';
|
|
11
|
-
import 'node:crypto';
|
|
12
|
-
import 'better-sqlite3';
|
|
13
|
-
import 'fs';
|
|
14
|
-
import '../shared/ccjk.COweQ1RR.mjs';
|
|
15
|
-
import 'node:fs/promises';
|
|
16
|
-
import 'node:child_process';
|
|
17
|
-
import 'node:util';
|
|
18
|
-
|
|
19
|
-
const DEFAULT_RESEARCH_PROGRAM_PATH = ".ccjk/research/program.md";
|
|
20
|
-
const DEFAULT_RESEARCH_MAX_ROUNDS = 10;
|
|
21
|
-
const DEFAULT_RESEARCH_MAX_NO_IMPROVE_ROUNDS = 3;
|
|
22
|
-
const DEFAULT_RESEARCH_BUDGET_MS = 5 * 60 * 1e3;
|
|
23
|
-
function normalizePositiveInteger(value, fallback) {
|
|
24
|
-
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
if (typeof value === "string" && value.trim()) {
|
|
28
|
-
const parsed = Number.parseInt(value.trim(), 10);
|
|
29
|
-
if (Number.isInteger(parsed) && parsed > 0) {
|
|
30
|
-
return parsed;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return fallback;
|
|
34
|
-
}
|
|
35
|
-
function normalizeOptionalNumber(value) {
|
|
36
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
if (typeof value === "string" && value.trim()) {
|
|
40
|
-
const parsed = Number.parseFloat(value.trim());
|
|
41
|
-
if (Number.isFinite(parsed)) {
|
|
42
|
-
return parsed;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return void 0;
|
|
46
|
-
}
|
|
47
|
-
function normalizeObjective(value) {
|
|
48
|
-
return value === "maximize" || value === "minimize" || value === "auto" ? value : "auto";
|
|
49
|
-
}
|
|
50
|
-
function normalizeString(value) {
|
|
51
|
-
if (typeof value !== "string") {
|
|
52
|
-
return void 0;
|
|
53
|
-
}
|
|
54
|
-
const trimmed = value.trim();
|
|
55
|
-
return trimmed || void 0;
|
|
56
|
-
}
|
|
57
|
-
function resolveResearchProgramPath(programPath, cwd) {
|
|
58
|
-
return programPath ? join(cwd || process.cwd(), programPath) : join(cwd || process.cwd(), DEFAULT_RESEARCH_PROGRAM_PATH);
|
|
59
|
-
}
|
|
60
|
-
function createDefaultResearchProgramTemplate(cwd) {
|
|
61
|
-
const workingDirectory = cwd || process.cwd();
|
|
62
|
-
return `---
|
|
63
|
-
name: repo-research
|
|
64
|
-
metric: test_pass_rate
|
|
65
|
-
objective: maximize
|
|
66
|
-
baselineCommand: pnpm test:run
|
|
67
|
-
candidateCommand: pnpm test:run
|
|
68
|
-
cwd: ${workingDirectory}
|
|
69
|
-
maxRounds: ${DEFAULT_RESEARCH_MAX_ROUNDS}
|
|
70
|
-
maxNoImproveRounds: ${DEFAULT_RESEARCH_MAX_NO_IMPROVE_ROUNDS}
|
|
71
|
-
budgetMs: ${DEFAULT_RESEARCH_BUDGET_MS}
|
|
72
|
-
targetMetric:
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
# Research Goal
|
|
76
|
-
|
|
77
|
-
Describe the optimization target for this repository.
|
|
78
|
-
|
|
79
|
-
## Guardrails
|
|
80
|
-
|
|
81
|
-
- Keep changes scoped and measurable.
|
|
82
|
-
- Prefer one candidate change per round.
|
|
83
|
-
- Stop when the target metric is reached or repeated no-improvement rounds occur.
|
|
84
|
-
|
|
85
|
-
## Notes
|
|
86
|
-
|
|
87
|
-
Document hypotheses, constraints, and any files or modules that must not change.
|
|
88
|
-
`;
|
|
89
|
-
}
|
|
90
|
-
function parseResearchProgram(content, programPath = DEFAULT_RESEARCH_PROGRAM_PATH) {
|
|
91
|
-
const parsed = matter(content);
|
|
92
|
-
const data = parsed.data || {};
|
|
93
|
-
const baselineCommand = normalizeString(data.baselineCommand);
|
|
94
|
-
if (!baselineCommand) {
|
|
95
|
-
throw new Error(`Missing required 'baselineCommand' in ${programPath}`);
|
|
96
|
-
}
|
|
97
|
-
const candidateCommand = normalizeString(data.candidateCommand);
|
|
98
|
-
if (!candidateCommand) {
|
|
99
|
-
throw new Error(`Missing required 'candidateCommand' in ${programPath}`);
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
name: normalizeString(data.name) || "repo-research",
|
|
103
|
-
metric: normalizeString(data.metric),
|
|
104
|
-
objective: normalizeObjective(data.objective),
|
|
105
|
-
baselineCommand,
|
|
106
|
-
candidateCommand,
|
|
107
|
-
cwd: normalizeString(data.cwd) || process.cwd(),
|
|
108
|
-
maxRounds: normalizePositiveInteger(data.maxRounds, DEFAULT_RESEARCH_MAX_ROUNDS),
|
|
109
|
-
maxNoImproveRounds: normalizePositiveInteger(data.maxNoImproveRounds, DEFAULT_RESEARCH_MAX_NO_IMPROVE_ROUNDS),
|
|
110
|
-
budgetMs: normalizePositiveInteger(data.budgetMs, DEFAULT_RESEARCH_BUDGET_MS),
|
|
111
|
-
targetMetric: normalizeOptionalNumber(data.targetMetric),
|
|
112
|
-
notes: parsed.content.trim(),
|
|
113
|
-
programPath
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
function readResearchProgram(programPath, cwd) {
|
|
117
|
-
const resolvedPath = resolveResearchProgramPath(programPath, cwd);
|
|
118
|
-
const content = readFile(resolvedPath);
|
|
119
|
-
return parseResearchProgram(content, resolvedPath);
|
|
120
|
-
}
|
|
121
|
-
function initResearchProgram(programPath, cwd) {
|
|
122
|
-
const resolvedPath = resolveResearchProgramPath(programPath, cwd);
|
|
123
|
-
const content = createDefaultResearchProgramTemplate(cwd);
|
|
124
|
-
writeFile(resolvedPath, content);
|
|
125
|
-
return {
|
|
126
|
-
programPath: resolvedPath,
|
|
127
|
-
content
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
class TaskQueue {
|
|
132
|
-
queue = [];
|
|
133
|
-
runningTasks = /* @__PURE__ */ new Set();
|
|
134
|
-
stats;
|
|
135
|
-
options;
|
|
136
|
-
taskIdCounter = 0;
|
|
137
|
-
executionTimes = [];
|
|
138
|
-
processing = false;
|
|
139
|
-
paused = false;
|
|
140
|
-
constructor(options = {}) {
|
|
141
|
-
this.options = {
|
|
142
|
-
concurrency: options.concurrency ?? Number.POSITIVE_INFINITY,
|
|
143
|
-
defaultTimeout: options.defaultTimeout ?? 3e4,
|
|
144
|
-
defaultMaxRetries: options.defaultMaxRetries ?? 0,
|
|
145
|
-
defaultRetryDelay: options.defaultRetryDelay ?? 1e3,
|
|
146
|
-
autoStart: options.autoStart ?? true
|
|
147
|
-
};
|
|
148
|
-
this.stats = {
|
|
149
|
-
totalTasks: 0,
|
|
150
|
-
pendingTasks: 0,
|
|
151
|
-
runningTasks: 0,
|
|
152
|
-
completedTasks: 0,
|
|
153
|
-
failedTasks: 0,
|
|
154
|
-
timeoutTasks: 0,
|
|
155
|
-
averageExecutionTime: 0,
|
|
156
|
-
createdAt: Date.now()
|
|
157
|
-
};
|
|
158
|
-
if (this.options.autoStart) {
|
|
159
|
-
this.start();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Add a task to the queue
|
|
164
|
-
*/
|
|
165
|
-
add(execute, options = {}) {
|
|
166
|
-
return new Promise((resolve, reject) => {
|
|
167
|
-
const task = {
|
|
168
|
-
id: this.generateTaskId(),
|
|
169
|
-
execute,
|
|
170
|
-
options: {
|
|
171
|
-
priority: options.priority ?? "normal",
|
|
172
|
-
timeout: options.timeout ?? this.options.defaultTimeout,
|
|
173
|
-
maxRetries: options.maxRetries ?? this.options.defaultMaxRetries,
|
|
174
|
-
retryDelay: options.retryDelay ?? this.options.defaultRetryDelay,
|
|
175
|
-
retryBackoff: options.retryBackoff ?? 1,
|
|
176
|
-
metadata: options.metadata ?? {}
|
|
177
|
-
},
|
|
178
|
-
createdAt: Date.now(),
|
|
179
|
-
retryCount: 0,
|
|
180
|
-
status: "pending",
|
|
181
|
-
resolve,
|
|
182
|
-
reject
|
|
183
|
-
};
|
|
184
|
-
this.queue.push(task);
|
|
185
|
-
this.stats.totalTasks++;
|
|
186
|
-
this.stats.pendingTasks++;
|
|
187
|
-
this.sortQueue();
|
|
188
|
-
if (!this.paused) {
|
|
189
|
-
this.processQueue();
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Start queue processing
|
|
195
|
-
*/
|
|
196
|
-
start() {
|
|
197
|
-
this.paused = false;
|
|
198
|
-
this.processQueue();
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Pause queue processing
|
|
202
|
-
*/
|
|
203
|
-
pause() {
|
|
204
|
-
this.paused = true;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Resume queue processing
|
|
208
|
-
*/
|
|
209
|
-
resume() {
|
|
210
|
-
this.start();
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Clear all pending tasks
|
|
214
|
-
*/
|
|
215
|
-
clear() {
|
|
216
|
-
const pendingTasks = this.queue.filter((task) => task.status === "pending");
|
|
217
|
-
pendingTasks.forEach((task) => {
|
|
218
|
-
task.status = "failed";
|
|
219
|
-
task.reject(new Error("Task cancelled: queue cleared"));
|
|
220
|
-
});
|
|
221
|
-
this.queue = this.queue.filter((task) => task.status === "running");
|
|
222
|
-
this.stats.pendingTasks = 0;
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Wait for all tasks to complete
|
|
226
|
-
*/
|
|
227
|
-
async drain() {
|
|
228
|
-
while (this.queue.length > 0 || this.runningTasks.size > 0) {
|
|
229
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Get queue statistics
|
|
234
|
-
*/
|
|
235
|
-
getStats() {
|
|
236
|
-
return { ...this.stats };
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Get current queue size
|
|
240
|
-
*/
|
|
241
|
-
size() {
|
|
242
|
-
return this.queue.length;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Check if queue is empty
|
|
246
|
-
*/
|
|
247
|
-
isEmpty() {
|
|
248
|
-
return this.queue.length === 0 && this.runningTasks.size === 0;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Check if queue is paused
|
|
252
|
-
*/
|
|
253
|
-
isPaused() {
|
|
254
|
-
return this.paused;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Process tasks in the queue
|
|
258
|
-
*/
|
|
259
|
-
async processQueue() {
|
|
260
|
-
if (this.processing || this.paused) {
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
this.processing = true;
|
|
264
|
-
while (!this.paused && this.queue.length > 0 && this.runningTasks.size < this.options.concurrency) {
|
|
265
|
-
const task = this.queue.find((t) => t.status === "pending");
|
|
266
|
-
if (!task) {
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
task.status = "running";
|
|
270
|
-
this.stats.pendingTasks--;
|
|
271
|
-
this.stats.runningTasks++;
|
|
272
|
-
this.runningTasks.add(task.id);
|
|
273
|
-
this.executeTask(task).catch(() => {
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
this.processing = false;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Execute a single task with timeout and retry support
|
|
280
|
-
*/
|
|
281
|
-
async executeTask(task) {
|
|
282
|
-
const startTime = Date.now();
|
|
283
|
-
try {
|
|
284
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
285
|
-
setTimeout(() => {
|
|
286
|
-
reject(new Error(`Task timeout after ${task.options.timeout}ms`));
|
|
287
|
-
}, task.options.timeout);
|
|
288
|
-
});
|
|
289
|
-
const result = await Promise.race([
|
|
290
|
-
task.execute(),
|
|
291
|
-
timeoutPromise
|
|
292
|
-
]);
|
|
293
|
-
const executionTime = Date.now() - startTime;
|
|
294
|
-
this.recordExecutionTime(executionTime);
|
|
295
|
-
task.status = "completed";
|
|
296
|
-
this.stats.completedTasks++;
|
|
297
|
-
task.resolve(result);
|
|
298
|
-
} catch (error) {
|
|
299
|
-
const isTimeout = error instanceof Error && error.message.includes("timeout");
|
|
300
|
-
if (isTimeout) {
|
|
301
|
-
task.status = "timeout";
|
|
302
|
-
this.stats.timeoutTasks++;
|
|
303
|
-
}
|
|
304
|
-
if (task.retryCount < task.options.maxRetries) {
|
|
305
|
-
task.retryCount++;
|
|
306
|
-
task.status = "pending";
|
|
307
|
-
const delay = task.options.retryDelay * task.options.retryBackoff ** (task.retryCount - 1);
|
|
308
|
-
setTimeout(() => {
|
|
309
|
-
this.stats.pendingTasks++;
|
|
310
|
-
this.sortQueue();
|
|
311
|
-
this.processQueue();
|
|
312
|
-
}, delay);
|
|
313
|
-
} else {
|
|
314
|
-
task.status = "failed";
|
|
315
|
-
this.stats.failedTasks++;
|
|
316
|
-
task.reject(error instanceof Error ? error : new Error(String(error)));
|
|
317
|
-
}
|
|
318
|
-
} finally {
|
|
319
|
-
this.runningTasks.delete(task.id);
|
|
320
|
-
this.stats.runningTasks--;
|
|
321
|
-
if (task.status === "completed" || task.status === "failed" || task.status === "timeout") {
|
|
322
|
-
this.queue = this.queue.filter((t) => t.id !== task.id);
|
|
323
|
-
}
|
|
324
|
-
this.processQueue();
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Sort queue by priority
|
|
329
|
-
*/
|
|
330
|
-
sortQueue() {
|
|
331
|
-
const priorityOrder = {
|
|
332
|
-
critical: 0,
|
|
333
|
-
high: 1,
|
|
334
|
-
normal: 2,
|
|
335
|
-
low: 3
|
|
336
|
-
};
|
|
337
|
-
this.queue.sort((a, b) => {
|
|
338
|
-
const priorityDiff = priorityOrder[a.options.priority] - priorityOrder[b.options.priority];
|
|
339
|
-
if (priorityDiff !== 0) {
|
|
340
|
-
return priorityDiff;
|
|
341
|
-
}
|
|
342
|
-
return a.createdAt - b.createdAt;
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Generate unique task ID
|
|
347
|
-
*/
|
|
348
|
-
generateTaskId() {
|
|
349
|
-
return `task_${++this.taskIdCounter}_${Date.now()}`;
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Record task execution time for statistics
|
|
353
|
-
*/
|
|
354
|
-
recordExecutionTime(time) {
|
|
355
|
-
this.executionTimes.push(time);
|
|
356
|
-
if (this.executionTimes.length > 100) {
|
|
357
|
-
this.executionTimes.shift();
|
|
358
|
-
}
|
|
359
|
-
const sum = this.executionTimes.reduce((acc, t) => acc + t, 0);
|
|
360
|
-
this.stats.averageExecutionTime = sum / this.executionTimes.length;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const DEFAULT_BUDGET_MS = 5 * 60 * 1e3;
|
|
365
|
-
const DEFAULT_SESSION_LIMIT = 10;
|
|
366
|
-
const RESEARCH_SESSION_KIND = "research";
|
|
367
|
-
const RESULTS_LEDGER_FILE = "research-results.tsv";
|
|
368
|
-
const RESULTS_LEDGER_HEADERS = [
|
|
369
|
-
"timestamp",
|
|
370
|
-
"sessionId",
|
|
371
|
-
"taskId",
|
|
372
|
-
"name",
|
|
373
|
-
"phase",
|
|
374
|
-
"verdict",
|
|
375
|
-
"status",
|
|
376
|
-
"exitCode",
|
|
377
|
-
"metricName",
|
|
378
|
-
"metricValue",
|
|
379
|
-
"durationMs",
|
|
380
|
-
"cwd",
|
|
381
|
-
"command"
|
|
382
|
-
];
|
|
383
|
-
class ResearchCommandError extends Error {
|
|
384
|
-
constructor(result) {
|
|
385
|
-
super(result.error || `Command exited with code ${result.exitCode}`);
|
|
386
|
-
this.result = result;
|
|
387
|
-
this.name = "ResearchCommandError";
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
function createPersistence$1(dbPath) {
|
|
391
|
-
return new TaskPersistence(dbPath);
|
|
392
|
-
}
|
|
393
|
-
function getResearchDataDir(dbPath) {
|
|
394
|
-
const resolvedDbPath = dbPath || join(homedir(), ".ccjk", "brain.db");
|
|
395
|
-
const dir = dirname(resolvedDbPath);
|
|
396
|
-
if (!existsSync(dir)) {
|
|
397
|
-
mkdirSync(dir, { recursive: true });
|
|
398
|
-
}
|
|
399
|
-
return dir;
|
|
400
|
-
}
|
|
401
|
-
function getResultsLedgerPath(dbPath) {
|
|
402
|
-
return join(getResearchDataDir(dbPath), RESULTS_LEDGER_FILE);
|
|
403
|
-
}
|
|
404
|
-
function escapeRegex(value) {
|
|
405
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
406
|
-
}
|
|
407
|
-
function extractMetricValue(output, metricName) {
|
|
408
|
-
if (!metricName) {
|
|
409
|
-
return void 0;
|
|
410
|
-
}
|
|
411
|
-
const matcher = new RegExp(`(?:^|\\b)${escapeRegex(metricName)}\\s*[:=]\\s*(-?\\d+(?:\\.\\d+)?)`, "im");
|
|
412
|
-
const match = output.match(matcher);
|
|
413
|
-
if (!match) {
|
|
414
|
-
return void 0;
|
|
415
|
-
}
|
|
416
|
-
const value = Number.parseFloat(match[1]);
|
|
417
|
-
return Number.isFinite(value) ? value : void 0;
|
|
418
|
-
}
|
|
419
|
-
function getFailureStatus(result, error) {
|
|
420
|
-
const message = [result.error, result.stderr, error?.message].filter(Boolean).join(" ");
|
|
421
|
-
return /timed out/i.test(message) ? "timeout" : "failed";
|
|
422
|
-
}
|
|
423
|
-
function inferResearchPhase(name) {
|
|
424
|
-
return /baseline/i.test(name) ? "baseline" : "experiment";
|
|
425
|
-
}
|
|
426
|
-
function buildPhaseHistory(runPhase) {
|
|
427
|
-
return ["brief", runPhase, "verify", "report"];
|
|
428
|
-
}
|
|
429
|
-
function sanitizeLedgerField(value) {
|
|
430
|
-
if (value === void 0 || value === null) {
|
|
431
|
-
return "";
|
|
432
|
-
}
|
|
433
|
-
return String(value).replace(/\t/g, " ").replace(/\r?\n/g, " ").trim();
|
|
434
|
-
}
|
|
435
|
-
function ensureResultsLedger(dbPath) {
|
|
436
|
-
const ledgerPath = getResultsLedgerPath(dbPath);
|
|
437
|
-
if (!existsSync(ledgerPath)) {
|
|
438
|
-
writeFileSync(ledgerPath, `${RESULTS_LEDGER_HEADERS.join(" ")}
|
|
439
|
-
`, "utf8");
|
|
440
|
-
}
|
|
441
|
-
return ledgerPath;
|
|
442
|
-
}
|
|
443
|
-
function serializeResultRow(row) {
|
|
444
|
-
const values = {
|
|
445
|
-
timestamp: sanitizeLedgerField(row.timestamp),
|
|
446
|
-
sessionId: sanitizeLedgerField(row.sessionId),
|
|
447
|
-
taskId: sanitizeLedgerField(row.taskId),
|
|
448
|
-
name: sanitizeLedgerField(row.name),
|
|
449
|
-
phase: sanitizeLedgerField(row.phase),
|
|
450
|
-
verdict: sanitizeLedgerField(row.verdict),
|
|
451
|
-
status: sanitizeLedgerField(row.status),
|
|
452
|
-
exitCode: sanitizeLedgerField(row.exitCode),
|
|
453
|
-
metricName: sanitizeLedgerField(row.metricName),
|
|
454
|
-
metricValue: sanitizeLedgerField(row.metricValue),
|
|
455
|
-
durationMs: sanitizeLedgerField(row.durationMs),
|
|
456
|
-
cwd: sanitizeLedgerField(row.cwd),
|
|
457
|
-
command: sanitizeLedgerField(row.command)
|
|
458
|
-
};
|
|
459
|
-
return RESULTS_LEDGER_HEADERS.map((header) => values[header]).join(" ");
|
|
460
|
-
}
|
|
461
|
-
function parseResultRow(line) {
|
|
462
|
-
if (!line.trim()) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
const columns = line.split(" ");
|
|
466
|
-
if (columns.length < RESULTS_LEDGER_HEADERS.length) {
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
const [
|
|
470
|
-
timestamp,
|
|
471
|
-
sessionId,
|
|
472
|
-
taskId,
|
|
473
|
-
name,
|
|
474
|
-
phase,
|
|
475
|
-
verdict,
|
|
476
|
-
status,
|
|
477
|
-
exitCode,
|
|
478
|
-
metricName,
|
|
479
|
-
metricValue,
|
|
480
|
-
durationMs,
|
|
481
|
-
cwd,
|
|
482
|
-
command
|
|
483
|
-
] = columns;
|
|
484
|
-
const parsedMetric = metricValue ? Number.parseFloat(metricValue) : void 0;
|
|
485
|
-
return {
|
|
486
|
-
timestamp,
|
|
487
|
-
sessionId,
|
|
488
|
-
taskId,
|
|
489
|
-
name,
|
|
490
|
-
phase: phase || "experiment",
|
|
491
|
-
verdict: verdict || "PARTIAL",
|
|
492
|
-
status,
|
|
493
|
-
exitCode: Number.parseInt(exitCode, 10) || 0,
|
|
494
|
-
metricName: metricName || void 0,
|
|
495
|
-
metricValue: Number.isFinite(parsedMetric) ? parsedMetric : void 0,
|
|
496
|
-
durationMs: Number.parseInt(durationMs, 10) || 0,
|
|
497
|
-
cwd,
|
|
498
|
-
command
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
function appendResultRow(row, dbPath) {
|
|
502
|
-
const ledgerPath = ensureResultsLedger(dbPath);
|
|
503
|
-
appendFileSync(ledgerPath, `${serializeResultRow(row)}
|
|
504
|
-
`, "utf8");
|
|
505
|
-
}
|
|
506
|
-
function readAllResultRows(dbPath) {
|
|
507
|
-
const ledgerPath = getResultsLedgerPath(dbPath);
|
|
508
|
-
if (!existsSync(ledgerPath)) {
|
|
509
|
-
return [];
|
|
510
|
-
}
|
|
511
|
-
const content = readFileSync(ledgerPath, "utf8");
|
|
512
|
-
const lines = content.split(/\r?\n/).filter(Boolean);
|
|
513
|
-
if (lines.length <= 1) {
|
|
514
|
-
return [];
|
|
515
|
-
}
|
|
516
|
-
return lines.slice(1).map(parseResultRow).filter((row) => Boolean(row));
|
|
517
|
-
}
|
|
518
|
-
function resolveResearchObjective(metricName, objective = "auto") {
|
|
519
|
-
if (objective === "maximize" || objective === "minimize") {
|
|
520
|
-
return objective;
|
|
521
|
-
}
|
|
522
|
-
const normalized = (metricName || "").toLowerCase();
|
|
523
|
-
if (!normalized) {
|
|
524
|
-
return "maximize";
|
|
525
|
-
}
|
|
526
|
-
const lowerIsBetter = ["loss", "error", "bpb", "perplexity", "ppl", "latency", "duration", "time", "cost", "price", "wer", "cer"];
|
|
527
|
-
if (lowerIsBetter.some((keyword) => normalized.includes(keyword))) {
|
|
528
|
-
return "minimize";
|
|
529
|
-
}
|
|
530
|
-
return "maximize";
|
|
531
|
-
}
|
|
532
|
-
function compareMetricValues(baselineMetricValue, candidateMetricValue, objective) {
|
|
533
|
-
if (baselineMetricValue === void 0 || candidateMetricValue === void 0) {
|
|
534
|
-
return "unknown";
|
|
535
|
-
}
|
|
536
|
-
if (candidateMetricValue === baselineMetricValue) {
|
|
537
|
-
return "equal";
|
|
538
|
-
}
|
|
539
|
-
if (objective === "minimize") {
|
|
540
|
-
return candidateMetricValue < baselineMetricValue ? "better" : "worse";
|
|
541
|
-
}
|
|
542
|
-
return candidateMetricValue > baselineMetricValue ? "better" : "worse";
|
|
543
|
-
}
|
|
544
|
-
function formatSignedNumber(value) {
|
|
545
|
-
if (value === void 0) {
|
|
546
|
-
return "unknown";
|
|
547
|
-
}
|
|
548
|
-
return `${value > 0 ? "+" : ""}${value}`;
|
|
549
|
-
}
|
|
550
|
-
function formatPercent(value) {
|
|
551
|
-
if (value === void 0) {
|
|
552
|
-
return "unknown";
|
|
553
|
-
}
|
|
554
|
-
return `${value > 0 ? "+" : ""}${value.toFixed(2)}%`;
|
|
555
|
-
}
|
|
556
|
-
function buildComparisonSummary(input) {
|
|
557
|
-
const result = compareMetricValues(input.baselineMetricValue, input.candidateMetricValue, input.objective);
|
|
558
|
-
const delta = input.baselineMetricValue !== void 0 && input.candidateMetricValue !== void 0 ? input.candidateMetricValue - input.baselineMetricValue : void 0;
|
|
559
|
-
const percentDelta = input.baselineMetricValue !== void 0 && input.baselineMetricValue !== 0 && delta !== void 0 ? delta / input.baselineMetricValue * 100 : void 0;
|
|
560
|
-
const goal = input.objective === "minimize" ? "lower" : "higher";
|
|
561
|
-
let summary = `Needs ${goal} ${input.objective === "minimize" ? "metric reduction" : "metric lift"} data.`;
|
|
562
|
-
if (result === "better") {
|
|
563
|
-
summary = `Candidate is better than baseline (${input.candidateMetricValue} vs ${input.baselineMetricValue}, \u0394 ${formatSignedNumber(delta)} / ${formatPercent(percentDelta)}).`;
|
|
564
|
-
} else if (result === "worse") {
|
|
565
|
-
summary = `Candidate is worse than baseline (${input.candidateMetricValue} vs ${input.baselineMetricValue}, \u0394 ${formatSignedNumber(delta)} / ${formatPercent(percentDelta)}).`;
|
|
566
|
-
} else if (result === "equal") {
|
|
567
|
-
summary = `Candidate matches baseline (${input.candidateMetricValue}).`;
|
|
568
|
-
}
|
|
569
|
-
return {
|
|
570
|
-
baselineSessionId: input.baselineSessionId,
|
|
571
|
-
baselineName: input.baselineName,
|
|
572
|
-
objective: input.objective,
|
|
573
|
-
result,
|
|
574
|
-
baselineMetricValue: input.baselineMetricValue,
|
|
575
|
-
candidateMetricValue: input.candidateMetricValue,
|
|
576
|
-
delta,
|
|
577
|
-
percentDelta,
|
|
578
|
-
summary
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
function determineVerdict(args) {
|
|
582
|
-
if (!args.success) {
|
|
583
|
-
return {
|
|
584
|
-
verdict: "FAIL",
|
|
585
|
-
reason: "Command execution failed."
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
if (args.metricName && args.metricValue === void 0) {
|
|
589
|
-
return {
|
|
590
|
-
verdict: "PARTIAL",
|
|
591
|
-
reason: `Metric ${args.metricName} was configured but not found in output.`
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
if (args.comparison?.result === "worse") {
|
|
595
|
-
return {
|
|
596
|
-
verdict: "FAIL",
|
|
597
|
-
reason: args.comparison.summary
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
if (args.comparison?.result === "unknown") {
|
|
601
|
-
return {
|
|
602
|
-
verdict: "PARTIAL",
|
|
603
|
-
reason: args.comparison.summary
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
if (args.comparison?.result === "equal") {
|
|
607
|
-
return {
|
|
608
|
-
verdict: "PARTIAL",
|
|
609
|
-
reason: args.comparison.summary
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
if (args.comparison?.result === "better") {
|
|
613
|
-
return {
|
|
614
|
-
verdict: "PASS",
|
|
615
|
-
reason: args.comparison.summary
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
if (args.metricName && args.metricValue !== void 0) {
|
|
619
|
-
return {
|
|
620
|
-
verdict: "PASS",
|
|
621
|
-
reason: `Metric ${args.metricName}=${args.metricValue} was captured successfully.`
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
return {
|
|
625
|
-
verdict: "PASS",
|
|
626
|
-
reason: "Command completed successfully."
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
function selectBestByMetric(rows) {
|
|
630
|
-
const newestMetricRow = [...rows].reverse().find((row) => row.metricName && row.metricValue !== void 0);
|
|
631
|
-
if (!newestMetricRow?.metricName) {
|
|
632
|
-
return [...rows].reverse().find((row) => row.verdict === "PASS") || rows[rows.length - 1];
|
|
633
|
-
}
|
|
634
|
-
const candidates = rows.filter((row) => row.metricName === newestMetricRow.metricName && row.metricValue !== void 0);
|
|
635
|
-
if (candidates.length === 0) {
|
|
636
|
-
return newestMetricRow;
|
|
637
|
-
}
|
|
638
|
-
const objective = resolveResearchObjective(newestMetricRow.metricName);
|
|
639
|
-
return candidates.reduce((best, current) => {
|
|
640
|
-
if (best.metricValue === void 0 || current.metricValue === void 0) {
|
|
641
|
-
return best;
|
|
642
|
-
}
|
|
643
|
-
if (objective === "minimize") {
|
|
644
|
-
return current.metricValue < best.metricValue ? current : best;
|
|
645
|
-
}
|
|
646
|
-
return current.metricValue > best.metricValue ? current : best;
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
function buildResearchTask(taskId, options) {
|
|
650
|
-
return {
|
|
651
|
-
id: taskId,
|
|
652
|
-
name: options.name,
|
|
653
|
-
description: `Run research command: ${options.command}`,
|
|
654
|
-
type: "research-run",
|
|
655
|
-
priority: "normal",
|
|
656
|
-
status: "pending",
|
|
657
|
-
requiredCapabilities: [],
|
|
658
|
-
input: {
|
|
659
|
-
parameters: {
|
|
660
|
-
command: options.command,
|
|
661
|
-
cwd: options.cwd,
|
|
662
|
-
metricName: options.metricName,
|
|
663
|
-
budgetMs: options.budgetMs
|
|
664
|
-
},
|
|
665
|
-
instructions: "Execute the configured research command and capture its metric output."
|
|
666
|
-
},
|
|
667
|
-
dependencies: [],
|
|
668
|
-
maxRetries: options.maxRetries,
|
|
669
|
-
retryCount: 0,
|
|
670
|
-
timeout: options.budgetMs,
|
|
671
|
-
metadata: {
|
|
672
|
-
tags: ["research", "experiment"],
|
|
673
|
-
category: "research",
|
|
674
|
-
createdBy: "ccjk research",
|
|
675
|
-
custom: {
|
|
676
|
-
metricName: options.metricName,
|
|
677
|
-
cwd: options.cwd,
|
|
678
|
-
baselineSessionId: options.baselineSessionId
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
682
|
-
progress: 0
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
function normalizeRunOptions(options) {
|
|
686
|
-
return {
|
|
687
|
-
command: options.command,
|
|
688
|
-
name: options.name || `research-${Date.now()}`,
|
|
689
|
-
cwd: options.cwd || process.cwd(),
|
|
690
|
-
budgetMs: options.budgetMs || DEFAULT_BUDGET_MS,
|
|
691
|
-
maxRetries: options.maxRetries ?? 0,
|
|
692
|
-
metricName: options.metricName,
|
|
693
|
-
baselineSessionId: options.baselineSessionId,
|
|
694
|
-
objective: options.objective || "auto",
|
|
695
|
-
dbPath: options.dbPath
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
async function runResearchExperiment(options) {
|
|
699
|
-
const normalized = normalizeRunOptions(options);
|
|
700
|
-
const persistence = createPersistence$1(normalized.dbPath);
|
|
701
|
-
const queue = new TaskQueue({
|
|
702
|
-
concurrency: 1,
|
|
703
|
-
defaultTimeout: normalized.budgetMs,
|
|
704
|
-
defaultMaxRetries: normalized.maxRetries
|
|
705
|
-
});
|
|
706
|
-
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
707
|
-
const runPhase = inferResearchPhase(normalized.name);
|
|
708
|
-
const phaseHistory = buildPhaseHistory(runPhase);
|
|
709
|
-
const sessionId = `research-${Date.now()}-${nanoid(6)}`;
|
|
710
|
-
const taskId = `research-task-${nanoid(8)}`;
|
|
711
|
-
const task = buildResearchTask(taskId, normalized);
|
|
712
|
-
const objective = resolveResearchObjective(normalized.metricName, normalized.objective);
|
|
713
|
-
let baselineSummary;
|
|
714
|
-
let comparison;
|
|
715
|
-
let baselineMetricValue;
|
|
716
|
-
if (normalized.baselineSessionId) {
|
|
717
|
-
baselineSummary = listResearchSessions(Number.MAX_SAFE_INTEGER, normalized.dbPath).find((session) => session.id === normalized.baselineSessionId);
|
|
718
|
-
const baselineReport = getResearchReport(normalized.baselineSessionId, normalized.dbPath);
|
|
719
|
-
if (baselineReport) {
|
|
720
|
-
baselineMetricValue = baselineReport.metricValue;
|
|
721
|
-
comparison = buildComparisonSummary({
|
|
722
|
-
baselineSessionId: baselineReport.sessionId,
|
|
723
|
-
baselineName: baselineReport.name,
|
|
724
|
-
baselineMetricValue,
|
|
725
|
-
candidateMetricValue: void 0,
|
|
726
|
-
objective
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
persistence.saveSession(sessionId, {
|
|
731
|
-
kind: RESEARCH_SESSION_KIND,
|
|
732
|
-
name: normalized.name,
|
|
733
|
-
command: normalized.command,
|
|
734
|
-
cwd: normalized.cwd,
|
|
735
|
-
metricName: normalized.metricName,
|
|
736
|
-
budgetMs: normalized.budgetMs,
|
|
737
|
-
objective,
|
|
738
|
-
baselineSessionId: normalized.baselineSessionId,
|
|
739
|
-
currentPhase: runPhase,
|
|
740
|
-
phaseHistory: ["brief", runPhase],
|
|
741
|
-
createdAt
|
|
742
|
-
});
|
|
743
|
-
persistence.saveTask(task, sessionId);
|
|
744
|
-
let attempts = 0;
|
|
745
|
-
let commandResult;
|
|
746
|
-
let error;
|
|
747
|
-
const startedAt = Date.now();
|
|
748
|
-
persistence.updateTaskStatus(taskId, "running");
|
|
749
|
-
try {
|
|
750
|
-
commandResult = await queue.add(async () => {
|
|
751
|
-
attempts += 1;
|
|
752
|
-
const result = await executeCommand(normalized.command, [], {
|
|
753
|
-
cwd: normalized.cwd,
|
|
754
|
-
timeout: normalized.budgetMs,
|
|
755
|
-
shell: true
|
|
756
|
-
});
|
|
757
|
-
if (!result.success) {
|
|
758
|
-
throw new ResearchCommandError(result);
|
|
759
|
-
}
|
|
760
|
-
return result;
|
|
761
|
-
}, {
|
|
762
|
-
timeout: normalized.budgetMs,
|
|
763
|
-
maxRetries: normalized.maxRetries,
|
|
764
|
-
metadata: {
|
|
765
|
-
sessionId,
|
|
766
|
-
command: normalized.command
|
|
767
|
-
}
|
|
768
|
-
});
|
|
769
|
-
} catch (caughtError) {
|
|
770
|
-
error = caughtError instanceof Error ? caughtError : new Error(String(caughtError));
|
|
771
|
-
if (caughtError instanceof ResearchCommandError) {
|
|
772
|
-
commandResult = caughtError.result;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
const durationMs = Date.now() - startedAt;
|
|
776
|
-
const finalizedResult = commandResult || {
|
|
777
|
-
success: false,
|
|
778
|
-
stdout: "",
|
|
779
|
-
stderr: "",
|
|
780
|
-
exitCode: 1,
|
|
781
|
-
error: error?.message || "Research command failed"
|
|
782
|
-
};
|
|
783
|
-
const status = finalizedResult.success ? "completed" : getFailureStatus(finalizedResult, error);
|
|
784
|
-
const combinedOutput = [finalizedResult.stdout, finalizedResult.stderr].filter(Boolean).join("\n");
|
|
785
|
-
const metricValue = extractMetricValue(combinedOutput, normalized.metricName);
|
|
786
|
-
if (normalized.baselineSessionId) {
|
|
787
|
-
comparison = buildComparisonSummary({
|
|
788
|
-
baselineSessionId: normalized.baselineSessionId,
|
|
789
|
-
baselineName: baselineSummary?.name || normalized.baselineSessionId,
|
|
790
|
-
baselineMetricValue,
|
|
791
|
-
candidateMetricValue: metricValue,
|
|
792
|
-
objective
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
const verdictDecision = determineVerdict({
|
|
796
|
-
success: finalizedResult.success,
|
|
797
|
-
metricName: normalized.metricName,
|
|
798
|
-
metricValue,
|
|
799
|
-
comparison
|
|
800
|
-
});
|
|
801
|
-
const verdict = verdictDecision.verdict;
|
|
802
|
-
const verdictReason = verdictDecision.reason;
|
|
803
|
-
const output = {
|
|
804
|
-
data: {
|
|
805
|
-
command: normalized.command,
|
|
806
|
-
cwd: normalized.cwd,
|
|
807
|
-
status,
|
|
808
|
-
exitCode: finalizedResult.exitCode,
|
|
809
|
-
stdout: finalizedResult.stdout,
|
|
810
|
-
stderr: finalizedResult.stderr,
|
|
811
|
-
metricName: normalized.metricName,
|
|
812
|
-
metricValue,
|
|
813
|
-
durationMs,
|
|
814
|
-
attempts,
|
|
815
|
-
phase: runPhase,
|
|
816
|
-
objective,
|
|
817
|
-
verdict,
|
|
818
|
-
verdictReason,
|
|
819
|
-
baselineSessionId: normalized.baselineSessionId,
|
|
820
|
-
comparison
|
|
821
|
-
},
|
|
822
|
-
logs: combinedOutput ? combinedOutput.split(/\r?\n/) : [],
|
|
823
|
-
metadata: {
|
|
824
|
-
status,
|
|
825
|
-
success: finalizedResult.success,
|
|
826
|
-
verdict,
|
|
827
|
-
objective
|
|
828
|
-
}
|
|
829
|
-
};
|
|
830
|
-
persistence.updateTaskStatus(
|
|
831
|
-
taskId,
|
|
832
|
-
finalizedResult.success ? "completed" : "failed",
|
|
833
|
-
output,
|
|
834
|
-
finalizedResult.success ? void 0 : error
|
|
835
|
-
);
|
|
836
|
-
persistence.recordMetrics({
|
|
837
|
-
taskId,
|
|
838
|
-
sessionId,
|
|
839
|
-
executionTime: durationMs,
|
|
840
|
-
retryCount: Math.max(0, attempts - 1),
|
|
841
|
-
success: finalizedResult.success,
|
|
842
|
-
errorType: finalizedResult.success ? void 0 : status
|
|
843
|
-
});
|
|
844
|
-
persistence.logDecision({
|
|
845
|
-
id: `decision-${nanoid(8)}`,
|
|
846
|
-
sessionId,
|
|
847
|
-
taskId,
|
|
848
|
-
decision: "record research run",
|
|
849
|
-
reasoning: normalized.metricName ? `Executed the research command and evaluated metric ${normalized.metricName} with objective ${objective}.` : "Executed the research command without a configured metric parser.",
|
|
850
|
-
context: JSON.stringify({
|
|
851
|
-
command: normalized.command,
|
|
852
|
-
cwd: normalized.cwd,
|
|
853
|
-
budgetMs: normalized.budgetMs,
|
|
854
|
-
metricName: normalized.metricName,
|
|
855
|
-
phase: runPhase,
|
|
856
|
-
objective,
|
|
857
|
-
baselineSessionId: normalized.baselineSessionId
|
|
858
|
-
}),
|
|
859
|
-
outcome: verdictReason
|
|
860
|
-
});
|
|
861
|
-
persistence.saveSession(sessionId, {
|
|
862
|
-
kind: RESEARCH_SESSION_KIND,
|
|
863
|
-
name: normalized.name,
|
|
864
|
-
command: normalized.command,
|
|
865
|
-
cwd: normalized.cwd,
|
|
866
|
-
metricName: normalized.metricName,
|
|
867
|
-
budgetMs: normalized.budgetMs,
|
|
868
|
-
objective,
|
|
869
|
-
baselineSessionId: normalized.baselineSessionId,
|
|
870
|
-
currentPhase: "report",
|
|
871
|
-
phaseHistory,
|
|
872
|
-
runPhase,
|
|
873
|
-
verdict,
|
|
874
|
-
verdictReason,
|
|
875
|
-
status,
|
|
876
|
-
exitCode: finalizedResult.exitCode,
|
|
877
|
-
metricValue,
|
|
878
|
-
comparison,
|
|
879
|
-
durationMs,
|
|
880
|
-
createdAt
|
|
881
|
-
});
|
|
882
|
-
appendResultRow({
|
|
883
|
-
timestamp: createdAt,
|
|
884
|
-
sessionId,
|
|
885
|
-
taskId,
|
|
886
|
-
name: normalized.name,
|
|
887
|
-
phase: runPhase,
|
|
888
|
-
verdict,
|
|
889
|
-
status,
|
|
890
|
-
exitCode: finalizedResult.exitCode,
|
|
891
|
-
metricName: normalized.metricName,
|
|
892
|
-
metricValue,
|
|
893
|
-
durationMs,
|
|
894
|
-
cwd: normalized.cwd,
|
|
895
|
-
command: normalized.command
|
|
896
|
-
}, normalized.dbPath);
|
|
897
|
-
return {
|
|
898
|
-
sessionId,
|
|
899
|
-
taskId,
|
|
900
|
-
name: normalized.name,
|
|
901
|
-
command: normalized.command,
|
|
902
|
-
cwd: normalized.cwd,
|
|
903
|
-
metricName: normalized.metricName,
|
|
904
|
-
metricValue,
|
|
905
|
-
success: finalizedResult.success,
|
|
906
|
-
status,
|
|
907
|
-
exitCode: finalizedResult.exitCode,
|
|
908
|
-
stdout: finalizedResult.stdout,
|
|
909
|
-
stderr: finalizedResult.stderr,
|
|
910
|
-
durationMs,
|
|
911
|
-
phase: runPhase,
|
|
912
|
-
objective,
|
|
913
|
-
verdict,
|
|
914
|
-
verdictReason,
|
|
915
|
-
baselineSessionId: normalized.baselineSessionId,
|
|
916
|
-
comparison,
|
|
917
|
-
phaseHistory,
|
|
918
|
-
createdAt
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
function listResearchSessions(limit = DEFAULT_SESSION_LIMIT, dbPath) {
|
|
922
|
-
const persistence = createPersistence$1(dbPath);
|
|
923
|
-
return persistence.listSessions(Math.max(limit * 5, 50)).filter((session) => session.metadata?.kind === RESEARCH_SESSION_KIND).slice(0, limit).map((session) => ({
|
|
924
|
-
id: session.id,
|
|
925
|
-
createdAt: session.createdAt,
|
|
926
|
-
name: session.metadata.name || session.id,
|
|
927
|
-
command: session.metadata.command || "",
|
|
928
|
-
cwd: session.metadata.cwd || process.cwd(),
|
|
929
|
-
metricName: session.metadata.metricName,
|
|
930
|
-
budgetMs: session.metadata.budgetMs || DEFAULT_BUDGET_MS,
|
|
931
|
-
currentPhase: session.metadata.currentPhase || "experiment",
|
|
932
|
-
objective: session.metadata.objective,
|
|
933
|
-
verdict: session.metadata.verdict,
|
|
934
|
-
baselineSessionId: session.metadata.baselineSessionId
|
|
935
|
-
}));
|
|
936
|
-
}
|
|
937
|
-
function getLatestResearchSession(dbPath) {
|
|
938
|
-
return listResearchSessions(1, dbPath)[0];
|
|
939
|
-
}
|
|
940
|
-
function getResearchSessionStatus(sessionId, dbPath) {
|
|
941
|
-
const persistence = createPersistence$1(dbPath);
|
|
942
|
-
const restored = persistence.restoreContext(sessionId);
|
|
943
|
-
if (!restored) {
|
|
944
|
-
return null;
|
|
945
|
-
}
|
|
946
|
-
return {
|
|
947
|
-
sessionId,
|
|
948
|
-
metadata: restored.metadata,
|
|
949
|
-
tasks: restored.tasks,
|
|
950
|
-
metrics: persistence.getSessionMetrics(sessionId),
|
|
951
|
-
decisions: persistence.getDecisionLog(sessionId),
|
|
952
|
-
recovery: persistence.recoverExecutionState(sessionId)
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
function listResearchResults(limit = DEFAULT_SESSION_LIMIT, dbPath) {
|
|
956
|
-
return readAllResultRows(dbPath).reverse().slice(0, limit);
|
|
957
|
-
}
|
|
958
|
-
function getBestResearchResult(dbPath) {
|
|
959
|
-
const rows = readAllResultRows(dbPath);
|
|
960
|
-
if (rows.length === 0) {
|
|
961
|
-
return void 0;
|
|
962
|
-
}
|
|
963
|
-
return selectBestByMetric(rows);
|
|
964
|
-
}
|
|
965
|
-
function getResearchReport(sessionId, dbPath) {
|
|
966
|
-
const resolvedSessionId = sessionId || getLatestResearchSession(dbPath)?.id;
|
|
967
|
-
if (!resolvedSessionId) {
|
|
968
|
-
return null;
|
|
969
|
-
}
|
|
970
|
-
const status = getResearchSessionStatus(resolvedSessionId, dbPath);
|
|
971
|
-
if (!status) {
|
|
972
|
-
return null;
|
|
973
|
-
}
|
|
974
|
-
const latestTask = status.tasks[status.tasks.length - 1];
|
|
975
|
-
const outputData = latestTask?.output?.data || {};
|
|
976
|
-
const phaseHistory = status.metadata.phaseHistory || [];
|
|
977
|
-
const comparison = status.metadata.comparison;
|
|
978
|
-
const verdictDecision = determineVerdict({
|
|
979
|
-
success: status.metrics.failedTasks === 0,
|
|
980
|
-
metricName: status.metadata.metricName,
|
|
981
|
-
metricValue: outputData.metricValue,
|
|
982
|
-
comparison
|
|
983
|
-
});
|
|
984
|
-
const verdict = status.metadata.verdict || verdictDecision.verdict;
|
|
985
|
-
const verdictReason = String(status.metadata.verdictReason || verdictDecision.reason);
|
|
986
|
-
const currentPhase = status.metadata.currentPhase || "report";
|
|
987
|
-
const createdAt = String(status.metadata.createdAt || "");
|
|
988
|
-
const outcome = String(
|
|
989
|
-
status.decisions[status.decisions.length - 1]?.outcome || status.decisions[status.decisions.length - 1]?.decision || outputData.stderr || outputData.status || "unknown"
|
|
990
|
-
).replace(/\s+/g, " ").trim().slice(0, 160);
|
|
991
|
-
const lines = [];
|
|
992
|
-
lines.push("# CCJK Research Report");
|
|
993
|
-
lines.push("");
|
|
994
|
-
lines.push(`**Session**: ${resolvedSessionId}`);
|
|
995
|
-
lines.push(`**Name**: ${status.metadata.name || resolvedSessionId}`);
|
|
996
|
-
lines.push(`**Created**: ${createdAt || "unknown"}`);
|
|
997
|
-
lines.push(`**Phase**: ${currentPhase}`);
|
|
998
|
-
lines.push(`**Verdict**: ${verdict}`);
|
|
999
|
-
lines.push(`**Command**: ${status.metadata.command || outputData.command || "unknown"}`);
|
|
1000
|
-
lines.push(`**CWD**: ${status.metadata.cwd || outputData.cwd || process.cwd()}`);
|
|
1001
|
-
lines.push(`**Exit Code**: ${outputData.exitCode ?? "unknown"}`);
|
|
1002
|
-
lines.push(`**Status**: ${outputData.status || status.metadata.status || "unknown"}`);
|
|
1003
|
-
lines.push(`**Metric**: ${status.metadata.metricName ? `${status.metadata.metricName}=${outputData.metricValue ?? "not found"}` : "not configured"}`);
|
|
1004
|
-
lines.push(`**Objective**: ${status.metadata.objective || outputData.objective || "unknown"}`);
|
|
1005
|
-
lines.push(`**Duration**: ${outputData.durationMs ?? status.metadata.durationMs ?? 0}ms`);
|
|
1006
|
-
lines.push(`**Reason**: ${verdictReason}`);
|
|
1007
|
-
lines.push(`**Outcome**: ${outcome}`);
|
|
1008
|
-
if (comparison) {
|
|
1009
|
-
lines.push("");
|
|
1010
|
-
lines.push("## Comparison");
|
|
1011
|
-
lines.push("");
|
|
1012
|
-
lines.push(`- Baseline: ${comparison.baselineName} (${comparison.baselineSessionId})`);
|
|
1013
|
-
lines.push(`- Objective: ${comparison.objective}`);
|
|
1014
|
-
lines.push(`- Result: ${comparison.result}`);
|
|
1015
|
-
lines.push(`- Summary: ${comparison.summary}`);
|
|
1016
|
-
}
|
|
1017
|
-
if (phaseHistory.length > 0) {
|
|
1018
|
-
lines.push("");
|
|
1019
|
-
lines.push("## Phase History");
|
|
1020
|
-
lines.push("");
|
|
1021
|
-
lines.push(`- ${phaseHistory.join(" \u2192 ")}`);
|
|
1022
|
-
}
|
|
1023
|
-
return {
|
|
1024
|
-
sessionId: resolvedSessionId,
|
|
1025
|
-
name: status.metadata.name || resolvedSessionId,
|
|
1026
|
-
createdAt,
|
|
1027
|
-
currentPhase,
|
|
1028
|
-
verdict,
|
|
1029
|
-
verdictReason,
|
|
1030
|
-
command: status.metadata.command || outputData.command || "unknown",
|
|
1031
|
-
cwd: status.metadata.cwd || outputData.cwd || process.cwd(),
|
|
1032
|
-
status: String(outputData.status || status.metadata.status || "unknown"),
|
|
1033
|
-
exitCode: Number(outputData.exitCode ?? 0),
|
|
1034
|
-
metricName: status.metadata.metricName,
|
|
1035
|
-
metricValue: typeof outputData.metricValue === "number" ? outputData.metricValue : void 0,
|
|
1036
|
-
objective: status.metadata.objective,
|
|
1037
|
-
baselineSessionId: status.metadata.baselineSessionId,
|
|
1038
|
-
comparison,
|
|
1039
|
-
durationMs: Number(outputData.durationMs ?? status.metadata.durationMs ?? 0),
|
|
1040
|
-
phaseHistory,
|
|
1041
|
-
outcome,
|
|
1042
|
-
content: lines.join("\n")
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
const RESEARCH_LOOP_SESSION_KIND = "research-loop";
|
|
1047
|
-
const DEFAULT_FAILURE_STREAK_LIMIT = 2;
|
|
1048
|
-
function createPersistence(dbPath) {
|
|
1049
|
-
return new TaskPersistence(dbPath);
|
|
1050
|
-
}
|
|
1051
|
-
function toPositiveInteger(value, fallback) {
|
|
1052
|
-
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
|
|
1053
|
-
}
|
|
1054
|
-
function toOptionalFiniteNumber(value) {
|
|
1055
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1056
|
-
}
|
|
1057
|
-
function applyProgramOverrides(program, overrides = {}) {
|
|
1058
|
-
return {
|
|
1059
|
-
...program,
|
|
1060
|
-
cwd: overrides.cwd || program.cwd,
|
|
1061
|
-
budgetMs: toPositiveInteger(overrides.budgetMs, program.budgetMs),
|
|
1062
|
-
maxRounds: toPositiveInteger(overrides.maxRounds, program.maxRounds),
|
|
1063
|
-
maxNoImproveRounds: toPositiveInteger(overrides.maxNoImproveRounds, program.maxNoImproveRounds),
|
|
1064
|
-
targetMetric: toOptionalFiniteNumber(overrides.targetMetric) ?? program.targetMetric
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
function nowIso() {
|
|
1068
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1069
|
-
}
|
|
1070
|
-
function toObjective(value, metricName) {
|
|
1071
|
-
if (value === "maximize" || value === "minimize") {
|
|
1072
|
-
return value;
|
|
1073
|
-
}
|
|
1074
|
-
const normalized = (metricName || "").toLowerCase();
|
|
1075
|
-
if (!normalized) {
|
|
1076
|
-
return "maximize";
|
|
1077
|
-
}
|
|
1078
|
-
const lowerIsBetter = ["loss", "error", "bpb", "perplexity", "ppl", "latency", "duration", "time", "cost", "price", "wer", "cer"];
|
|
1079
|
-
return lowerIsBetter.some((keyword) => normalized.includes(keyword)) ? "minimize" : "maximize";
|
|
1080
|
-
}
|
|
1081
|
-
function isAcceptedResult(result) {
|
|
1082
|
-
return result.verdict === "PASS";
|
|
1083
|
-
}
|
|
1084
|
-
function cloneLoopMetadata(metadata, patch = {}) {
|
|
1085
|
-
return {
|
|
1086
|
-
...metadata,
|
|
1087
|
-
...patch,
|
|
1088
|
-
acceptedRoundSessionIds: patch.acceptedRoundSessionIds || [...metadata.acceptedRoundSessionIds],
|
|
1089
|
-
rejectedRoundSessionIds: patch.rejectedRoundSessionIds || [...metadata.rejectedRoundSessionIds],
|
|
1090
|
-
roundSessionIds: patch.roundSessionIds || [...metadata.roundSessionIds],
|
|
1091
|
-
updatedAt: patch.updatedAt || nowIso()
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
function ensureLoopMetadata(raw, sessionId) {
|
|
1095
|
-
const createdAt = typeof raw.createdAt === "string" && raw.createdAt ? raw.createdAt : nowIso();
|
|
1096
|
-
return {
|
|
1097
|
-
kind: "research-loop",
|
|
1098
|
-
name: typeof raw.name === "string" && raw.name ? raw.name : sessionId,
|
|
1099
|
-
programPath: typeof raw.programPath === "string" ? raw.programPath : ".ccjk/research/program.md",
|
|
1100
|
-
metric: typeof raw.metric === "string" && raw.metric ? raw.metric : void 0,
|
|
1101
|
-
objective: raw.objective === "maximize" || raw.objective === "minimize" || raw.objective === "auto" ? raw.objective : "auto",
|
|
1102
|
-
cwd: typeof raw.cwd === "string" && raw.cwd ? raw.cwd : process.cwd(),
|
|
1103
|
-
budgetMs: toPositiveInteger(raw.budgetMs, 5 * 60 * 1e3),
|
|
1104
|
-
maxRounds: toPositiveInteger(raw.maxRounds, 10),
|
|
1105
|
-
maxNoImproveRounds: toPositiveInteger(raw.maxNoImproveRounds, 3),
|
|
1106
|
-
targetMetric: typeof raw.targetMetric === "number" && Number.isFinite(raw.targetMetric) ? raw.targetMetric : void 0,
|
|
1107
|
-
status: raw.status === "running" || raw.status === "stopped" || raw.status === "completed" || raw.status === "failed" ? raw.status : "running",
|
|
1108
|
-
baselineSessionId: typeof raw.baselineSessionId === "string" && raw.baselineSessionId ? raw.baselineSessionId : void 0,
|
|
1109
|
-
currentRound: toPositiveInteger(raw.currentRound, 0) - 1 >= 0 ? toPositiveInteger(raw.currentRound, 0) : 0,
|
|
1110
|
-
bestSessionId: typeof raw.bestSessionId === "string" && raw.bestSessionId ? raw.bestSessionId : void 0,
|
|
1111
|
-
bestMetricValue: typeof raw.bestMetricValue === "number" && Number.isFinite(raw.bestMetricValue) ? raw.bestMetricValue : void 0,
|
|
1112
|
-
acceptedRoundSessionIds: Array.isArray(raw.acceptedRoundSessionIds) ? raw.acceptedRoundSessionIds.filter((value) => typeof value === "string") : [],
|
|
1113
|
-
rejectedRoundSessionIds: Array.isArray(raw.rejectedRoundSessionIds) ? raw.rejectedRoundSessionIds.filter((value) => typeof value === "string") : [],
|
|
1114
|
-
roundSessionIds: Array.isArray(raw.roundSessionIds) ? raw.roundSessionIds.filter((value) => typeof value === "string") : [],
|
|
1115
|
-
noImproveStreak: typeof raw.noImproveStreak === "number" && raw.noImproveStreak >= 0 ? raw.noImproveStreak : 0,
|
|
1116
|
-
failureStreak: typeof raw.failureStreak === "number" && raw.failureStreak >= 0 ? raw.failureStreak : 0,
|
|
1117
|
-
stopReason: raw.stopReason,
|
|
1118
|
-
createdAt,
|
|
1119
|
-
updatedAt: typeof raw.updatedAt === "string" && raw.updatedAt ? raw.updatedAt : createdAt,
|
|
1120
|
-
lastRoundSessionId: typeof raw.lastRoundSessionId === "string" && raw.lastRoundSessionId ? raw.lastRoundSessionId : void 0,
|
|
1121
|
-
notes: typeof raw.notes === "string" && raw.notes ? raw.notes : void 0
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
function getLoopSessionRecord(sessionId, dbPath) {
|
|
1125
|
-
const persistence = createPersistence(dbPath);
|
|
1126
|
-
const session = persistence.getSession(sessionId);
|
|
1127
|
-
if (!session || session.metadata?.kind !== RESEARCH_LOOP_SESSION_KIND) {
|
|
1128
|
-
return null;
|
|
1129
|
-
}
|
|
1130
|
-
return {
|
|
1131
|
-
id: session.id,
|
|
1132
|
-
createdAt: session.createdAt,
|
|
1133
|
-
updatedAt: session.updatedAt,
|
|
1134
|
-
metadata: ensureLoopMetadata(session.metadata, session.id)
|
|
1135
|
-
};
|
|
1136
|
-
}
|
|
1137
|
-
function getLatestLoopSession(dbPath) {
|
|
1138
|
-
const persistence = createPersistence(dbPath);
|
|
1139
|
-
const session = persistence.listSessions(100).find((item) => item.metadata?.kind === RESEARCH_LOOP_SESSION_KIND);
|
|
1140
|
-
if (!session) {
|
|
1141
|
-
return null;
|
|
1142
|
-
}
|
|
1143
|
-
return {
|
|
1144
|
-
id: session.id,
|
|
1145
|
-
createdAt: session.createdAt,
|
|
1146
|
-
metadata: ensureLoopMetadata(session.metadata, session.id)
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
function getResolvedLoopSessionId(sessionId, dbPath) {
|
|
1150
|
-
return sessionId || getLatestLoopSession(dbPath)?.id;
|
|
1151
|
-
}
|
|
1152
|
-
function saveLoopMetadata(sessionId, metadata, dbPath) {
|
|
1153
|
-
const persistence = createPersistence(dbPath);
|
|
1154
|
-
const normalized = ensureLoopMetadata({ ...metadata, updatedAt: nowIso() }, sessionId);
|
|
1155
|
-
persistence.saveSession(sessionId, normalized);
|
|
1156
|
-
return normalized;
|
|
1157
|
-
}
|
|
1158
|
-
function buildRoundRecord(round, result) {
|
|
1159
|
-
return {
|
|
1160
|
-
round,
|
|
1161
|
-
sessionId: result.sessionId,
|
|
1162
|
-
name: result.name,
|
|
1163
|
-
status: result.status,
|
|
1164
|
-
verdict: result.verdict,
|
|
1165
|
-
metricName: result.metricName,
|
|
1166
|
-
metricValue: result.metricValue,
|
|
1167
|
-
accepted: isAcceptedResult(result),
|
|
1168
|
-
objective: result.objective,
|
|
1169
|
-
command: result.command,
|
|
1170
|
-
reason: result.verdictReason,
|
|
1171
|
-
baselineSessionId: result.baselineSessionId,
|
|
1172
|
-
comparison: result.comparison,
|
|
1173
|
-
createdAt: result.createdAt
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
function getRoundRecords(metadata, dbPath) {
|
|
1177
|
-
return metadata.roundSessionIds.map((sessionId, index) => {
|
|
1178
|
-
const report = getResearchReport(sessionId, dbPath);
|
|
1179
|
-
if (!report) {
|
|
1180
|
-
return null;
|
|
1181
|
-
}
|
|
1182
|
-
const record = {
|
|
1183
|
-
round: index + 1,
|
|
1184
|
-
sessionId,
|
|
1185
|
-
name: report.name,
|
|
1186
|
-
status: report.status,
|
|
1187
|
-
verdict: report.verdict,
|
|
1188
|
-
metricName: report.metricName,
|
|
1189
|
-
metricValue: report.metricValue,
|
|
1190
|
-
accepted: metadata.acceptedRoundSessionIds.includes(sessionId),
|
|
1191
|
-
objective: report.objective || toObjective(metadata.objective, metadata.metric),
|
|
1192
|
-
command: report.command,
|
|
1193
|
-
reason: report.verdictReason,
|
|
1194
|
-
baselineSessionId: report.baselineSessionId,
|
|
1195
|
-
comparison: report.comparison,
|
|
1196
|
-
createdAt: report.createdAt
|
|
1197
|
-
};
|
|
1198
|
-
return record;
|
|
1199
|
-
}).filter((value) => value !== null);
|
|
1200
|
-
}
|
|
1201
|
-
function isTargetReached(metricValue, objective, targetMetric) {
|
|
1202
|
-
if (metricValue === void 0 || targetMetric === void 0) {
|
|
1203
|
-
return false;
|
|
1204
|
-
}
|
|
1205
|
-
return objective === "minimize" ? metricValue <= targetMetric : metricValue >= targetMetric;
|
|
1206
|
-
}
|
|
1207
|
-
function evaluateLoopStopCondition(input) {
|
|
1208
|
-
const objective = toObjective(input.metadata.objective, input.metadata.metric);
|
|
1209
|
-
if (input.metadata.status === "completed" || input.metadata.status === "failed") {
|
|
1210
|
-
return { shouldStop: true, reason: input.metadata.stopReason, status: input.metadata.status };
|
|
1211
|
-
}
|
|
1212
|
-
if (input.metadata.status === "stopped") {
|
|
1213
|
-
return { shouldStop: true, reason: input.metadata.stopReason || "manual-stop", status: "stopped" };
|
|
1214
|
-
}
|
|
1215
|
-
if (input.phase === "baseline" && input.latestResult && !input.latestResult.success) {
|
|
1216
|
-
return { shouldStop: true, reason: "baseline-failed", status: "failed" };
|
|
1217
|
-
}
|
|
1218
|
-
if (input.metadata.currentRound >= input.program.maxRounds) {
|
|
1219
|
-
return { shouldStop: true, reason: "max-rounds-reached", status: "completed" };
|
|
1220
|
-
}
|
|
1221
|
-
if (input.metadata.noImproveStreak >= input.program.maxNoImproveRounds) {
|
|
1222
|
-
return { shouldStop: true, reason: "max-no-improve-rounds-reached", status: "completed" };
|
|
1223
|
-
}
|
|
1224
|
-
if (isTargetReached(input.metadata.bestMetricValue, objective, input.program.targetMetric)) {
|
|
1225
|
-
return { shouldStop: true, reason: "target-metric-reached", status: "completed" };
|
|
1226
|
-
}
|
|
1227
|
-
if (input.phase === "round" && input.metadata.failureStreak >= DEFAULT_FAILURE_STREAK_LIMIT) {
|
|
1228
|
-
return { shouldStop: true, reason: "candidate-failed-repeatedly", status: "failed" };
|
|
1229
|
-
}
|
|
1230
|
-
return { shouldStop: false };
|
|
1231
|
-
}
|
|
1232
|
-
function createLoopSession(program, dbPath) {
|
|
1233
|
-
const sessionId = `research-loop-${Date.now()}-${nanoid(6)}`;
|
|
1234
|
-
const createdAt = nowIso();
|
|
1235
|
-
const metadata = {
|
|
1236
|
-
kind: "research-loop",
|
|
1237
|
-
name: program.name,
|
|
1238
|
-
programPath: program.programPath,
|
|
1239
|
-
metric: program.metric,
|
|
1240
|
-
objective: program.objective,
|
|
1241
|
-
cwd: program.cwd,
|
|
1242
|
-
budgetMs: program.budgetMs,
|
|
1243
|
-
maxRounds: program.maxRounds,
|
|
1244
|
-
maxNoImproveRounds: program.maxNoImproveRounds,
|
|
1245
|
-
targetMetric: program.targetMetric,
|
|
1246
|
-
status: "running",
|
|
1247
|
-
baselineSessionId: void 0,
|
|
1248
|
-
currentRound: 0,
|
|
1249
|
-
bestSessionId: void 0,
|
|
1250
|
-
bestMetricValue: void 0,
|
|
1251
|
-
acceptedRoundSessionIds: [],
|
|
1252
|
-
rejectedRoundSessionIds: [],
|
|
1253
|
-
roundSessionIds: [],
|
|
1254
|
-
noImproveStreak: 0,
|
|
1255
|
-
failureStreak: 0,
|
|
1256
|
-
createdAt,
|
|
1257
|
-
updatedAt: createdAt,
|
|
1258
|
-
notes: program.notes
|
|
1259
|
-
};
|
|
1260
|
-
return {
|
|
1261
|
-
sessionId,
|
|
1262
|
-
metadata: saveLoopMetadata(sessionId, metadata, dbPath)
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
async function ensureBaseline(sessionId, metadata, program, dbPath) {
|
|
1266
|
-
if (metadata.baselineSessionId) {
|
|
1267
|
-
const report = getResearchReport(metadata.baselineSessionId, dbPath);
|
|
1268
|
-
if (report) {
|
|
1269
|
-
return {
|
|
1270
|
-
metadata,
|
|
1271
|
-
baseline: {
|
|
1272
|
-
sessionId: report.sessionId,
|
|
1273
|
-
taskId: "",
|
|
1274
|
-
name: report.name,
|
|
1275
|
-
command: report.command,
|
|
1276
|
-
cwd: report.cwd,
|
|
1277
|
-
metricName: report.metricName,
|
|
1278
|
-
metricValue: report.metricValue,
|
|
1279
|
-
success: report.status === "completed",
|
|
1280
|
-
status: report.status,
|
|
1281
|
-
exitCode: report.exitCode,
|
|
1282
|
-
stdout: "",
|
|
1283
|
-
stderr: "",
|
|
1284
|
-
durationMs: report.durationMs,
|
|
1285
|
-
phase: "baseline",
|
|
1286
|
-
objective: report.objective || toObjective(program.objective, program.metric),
|
|
1287
|
-
verdict: report.verdict,
|
|
1288
|
-
verdictReason: report.verdictReason,
|
|
1289
|
-
baselineSessionId: report.baselineSessionId,
|
|
1290
|
-
comparison: report.comparison,
|
|
1291
|
-
phaseHistory: report.phaseHistory,
|
|
1292
|
-
createdAt: report.createdAt
|
|
1293
|
-
}
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
const baseline = await runResearchExperiment({
|
|
1298
|
-
name: `${program.name}-baseline`,
|
|
1299
|
-
command: program.baselineCommand,
|
|
1300
|
-
metricName: program.metric,
|
|
1301
|
-
budgetMs: program.budgetMs,
|
|
1302
|
-
cwd: program.cwd,
|
|
1303
|
-
objective: program.objective,
|
|
1304
|
-
dbPath
|
|
1305
|
-
});
|
|
1306
|
-
const nextMetadata = cloneLoopMetadata(metadata, {
|
|
1307
|
-
baselineSessionId: baseline.sessionId,
|
|
1308
|
-
bestSessionId: baseline.sessionId,
|
|
1309
|
-
bestMetricValue: baseline.metricValue,
|
|
1310
|
-
failureStreak: baseline.success ? 0 : metadata.failureStreak + 1
|
|
1311
|
-
});
|
|
1312
|
-
return {
|
|
1313
|
-
metadata: saveLoopMetadata(sessionId, nextMetadata, dbPath),
|
|
1314
|
-
baseline
|
|
1315
|
-
};
|
|
1316
|
-
}
|
|
1317
|
-
async function executeResearchRound(sessionId, metadata, program, dbPath) {
|
|
1318
|
-
const roundNumber = metadata.currentRound + 1;
|
|
1319
|
-
const baselineSessionId = metadata.bestSessionId || metadata.baselineSessionId;
|
|
1320
|
-
const result = await runResearchExperiment({
|
|
1321
|
-
name: `${program.name}-round-${roundNumber}`,
|
|
1322
|
-
command: program.candidateCommand,
|
|
1323
|
-
metricName: program.metric,
|
|
1324
|
-
budgetMs: program.budgetMs,
|
|
1325
|
-
cwd: program.cwd,
|
|
1326
|
-
objective: program.objective,
|
|
1327
|
-
baselineSessionId,
|
|
1328
|
-
dbPath
|
|
1329
|
-
});
|
|
1330
|
-
const accepted = isAcceptedResult(result);
|
|
1331
|
-
const acceptedRoundSessionIds = accepted ? [...metadata.acceptedRoundSessionIds, result.sessionId] : [...metadata.acceptedRoundSessionIds];
|
|
1332
|
-
const rejectedRoundSessionIds = accepted ? [...metadata.rejectedRoundSessionIds] : [...metadata.rejectedRoundSessionIds, result.sessionId];
|
|
1333
|
-
const bestSessionId = accepted ? result.sessionId : metadata.bestSessionId;
|
|
1334
|
-
const bestMetricValue = accepted ? result.metricValue : metadata.bestMetricValue;
|
|
1335
|
-
const nextMetadata = cloneLoopMetadata(metadata, {
|
|
1336
|
-
currentRound: roundNumber,
|
|
1337
|
-
bestSessionId,
|
|
1338
|
-
bestMetricValue,
|
|
1339
|
-
roundSessionIds: [...metadata.roundSessionIds, result.sessionId],
|
|
1340
|
-
acceptedRoundSessionIds,
|
|
1341
|
-
rejectedRoundSessionIds,
|
|
1342
|
-
noImproveStreak: accepted ? 0 : metadata.noImproveStreak + 1,
|
|
1343
|
-
failureStreak: result.success ? 0 : metadata.failureStreak + 1,
|
|
1344
|
-
lastRoundSessionId: result.sessionId
|
|
1345
|
-
});
|
|
1346
|
-
return {
|
|
1347
|
-
metadata: saveLoopMetadata(sessionId, nextMetadata, dbPath),
|
|
1348
|
-
result,
|
|
1349
|
-
round: buildRoundRecord(roundNumber, result)
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
function getResearchLoopStatusInternal(sessionId, dbPath) {
|
|
1353
|
-
const loopSession = getLoopSessionRecord(sessionId, dbPath);
|
|
1354
|
-
if (!loopSession) {
|
|
1355
|
-
return null;
|
|
1356
|
-
}
|
|
1357
|
-
const baselineReport = loopSession.metadata.baselineSessionId ? getResearchReport(loopSession.metadata.baselineSessionId, dbPath) : null;
|
|
1358
|
-
const rounds = getRoundRecords(loopSession.metadata, dbPath);
|
|
1359
|
-
return {
|
|
1360
|
-
sessionId,
|
|
1361
|
-
metadata: loopSession.metadata,
|
|
1362
|
-
baseline: baselineReport ? {
|
|
1363
|
-
sessionId: baselineReport.sessionId,
|
|
1364
|
-
taskId: "",
|
|
1365
|
-
name: baselineReport.name,
|
|
1366
|
-
command: baselineReport.command,
|
|
1367
|
-
cwd: baselineReport.cwd,
|
|
1368
|
-
metricName: baselineReport.metricName,
|
|
1369
|
-
metricValue: baselineReport.metricValue,
|
|
1370
|
-
success: baselineReport.status === "completed",
|
|
1371
|
-
status: baselineReport.status,
|
|
1372
|
-
exitCode: baselineReport.exitCode,
|
|
1373
|
-
stdout: "",
|
|
1374
|
-
stderr: "",
|
|
1375
|
-
durationMs: baselineReport.durationMs,
|
|
1376
|
-
phase: "baseline",
|
|
1377
|
-
objective: baselineReport.objective || toObjective(loopSession.metadata.objective, loopSession.metadata.metric),
|
|
1378
|
-
verdict: baselineReport.verdict,
|
|
1379
|
-
verdictReason: baselineReport.verdictReason,
|
|
1380
|
-
baselineSessionId: baselineReport.baselineSessionId,
|
|
1381
|
-
comparison: baselineReport.comparison,
|
|
1382
|
-
phaseHistory: baselineReport.phaseHistory,
|
|
1383
|
-
createdAt: baselineReport.createdAt
|
|
1384
|
-
} : null,
|
|
1385
|
-
latestRound: rounds[rounds.length - 1],
|
|
1386
|
-
rounds
|
|
1387
|
-
};
|
|
1388
|
-
}
|
|
1389
|
-
async function startResearchLoop(options = {}) {
|
|
1390
|
-
const program = applyProgramOverrides(readResearchProgram(options.programPath, options.cwd), options.overrides);
|
|
1391
|
-
const { sessionId } = createLoopSession(program, options.dbPath);
|
|
1392
|
-
return await resumeResearchLoop({ ...options, sessionId });
|
|
1393
|
-
}
|
|
1394
|
-
async function runResearchRound(options = {}) {
|
|
1395
|
-
const resolvedSessionId = getResolvedLoopSessionId(options.sessionId, options.dbPath);
|
|
1396
|
-
if (!resolvedSessionId) {
|
|
1397
|
-
throw new Error("No research loop session found.");
|
|
1398
|
-
}
|
|
1399
|
-
const loopSession = getLoopSessionRecord(resolvedSessionId, options.dbPath);
|
|
1400
|
-
if (!loopSession) {
|
|
1401
|
-
throw new Error(`Research loop session not found: ${resolvedSessionId}`);
|
|
1402
|
-
}
|
|
1403
|
-
const program = applyProgramOverrides(readResearchProgram(loopSession.metadata.programPath, options.cwd), options.overrides);
|
|
1404
|
-
let metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(loopSession.metadata, { status: "running", stopReason: void 0 }), options.dbPath);
|
|
1405
|
-
const baselineState = await ensureBaseline(resolvedSessionId, metadata, program, options.dbPath);
|
|
1406
|
-
metadata = baselineState.metadata;
|
|
1407
|
-
const stopAfterBaseline = evaluateLoopStopCondition({ metadata, latestResult: baselineState.baseline, program, phase: "baseline" });
|
|
1408
|
-
if (stopAfterBaseline.shouldStop) {
|
|
1409
|
-
metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(metadata, {
|
|
1410
|
-
status: stopAfterBaseline.status || metadata.status,
|
|
1411
|
-
stopReason: stopAfterBaseline.reason
|
|
1412
|
-
}), options.dbPath);
|
|
1413
|
-
return getResearchLoopStatusInternal(resolvedSessionId, options.dbPath);
|
|
1414
|
-
}
|
|
1415
|
-
const roundState = await executeResearchRound(resolvedSessionId, metadata, program, options.dbPath);
|
|
1416
|
-
metadata = roundState.metadata;
|
|
1417
|
-
const stopState = evaluateLoopStopCondition({ metadata, latestResult: roundState.result, program, phase: "round" });
|
|
1418
|
-
if (stopState.shouldStop) {
|
|
1419
|
-
metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(metadata, {
|
|
1420
|
-
status: stopState.status || metadata.status,
|
|
1421
|
-
stopReason: stopState.reason
|
|
1422
|
-
}), options.dbPath);
|
|
1423
|
-
}
|
|
1424
|
-
return getResearchLoopStatusInternal(resolvedSessionId, options.dbPath);
|
|
1425
|
-
}
|
|
1426
|
-
async function resumeResearchLoop(options = {}) {
|
|
1427
|
-
const resolvedSessionId = getResolvedLoopSessionId(options.sessionId, options.dbPath);
|
|
1428
|
-
if (!resolvedSessionId) {
|
|
1429
|
-
throw new Error("No research loop session found.");
|
|
1430
|
-
}
|
|
1431
|
-
const loopSession = getLoopSessionRecord(resolvedSessionId, options.dbPath);
|
|
1432
|
-
if (!loopSession) {
|
|
1433
|
-
throw new Error(`Research loop session not found: ${resolvedSessionId}`);
|
|
1434
|
-
}
|
|
1435
|
-
const program = applyProgramOverrides(readResearchProgram(loopSession.metadata.programPath, options.cwd), options.overrides);
|
|
1436
|
-
let metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(loopSession.metadata, {
|
|
1437
|
-
status: loopSession.metadata.status === "completed" || loopSession.metadata.status === "failed" ? loopSession.metadata.status : "running",
|
|
1438
|
-
stopReason: loopSession.metadata.status === "stopped" ? void 0 : loopSession.metadata.stopReason
|
|
1439
|
-
}), options.dbPath);
|
|
1440
|
-
const baselineState = await ensureBaseline(resolvedSessionId, metadata, program, options.dbPath);
|
|
1441
|
-
metadata = baselineState.metadata;
|
|
1442
|
-
while (true) {
|
|
1443
|
-
const stopBeforeRound = evaluateLoopStopCondition({ metadata, program });
|
|
1444
|
-
if (stopBeforeRound.shouldStop) {
|
|
1445
|
-
metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(metadata, {
|
|
1446
|
-
status: stopBeforeRound.status || metadata.status,
|
|
1447
|
-
stopReason: stopBeforeRound.reason
|
|
1448
|
-
}), options.dbPath);
|
|
1449
|
-
return getResearchLoopStatusInternal(resolvedSessionId, options.dbPath);
|
|
1450
|
-
}
|
|
1451
|
-
const roundState = await executeResearchRound(resolvedSessionId, metadata, program, options.dbPath);
|
|
1452
|
-
metadata = roundState.metadata;
|
|
1453
|
-
const stopAfterRound = evaluateLoopStopCondition({ metadata, latestResult: roundState.result, program, phase: "round" });
|
|
1454
|
-
if (stopAfterRound.shouldStop) {
|
|
1455
|
-
metadata = saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(metadata, {
|
|
1456
|
-
status: stopAfterRound.status || metadata.status,
|
|
1457
|
-
stopReason: stopAfterRound.reason || "resume-complete"
|
|
1458
|
-
}), options.dbPath);
|
|
1459
|
-
return getResearchLoopStatusInternal(resolvedSessionId, options.dbPath);
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
function stopResearchLoop(options = {}) {
|
|
1464
|
-
const resolvedSessionId = getResolvedLoopSessionId(options.sessionId, options.dbPath);
|
|
1465
|
-
if (!resolvedSessionId) {
|
|
1466
|
-
return null;
|
|
1467
|
-
}
|
|
1468
|
-
const loopSession = getLoopSessionRecord(resolvedSessionId, options.dbPath);
|
|
1469
|
-
if (!loopSession) {
|
|
1470
|
-
return null;
|
|
1471
|
-
}
|
|
1472
|
-
saveLoopMetadata(resolvedSessionId, cloneLoopMetadata(loopSession.metadata, {
|
|
1473
|
-
status: "stopped",
|
|
1474
|
-
stopReason: "manual-stop"
|
|
1475
|
-
}), options.dbPath);
|
|
1476
|
-
return getResearchLoopStatusInternal(resolvedSessionId, options.dbPath);
|
|
1477
|
-
}
|
|
1478
|
-
function getResearchLoopStatus(sessionId, dbPath) {
|
|
1479
|
-
const resolvedSessionId = getResolvedLoopSessionId(sessionId, dbPath);
|
|
1480
|
-
if (!resolvedSessionId) {
|
|
1481
|
-
return null;
|
|
1482
|
-
}
|
|
1483
|
-
return getResearchLoopStatusInternal(resolvedSessionId, dbPath);
|
|
1484
|
-
}
|
|
1485
|
-
function getResearchLoopReport(sessionId, dbPath) {
|
|
1486
|
-
const status = getResearchLoopStatus(sessionId, dbPath);
|
|
1487
|
-
if (!status) {
|
|
1488
|
-
return null;
|
|
1489
|
-
}
|
|
1490
|
-
const lines = [];
|
|
1491
|
-
lines.push("# CCJK Research Loop Report");
|
|
1492
|
-
lines.push("");
|
|
1493
|
-
lines.push(`**Session**: ${status.sessionId}`);
|
|
1494
|
-
lines.push(`**Name**: ${status.metadata.name}`);
|
|
1495
|
-
lines.push(`**Status**: ${status.metadata.status}`);
|
|
1496
|
-
lines.push(`**Stop Reason**: ${status.metadata.stopReason || "running"}`);
|
|
1497
|
-
lines.push(`**Rounds**: ${status.metadata.currentRound}/${status.metadata.maxRounds}`);
|
|
1498
|
-
lines.push(`**No-Improve Streak**: ${status.metadata.noImproveStreak}/${status.metadata.maxNoImproveRounds}`);
|
|
1499
|
-
lines.push(`**Metric**: ${status.metadata.metric || "not configured"}`);
|
|
1500
|
-
lines.push(`**Objective**: ${status.metadata.objective}`);
|
|
1501
|
-
lines.push(`**Target Metric**: ${status.metadata.targetMetric ?? "not configured"}`);
|
|
1502
|
-
lines.push(`**Best Session**: ${status.metadata.bestSessionId || "none"}`);
|
|
1503
|
-
lines.push(`**Best Metric**: ${status.metadata.bestMetricValue ?? "not found"}`);
|
|
1504
|
-
lines.push(`**Created**: ${status.metadata.createdAt}`);
|
|
1505
|
-
lines.push(`**Updated**: ${status.metadata.updatedAt}`);
|
|
1506
|
-
if (status.baseline) {
|
|
1507
|
-
lines.push("");
|
|
1508
|
-
lines.push("## Baseline");
|
|
1509
|
-
lines.push("");
|
|
1510
|
-
lines.push(`- Session: ${status.baseline.sessionId}`);
|
|
1511
|
-
lines.push(`- Verdict: ${status.baseline.verdict}`);
|
|
1512
|
-
lines.push(`- Metric: ${status.baseline.metricName ? `${status.baseline.metricName}=${status.baseline.metricValue ?? "not found"}` : "not configured"}`);
|
|
1513
|
-
lines.push(`- Reason: ${status.baseline.verdictReason}`);
|
|
1514
|
-
}
|
|
1515
|
-
if (status.rounds.length > 0) {
|
|
1516
|
-
lines.push("");
|
|
1517
|
-
lines.push("## Rounds");
|
|
1518
|
-
lines.push("");
|
|
1519
|
-
for (const round of status.rounds) {
|
|
1520
|
-
lines.push(`- Round ${round.round}: ${round.sessionId} \xB7 ${round.verdict} \xB7 ${round.metricName ? `${round.metricName}=${round.metricValue ?? "not found"}` : "no metric"} \xB7 ${round.accepted ? "accepted" : "rejected"}`);
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
return {
|
|
1524
|
-
sessionId: status.sessionId,
|
|
1525
|
-
name: status.metadata.name,
|
|
1526
|
-
status: status.metadata.status,
|
|
1527
|
-
stopReason: status.metadata.stopReason,
|
|
1528
|
-
currentRound: status.metadata.currentRound,
|
|
1529
|
-
maxRounds: status.metadata.maxRounds,
|
|
1530
|
-
noImproveStreak: status.metadata.noImproveStreak,
|
|
1531
|
-
maxNoImproveRounds: status.metadata.maxNoImproveRounds,
|
|
1532
|
-
acceptedRounds: status.metadata.acceptedRoundSessionIds.length,
|
|
1533
|
-
rejectedRounds: status.metadata.rejectedRoundSessionIds.length,
|
|
1534
|
-
bestSessionId: status.metadata.bestSessionId,
|
|
1535
|
-
bestMetricValue: status.metadata.bestMetricValue,
|
|
1536
|
-
metric: status.metadata.metric,
|
|
1537
|
-
objective: status.metadata.objective,
|
|
1538
|
-
targetMetric: status.metadata.targetMetric,
|
|
1539
|
-
baselineSessionId: status.metadata.baselineSessionId,
|
|
1540
|
-
createdAt: status.metadata.createdAt,
|
|
1541
|
-
updatedAt: status.metadata.updatedAt,
|
|
1542
|
-
content: lines.join("\n")
|
|
1543
|
-
};
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
function printDivider() {
|
|
1547
|
-
console.log(a.dim("\u2500".repeat(60)));
|
|
1548
|
-
}
|
|
1549
|
-
function formatMetric(metricName, metricValue) {
|
|
1550
|
-
if (!metricName) {
|
|
1551
|
-
return "not configured";
|
|
1552
|
-
}
|
|
1553
|
-
if (metricValue === void 0) {
|
|
1554
|
-
return `${metricName} (not found)`;
|
|
1555
|
-
}
|
|
1556
|
-
return `${metricName}=${metricValue}`;
|
|
1557
|
-
}
|
|
1558
|
-
function formatTimestamp(value) {
|
|
1559
|
-
if (!value) {
|
|
1560
|
-
return "unknown";
|
|
1561
|
-
}
|
|
1562
|
-
const date = new Date(value);
|
|
1563
|
-
return Number.isNaN(date.getTime()) ? value : date.toISOString();
|
|
1564
|
-
}
|
|
1565
|
-
function previewCommand(command, maxLength = 48) {
|
|
1566
|
-
if (command.length <= maxLength) {
|
|
1567
|
-
return command;
|
|
1568
|
-
}
|
|
1569
|
-
return `${command.slice(0, maxLength - 1)}\u2026`;
|
|
1570
|
-
}
|
|
1571
|
-
function getLatestTaskData(status) {
|
|
1572
|
-
if (!status || status.tasks.length === 0) {
|
|
1573
|
-
return {};
|
|
1574
|
-
}
|
|
1575
|
-
const latestTask = status.tasks[status.tasks.length - 1];
|
|
1576
|
-
return latestTask?.output?.data || {};
|
|
1577
|
-
}
|
|
1578
|
-
function getLoopOverrides(options) {
|
|
1579
|
-
return {
|
|
1580
|
-
cwd: options.cwd,
|
|
1581
|
-
budgetMs: options.budgetMs,
|
|
1582
|
-
maxRounds: options.maxRounds,
|
|
1583
|
-
maxNoImproveRounds: options.maxNoImproveRounds,
|
|
1584
|
-
targetMetric: options.targetMetric
|
|
1585
|
-
};
|
|
1586
|
-
}
|
|
1587
|
-
function printResearchLoopStatus(status) {
|
|
1588
|
-
console.log("");
|
|
1589
|
-
console.log(a.bold.cyan("\u{1F501} Research Loop Status"));
|
|
1590
|
-
printDivider();
|
|
1591
|
-
console.log(a.gray(`Session: ${status.sessionId}`));
|
|
1592
|
-
console.log(a.gray(`Name: ${status.metadata.name}`));
|
|
1593
|
-
console.log(a.gray(`Status: ${status.metadata.status}`));
|
|
1594
|
-
console.log(a.gray(`Stop: ${status.metadata.stopReason || "running"}`));
|
|
1595
|
-
console.log(a.gray(`Rounds: ${status.metadata.currentRound}/${status.metadata.maxRounds}`));
|
|
1596
|
-
console.log(a.gray(`Objective: ${status.metadata.objective}`));
|
|
1597
|
-
console.log(a.gray(`Metric: ${formatMetric(status.metadata.metric, status.metadata.bestMetricValue)}`));
|
|
1598
|
-
console.log(a.gray(`Baseline: ${status.metadata.baselineSessionId || "none"}`));
|
|
1599
|
-
console.log(a.gray(`Best: ${status.metadata.bestSessionId || "none"}`));
|
|
1600
|
-
console.log(a.gray(`Accepted: ${status.metadata.acceptedRoundSessionIds.length}`));
|
|
1601
|
-
console.log(a.gray(`Rejected: ${status.metadata.rejectedRoundSessionIds.length}`));
|
|
1602
|
-
console.log(a.gray(`Streak: ${status.metadata.noImproveStreak}/${status.metadata.maxNoImproveRounds}`));
|
|
1603
|
-
if (status.latestRound) {
|
|
1604
|
-
console.log(a.gray(`Latest: round ${status.latestRound.round} \xB7 ${status.latestRound.verdict} \xB7 ${formatMetric(status.latestRound.metricName, status.latestRound.metricValue)}`));
|
|
1605
|
-
}
|
|
1606
|
-
console.log("");
|
|
1607
|
-
}
|
|
1608
|
-
async function researchCommand(action, args = [], options = {}) {
|
|
1609
|
-
switch (action) {
|
|
1610
|
-
case "run":
|
|
1611
|
-
await runResearchCommand(options);
|
|
1612
|
-
return;
|
|
1613
|
-
case "init":
|
|
1614
|
-
await initResearchCommand(options);
|
|
1615
|
-
return;
|
|
1616
|
-
case "loop":
|
|
1617
|
-
await startResearchLoopCommand(options);
|
|
1618
|
-
return;
|
|
1619
|
-
case "round":
|
|
1620
|
-
await runResearchRoundCommand(args[0] || void 0, options);
|
|
1621
|
-
return;
|
|
1622
|
-
case "resume":
|
|
1623
|
-
await resumeResearchLoopCommand(args[0] || void 0, options);
|
|
1624
|
-
return;
|
|
1625
|
-
case "stop":
|
|
1626
|
-
await stopResearchLoopCommand(args[0] || void 0, options);
|
|
1627
|
-
return;
|
|
1628
|
-
case "status":
|
|
1629
|
-
await showResearchStatus(args[0] || void 0, options);
|
|
1630
|
-
return;
|
|
1631
|
-
case "sessions":
|
|
1632
|
-
case "list":
|
|
1633
|
-
await listResearchCommand(options);
|
|
1634
|
-
return;
|
|
1635
|
-
case "results":
|
|
1636
|
-
await showResearchResults(options);
|
|
1637
|
-
return;
|
|
1638
|
-
case "report":
|
|
1639
|
-
await showResearchReport(args[0] || void 0, options);
|
|
1640
|
-
return;
|
|
1641
|
-
case "help":
|
|
1642
|
-
case "":
|
|
1643
|
-
showResearchHelp();
|
|
1644
|
-
return;
|
|
1645
|
-
default:
|
|
1646
|
-
console.error(a.red(`Unknown research action: ${action}`));
|
|
1647
|
-
showResearchHelp();
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
async function runResearchCommand(options) {
|
|
1651
|
-
if (!options.cmd) {
|
|
1652
|
-
console.error(a.red("Error: --cmd is required for `ccjk research run`"));
|
|
1653
|
-
console.log(a.dim('Example: ccjk research run --name baseline --cmd "python train.py" --metric val_bpb'));
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
const result = await runResearchExperiment({
|
|
1657
|
-
name: options.name,
|
|
1658
|
-
command: options.cmd,
|
|
1659
|
-
metricName: options.metric,
|
|
1660
|
-
budgetMs: options.budgetMs,
|
|
1661
|
-
cwd: options.cwd,
|
|
1662
|
-
baselineSessionId: options.baseline,
|
|
1663
|
-
objective: options.objective,
|
|
1664
|
-
dbPath: options.dbPath
|
|
1665
|
-
});
|
|
1666
|
-
console.log("");
|
|
1667
|
-
console.log(a.bold.cyan("\u{1F52C} Research Run"));
|
|
1668
|
-
printDivider();
|
|
1669
|
-
console.log(a.gray(`Session: ${result.sessionId}`));
|
|
1670
|
-
console.log(a.gray(`Task: ${result.taskId}`));
|
|
1671
|
-
console.log(a.gray(`Name: ${result.name}`));
|
|
1672
|
-
console.log(a.gray(`Phase: ${result.phase}`));
|
|
1673
|
-
console.log(a.gray(`Objective: ${result.objective}`));
|
|
1674
|
-
console.log(a.gray(`Verdict: ${result.verdict}`));
|
|
1675
|
-
console.log(a.gray(`Reason: ${result.verdictReason}`));
|
|
1676
|
-
console.log(a.gray(`Command: ${result.command}`));
|
|
1677
|
-
console.log(a.gray(`CWD: ${result.cwd}`));
|
|
1678
|
-
console.log(a.gray(`Status: ${result.status}`));
|
|
1679
|
-
console.log(a.gray(`Exit code: ${result.exitCode}`));
|
|
1680
|
-
console.log(a.gray(`Metric: ${formatMetric(result.metricName, result.metricValue)}`));
|
|
1681
|
-
if (result.comparison) {
|
|
1682
|
-
console.log(a.gray(`Baseline: ${result.comparison.baselineName} (${result.comparison.baselineSessionId})`));
|
|
1683
|
-
console.log(a.gray(`Compare: ${result.comparison.result}`));
|
|
1684
|
-
}
|
|
1685
|
-
console.log(a.gray(`Duration: ${result.durationMs}ms`));
|
|
1686
|
-
if (result.stderr) {
|
|
1687
|
-
console.log("");
|
|
1688
|
-
console.log(a.bold("stderr"));
|
|
1689
|
-
console.log(a.dim(result.stderr));
|
|
1690
|
-
}
|
|
1691
|
-
if (result.stdout) {
|
|
1692
|
-
console.log("");
|
|
1693
|
-
console.log(a.bold("stdout"));
|
|
1694
|
-
console.log(a.dim(result.stdout));
|
|
1695
|
-
}
|
|
1696
|
-
console.log("");
|
|
1697
|
-
}
|
|
1698
|
-
async function initResearchCommand(options) {
|
|
1699
|
-
const { programPath } = initResearchProgram(options.program, options.cwd);
|
|
1700
|
-
console.log("");
|
|
1701
|
-
console.log(a.bold.cyan("\u{1F9ED} Research Program"));
|
|
1702
|
-
printDivider();
|
|
1703
|
-
console.log(a.gray(`Program: ${programPath}`));
|
|
1704
|
-
console.log("");
|
|
1705
|
-
}
|
|
1706
|
-
async function startResearchLoopCommand(options) {
|
|
1707
|
-
const status = await startResearchLoop({
|
|
1708
|
-
programPath: options.program,
|
|
1709
|
-
cwd: options.cwd,
|
|
1710
|
-
dbPath: options.dbPath,
|
|
1711
|
-
overrides: getLoopOverrides(options)
|
|
1712
|
-
});
|
|
1713
|
-
printResearchLoopStatus(status);
|
|
1714
|
-
}
|
|
1715
|
-
async function runResearchRoundCommand(sessionId, options) {
|
|
1716
|
-
const status = await runResearchRound({
|
|
1717
|
-
sessionId,
|
|
1718
|
-
cwd: options.cwd,
|
|
1719
|
-
dbPath: options.dbPath,
|
|
1720
|
-
overrides: getLoopOverrides(options)
|
|
1721
|
-
});
|
|
1722
|
-
printResearchLoopStatus(status);
|
|
1723
|
-
}
|
|
1724
|
-
async function resumeResearchLoopCommand(sessionId, options) {
|
|
1725
|
-
const status = await resumeResearchLoop({
|
|
1726
|
-
sessionId,
|
|
1727
|
-
cwd: options.cwd,
|
|
1728
|
-
dbPath: options.dbPath,
|
|
1729
|
-
overrides: getLoopOverrides(options)
|
|
1730
|
-
});
|
|
1731
|
-
printResearchLoopStatus(status);
|
|
1732
|
-
}
|
|
1733
|
-
async function stopResearchLoopCommand(sessionId, options) {
|
|
1734
|
-
const status = stopResearchLoop({ sessionId, dbPath: options.dbPath });
|
|
1735
|
-
if (!status) {
|
|
1736
|
-
console.log(a.yellow(sessionId ? `Research loop session not found: ${sessionId}` : "No research loop sessions found."));
|
|
1737
|
-
console.log("");
|
|
1738
|
-
return;
|
|
1739
|
-
}
|
|
1740
|
-
printResearchLoopStatus(status);
|
|
1741
|
-
}
|
|
1742
|
-
async function showResearchStatus(sessionId, options) {
|
|
1743
|
-
const loopStatus = getResearchLoopStatus(sessionId, options.dbPath);
|
|
1744
|
-
if (loopStatus) {
|
|
1745
|
-
printResearchLoopStatus(loopStatus);
|
|
1746
|
-
return;
|
|
1747
|
-
}
|
|
1748
|
-
const resolvedSessionId = sessionId || getLatestResearchSession(options.dbPath)?.id;
|
|
1749
|
-
if (!resolvedSessionId) {
|
|
1750
|
-
console.log(a.yellow("No research sessions found."));
|
|
1751
|
-
console.log("");
|
|
1752
|
-
return;
|
|
1753
|
-
}
|
|
1754
|
-
const status = getResearchSessionStatus(resolvedSessionId, options.dbPath);
|
|
1755
|
-
if (!status) {
|
|
1756
|
-
console.log(a.yellow(`Research session not found: ${resolvedSessionId}`));
|
|
1757
|
-
console.log("");
|
|
1758
|
-
return;
|
|
1759
|
-
}
|
|
1760
|
-
const outputData = getLatestTaskData(status);
|
|
1761
|
-
const metricValue = typeof outputData.metricValue === "number" ? outputData.metricValue : typeof status.metadata.metricValue === "number" ? status.metadata.metricValue : void 0;
|
|
1762
|
-
console.log("");
|
|
1763
|
-
console.log(a.bold.cyan("\u{1F9EA} Research Status"));
|
|
1764
|
-
printDivider();
|
|
1765
|
-
console.log(a.gray(`Session: ${status.sessionId}`));
|
|
1766
|
-
console.log(a.gray(`Name: ${status.metadata.name || status.sessionId}`));
|
|
1767
|
-
console.log(a.gray(`Phase: ${status.metadata.currentPhase || "unknown"}`));
|
|
1768
|
-
console.log(a.gray(`Objective: ${status.metadata.objective || "unknown"}`));
|
|
1769
|
-
console.log(a.gray(`Verdict: ${status.metadata.verdict || "unknown"}`));
|
|
1770
|
-
console.log(a.gray(`Reason: ${status.metadata.verdictReason || "unknown"}`));
|
|
1771
|
-
console.log(a.gray(`Command: ${status.metadata.command || "unknown"}`));
|
|
1772
|
-
console.log(a.gray(`Metric: ${formatMetric(status.metadata.metricName, metricValue)}`));
|
|
1773
|
-
console.log(a.gray(`Status: ${outputData.status || status.metadata.status || "unknown"}`));
|
|
1774
|
-
console.log(a.gray(`Exit code: ${outputData.exitCode ?? status.metadata.exitCode ?? "unknown"}`));
|
|
1775
|
-
console.log(a.gray(`Duration: ${outputData.durationMs ?? status.metadata.durationMs ?? "unknown"}ms`));
|
|
1776
|
-
console.log(a.gray(`Tasks: ${status.metrics.completedTasks}/${status.metrics.totalTasks} completed`));
|
|
1777
|
-
console.log(a.gray(`Success: ${Math.round((status.metrics.successRate || 0) * 100)}%`));
|
|
1778
|
-
console.log(a.gray(`Avg ms: ${status.metrics.avgExecutionTime}`));
|
|
1779
|
-
console.log(a.gray(`Next: ${status.recovery.nextExecutable.length}`));
|
|
1780
|
-
if (status.metadata.comparison) {
|
|
1781
|
-
const comparison = status.metadata.comparison;
|
|
1782
|
-
console.log(a.gray(`Baseline: ${comparison.baselineName || comparison.baselineSessionId || "unknown"}`));
|
|
1783
|
-
console.log(a.gray(`Compare: ${comparison.result || "unknown"}`));
|
|
1784
|
-
console.log(a.gray(`Summary: ${comparison.summary || "unknown"}`));
|
|
1785
|
-
}
|
|
1786
|
-
if (status.decisions.length > 0) {
|
|
1787
|
-
const lastDecision = status.decisions[status.decisions.length - 1];
|
|
1788
|
-
console.log(a.gray(`Decision: ${lastDecision.outcome || lastDecision.decision}`));
|
|
1789
|
-
}
|
|
1790
|
-
console.log("");
|
|
1791
|
-
}
|
|
1792
|
-
async function listResearchCommand(options) {
|
|
1793
|
-
const sessions = listResearchSessions(options.limit || 10, options.dbPath);
|
|
1794
|
-
console.log("");
|
|
1795
|
-
console.log(a.bold.cyan("\u{1F4DA} Research Sessions"));
|
|
1796
|
-
printDivider();
|
|
1797
|
-
if (sessions.length === 0) {
|
|
1798
|
-
console.log(a.yellow("No research sessions found."));
|
|
1799
|
-
console.log("");
|
|
1800
|
-
return;
|
|
1801
|
-
}
|
|
1802
|
-
for (const session of sessions) {
|
|
1803
|
-
console.log(a.bold(session.name));
|
|
1804
|
-
console.log(a.gray(` ${session.id}`));
|
|
1805
|
-
console.log(a.gray(` phase: ${session.currentPhase}`));
|
|
1806
|
-
console.log(a.gray(` objective: ${session.objective || "unknown"}`));
|
|
1807
|
-
console.log(a.gray(` verdict: ${session.verdict || "unknown"}`));
|
|
1808
|
-
if (session.baselineSessionId) {
|
|
1809
|
-
console.log(a.gray(` baseline: ${session.baselineSessionId}`));
|
|
1810
|
-
}
|
|
1811
|
-
console.log(a.gray(` cmd: ${session.command}`));
|
|
1812
|
-
console.log(a.gray(` metric: ${session.metricName || "not configured"}`));
|
|
1813
|
-
console.log(a.gray(` cwd: ${session.cwd}`));
|
|
1814
|
-
}
|
|
1815
|
-
console.log("");
|
|
1816
|
-
}
|
|
1817
|
-
async function showResearchResults(options) {
|
|
1818
|
-
const rows = listResearchResults(options.limit || 10, options.dbPath);
|
|
1819
|
-
const best = getBestResearchResult(options.dbPath);
|
|
1820
|
-
console.log("");
|
|
1821
|
-
console.log(a.bold.cyan("\u{1F4C8} Research Results"));
|
|
1822
|
-
printDivider();
|
|
1823
|
-
if (rows.length === 0) {
|
|
1824
|
-
console.log(a.yellow("No research results found."));
|
|
1825
|
-
console.log("");
|
|
1826
|
-
return;
|
|
1827
|
-
}
|
|
1828
|
-
if (best) {
|
|
1829
|
-
console.log(a.bold("Best"));
|
|
1830
|
-
console.log(a.gray(` ${best.name} \xB7 ${formatMetric(best.metricName, best.metricValue)} \xB7 ${best.status} \xB7 ${best.durationMs}ms`));
|
|
1831
|
-
console.log(a.gray(` objective: ${best.metricName ? ["loss", "error", "bpb", "perplexity", "ppl", "latency", "duration", "time", "cost", "price", "wer", "cer"].some((keyword) => best.metricName?.toLowerCase().includes(keyword)) ? "minimize" : "maximize" : "unknown"}`));
|
|
1832
|
-
console.log(a.gray(` ${previewCommand(best.command)}`));
|
|
1833
|
-
console.log("");
|
|
1834
|
-
}
|
|
1835
|
-
console.log(a.bold("Recent"));
|
|
1836
|
-
for (const row of rows) {
|
|
1837
|
-
console.log(a.gray(`${formatTimestamp(row.timestamp)} \xB7 ${row.name} \xB7 ${row.status} \xB7 ${formatMetric(row.metricName, row.metricValue)} \xB7 ${row.durationMs}ms \xB7 ${previewCommand(row.command)}`));
|
|
1838
|
-
}
|
|
1839
|
-
console.log("");
|
|
1840
|
-
}
|
|
1841
|
-
async function showResearchReport(sessionId, options) {
|
|
1842
|
-
const loopReport = getResearchLoopReport(sessionId, options.dbPath);
|
|
1843
|
-
if (loopReport) {
|
|
1844
|
-
console.log("");
|
|
1845
|
-
console.log(a.bold.cyan("\u{1F4DD} Research Loop Report"));
|
|
1846
|
-
printDivider();
|
|
1847
|
-
console.log(loopReport.content);
|
|
1848
|
-
console.log("");
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
const report = getResearchReport(sessionId, options.dbPath);
|
|
1852
|
-
if (!report) {
|
|
1853
|
-
console.log(a.yellow(sessionId ? `Research session not found: ${sessionId}` : "No research sessions found."));
|
|
1854
|
-
console.log("");
|
|
1855
|
-
return;
|
|
1856
|
-
}
|
|
1857
|
-
console.log("");
|
|
1858
|
-
console.log(a.bold.cyan("\u{1F4DD} Research Report"));
|
|
1859
|
-
printDivider();
|
|
1860
|
-
console.log(a.gray(`Session: ${report.sessionId}`));
|
|
1861
|
-
console.log(a.gray(`Name: ${report.name}`));
|
|
1862
|
-
console.log(a.gray(`Created: ${formatTimestamp(report.createdAt)}`));
|
|
1863
|
-
console.log(a.gray(`Command: ${report.command}`));
|
|
1864
|
-
console.log(a.gray(`CWD: ${report.cwd}`));
|
|
1865
|
-
console.log(a.gray(`Status: ${report.status}`));
|
|
1866
|
-
console.log(a.gray(`Exit code: ${report.exitCode}`));
|
|
1867
|
-
console.log(a.gray(`Duration: ${report.durationMs}ms`));
|
|
1868
|
-
console.log(a.gray(`Metric: ${formatMetric(report.metricName, report.metricValue)}`));
|
|
1869
|
-
console.log(a.gray(`Objective: ${report.objective || "unknown"}`));
|
|
1870
|
-
console.log(a.gray(`Reason: ${report.verdictReason}`));
|
|
1871
|
-
if (report.comparison) {
|
|
1872
|
-
console.log(a.gray(`Baseline: ${report.comparison.baselineName} (${report.comparison.baselineSessionId})`));
|
|
1873
|
-
console.log(a.gray(`Compare: ${report.comparison.result}`));
|
|
1874
|
-
}
|
|
1875
|
-
console.log(a.gray(`Outcome: ${report.outcome}`));
|
|
1876
|
-
if (report.phaseHistory.length > 0) {
|
|
1877
|
-
console.log(a.gray(`Phases: ${report.phaseHistory.join(" \u2192 ")}`));
|
|
1878
|
-
}
|
|
1879
|
-
console.log("");
|
|
1880
|
-
}
|
|
1881
|
-
function showResearchHelp() {
|
|
1882
|
-
console.log("");
|
|
1883
|
-
console.log(a.bold.cyan("ccjk research"));
|
|
1884
|
-
printDivider();
|
|
1885
|
-
console.log(" init Create a research program template");
|
|
1886
|
-
console.log(" loop Start a persisted research loop");
|
|
1887
|
-
console.log(" round Run one candidate round for a loop");
|
|
1888
|
-
console.log(" resume Continue a persisted research loop until stop");
|
|
1889
|
-
console.log(" stop Stop a running research loop");
|
|
1890
|
-
console.log(" run Run a persisted research experiment with optional baseline comparison");
|
|
1891
|
-
console.log(" status Show the latest or selected research session status");
|
|
1892
|
-
console.log(" sessions List recent research sessions");
|
|
1893
|
-
console.log(" results Show recent result rows and the current best run");
|
|
1894
|
-
console.log(" report Render a compact persisted research report");
|
|
1895
|
-
console.log("");
|
|
1896
|
-
console.log(a.dim("Example: ccjk research init"));
|
|
1897
|
-
console.log(a.dim("Example: ccjk research loop --program .ccjk/research/program.md"));
|
|
1898
|
-
console.log(a.dim("Example: ccjk research round research-loop-123"));
|
|
1899
|
-
console.log(a.dim('Example: ccjk research run --name baseline --cmd "python train.py" --metric val_bpb --objective minimize'));
|
|
1900
|
-
console.log(a.dim("Example: ccjk research report research-123"));
|
|
1901
|
-
console.log("");
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
export { researchCommand, showResearchHelp };
|