codemini-cli 0.4.7 → 0.4.9
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/README.md +103 -1
- package/codemini-web/dist/assets/abap-BRbAAyvE.js +1 -0
- package/codemini-web/dist/assets/actionscript-3-Cj-0sM4g.js +1 -0
- package/codemini-web/dist/assets/ada-DhEA_nP5.js +1 -0
- package/codemini-web/dist/assets/andromeeda-CWmR-N6V.js +1 -0
- package/codemini-web/dist/assets/angular-html-Cde9qVP5.js +1 -0
- package/codemini-web/dist/assets/angular-ts-DefScAWP.js +1 -0
- package/codemini-web/dist/assets/apache-D5R2GKIs.js +1 -0
- package/codemini-web/dist/assets/apex-Qu8W4hal.js +1 -0
- package/codemini-web/dist/assets/apl-w753UHCW.js +1 -0
- package/codemini-web/dist/assets/applescript-CBey3ErE.js +1 -0
- package/codemini-web/dist/assets/ara-CRKnUAN1.js +1 -0
- package/codemini-web/dist/assets/asciidoc-1KYZEB6-.js +1 -0
- package/codemini-web/dist/assets/asm-DAaViY0U.js +1 -0
- package/codemini-web/dist/assets/astro-DBA9Da7s.js +1 -0
- package/codemini-web/dist/assets/aurora-x-LPpmXm4i.js +1 -0
- package/codemini-web/dist/assets/awk-ButuPTaW.js +1 -0
- package/codemini-web/dist/assets/ayu-dark-Dv4ngVMP.js +1 -0
- package/codemini-web/dist/assets/ayu-light-CxeOePuA.js +1 -0
- package/codemini-web/dist/assets/ayu-mirage-i2YLXKmY.js +1 -0
- package/codemini-web/dist/assets/ballerina-DodmBVwR.js +1 -0
- package/codemini-web/dist/assets/bat-jA-YqDhG.js +1 -0
- package/codemini-web/dist/assets/beancount-BCkjWTs-.js +1 -0
- package/codemini-web/dist/assets/berry-DjEHm1kC.js +1 -0
- package/codemini-web/dist/assets/bibtex-aOfmXHFj.js +1 -0
- package/codemini-web/dist/assets/bicep-BZLx0b6B.js +1 -0
- package/codemini-web/dist/assets/bird2-Bs7YDhA3.js +1 -0
- package/codemini-web/dist/assets/blade-B-u5p0Rp.js +1 -0
- package/codemini-web/dist/assets/bsl-CPV9KqsG.js +1 -0
- package/codemini-web/dist/assets/c-Bv0tI3pq.js +1 -0
- package/codemini-web/dist/assets/c3-BDcFIiRd.js +1 -0
- package/codemini-web/dist/assets/cadence-DaglWUgA.js +1 -0
- package/codemini-web/dist/assets/cairo-CyiRuu7R.js +1 -0
- package/codemini-web/dist/assets/catppuccin-frappe-CSAC76is.js +1 -0
- package/codemini-web/dist/assets/catppuccin-latte-Jt6sqtds.js +1 -0
- package/codemini-web/dist/assets/catppuccin-macchiato-HM96_05s.js +1 -0
- package/codemini-web/dist/assets/catppuccin-mocha-CXgIAGBL.js +1 -0
- package/codemini-web/dist/assets/clarity-DS5YLe8G.js +1 -0
- package/codemini-web/dist/assets/clojure-BVGPdaE2.js +1 -0
- package/codemini-web/dist/assets/cmake-CCC7tP43.js +1 -0
- package/codemini-web/dist/assets/cobol-CkQrskif.js +1 -0
- package/codemini-web/dist/assets/codeowners-DXhoR5Ap.js +1 -0
- package/codemini-web/dist/assets/codeql-BGjlu3KC.js +1 -0
- package/codemini-web/dist/assets/coffee-rY-gkJy7.js +1 -0
- package/codemini-web/dist/assets/common-lisp-BE6wRQeA.js +1 -0
- package/codemini-web/dist/assets/coq-CRT8yML1.js +1 -0
- package/codemini-web/dist/assets/cpp-Bw-qV0P6.js +1 -0
- package/codemini-web/dist/assets/crystal-Dh09vXLx.js +1 -0
- package/codemini-web/dist/assets/csharp-Ca2kU4Te.js +1 -0
- package/codemini-web/dist/assets/css-BTi88BmP.js +1 -0
- package/codemini-web/dist/assets/csv-DUpZC5ZD.js +1 -0
- package/codemini-web/dist/assets/cue-DlXQ7arx.js +1 -0
- package/codemini-web/dist/assets/cypher-D6dhuZbo.js +1 -0
- package/codemini-web/dist/assets/d-BUgyoY6k.js +1 -0
- package/codemini-web/dist/assets/dark-plus-DNkJKrcZ.js +1 -0
- package/codemini-web/dist/assets/dart-Czrjv-nr.js +1 -0
- package/codemini-web/dist/assets/dax-sEzq00Tq.js +1 -0
- package/codemini-web/dist/assets/desktop-3VGbzlmJ.js +1 -0
- package/codemini-web/dist/assets/diff-D4HSRbRn.js +1 -0
- package/codemini-web/dist/assets/docker-DkLGgDMo.js +1 -0
- package/codemini-web/dist/assets/dotenv-BWp1FaLo.js +1 -0
- package/codemini-web/dist/assets/dracula-Donvxzd6.js +1 -0
- package/codemini-web/dist/assets/dracula-soft-BqL-kkUg.js +1 -0
- package/codemini-web/dist/assets/dream-maker-DtLD6KM3.js +1 -0
- package/codemini-web/dist/assets/edge-CCRtknu5.js +1 -0
- package/codemini-web/dist/assets/elixir-5EYbFEoC.js +1 -0
- package/codemini-web/dist/assets/elm-Cezz_HNz.js +1 -0
- package/codemini-web/dist/assets/emacs-lisp-D4W-_rAk.js +1 -0
- package/codemini-web/dist/assets/erb-C6pPz4fX.js +1 -0
- package/codemini-web/dist/assets/erlang-BC8wryba.js +1 -0
- package/codemini-web/dist/assets/everforest-dark-pZNhY4MK.js +1 -0
- package/codemini-web/dist/assets/everforest-light-BijKClkf.js +1 -0
- package/codemini-web/dist/assets/fennel-Cd-BhZ0S.js +1 -0
- package/codemini-web/dist/assets/fish-CpsjJ6FK.js +1 -0
- package/codemini-web/dist/assets/fluent-D1peBFgx.js +1 -0
- package/codemini-web/dist/assets/fortran-fixed-form-CyrImzNA.js +1 -0
- package/codemini-web/dist/assets/fortran-free-form-CIAQqF5W.js +1 -0
- package/codemini-web/dist/assets/fsharp-OCW_PZ4J.js +1 -0
- package/codemini-web/dist/assets/gdresource-Cl3bohRI.js +1 -0
- package/codemini-web/dist/assets/gdscript-B_XVILZe.js +1 -0
- package/codemini-web/dist/assets/gdshader-BOrkFM_X.js +1 -0
- package/codemini-web/dist/assets/genie-BE7nKhIq.js +1 -0
- package/codemini-web/dist/assets/gherkin-DzGJhdqS.js +1 -0
- package/codemini-web/dist/assets/git-commit-DJZpdBwB.js +1 -0
- package/codemini-web/dist/assets/git-rebase-BJE30GTP.js +1 -0
- package/codemini-web/dist/assets/github-dark-BB9G20EV.js +1 -0
- package/codemini-web/dist/assets/github-dark-default-CBFNEU03.js +1 -0
- package/codemini-web/dist/assets/github-dark-dimmed-sQhEp72S.js +1 -0
- package/codemini-web/dist/assets/github-dark-high-contrast-C8GVvrcM.js +1 -0
- package/codemini-web/dist/assets/github-light-default-iyEXWnoa.js +1 -0
- package/codemini-web/dist/assets/github-light-high-contrast-DLnsZL7l.js +1 -0
- package/codemini-web/dist/assets/github-light-pT7U8Cnd.js +1 -0
- package/codemini-web/dist/assets/gleam-B9ISJjDl.js +1 -0
- package/codemini-web/dist/assets/glimmer-js-C4PTXfaW.js +1 -0
- package/codemini-web/dist/assets/glimmer-ts-Df1V6YK_.js +1 -0
- package/codemini-web/dist/assets/glsl-C8VPaAWs.js +1 -0
- package/codemini-web/dist/assets/gn-RQRMslrP.js +1 -0
- package/codemini-web/dist/assets/gnuplot-CfIGZWjt.js +1 -0
- package/codemini-web/dist/assets/go-BTh90-YS.js +1 -0
- package/codemini-web/dist/assets/graphql-WZCiqIl-.js +1 -0
- package/codemini-web/dist/assets/groovy-lvGC2zUz.js +1 -0
- package/codemini-web/dist/assets/gruvbox-dark-hard-CC38iqQ4.js +1 -0
- package/codemini-web/dist/assets/gruvbox-dark-medium-DaS0IqFN.js +1 -0
- package/codemini-web/dist/assets/gruvbox-dark-soft-C4niJipy.js +1 -0
- package/codemini-web/dist/assets/gruvbox-light-hard-DTfv4LmB.js +1 -0
- package/codemini-web/dist/assets/gruvbox-light-medium-m1VBpvsE.js +1 -0
- package/codemini-web/dist/assets/gruvbox-light-soft-CiE1IJdk.js +1 -0
- package/codemini-web/dist/assets/hack-zJL_tEH0.js +1 -0
- package/codemini-web/dist/assets/haml-qjVLLTZk.js +1 -0
- package/codemini-web/dist/assets/handlebars-B3RyMMk0.js +1 -0
- package/codemini-web/dist/assets/haskell-DdaZtXdd.js +1 -0
- package/codemini-web/dist/assets/haxe-Df79h8x1.js +1 -0
- package/codemini-web/dist/assets/hcl-BibREsa1.js +1 -0
- package/codemini-web/dist/assets/highlighted-body-OFNGDK62-DjZhmRtv.js +1 -0
- package/codemini-web/dist/assets/hjson-D-iSecYq.js +1 -0
- package/codemini-web/dist/assets/hlsl-CckLjo_3.js +1 -0
- package/codemini-web/dist/assets/horizon-BG-OH9yH.js +1 -0
- package/codemini-web/dist/assets/horizon-bright-CpoqdULz.js +1 -0
- package/codemini-web/dist/assets/houston-C8DdNIgg.js +1 -0
- package/codemini-web/dist/assets/html-DP-V-rfg.js +1 -0
- package/codemini-web/dist/assets/html-derivative-DB9UhNDN.js +1 -0
- package/codemini-web/dist/assets/http-Deln4Vyb.js +1 -0
- package/codemini-web/dist/assets/hurl-CYSuhGkj.js +1 -0
- package/codemini-web/dist/assets/hxml-BmF7ngDz.js +1 -0
- package/codemini-web/dist/assets/hy-6acR1htR.js +1 -0
- package/codemini-web/dist/assets/imba-I9bJJvhi.js +1 -0
- package/codemini-web/dist/assets/index-Boi36rz_.css +2 -0
- package/codemini-web/dist/assets/index-CqDOO9gZ.js +206 -0
- package/codemini-web/dist/assets/ini-ovi-wMtM.js +1 -0
- package/codemini-web/dist/assets/java-X0I2c5Az.js +1 -0
- package/codemini-web/dist/assets/javascript-WC6XFf_S.js +1 -0
- package/codemini-web/dist/assets/jinja-BcRTlqOI.js +1 -0
- package/codemini-web/dist/assets/jison-DuNOGix6.js +1 -0
- package/codemini-web/dist/assets/json-CmuSmrUv.js +1 -0
- package/codemini-web/dist/assets/json5-JNG5kh3j.js +1 -0
- package/codemini-web/dist/assets/jsonc-Bo6bgSpa.js +1 -0
- package/codemini-web/dist/assets/jsonl-eDmbsRcr.js +1 -0
- package/codemini-web/dist/assets/jsonnet-BrmnmEy9.js +1 -0
- package/codemini-web/dist/assets/jssm-C-QfdDgD.js +1 -0
- package/codemini-web/dist/assets/jsx-Bl4e1-KE.js +1 -0
- package/codemini-web/dist/assets/julia-Cqc1ADyw.js +1 -0
- package/codemini-web/dist/assets/just-O9z-zIlY.js +1 -0
- package/codemini-web/dist/assets/kanagawa-dragon-Dc8jzBf8.js +1 -0
- package/codemini-web/dist/assets/kanagawa-lotus-DglQpAHb.js +1 -0
- package/codemini-web/dist/assets/kanagawa-wave-CTxJC692.js +1 -0
- package/codemini-web/dist/assets/kdl-CPujEk7a.js +1 -0
- package/codemini-web/dist/assets/kotlin-GNGS6f4G.js +1 -0
- package/codemini-web/dist/assets/kusto-ByPWIc1b.js +1 -0
- package/codemini-web/dist/assets/laserwave-BLDq6SCM.js +1 -0
- package/codemini-web/dist/assets/latex-BEPTKliI.js +1 -0
- package/codemini-web/dist/assets/lean-CQ4oht2M.js +1 -0
- package/codemini-web/dist/assets/less-DgluPI4Z.js +1 -0
- package/codemini-web/dist/assets/light-plus-Ce6vIMrA.js +1 -0
- package/codemini-web/dist/assets/liquid-BK2PyMjt.js +1 -0
- package/codemini-web/dist/assets/llvm-C_Bk8N51.js +1 -0
- package/codemini-web/dist/assets/log-Cqyx7kYB.js +1 -0
- package/codemini-web/dist/assets/logo-BMyACSNp.js +1 -0
- package/codemini-web/dist/assets/lua-BroxvhVt.js +1 -0
- package/codemini-web/dist/assets/luau-Dw3qkd4h.js +1 -0
- package/codemini-web/dist/assets/make-DRoG6w-e.js +1 -0
- package/codemini-web/dist/assets/markdown-DMIvNSB1.js +1 -0
- package/codemini-web/dist/assets/marko-CTEKS39A.js +1 -0
- package/codemini-web/dist/assets/material-theme-D1yzOeFY.js +1 -0
- package/codemini-web/dist/assets/material-theme-darker-DhWqiNtj.js +1 -0
- package/codemini-web/dist/assets/material-theme-lighter-PKoq0Soa.js +1 -0
- package/codemini-web/dist/assets/material-theme-ocean-TtH-ZZAj.js +1 -0
- package/codemini-web/dist/assets/material-theme-palenight-DPEAidnA.js +1 -0
- package/codemini-web/dist/assets/matlab-Buftnej6.js +1 -0
- package/codemini-web/dist/assets/mdc-BOaCYzzL.js +1 -0
- package/codemini-web/dist/assets/mdx-COL7Vpwq.js +1 -0
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-frRIem48.js +1 -0
- package/codemini-web/dist/assets/mermaid-tvyj1ZQ2.js +1 -0
- package/codemini-web/dist/assets/min-dark-D66g901Q.js +1 -0
- package/codemini-web/dist/assets/min-light-CMnDj2iG.js +1 -0
- package/codemini-web/dist/assets/mipsasm-C6fvALrw.js +1 -0
- package/codemini-web/dist/assets/mojo-B3qnM1a8.js +1 -0
- package/codemini-web/dist/assets/monokai-DCoxt20T.js +1 -0
- package/codemini-web/dist/assets/moonbit-Cjo3d0oi.js +1 -0
- package/codemini-web/dist/assets/move-BZSDQnwS.js +1 -0
- package/codemini-web/dist/assets/narrat-DY5cg5OF.js +1 -0
- package/codemini-web/dist/assets/nextflow-Cto1mpL3.js +1 -0
- package/codemini-web/dist/assets/nextflow-groovy-D1X5Yd05.js +1 -0
- package/codemini-web/dist/assets/nginx-Da_Uewgc.js +1 -0
- package/codemini-web/dist/assets/night-owl-DuMFo77c.js +1 -0
- package/codemini-web/dist/assets/night-owl-light-DihOYNub.js +1 -0
- package/codemini-web/dist/assets/nim-BZyx58NM.js +1 -0
- package/codemini-web/dist/assets/nix-C2G-gZoY.js +1 -0
- package/codemini-web/dist/assets/nord-CqZqLQaJ.js +1 -0
- package/codemini-web/dist/assets/nushell-S11HUHTG.js +1 -0
- package/codemini-web/dist/assets/objective-c-D9GKvYFi.js +1 -0
- package/codemini-web/dist/assets/objective-cpp-SqrtXFXh.js +1 -0
- package/codemini-web/dist/assets/ocaml-C_PTi_Pz.js +1 -0
- package/codemini-web/dist/assets/odin-BWpZDKBG.js +1 -0
- package/codemini-web/dist/assets/one-dark-pro-DpWTHpwg.js +1 -0
- package/codemini-web/dist/assets/one-light-Cu0d64Hp.js +1 -0
- package/codemini-web/dist/assets/openscad-BM4fjXzn.js +1 -0
- package/codemini-web/dist/assets/pascal-DYsRufgb.js +1 -0
- package/codemini-web/dist/assets/perl-BW8t13Xq.js +1 -0
- package/codemini-web/dist/assets/php-Cq5FOhfR.js +1 -0
- package/codemini-web/dist/assets/pkl-Djf8ANrI.js +1 -0
- package/codemini-web/dist/assets/plastic-CmjIC4JL.js +1 -0
- package/codemini-web/dist/assets/plsql-B1bmZxUF.js +1 -0
- package/codemini-web/dist/assets/po-BvnTR3_f.js +1 -0
- package/codemini-web/dist/assets/poimandres-BTndTogr.js +1 -0
- package/codemini-web/dist/assets/polar-CAj5SJyd.js +1 -0
- package/codemini-web/dist/assets/postcss-DrpvRGGG.js +1 -0
- package/codemini-web/dist/assets/powerquery-I1Ei5hrS.js +1 -0
- package/codemini-web/dist/assets/powershell-Coc0WruX.js +1 -0
- package/codemini-web/dist/assets/prisma-Ojgxt2lx.js +1 -0
- package/codemini-web/dist/assets/prolog-C1UOAv4v.js +1 -0
- package/codemini-web/dist/assets/proto-D07RTuB5.js +1 -0
- package/codemini-web/dist/assets/pug-B4WHazil.js +1 -0
- package/codemini-web/dist/assets/puppet-D_zyrMo2.js +1 -0
- package/codemini-web/dist/assets/purescript-CV-DVmZj.js +1 -0
- package/codemini-web/dist/assets/python-DcnbpNOV.js +1 -0
- package/codemini-web/dist/assets/qml-DWxWu28U.js +1 -0
- package/codemini-web/dist/assets/qmldir-BBNnU9RJ.js +1 -0
- package/codemini-web/dist/assets/qss-CC0PKRbL.js +1 -0
- package/codemini-web/dist/assets/r-B4lG5syH.js +1 -0
- package/codemini-web/dist/assets/racket-Cbwns2Cq.js +1 -0
- package/codemini-web/dist/assets/raku-CeV6tH_x.js +1 -0
- package/codemini-web/dist/assets/razor-CQPYUgex.js +1 -0
- package/codemini-web/dist/assets/red-CVEaJbMR.js +1 -0
- package/codemini-web/dist/assets/reg-C_WE1pkC.js +1 -0
- package/codemini-web/dist/assets/regexp-da3KYCEG.js +1 -0
- package/codemini-web/dist/assets/rel-CpHQF4b7.js +1 -0
- package/codemini-web/dist/assets/riscv-Co5eiPIZ.js +1 -0
- package/codemini-web/dist/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
- package/codemini-web/dist/assets/ron-CgTit1dG.js +1 -0
- package/codemini-web/dist/assets/rose-pine-BDTwvYHf.js +1 -0
- package/codemini-web/dist/assets/rose-pine-dawn-CAIk_wLV.js +1 -0
- package/codemini-web/dist/assets/rose-pine-moon-C5gdiznP.js +1 -0
- package/codemini-web/dist/assets/rosmsg-C0tpzWlc.js +1 -0
- package/codemini-web/dist/assets/rst-B-OS2pa5.js +1 -0
- package/codemini-web/dist/assets/ruby-BM15fmxz.js +1 -0
- package/codemini-web/dist/assets/rust-BWAfVMY4.js +1 -0
- package/codemini-web/dist/assets/sas-DYNukvU9.js +1 -0
- package/codemini-web/dist/assets/sass-MovLey2R.js +1 -0
- package/codemini-web/dist/assets/scala-C2w7y2mZ.js +1 -0
- package/codemini-web/dist/assets/scheme-Bf85FNnm.js +1 -0
- package/codemini-web/dist/assets/scss-C0BQ8YVM.js +1 -0
- package/codemini-web/dist/assets/sdbl-DoQ_zDzo.js +1 -0
- package/codemini-web/dist/assets/shaderlab-TbUUdmUb.js +1 -0
- package/codemini-web/dist/assets/shellscript-KUJZnuCi.js +1 -0
- package/codemini-web/dist/assets/shellsession-BeWGuVoR.js +1 -0
- package/codemini-web/dist/assets/slack-dark-BnOYKTBJ.js +1 -0
- package/codemini-web/dist/assets/slack-ochin-43udxtUg.js +1 -0
- package/codemini-web/dist/assets/smalltalk-Mlf5-xbr.js +1 -0
- package/codemini-web/dist/assets/snazzy-light-kw-pZEiM.js +1 -0
- package/codemini-web/dist/assets/solarized-dark-BDezFa9V.js +1 -0
- package/codemini-web/dist/assets/solarized-light-CkoenhS2.js +1 -0
- package/codemini-web/dist/assets/solidity-DYHGECBw.js +1 -0
- package/codemini-web/dist/assets/soy-C6D0Ibo9.js +1 -0
- package/codemini-web/dist/assets/sparql-DIFvSn1n.js +1 -0
- package/codemini-web/dist/assets/splunk-DOdklC0I.js +1 -0
- package/codemini-web/dist/assets/sql-CZAMrWdL.js +1 -0
- package/codemini-web/dist/assets/ssh-config-DwwFW7AS.js +1 -0
- package/codemini-web/dist/assets/stata-C5mLa_ER.js +1 -0
- package/codemini-web/dist/assets/stylus-BO6mlOab.js +1 -0
- package/codemini-web/dist/assets/surrealql-DyoUfV6n.js +1 -0
- package/codemini-web/dist/assets/svelte-DJ-0FpL2.js +1 -0
- package/codemini-web/dist/assets/swift-D9A08YU9.js +1 -0
- package/codemini-web/dist/assets/synthwave-84-C69NN2j9.js +1 -0
- package/codemini-web/dist/assets/system-verilog-DjR3sN6w.js +1 -0
- package/codemini-web/dist/assets/systemd-CJWuVSJU.js +1 -0
- package/codemini-web/dist/assets/talonscript-CXqq0wX-.js +1 -0
- package/codemini-web/dist/assets/tasl-GVNf7pB7.js +1 -0
- package/codemini-web/dist/assets/tcl-DNlfRSl5.js +1 -0
- package/codemini-web/dist/assets/templ-7Bvm-rei.js +1 -0
- package/codemini-web/dist/assets/terraform-DUK0FOOj.js +1 -0
- package/codemini-web/dist/assets/tex-ezg8IclB.js +1 -0
- package/codemini-web/dist/assets/tokyo-night-DWTtuXS3.js +1 -0
- package/codemini-web/dist/assets/toml-X5n3zjEH.js +1 -0
- package/codemini-web/dist/assets/ts-tags-BfuR6EQ0.js +1 -0
- package/codemini-web/dist/assets/tsv-Bqs_rchc.js +1 -0
- package/codemini-web/dist/assets/tsx-CfyUE2pW.js +1 -0
- package/codemini-web/dist/assets/turtle-BsUuoeVK.js +1 -0
- package/codemini-web/dist/assets/twig-_uxJ-QmX.js +1 -0
- package/codemini-web/dist/assets/typescript-C6LvTgbf.js +1 -0
- package/codemini-web/dist/assets/typespec-8nkhqWz6.js +1 -0
- package/codemini-web/dist/assets/typst-CPL77SDw.js +1 -0
- package/codemini-web/dist/assets/v-CoJD3IPx.js +1 -0
- package/codemini-web/dist/assets/vala-C42IfotU.js +1 -0
- package/codemini-web/dist/assets/vb-CVMKTK26.js +1 -0
- package/codemini-web/dist/assets/verilog-P63PhzSt.js +1 -0
- package/codemini-web/dist/assets/vesper-BGr95374.js +1 -0
- package/codemini-web/dist/assets/vhdl-2WwUdgX8.js +1 -0
- package/codemini-web/dist/assets/viml-CGPGWJA6.js +1 -0
- package/codemini-web/dist/assets/vitesse-black-cI0k84-I.js +1 -0
- package/codemini-web/dist/assets/vitesse-dark-SouM0FMW.js +1 -0
- package/codemini-web/dist/assets/vitesse-light-WiCy6lDO.js +1 -0
- package/codemini-web/dist/assets/vue-DkOBu49o.js +1 -0
- package/codemini-web/dist/assets/vue-html-Bx2Sgp8M.js +1 -0
- package/codemini-web/dist/assets/vue-vine-veyFk6GJ.js +1 -0
- package/codemini-web/dist/assets/vyper-DP_vqZO9.js +1 -0
- package/codemini-web/dist/assets/wasm-Db7VBw0n.js +1 -0
- package/codemini-web/dist/assets/wasm-DiIFv9DE.js +1 -0
- package/codemini-web/dist/assets/wenyan-ZEcjghA1.js +1 -0
- package/codemini-web/dist/assets/wgsl-CdusuPLe.js +1 -0
- package/codemini-web/dist/assets/wikitext-CBIB6hmW.js +1 -0
- package/codemini-web/dist/assets/wit-ZhUbVeze.js +1 -0
- package/codemini-web/dist/assets/wolfram-HyMOyERF.js +1 -0
- package/codemini-web/dist/assets/xml-BkdunjRC.js +1 -0
- package/codemini-web/dist/assets/xsl-C66i1pDH.js +1 -0
- package/codemini-web/dist/assets/yaml-D_uvhEF7.js +1 -0
- package/codemini-web/dist/assets/zenscript-C6ZuzgrL.js +1 -0
- package/codemini-web/dist/assets/zig-Do2h8XKj.js +1 -0
- package/codemini-web/dist/index.html +21 -0
- package/codemini-web/lib/approval-manager.js +32 -0
- package/codemini-web/lib/runtime-bridge.js +518 -0
- package/codemini-web/server.js +846 -0
- package/deployment.md +5 -5
- package/package.json +6 -1
- package/src/cli.js +17 -6
- package/src/commands/chat.js +8 -2
- package/src/commands/run.js +9 -3
- package/src/commands/skill.js +1 -1
- package/src/commands/web.js +57 -0
- package/src/core/agent-loop.js +45 -14
- package/src/core/chat-runtime.js +602 -81
- package/src/core/config-store.js +9 -2
- package/src/core/fff-adapter.js +1 -1
- package/src/core/session-store.js +104 -9
- package/src/core/soul.js +13 -0
- package/templates/project-requirements/report-shell.html +2 -1
package/src/core/chat-runtime.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from './provider/index.js';
|
|
13
13
|
import { isDangerousCommand, runShellCommand } from './shell.js';
|
|
14
14
|
import { getBuiltinTools } from './tools.js';
|
|
15
|
-
import { createSession, listSessions, loadSession, pruneSessions, saveSession } from './session-store.js';
|
|
15
|
+
import { createSession, deriveSessionTitle, listSessions, loadSession, pruneSessions, saveSession } from './session-store.js';
|
|
16
16
|
import { getConfigValue, loadConfig, resetConfig, setConfigValue } from './config-store.js';
|
|
17
17
|
import { evaluateCommandPolicy } from './command-policy.js';
|
|
18
18
|
import { appendInputHistory, loadInputHistory } from './input-history-store.js';
|
|
@@ -55,7 +55,7 @@ function toOpenAIMessages(sessionMessages) {
|
|
|
55
55
|
}
|
|
56
56
|
mapped.push({
|
|
57
57
|
role: msg.role,
|
|
58
|
-
content: msg.content,
|
|
58
|
+
content: typeof msg.model_content === 'string' && msg.model_content ? msg.model_content : msg.content,
|
|
59
59
|
...(typeof msg.reasoning_content === 'string' && msg.reasoning_content ? { reasoning_content: msg.reasoning_content } : {}),
|
|
60
60
|
...(Array.isArray(msg.reasoning_details) && msg.reasoning_details.length > 0 ? { reasoning_details: msg.reasoning_details } : {}),
|
|
61
61
|
...(msg.tool_calls ? { tool_calls: msg.tool_calls } : {})
|
|
@@ -102,6 +102,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
102
102
|
'gateway.timeout_ms': '网关超时时间(毫秒)',
|
|
103
103
|
'gateway.max_retries': '网关重试次数',
|
|
104
104
|
'model.name': '当前模型名称',
|
|
105
|
+
'model.fast_name': '快速模型名称',
|
|
105
106
|
'model.max_context_tokens': '模型上下文 token 上限',
|
|
106
107
|
'ui.language': '界面语言',
|
|
107
108
|
'ui.reply_language': '回复语言',
|
|
@@ -156,6 +157,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
156
157
|
exit: '退出聊天',
|
|
157
158
|
commands: '列出 slash/自定义命令',
|
|
158
159
|
status: '查看运行状态(mode/model/session)',
|
|
160
|
+
model: '查看或切换模型',
|
|
159
161
|
mode: '设置执行模式:normal|auto|plan',
|
|
160
162
|
compact: '压缩消息上下文',
|
|
161
163
|
checkpoint: '创建/查看/加载检查点',
|
|
@@ -193,6 +195,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
193
195
|
retryCommand: '重试上一条用户请求',
|
|
194
196
|
stopCommand: '中止当前回答',
|
|
195
197
|
statusCommand: '查看运行状态',
|
|
198
|
+
modelCommand: '查看或切换模型',
|
|
196
199
|
resumeSession: '恢复一个已保存的会话'
|
|
197
200
|
}
|
|
198
201
|
},
|
|
@@ -204,6 +207,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
204
207
|
'gateway.timeout_ms': 'gateway timeout in milliseconds',
|
|
205
208
|
'gateway.max_retries': 'gateway retry count',
|
|
206
209
|
'model.name': 'active model name',
|
|
210
|
+
'model.fast_name': 'fast model name',
|
|
207
211
|
'model.max_context_tokens': 'model context token limit',
|
|
208
212
|
'ui.language': 'UI language',
|
|
209
213
|
'ui.reply_language': 'reply language',
|
|
@@ -258,6 +262,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
258
262
|
exit: 'exit chat',
|
|
259
263
|
commands: 'list slash/custom commands',
|
|
260
264
|
status: 'show runtime status (mode/model/session)',
|
|
265
|
+
model: 'show or switch model',
|
|
261
266
|
mode: 'set execution mode: normal|auto|plan',
|
|
262
267
|
compact: 'compress message context',
|
|
263
268
|
checkpoint: 'create/list/load conversation checkpoints',
|
|
@@ -295,6 +300,7 @@ function getCompletionCopy(language = 'zh') {
|
|
|
295
300
|
retryCommand: 'retry the last user request',
|
|
296
301
|
stopCommand: 'stop the current response',
|
|
297
302
|
statusCommand: 'show runtime status',
|
|
303
|
+
modelCommand: 'show or switch model',
|
|
298
304
|
resumeSession: 'resume a saved session'
|
|
299
305
|
}
|
|
300
306
|
}
|
|
@@ -309,6 +315,7 @@ function describeConfigKey(key, mode = 'set', language = 'zh') {
|
|
|
309
315
|
}
|
|
310
316
|
|
|
311
317
|
const SUB_AGENT_ROLES = ['planner', 'advisor', 'coder', 'reviewer', 'tester', 'summarizer'];
|
|
318
|
+
const CODEWIKI_READ_ONLY_TOOLS = ['read', 'grep', 'list', 'glob', 'query_project_index', 'read_plan'];
|
|
312
319
|
export const ROLE_TOOL_POLICY = {
|
|
313
320
|
planner: ['read', 'grep', 'list', 'query_project_index', 'tool_search', 'glob', 'ast_query', 'read_ast_node', 'web_fetch', 'web_search', 'read_plan', 'update_plan'],
|
|
314
321
|
advisor: ['read', 'grep', 'list', 'query_project_index', 'tool_search', 'read_plan'],
|
|
@@ -2112,13 +2119,21 @@ function buildRuntimeStateSnapshot({ currentSession, config, model, executionMod
|
|
|
2112
2119
|
const currentContextTokens = parentTokens + subTokens;
|
|
2113
2120
|
const maxContextTokens = effectiveMaxContextTokens(config);
|
|
2114
2121
|
const contextUsagePct = maxContextTokens > 0 ? Math.min(100, Math.max(0, (currentContextTokens / maxContextTokens) * 100)) : 0;
|
|
2122
|
+
const planState = currentSession?.planState;
|
|
2115
2123
|
const snapshot = {
|
|
2116
2124
|
sessionId: currentSession?.id || '',
|
|
2117
|
-
|
|
2125
|
+
sessionTitle: currentSession?.title || '',
|
|
2126
|
+
messageCount: Array.isArray(currentSession?.messages) ? currentSession.messages.length : 0,
|
|
2127
|
+
mode: executionMode || config.execution?.mode || 'normal',
|
|
2118
2128
|
sdkProvider: config.sdk?.provider || 'openai-compatible',
|
|
2119
2129
|
agentRole: 'general',
|
|
2120
2130
|
model: model || config.model?.name || '',
|
|
2121
|
-
|
|
2131
|
+
mainModel: config.model?.name || '',
|
|
2132
|
+
fastModel: config.model?.fast_name || config.model?.name || '',
|
|
2133
|
+
maxContextTokens,
|
|
2134
|
+
pendingPlanApproval: planState?.status === 'pending_approval'
|
|
2135
|
+
? { goal: planState.goal, summary: planState.finalSummary || planState.summary, filePath: planState.filePath, steps: planState.steps || [] }
|
|
2136
|
+
: null
|
|
2122
2137
|
};
|
|
2123
2138
|
Object.defineProperties(snapshot, {
|
|
2124
2139
|
currentContextTokens: {
|
|
@@ -2131,11 +2146,6 @@ function buildRuntimeStateSnapshot({ currentSession, config, model, executionMod
|
|
|
2131
2146
|
enumerable: false,
|
|
2132
2147
|
writable: false
|
|
2133
2148
|
},
|
|
2134
|
-
pendingPlanApproval: {
|
|
2135
|
-
value: currentSession?.planState?.status === 'pending_approval',
|
|
2136
|
-
enumerable: false,
|
|
2137
|
-
writable: false
|
|
2138
|
-
},
|
|
2139
2149
|
pendingReflectSkill: {
|
|
2140
2150
|
value: currentSession?.planState?.status === 'pending_reflect_skill',
|
|
2141
2151
|
enumerable: false,
|
|
@@ -2145,6 +2155,70 @@ function buildRuntimeStateSnapshot({ currentSession, config, model, executionMod
|
|
|
2145
2155
|
return snapshot;
|
|
2146
2156
|
}
|
|
2147
2157
|
|
|
2158
|
+
function resolveDefaultModel(config) {
|
|
2159
|
+
return String(config?.model?.name || '').trim();
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
function resolveFastModel(config) {
|
|
2163
|
+
return String(config?.model?.fast_name || config?.model?.lite_name || config?.model?.name || '').trim();
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
function normalizeGeneratedSessionTitle(value, fallback = '') {
|
|
2167
|
+
const cleaned = String(value || '')
|
|
2168
|
+
.replace(/^[\s"'`#::「『【\[]+|[\s"'`。.!??!」』】\]]+$/g, '')
|
|
2169
|
+
.replace(/\s+/g, ' ')
|
|
2170
|
+
.trim();
|
|
2171
|
+
const title = cleaned || fallback || '';
|
|
2172
|
+
if (!title) return '';
|
|
2173
|
+
return title.length > 48 ? `${title.slice(0, 45).trimEnd()}...` : title;
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
function shouldReplaceSessionTitle(title) {
|
|
2177
|
+
const value = String(title || '').trim();
|
|
2178
|
+
return !value || value === '新会话' || value === 'New session';
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
async function generateSessionTitle({ userText, assistantText = '', config, signal }) {
|
|
2182
|
+
const fallback = normalizeGeneratedSessionTitle(deriveSessionTitle([{ role: 'user', content: userText }]));
|
|
2183
|
+
const latestConfig = await loadConfig().catch(() => config);
|
|
2184
|
+
const effectiveConfig = latestConfig || config;
|
|
2185
|
+
const fastModel = resolveFastModel(effectiveConfig);
|
|
2186
|
+
if (!fastModel) return fallback;
|
|
2187
|
+
const titleInput = [
|
|
2188
|
+
`User:\n${String(userText || '').slice(0, 1200)}`,
|
|
2189
|
+
assistantText ? `Assistant:\n${String(assistantText || '').slice(0, 1600)}` : ''
|
|
2190
|
+
].filter(Boolean).join('\n\n');
|
|
2191
|
+
try {
|
|
2192
|
+
const result = await createChatCompletion({
|
|
2193
|
+
sdkProvider: effectiveConfig.sdk?.provider,
|
|
2194
|
+
baseUrl: effectiveConfig.gateway.base_url,
|
|
2195
|
+
apiKey: effectiveConfig.gateway.api_key,
|
|
2196
|
+
model: fastModel,
|
|
2197
|
+
messages: [
|
|
2198
|
+
{
|
|
2199
|
+
role: 'system',
|
|
2200
|
+
content: [
|
|
2201
|
+
'Generate a concise chat session title.',
|
|
2202
|
+
'Base it on the completed user-assistant exchange, not only the user prompt.',
|
|
2203
|
+
'Return only the title text.',
|
|
2204
|
+
'Use the same language as the user when possible.',
|
|
2205
|
+
'No quotes, no markdown, no punctuation at the ends.',
|
|
2206
|
+
'Maximum 18 Chinese characters or 8 English words.'
|
|
2207
|
+
].join(' ')
|
|
2208
|
+
},
|
|
2209
|
+
{ role: 'user', content: titleInput }
|
|
2210
|
+
],
|
|
2211
|
+
tools: [],
|
|
2212
|
+
timeoutMs: Math.min(Number(effectiveConfig.gateway?.timeout_ms || 30000), 30000),
|
|
2213
|
+
maxRetries: 0,
|
|
2214
|
+
signal
|
|
2215
|
+
});
|
|
2216
|
+
return normalizeGeneratedSessionTitle(result?.text, fallback) || fallback;
|
|
2217
|
+
} catch {
|
|
2218
|
+
return fallback;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2148
2222
|
function estimatePromptTokensForRequest(sessionMessages, userText = '') {
|
|
2149
2223
|
const tokenMsgs = [
|
|
2150
2224
|
...(Array.isArray(sessionMessages) ? sessionMessages : []),
|
|
@@ -2330,6 +2404,7 @@ async function expandFileMentions(rawText, workspaceRoot = process.cwd()) {
|
|
|
2330
2404
|
|
|
2331
2405
|
async function askModel({
|
|
2332
2406
|
text,
|
|
2407
|
+
modelText,
|
|
2333
2408
|
session,
|
|
2334
2409
|
config,
|
|
2335
2410
|
model,
|
|
@@ -2344,13 +2419,14 @@ async function askModel({
|
|
|
2344
2419
|
maxSteps: maxStepsOverride,
|
|
2345
2420
|
skipAnalysisNudge = false
|
|
2346
2421
|
}) {
|
|
2422
|
+
const modelInputText = typeof modelText === 'string' && modelText ? modelText : text;
|
|
2347
2423
|
const maxContextTokens = effectiveMaxContextTokens(config);
|
|
2348
2424
|
const triggerPct = Number(config.context?.preflight_trigger_pct || 92);
|
|
2349
2425
|
const hardPct = Number(config.context?.hard_limit_pct || 98);
|
|
2350
|
-
const preflightTokens = estimatePromptTokensForRequest(session.messages,
|
|
2426
|
+
const preflightTokens = estimatePromptTokensForRequest(session.messages, modelInputText);
|
|
2351
2427
|
const preflightPct = (preflightTokens / maxContextTokens) * 100;
|
|
2352
2428
|
|
|
2353
|
-
if (preflightPct >= triggerPct) {
|
|
2429
|
+
if (persistSession && preflightPct >= triggerPct) {
|
|
2354
2430
|
const auto = compactMessagesLocally(session.messages, {
|
|
2355
2431
|
mode: preflightPct >= hardPct ? 'aggressive' : 'conservative'
|
|
2356
2432
|
});
|
|
@@ -2414,11 +2490,19 @@ async function askModel({
|
|
|
2414
2490
|
}
|
|
2415
2491
|
|
|
2416
2492
|
if (text) {
|
|
2417
|
-
session.messages.
|
|
2493
|
+
const shouldGenerateTitle = !session.messages.some((msg) => msg?.role === 'user');
|
|
2494
|
+
const modelExtra =
|
|
2495
|
+
typeof modelText === 'string' && modelText && modelText !== text ? { model_content: modelText } : {};
|
|
2496
|
+
session.messages.push(stampedMessage('user', text, modelExtra));
|
|
2497
|
+
if (!shouldGenerateTitle) {
|
|
2498
|
+
session.title = deriveSessionTitle(session.messages);
|
|
2499
|
+
}
|
|
2500
|
+
session.model = model || config.model.name;
|
|
2501
|
+
session.mode = executionMode || config.execution?.mode || 'normal';
|
|
2418
2502
|
if (persistSession) await saveSession(session);
|
|
2419
2503
|
}
|
|
2420
2504
|
|
|
2421
|
-
const projectContextSnippet = await buildProjectContextSnippet(process.cwd(),
|
|
2505
|
+
const projectContextSnippet = await buildProjectContextSnippet(process.cwd(), modelInputText).catch(() => '');
|
|
2422
2506
|
const projectContextGuidance =
|
|
2423
2507
|
'Use this project context as lightweight guidance and verify important details with fresh reads when needed.';
|
|
2424
2508
|
const effectiveSystemPrompt = projectContextSnippet
|
|
@@ -2478,6 +2562,22 @@ async function askModel({
|
|
|
2478
2562
|
}
|
|
2479
2563
|
|
|
2480
2564
|
let activeAssistantIndex = -1;
|
|
2565
|
+
const pendingToolMeta = new Map();
|
|
2566
|
+
const attachToolMetaToSessionCall = (toolId, meta = {}) => {
|
|
2567
|
+
if (!toolId) return false;
|
|
2568
|
+
for (let i = session.messages.length - 1; i >= 0; i -= 1) {
|
|
2569
|
+
const msg = session.messages[i];
|
|
2570
|
+
if (msg?.role !== 'assistant' || !Array.isArray(msg.tool_calls)) continue;
|
|
2571
|
+
const call = msg.tool_calls.find((tc) => String(tc?.id || '') === String(toolId));
|
|
2572
|
+
if (!call) continue;
|
|
2573
|
+
if (Number.isFinite(Number(meta.durationMs))) call.durationMs = Number(meta.durationMs);
|
|
2574
|
+
if (typeof meta.summary === 'string' && meta.summary.trim()) call.summary = meta.summary.trim();
|
|
2575
|
+
if (typeof meta.status === 'string' && meta.status.trim()) call.status = meta.status.trim();
|
|
2576
|
+
msg.at = new Date().toISOString();
|
|
2577
|
+
return true;
|
|
2578
|
+
}
|
|
2579
|
+
return false;
|
|
2580
|
+
};
|
|
2481
2581
|
const wrappedAgentEvent = (event) => {
|
|
2482
2582
|
// Always accumulate messages in session (for token tracking), only save when persisting
|
|
2483
2583
|
if (event?.type === 'assistant:start') {
|
|
@@ -2508,19 +2608,42 @@ async function askModel({
|
|
|
2508
2608
|
if (persistSession) scheduleSessionSave();
|
|
2509
2609
|
}
|
|
2510
2610
|
activeAssistantIndex = -1;
|
|
2611
|
+
} else if (event?.type === 'tool:end' || event?.type === 'tool:error' || event?.type === 'tool:blocked') {
|
|
2612
|
+
const toolId = String(event.id || '');
|
|
2613
|
+
if (toolId) {
|
|
2614
|
+
const meta = {
|
|
2615
|
+
durationMs: Number.isFinite(Number(event.durationMs)) ? Number(event.durationMs) : undefined,
|
|
2616
|
+
summary: typeof event.summary === 'string' ? event.summary : '',
|
|
2617
|
+
status:
|
|
2618
|
+
event.type === 'tool:error'
|
|
2619
|
+
? 'error'
|
|
2620
|
+
: event.type === 'tool:blocked'
|
|
2621
|
+
? 'blocked'
|
|
2622
|
+
: 'done'
|
|
2623
|
+
};
|
|
2624
|
+
pendingToolMeta.set(toolId, meta);
|
|
2625
|
+
if (attachToolMetaToSessionCall(toolId, meta) && persistSession) scheduleSessionSave();
|
|
2626
|
+
}
|
|
2511
2627
|
} else if (event?.type === 'tool:result') {
|
|
2628
|
+
const toolId = String(event.id || '');
|
|
2629
|
+
const meta = pendingToolMeta.get(toolId) || {};
|
|
2512
2630
|
session.messages.push(
|
|
2513
2631
|
stampedMessage('tool', event.content || '', {
|
|
2514
|
-
tool_call_id:
|
|
2632
|
+
tool_call_id: toolId,
|
|
2633
|
+
...(Number.isFinite(Number(meta.durationMs)) ? { tool_duration_ms: Number(meta.durationMs) } : {}),
|
|
2634
|
+
...(meta.summary ? { tool_summary: meta.summary } : {}),
|
|
2635
|
+
...(meta.status ? { tool_status: meta.status } : {})
|
|
2515
2636
|
})
|
|
2516
2637
|
);
|
|
2638
|
+
pendingToolMeta.delete(toolId);
|
|
2517
2639
|
if (persistSession) scheduleSessionSave();
|
|
2518
2640
|
}
|
|
2519
2641
|
|
|
2520
2642
|
if (onAgentEvent) onAgentEvent(event);
|
|
2521
2643
|
};
|
|
2522
2644
|
|
|
2523
|
-
const loopUserPrompt = persistSession ? '' :
|
|
2645
|
+
const loopUserPrompt = persistSession ? '' : modelInputText;
|
|
2646
|
+
const expectedModelText = typeof modelText === 'string' && modelText && modelText !== text ? modelText : '';
|
|
2524
2647
|
const loopResult = await runAgentLoop({
|
|
2525
2648
|
systemPrompt: effectiveSystemPrompt,
|
|
2526
2649
|
userPrompt: loopUserPrompt,
|
|
@@ -2530,7 +2653,7 @@ async function askModel({
|
|
|
2530
2653
|
toolHandlers: filteredHandlers,
|
|
2531
2654
|
initialMessages: toOpenAIMessages(session.messages),
|
|
2532
2655
|
onEvent: wrappedAgentEvent,
|
|
2533
|
-
executionMode: executionMode || config.execution?.mode || '
|
|
2656
|
+
executionMode: executionMode || config.execution?.mode || 'normal',
|
|
2534
2657
|
alwaysAllowTools:
|
|
2535
2658
|
alwaysAllowTools || config.execution?.always_allow_tools || ['run', 'read', 'write'],
|
|
2536
2659
|
toolResultMaxChars: config.context?.tool_result_max_chars || 12000,
|
|
@@ -2581,6 +2704,26 @@ async function askModel({
|
|
|
2581
2704
|
session.messages = loopResult.messages
|
|
2582
2705
|
.filter((m) => m.role !== 'system')
|
|
2583
2706
|
.map((m) => ({ ...m, at: new Date().toISOString() }));
|
|
2707
|
+
if (expectedModelText) {
|
|
2708
|
+
for (let i = session.messages.length - 1; i >= 0; i -= 1) {
|
|
2709
|
+
const message = session.messages[i];
|
|
2710
|
+
if (message?.role === 'user' && message.content === expectedModelText) {
|
|
2711
|
+
message.content = text;
|
|
2712
|
+
message.model_content = expectedModelText;
|
|
2713
|
+
break;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
if (shouldReplaceSessionTitle(session.title)) {
|
|
2718
|
+
session.title = await generateSessionTitle({
|
|
2719
|
+
userText: text,
|
|
2720
|
+
assistantText: loopResult.text || '',
|
|
2721
|
+
config,
|
|
2722
|
+
signal
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2725
|
+
session.model = model || config.model.name;
|
|
2726
|
+
session.mode = executionMode || config.execution?.mode || 'normal';
|
|
2584
2727
|
await flushScheduledSave();
|
|
2585
2728
|
await saveSession(session);
|
|
2586
2729
|
try {
|
|
@@ -2684,7 +2827,60 @@ async function runSubAgentTask({
|
|
|
2684
2827
|
blockedCount,
|
|
2685
2828
|
toolErrorCount,
|
|
2686
2829
|
hasErrorLine,
|
|
2687
|
-
artifactPaths: artifactPaths.slice(0, SUB_AGENT_HANDOFF_MAX_ITEMS)
|
|
2830
|
+
artifactPaths: artifactPaths.slice(0, SUB_AGENT_HANDOFF_MAX_ITEMS),
|
|
2831
|
+
messages: Array.isArray(subSession.messages) ? structuredClone(subSession.messages) : []
|
|
2832
|
+
};
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
function buildPlanStepTranscript({ stepRecord, stepIndex, totalSteps, messages }) {
|
|
2836
|
+
const toolCardsById = new Map();
|
|
2837
|
+
const toolCards = [];
|
|
2838
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
2839
|
+
|
|
2840
|
+
for (const msg of source) {
|
|
2841
|
+
if (msg?.role === 'assistant' && Array.isArray(msg.tool_calls)) {
|
|
2842
|
+
for (const tc of msg.tool_calls) {
|
|
2843
|
+
const id = String(tc?.id || `tool-${toolCards.length + 1}`);
|
|
2844
|
+
if (toolCardsById.has(id)) continue;
|
|
2845
|
+
const card = {
|
|
2846
|
+
id,
|
|
2847
|
+
name: tc?.function?.name || tc?.name || 'tool',
|
|
2848
|
+
arguments: tc?.function?.arguments || tc?.arguments || {},
|
|
2849
|
+
status: tc?.status || 'done',
|
|
2850
|
+
durationMs: Number.isFinite(Number(tc?.durationMs)) ? Number(tc.durationMs) : null,
|
|
2851
|
+
summary: tc?.summary || '',
|
|
2852
|
+
result: ''
|
|
2853
|
+
};
|
|
2854
|
+
toolCardsById.set(id, card);
|
|
2855
|
+
toolCards.push(card);
|
|
2856
|
+
}
|
|
2857
|
+
} else if (msg?.role === 'tool') {
|
|
2858
|
+
const id = String(msg.tool_call_id || '');
|
|
2859
|
+
const card = toolCardsById.get(id);
|
|
2860
|
+
if (!card) continue;
|
|
2861
|
+
card.result = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content || '');
|
|
2862
|
+
if (typeof msg.tool_summary === 'string' && msg.tool_summary.trim()) card.summary = msg.tool_summary.trim();
|
|
2863
|
+
if (Number.isFinite(Number(msg.tool_duration_ms))) card.durationMs = Number(msg.tool_duration_ms);
|
|
2864
|
+
if (typeof msg.tool_status === 'string' && msg.tool_status.trim()) card.status = msg.tool_status.trim();
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
const segments = [];
|
|
2869
|
+
if (toolCards.length > 0) {
|
|
2870
|
+
segments.push({ type: 'tools', cards: toolCards });
|
|
2871
|
+
}
|
|
2872
|
+
if (stepRecord.role === 'summarizer' && stepRecord.output) {
|
|
2873
|
+
segments.push({ type: 'text', text: stepRecord.output, isStreaming: false });
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
return {
|
|
2877
|
+
step: stepIndex + 1,
|
|
2878
|
+
total: totalSteps,
|
|
2879
|
+
role: stepRecord.role || 'general',
|
|
2880
|
+
title: stepRecord.title || '',
|
|
2881
|
+
status: stepRecord.failed ? 'failed' : 'done',
|
|
2882
|
+
summary: stepRecord.failed ? stepRecord.failureReason : trimInline(stepRecord.output || '', 160),
|
|
2883
|
+
segments
|
|
2688
2884
|
};
|
|
2689
2885
|
}
|
|
2690
2886
|
|
|
@@ -2712,8 +2908,11 @@ async function executePlanWithSubAgents({
|
|
|
2712
2908
|
return { text: '(no steps to execute)', aborted: false };
|
|
2713
2909
|
}
|
|
2714
2910
|
|
|
2911
|
+
emitPlanEvent({ type: 'assistant:start' });
|
|
2912
|
+
|
|
2715
2913
|
const priorSteps = [];
|
|
2716
2914
|
const results = [];
|
|
2915
|
+
const transcript = [];
|
|
2717
2916
|
|
|
2718
2917
|
// Emit structured plan steps so TUI can show all steps with real role/title
|
|
2719
2918
|
emitPlanEvent({
|
|
@@ -2725,6 +2924,15 @@ async function executePlanWithSubAgents({
|
|
|
2725
2924
|
const step = steps[i];
|
|
2726
2925
|
if (signal?.aborted) break;
|
|
2727
2926
|
|
|
2927
|
+
emitPlanEvent({
|
|
2928
|
+
type: 'plan:step_start',
|
|
2929
|
+
planFile: planFilePath,
|
|
2930
|
+
step: i + 1,
|
|
2931
|
+
total: steps.length,
|
|
2932
|
+
role: step.role,
|
|
2933
|
+
title: step.title
|
|
2934
|
+
});
|
|
2935
|
+
|
|
2728
2936
|
emitPlanEvent({
|
|
2729
2937
|
type: 'plan:progress',
|
|
2730
2938
|
planFile: planFilePath,
|
|
@@ -2772,6 +2980,7 @@ async function executePlanWithSubAgents({
|
|
|
2772
2980
|
toolErrorCount: output.toolErrorCount || 0,
|
|
2773
2981
|
hasErrorLine: output.hasErrorLine || false,
|
|
2774
2982
|
artifactPaths: output.artifactPaths || [],
|
|
2983
|
+
messages: output.messages || [],
|
|
2775
2984
|
failed:
|
|
2776
2985
|
output.hasErrorLine ||
|
|
2777
2986
|
stepOutputHasFailureSignals(step.role, output.text || ''),
|
|
@@ -2785,6 +2994,12 @@ async function executePlanWithSubAgents({
|
|
|
2785
2994
|
}
|
|
2786
2995
|
priorSteps.push(stepRecord);
|
|
2787
2996
|
results.push(stepRecord);
|
|
2997
|
+
transcript.push(buildPlanStepTranscript({
|
|
2998
|
+
stepRecord,
|
|
2999
|
+
stepIndex: i,
|
|
3000
|
+
totalSteps: steps.length,
|
|
3001
|
+
messages: output.messages || []
|
|
3002
|
+
}));
|
|
2788
3003
|
|
|
2789
3004
|
// Write step result to plan file for subsequent steps to read
|
|
2790
3005
|
if (planFilePath) {
|
|
@@ -2809,6 +3024,17 @@ async function executePlanWithSubAgents({
|
|
|
2809
3024
|
summary: stepRecord.failed ? stepRecord.failureReason : trimInline(stepRecord.output, 160)
|
|
2810
3025
|
});
|
|
2811
3026
|
|
|
3027
|
+
emitPlanEvent({
|
|
3028
|
+
type: 'plan:step_done',
|
|
3029
|
+
planFile: planFilePath,
|
|
3030
|
+
step: i + 1,
|
|
3031
|
+
total: steps.length,
|
|
3032
|
+
role: step.role,
|
|
3033
|
+
title: step.title,
|
|
3034
|
+
status: stepRecord.failed ? 'failed' : 'done',
|
|
3035
|
+
summary: stepRecord.failed ? stepRecord.failureReason : trimInline(stepRecord.output, 160)
|
|
3036
|
+
});
|
|
3037
|
+
|
|
2812
3038
|
if (stepRecord.failed && i < steps.length - 1) {
|
|
2813
3039
|
const summarizerIndex = steps.findIndex((candidate, index) => index > i && candidate.role === 'summarizer');
|
|
2814
3040
|
if (summarizerIndex > i) {
|
|
@@ -2848,7 +3074,11 @@ async function executePlanWithSubAgents({
|
|
|
2848
3074
|
return {
|
|
2849
3075
|
text: summaryLines.join('\n'),
|
|
2850
3076
|
aborted: !!signal?.aborted,
|
|
2851
|
-
results
|
|
3077
|
+
results,
|
|
3078
|
+
transcript,
|
|
3079
|
+
sessionText:
|
|
3080
|
+
[...results].reverse().find((r) => r.role === 'summarizer')?.output ||
|
|
3081
|
+
summaryLines.join('\n')
|
|
2852
3082
|
};
|
|
2853
3083
|
}
|
|
2854
3084
|
|
|
@@ -3007,10 +3237,29 @@ function renderAutoPlanMarkdown({
|
|
|
3007
3237
|
}
|
|
3008
3238
|
|
|
3009
3239
|
function parseProjectRequirementsOptions(args = []) {
|
|
3010
|
-
|
|
3240
|
+
let depth = 'standard';
|
|
3241
|
+
const focusArgs = [];
|
|
3242
|
+
for (const arg of Array.isArray(args) ? args : []) {
|
|
3243
|
+
const value = String(arg || '').trim();
|
|
3244
|
+
const normalized = value.toLowerCase();
|
|
3245
|
+
if (['--fast', '--quick', '--lite', '--light', '--快速'].includes(normalized)) {
|
|
3246
|
+
depth = 'fast';
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
3249
|
+
if (['--standard', '--balanced', '--默认', '--标准'].includes(normalized)) {
|
|
3250
|
+
depth = 'standard';
|
|
3251
|
+
continue;
|
|
3252
|
+
}
|
|
3253
|
+
if (['--deep', '--full', '--thorough', '--深度'].includes(normalized)) {
|
|
3254
|
+
depth = 'deep';
|
|
3255
|
+
continue;
|
|
3256
|
+
}
|
|
3257
|
+
focusArgs.push(arg);
|
|
3258
|
+
}
|
|
3259
|
+
const raw = focusArgs.join(' ').trim();
|
|
3011
3260
|
const normalized = raw.toLowerCase();
|
|
3012
3261
|
const hasIgnoreIntent = /(忽略|跳过|不生成|不要|无需|排除|exclude|skip|omit|without|no\s+)/i.test(raw);
|
|
3013
|
-
if (!hasIgnoreIntent) return { raw, ignoredSections: [] };
|
|
3262
|
+
if (!hasIgnoreIntent) return { raw, focusArgs, depth, ignoredSections: [] };
|
|
3014
3263
|
|
|
3015
3264
|
const ignored = [];
|
|
3016
3265
|
for (const section of PROJECT_REQUIREMENTS_SECTION_MARKERS) {
|
|
@@ -3023,7 +3272,7 @@ function parseProjectRequirementsOptions(args = []) {
|
|
|
3023
3272
|
});
|
|
3024
3273
|
if (matched) ignored.push(section);
|
|
3025
3274
|
}
|
|
3026
|
-
return { raw, ignoredSections: ignored };
|
|
3275
|
+
return { raw, focusArgs, depth, ignoredSections: ignored };
|
|
3027
3276
|
}
|
|
3028
3277
|
|
|
3029
3278
|
function renderProjectRequirementsSectionContract(ignoredSections = []) {
|
|
@@ -3041,7 +3290,7 @@ function renderProjectRequirementsSectionContract(ignoredSections = []) {
|
|
|
3041
3290
|
|
|
3042
3291
|
function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
|
|
3043
3292
|
const options = parseProjectRequirementsOptions(args);
|
|
3044
|
-
const userArgs =
|
|
3293
|
+
const userArgs = options.raw;
|
|
3045
3294
|
const requestedFocus = userArgs ? `User request/focus: ${userArgs}` : 'User request/focus: full workspace requirements report.';
|
|
3046
3295
|
const reportDate = formatLocalDate();
|
|
3047
3296
|
const reportPath = `docs/requirements/${reportDate}-project-requirements.html`;
|
|
@@ -3060,6 +3309,120 @@ function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
|
|
|
3060
3309
|
'Do not invent dates; use the report paths above.'
|
|
3061
3310
|
].join('\n');
|
|
3062
3311
|
|
|
3312
|
+
const writeReportStep = {
|
|
3313
|
+
title: '🎨 Write banking-style requirements HTML report',
|
|
3314
|
+
role: 'coder',
|
|
3315
|
+
task: [
|
|
3316
|
+
'Create the final project requirements report from the accumulated plan context.',
|
|
3317
|
+
reportContract,
|
|
3318
|
+
'Follow the project-requirements skill instructions below exactly, including chunked HTML writing for medium/large reports.',
|
|
3319
|
+
'Use the blue/white/gray banking-style shell and produce polished inline HTML/CSS/SVG diagrams. Keep the report professional, light, and conservative.',
|
|
3320
|
+
'Organize the main requirements section primarily by API/interface business requirement cards.',
|
|
3321
|
+
'The final HTML must be self-contained and directly openable from disk.',
|
|
3322
|
+
'Write the primary report to the exact primary report path above. Create the companion Markdown only if useful.',
|
|
3323
|
+
'Skill instructions:',
|
|
3324
|
+
renderedSkillPrompt
|
|
3325
|
+
].join('\n\n')
|
|
3326
|
+
};
|
|
3327
|
+
const reviewStep = {
|
|
3328
|
+
title: '🔎 Review API coverage and traceability',
|
|
3329
|
+
role: 'reviewer',
|
|
3330
|
+
task: [
|
|
3331
|
+
'Review the generated requirements report against the project-requirements contract and accumulated evidence.',
|
|
3332
|
+
reportContract,
|
|
3333
|
+
'Check that major APIs/interfaces are represented, business requirements are decomposed per API, evidence paths are present, inferred/unknown content is labeled, diagrams are visible as inline HTML/CSS/SVG without external rendering libraries, and the report path matches the required local date.',
|
|
3334
|
+
'Check that the visual style is light blue/white/gray and suitable for banking/financial review.',
|
|
3335
|
+
'Report concrete gaps and risks only. Do not rewrite the whole report.'
|
|
3336
|
+
].join('\n')
|
|
3337
|
+
};
|
|
3338
|
+
const summaryStep = {
|
|
3339
|
+
title: '🧾 Summarize final report and unresolved questions',
|
|
3340
|
+
role: 'summarizer',
|
|
3341
|
+
task: [
|
|
3342
|
+
'Synthesize the project requirements pipeline results into a concise final status for the user.',
|
|
3343
|
+
reportContract,
|
|
3344
|
+
'Mention the generated report path, API/interface coverage, strongest business requirement findings, unresolved questions, what was not verified, and the best next action.',
|
|
3345
|
+
'Do not re-analyze the codebase unless the accumulated evidence is clearly insufficient.'
|
|
3346
|
+
].join('\n')
|
|
3347
|
+
};
|
|
3348
|
+
|
|
3349
|
+
if (options.depth === 'fast') {
|
|
3350
|
+
return [
|
|
3351
|
+
{
|
|
3352
|
+
title: '⚡ Map evidence and interfaces',
|
|
3353
|
+
role: 'planner',
|
|
3354
|
+
task: [
|
|
3355
|
+
'Quickly map project evidence and build a practical API/interface inventory before report writing.',
|
|
3356
|
+
reportContract,
|
|
3357
|
+
'Inspect top-level docs, manifests, route/command entry points, obvious handlers, schemas, tests, and project index results when available.',
|
|
3358
|
+
'Produce a concise evidence map and major interface inventory with evidence paths, prioritizing broad coverage over exhaustive edge cases.',
|
|
3359
|
+
'Do not write the final report.'
|
|
3360
|
+
].join('\n')
|
|
3361
|
+
},
|
|
3362
|
+
{
|
|
3363
|
+
title: '🧩 Synthesize requirements, flows, and risks',
|
|
3364
|
+
role: 'advisor',
|
|
3365
|
+
task: [
|
|
3366
|
+
'Synthesize requirement-ready findings from the evidence map and interface inventory.',
|
|
3367
|
+
reportContract,
|
|
3368
|
+
'For major interfaces capture capability, actor, trigger, inputs, outputs, business rules, validation/permission notes, data reads/writes, core flow dependencies, risks, acceptance criteria, and open questions.',
|
|
3369
|
+
'Keep findings compact and API-centered. Preserve evidence paths and EXTRACTED/INFERRED/UNKNOWN labels. Do not write the final report.'
|
|
3370
|
+
].join('\n')
|
|
3371
|
+
},
|
|
3372
|
+
writeReportStep,
|
|
3373
|
+
{
|
|
3374
|
+
title: '🔎 Review and summarize coverage',
|
|
3375
|
+
role: 'reviewer',
|
|
3376
|
+
task: [
|
|
3377
|
+
'Review the generated report and produce the final user-facing status in one pass.',
|
|
3378
|
+
reportContract,
|
|
3379
|
+
'Check major interface coverage, evidence paths, EXTRACTED/INFERRED/UNKNOWN labels, visible diagrams, and report path.',
|
|
3380
|
+
'Do not rewrite the whole report. Report concrete gaps, unresolved questions, and the single best next action.'
|
|
3381
|
+
].join('\n')
|
|
3382
|
+
}
|
|
3383
|
+
];
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3386
|
+
if (options.depth === 'standard') {
|
|
3387
|
+
return [
|
|
3388
|
+
{
|
|
3389
|
+
title: '🧭 Map entry points and evidence sources',
|
|
3390
|
+
role: 'planner',
|
|
3391
|
+
task: [
|
|
3392
|
+
'Map project entry points and evidence sources before any report writing.',
|
|
3393
|
+
reportContract,
|
|
3394
|
+
'Inspect top-level docs, package manifests, route/command entry points, tests, obvious interface files, and project index results when useful.',
|
|
3395
|
+
'Produce a concise evidence map grouped by docs, routes/commands, handlers, schemas, tests, configuration, storage, and operations.',
|
|
3396
|
+
'Include evidence paths and open questions. Do not write the final report.'
|
|
3397
|
+
].join('\n')
|
|
3398
|
+
},
|
|
3399
|
+
{
|
|
3400
|
+
title: '📚 Build API and interface inventory',
|
|
3401
|
+
role: 'planner',
|
|
3402
|
+
task: [
|
|
3403
|
+
'Build the canonical API/interface inventory using the evidence map.',
|
|
3404
|
+
reportContract,
|
|
3405
|
+
'Enumerate every major HTTP endpoint, CLI command, tool call, MCP/RPC handler, queue/scheduled job, exported SDK function, and user-facing workflow entry point.',
|
|
3406
|
+
'For each item include type, route/command/function, owner module, evidence path, likely actor, and whether it is EXTRACTED, INFERRED, or UNKNOWN.',
|
|
3407
|
+
'Do not write the final report.'
|
|
3408
|
+
].join('\n')
|
|
3409
|
+
},
|
|
3410
|
+
{
|
|
3411
|
+
title: '🧩 Decompose requirements, flows, data, and risks',
|
|
3412
|
+
role: 'advisor',
|
|
3413
|
+
task: [
|
|
3414
|
+
'Decompose requirement-ready findings for each major API/interface from the inventory.',
|
|
3415
|
+
reportContract,
|
|
3416
|
+
'For each interface capture business capability, actor, user goal, trigger, inputs, outputs, preconditions, main/alternate flows, business rules, validation and permission checks, sensitive data, data reads/writes, side effects, acceptance criteria, and open questions.',
|
|
3417
|
+
'Keep findings API-centered rather than module-centered. Preserve evidence paths and EXTRACTED/INFERRED/UNKNOWN labels. Do not write the final report.'
|
|
3418
|
+
].join('\n')
|
|
3419
|
+
},
|
|
3420
|
+
writeReportStep,
|
|
3421
|
+
reviewStep,
|
|
3422
|
+
summaryStep
|
|
3423
|
+
];
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3063
3426
|
return [
|
|
3064
3427
|
{
|
|
3065
3428
|
title: '🧭 Map entry points and evidence sources',
|
|
@@ -3123,42 +3486,9 @@ function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
|
|
|
3123
3486
|
'Favor clear business process decomposition over broad architecture prose. Do not write the final report.'
|
|
3124
3487
|
].join('\n')
|
|
3125
3488
|
},
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
task: [
|
|
3130
|
-
'Create the final project requirements report from the accumulated plan context.',
|
|
3131
|
-
reportContract,
|
|
3132
|
-
'Follow the project-requirements skill instructions below exactly, including chunked HTML writing for medium/large reports.',
|
|
3133
|
-
'Use the blue/white/gray banking-style shell and produce polished inline HTML/CSS/SVG diagrams. Keep the report professional, light, and conservative.',
|
|
3134
|
-
'Organize the main requirements section primarily by API/interface business requirement cards.',
|
|
3135
|
-
'The final HTML must be self-contained and directly openable from disk.',
|
|
3136
|
-
'Write the primary report to the exact primary report path above. Create the companion Markdown only if useful.',
|
|
3137
|
-
'Skill instructions:',
|
|
3138
|
-
renderedSkillPrompt
|
|
3139
|
-
].join('\n\n')
|
|
3140
|
-
},
|
|
3141
|
-
{
|
|
3142
|
-
title: '🔎 Review API coverage and traceability',
|
|
3143
|
-
role: 'reviewer',
|
|
3144
|
-
task: [
|
|
3145
|
-
'Review the generated requirements report against the project-requirements contract and accumulated evidence.',
|
|
3146
|
-
reportContract,
|
|
3147
|
-
'Check that major APIs/interfaces are represented, business requirements are decomposed per API, evidence paths are present, inferred/unknown content is labeled, diagrams are visible as inline HTML/CSS/SVG without external rendering libraries, and the report path matches the required local date.',
|
|
3148
|
-
'Check that the visual style is light blue/white/gray and suitable for banking/financial review.',
|
|
3149
|
-
'Report concrete gaps and risks only. Do not rewrite the whole report.'
|
|
3150
|
-
].join('\n')
|
|
3151
|
-
},
|
|
3152
|
-
{
|
|
3153
|
-
title: '🧾 Summarize final report and unresolved questions',
|
|
3154
|
-
role: 'summarizer',
|
|
3155
|
-
task: [
|
|
3156
|
-
'Synthesize the project requirements pipeline results into a concise final status for the user.',
|
|
3157
|
-
reportContract,
|
|
3158
|
-
'Mention the generated report path, API/interface coverage, strongest business requirement findings, unresolved questions, what was not verified, and the best next action.',
|
|
3159
|
-
'Do not re-analyze the codebase unless the accumulated evidence is clearly insufficient.'
|
|
3160
|
-
].join('\n')
|
|
3161
|
-
}
|
|
3489
|
+
writeReportStep,
|
|
3490
|
+
reviewStep,
|
|
3491
|
+
summaryStep
|
|
3162
3492
|
];
|
|
3163
3493
|
}
|
|
3164
3494
|
|
|
@@ -3200,7 +3530,8 @@ async function createProjectRequirementsShell({
|
|
|
3200
3530
|
manifestPath,
|
|
3201
3531
|
planFile,
|
|
3202
3532
|
goal,
|
|
3203
|
-
steps
|
|
3533
|
+
steps,
|
|
3534
|
+
depth = 'standard'
|
|
3204
3535
|
}) {
|
|
3205
3536
|
const workspaceRoot = process.cwd();
|
|
3206
3537
|
const absoluteReportPath = path.resolve(workspaceRoot, reportPath);
|
|
@@ -3231,6 +3562,7 @@ async function createProjectRequirementsShell({
|
|
|
3231
3562
|
];
|
|
3232
3563
|
const manifest = {
|
|
3233
3564
|
status: 'running',
|
|
3565
|
+
depth,
|
|
3234
3566
|
goal,
|
|
3235
3567
|
html: reportPath,
|
|
3236
3568
|
markdown: companionPath,
|
|
@@ -3278,7 +3610,8 @@ async function runProjectRequirementsPipeline({
|
|
|
3278
3610
|
onSubSessionActive
|
|
3279
3611
|
}) {
|
|
3280
3612
|
const renderedSkillPrompt = await expandFileMentions(renderCommandPrompt(custom, parsedInput.args), process.cwd());
|
|
3281
|
-
const
|
|
3613
|
+
const options = parseProjectRequirementsOptions(parsedInput.args);
|
|
3614
|
+
const userFocus = options.raw;
|
|
3282
3615
|
const goal = userFocus ? `project requirements report: ${userFocus}` : 'project requirements report';
|
|
3283
3616
|
const reportDate = formatLocalDate();
|
|
3284
3617
|
const reportPath = `docs/requirements/${reportDate}-project-requirements.html`;
|
|
@@ -3298,15 +3631,17 @@ async function runProjectRequirementsPipeline({
|
|
|
3298
3631
|
manifestPath,
|
|
3299
3632
|
planFile,
|
|
3300
3633
|
goal,
|
|
3301
|
-
steps
|
|
3634
|
+
steps,
|
|
3635
|
+
depth: options.depth
|
|
3302
3636
|
});
|
|
3303
3637
|
const planState = {
|
|
3304
3638
|
status: 'approved',
|
|
3305
3639
|
source: 'project-requirements',
|
|
3640
|
+
depth: options.depth,
|
|
3306
3641
|
goal,
|
|
3307
3642
|
filePath: planFile,
|
|
3308
|
-
summary:
|
|
3309
|
-
finalSummary:
|
|
3643
|
+
summary: `Dedicated ${options.depth} sub-agent pipeline for project requirements report generation.`,
|
|
3644
|
+
finalSummary: `Executing ${options.depth} project requirements pipeline.`,
|
|
3310
3645
|
steps
|
|
3311
3646
|
};
|
|
3312
3647
|
if (onAgentEvent) {
|
|
@@ -3511,7 +3846,8 @@ function compactHistoryPreview(value, maxChars = 72) {
|
|
|
3511
3846
|
function formatHistoryList({ currentSession, sessions }) {
|
|
3512
3847
|
const currentMessages = Array.isArray(currentSession?.messages) ? currentSession.messages.length : 0;
|
|
3513
3848
|
const lines = [
|
|
3514
|
-
`Current session ${currentSession.id}`,
|
|
3849
|
+
`Current session ${currentSession.title || currentSession.id}`,
|
|
3850
|
+
`Session id ${currentSession.id}`,
|
|
3515
3851
|
`Messages ${currentMessages}`,
|
|
3516
3852
|
'',
|
|
3517
3853
|
'Recent sessions'
|
|
@@ -3520,8 +3856,9 @@ function formatHistoryList({ currentSession, sessions }) {
|
|
|
3520
3856
|
for (const [index, session] of sessions.entries()) {
|
|
3521
3857
|
const count = Number(session.messageCount || 0);
|
|
3522
3858
|
lines.push(
|
|
3523
|
-
`${index + 1}. ${session.id}`,
|
|
3524
|
-
`
|
|
3859
|
+
`${index + 1}. ${session.title || session.id}`,
|
|
3860
|
+
` id=${session.id}`,
|
|
3861
|
+
` ${count} ${count === 1 ? 'msg' : 'msgs'} | ${formatHistoryTimestamp(session.updatedAt)}${session.model ? ` | ${session.model}` : ''}`,
|
|
3525
3862
|
` ${compactHistoryPreview(session.preview)}`,
|
|
3526
3863
|
` resume: /history resume ${session.id}`
|
|
3527
3864
|
);
|
|
@@ -3538,6 +3875,9 @@ export async function createChatRuntime({
|
|
|
3538
3875
|
systemPrompt,
|
|
3539
3876
|
requestToolApproval
|
|
3540
3877
|
}) {
|
|
3878
|
+
if (session && typeof session === 'object' && !session.projectDir) {
|
|
3879
|
+
session.projectDir = process.cwd();
|
|
3880
|
+
}
|
|
3541
3881
|
let activeRequestToolApproval = typeof requestToolApproval === 'function' ? requestToolApproval : null;
|
|
3542
3882
|
const startupEvents = [];
|
|
3543
3883
|
const initialIndex = await initializeProjectIndex(process.cwd()).catch(() => null);
|
|
@@ -3573,8 +3913,12 @@ export async function createChatRuntime({
|
|
|
3573
3913
|
}
|
|
3574
3914
|
let currentSession = session;
|
|
3575
3915
|
let config = initialConfig;
|
|
3916
|
+
model = model || currentSession?.model || resolveDefaultModel(config);
|
|
3917
|
+
if (currentSession && typeof currentSession === 'object') {
|
|
3918
|
+
currentSession.model = model;
|
|
3919
|
+
}
|
|
3576
3920
|
const baseSystemPrompt = systemPrompt;
|
|
3577
|
-
let executionMode = config.execution?.mode || '
|
|
3921
|
+
let executionMode = config.execution?.mode || 'normal';
|
|
3578
3922
|
if (hasPendingPlanApproval(currentSession)) {
|
|
3579
3923
|
executionMode = 'plan';
|
|
3580
3924
|
}
|
|
@@ -3600,6 +3944,7 @@ export async function createChatRuntime({
|
|
|
3600
3944
|
let historySessionCache = [
|
|
3601
3945
|
{
|
|
3602
3946
|
id: currentSession.id,
|
|
3947
|
+
title: currentSession.title || deriveSessionTitle(currentSession.messages || []),
|
|
3603
3948
|
messageCount: Array.isArray(currentSession.messages) ? currentSession.messages.length : 0
|
|
3604
3949
|
}
|
|
3605
3950
|
];
|
|
@@ -3609,10 +3954,12 @@ export async function createChatRuntime({
|
|
|
3609
3954
|
const merged = [
|
|
3610
3955
|
{
|
|
3611
3956
|
id: currentSession.id,
|
|
3957
|
+
title: currentSession.title || deriveSessionTitle(currentSession.messages || []),
|
|
3612
3958
|
messageCount: Array.isArray(currentSession.messages) ? currentSession.messages.length : 0
|
|
3613
3959
|
},
|
|
3614
3960
|
...initialSessions.map((session) => ({
|
|
3615
3961
|
id: session.id,
|
|
3962
|
+
title: session.title || '',
|
|
3616
3963
|
messageCount: Number(session.messageCount || 0)
|
|
3617
3964
|
}))
|
|
3618
3965
|
];
|
|
@@ -3635,6 +3982,7 @@ export async function createChatRuntime({
|
|
|
3635
3982
|
'gateway.base_url',
|
|
3636
3983
|
'gateway.api_key',
|
|
3637
3984
|
'model.name',
|
|
3985
|
+
'model.fast_name',
|
|
3638
3986
|
'ui.language',
|
|
3639
3987
|
'ui.reply_language',
|
|
3640
3988
|
'execution.mode',
|
|
@@ -3663,6 +4011,7 @@ export async function createChatRuntime({
|
|
|
3663
4011
|
const commandPriorityOrder = [
|
|
3664
4012
|
'/help',
|
|
3665
4013
|
'/status',
|
|
4014
|
+
'/model',
|
|
3666
4015
|
'/config',
|
|
3667
4016
|
'/memory',
|
|
3668
4017
|
'/capture',
|
|
@@ -3687,6 +4036,7 @@ export async function createChatRuntime({
|
|
|
3687
4036
|
{ name: 'exit', description: completionCopy.commands.exit },
|
|
3688
4037
|
{ name: 'commands', description: completionCopy.commands.commands },
|
|
3689
4038
|
{ name: 'status', description: completionCopy.commands.status },
|
|
4039
|
+
{ name: 'model', description: completionCopy.commands.model },
|
|
3690
4040
|
{ name: 'mode', description: completionCopy.commands.mode },
|
|
3691
4041
|
{ name: 'compact', description: completionCopy.commands.compact },
|
|
3692
4042
|
{ name: 'checkpoint', description: completionCopy.commands.checkpoint },
|
|
@@ -3737,6 +4087,7 @@ export async function createChatRuntime({
|
|
|
3737
4087
|
const historyTemplates = ['/history list', '/history current', '/history resume <session_id>'];
|
|
3738
4088
|
const memoryTemplates = ['/memory list <scope>', '/memory search <scope> <query>', '/memory forget <scope> <id>'];
|
|
3739
4089
|
const modeTemplates = ['/mode normal', '/mode auto', '/mode plan'];
|
|
4090
|
+
const modelTemplates = ['/model current', '/model main', '/model fast', '/model set <name>'];
|
|
3740
4091
|
const checkpointTemplates = [
|
|
3741
4092
|
'/checkpoint create <name>',
|
|
3742
4093
|
'/checkpoint list',
|
|
@@ -3755,6 +4106,7 @@ export async function createChatRuntime({
|
|
|
3755
4106
|
...memoryTemplates,
|
|
3756
4107
|
...historyTemplates,
|
|
3757
4108
|
...modeTemplates,
|
|
4109
|
+
...modelTemplates,
|
|
3758
4110
|
...checkpointTemplates,
|
|
3759
4111
|
...specTemplates,
|
|
3760
4112
|
...planTemplates,
|
|
@@ -3802,6 +4154,7 @@ export async function createChatRuntime({
|
|
|
3802
4154
|
'memory',
|
|
3803
4155
|
'compact',
|
|
3804
4156
|
'mode',
|
|
4157
|
+
'model',
|
|
3805
4158
|
'checkpoint',
|
|
3806
4159
|
'plan',
|
|
3807
4160
|
'agents',
|
|
@@ -3821,6 +4174,7 @@ export async function createChatRuntime({
|
|
|
3821
4174
|
for (const template of memoryTemplates) registerSuggestion(template, completionCopy.generic.memoryCommand);
|
|
3822
4175
|
for (const template of historyTemplates) registerSuggestion(template, completionCopy.generic.historyCommand);
|
|
3823
4176
|
for (const template of modeTemplates) registerSuggestion(template, completionCopy.generic.modeCommand);
|
|
4177
|
+
for (const template of modelTemplates) registerSuggestion(template, completionCopy.generic.modelCommand || completionCopy.commands.model);
|
|
3824
4178
|
for (const template of checkpointTemplates) registerSuggestion(template, completionCopy.generic.checkpointCommand);
|
|
3825
4179
|
for (const template of specTemplates) registerSuggestion(template, completionCopy.generic.specCommand);
|
|
3826
4180
|
for (const template of planTemplates) {
|
|
@@ -3915,6 +4269,15 @@ export async function createChatRuntime({
|
|
|
3915
4269
|
if (commandPart === 'status') {
|
|
3916
4270
|
return [registerSuggestion('/status', completionCopy.generic.statusCommand)];
|
|
3917
4271
|
}
|
|
4272
|
+
if (commandPart === 'model') {
|
|
4273
|
+
if (tokens.length === 1 || (tokens.length === 2 && !hasTrailingSpace)) {
|
|
4274
|
+
const sub = tokens[1] || '';
|
|
4275
|
+
return ['current', 'main', 'fast', 'set']
|
|
4276
|
+
.filter((m) => m.startsWith(sub))
|
|
4277
|
+
.map((m) => registerSuggestion(`/model ${m}${m === 'set' ? ' ' : ''}`, completionCopy.generic.modelCommand));
|
|
4278
|
+
}
|
|
4279
|
+
return materializeSuggestions(modelTemplates);
|
|
4280
|
+
}
|
|
3918
4281
|
if (commandPart === 'mode') {
|
|
3919
4282
|
if (tokens.length === 1 || (tokens.length === 2 && !hasTrailingSpace)) {
|
|
3920
4283
|
const sub = tokens[1] || '';
|
|
@@ -3999,7 +4362,7 @@ export async function createChatRuntime({
|
|
|
3999
4362
|
.filter((session) => String(session.id || '').startsWith(''))
|
|
4000
4363
|
.map((session) => ({
|
|
4001
4364
|
value: `/history resume ${session.id}`,
|
|
4002
|
-
display: `/history resume ${session.id} · ${Number(session.messageCount || 0)} msgs`,
|
|
4365
|
+
display: `/history resume ${session.id} · ${session.title || 'untitled'} · ${Number(session.messageCount || 0)} msgs`,
|
|
4003
4366
|
description: completionCopy.generic.resumeSession
|
|
4004
4367
|
}));
|
|
4005
4368
|
if (dynamic.length > 0) return dynamic;
|
|
@@ -4014,7 +4377,7 @@ export async function createChatRuntime({
|
|
|
4014
4377
|
.filter((session) => String(session.id || '').startsWith(idPrefix))
|
|
4015
4378
|
.map((session) => ({
|
|
4016
4379
|
value: `/history resume ${session.id}`,
|
|
4017
|
-
display: `/history resume ${session.id} · ${Number(session.messageCount || 0)} msgs`,
|
|
4380
|
+
display: `/history resume ${session.id} · ${session.title || 'untitled'} · ${Number(session.messageCount || 0)} msgs`,
|
|
4018
4381
|
description: completionCopy.generic.resumeSession
|
|
4019
4382
|
}));
|
|
4020
4383
|
if (dynamic.length > 0) return dynamic;
|
|
@@ -4053,22 +4416,41 @@ export async function createChatRuntime({
|
|
|
4053
4416
|
if (systemText) {
|
|
4054
4417
|
currentSession.messages.push(stampedMessage('system', systemText));
|
|
4055
4418
|
}
|
|
4419
|
+
if (shouldReplaceSessionTitle(currentSession.title)) {
|
|
4420
|
+
currentSession.title = deriveSessionTitle(currentSession.messages);
|
|
4421
|
+
}
|
|
4422
|
+
currentSession.model = model || config.model.name;
|
|
4423
|
+
currentSession.mode = executionMode || config.execution?.mode || 'normal';
|
|
4056
4424
|
await saveSession(currentSession);
|
|
4057
4425
|
};
|
|
4058
4426
|
|
|
4059
|
-
const persistAssistantExchange = async (userText, assistantText, { includeUser = true } = {}) => {
|
|
4427
|
+
const persistAssistantExchange = async (userText, assistantText, { includeUser = true, extra = {} } = {}) => {
|
|
4060
4428
|
if (includeUser && userText) {
|
|
4061
4429
|
currentSession.messages.push(stampedMessage('user', userText));
|
|
4062
4430
|
}
|
|
4063
4431
|
if (assistantText) {
|
|
4064
|
-
currentSession.messages.push(stampedMessage('assistant', assistantText));
|
|
4432
|
+
currentSession.messages.push(stampedMessage('assistant', assistantText, extra));
|
|
4433
|
+
}
|
|
4434
|
+
if (shouldReplaceSessionTitle(currentSession.title)) {
|
|
4435
|
+
currentSession.title = await generateSessionTitle({
|
|
4436
|
+
userText,
|
|
4437
|
+
assistantText,
|
|
4438
|
+
config
|
|
4439
|
+
});
|
|
4065
4440
|
}
|
|
4441
|
+
currentSession.model = model || config.model.name;
|
|
4442
|
+
currentSession.mode = executionMode || config.execution?.mode || 'normal';
|
|
4066
4443
|
await saveSession(currentSession);
|
|
4067
4444
|
};
|
|
4068
4445
|
|
|
4069
4446
|
const persistUserExchange = async (userText) => {
|
|
4070
4447
|
if (!userText) return;
|
|
4071
4448
|
currentSession.messages.push(stampedMessage('user', userText));
|
|
4449
|
+
if (shouldReplaceSessionTitle(currentSession.title)) {
|
|
4450
|
+
currentSession.title = deriveSessionTitle(currentSession.messages);
|
|
4451
|
+
}
|
|
4452
|
+
currentSession.model = model || config.model.name;
|
|
4453
|
+
currentSession.mode = executionMode || config.execution?.mode || 'normal';
|
|
4072
4454
|
await saveSession(currentSession);
|
|
4073
4455
|
};
|
|
4074
4456
|
|
|
@@ -4202,12 +4584,13 @@ export async function createChatRuntime({
|
|
|
4202
4584
|
let activeAbortController = null;
|
|
4203
4585
|
let activeSubSession = null;
|
|
4204
4586
|
|
|
4205
|
-
const submit = async (line, onAgentEvent) => {
|
|
4587
|
+
const submit = async (line, onAgentEvent, options = {}) => {
|
|
4206
4588
|
// 每次提交创建新的 AbortController,替代旧的
|
|
4207
4589
|
activeAbortController = new AbortController();
|
|
4208
4590
|
const { signal } = activeAbortController;
|
|
4209
4591
|
const activeReplySystemPrompt = await buildActiveSystemPrompt();
|
|
4210
4592
|
const parsedInput = parseInput(line);
|
|
4593
|
+
const readOnlyCodeWiki = options?.readOnlyCodeWiki === true;
|
|
4211
4594
|
const maybeAutoDreamFromRuntime = async () => {
|
|
4212
4595
|
const threshold = Number(config?.memory?.auto_dream_threshold ?? 10);
|
|
4213
4596
|
if (!(threshold > 0)) return null;
|
|
@@ -4241,7 +4624,7 @@ export async function createChatRuntime({
|
|
|
4241
4624
|
}
|
|
4242
4625
|
};
|
|
4243
4626
|
try {
|
|
4244
|
-
if (shouldPersistInputHistory(parsedInput)) {
|
|
4627
|
+
if (!readOnlyCodeWiki && shouldPersistInputHistory(parsedInput)) {
|
|
4245
4628
|
await appendInputHistory(line);
|
|
4246
4629
|
}
|
|
4247
4630
|
} catch {
|
|
@@ -4250,6 +4633,35 @@ export async function createChatRuntime({
|
|
|
4250
4633
|
if (parsedInput.type === 'empty') {
|
|
4251
4634
|
return { type: 'noop' };
|
|
4252
4635
|
}
|
|
4636
|
+
if (readOnlyCodeWiki) {
|
|
4637
|
+
const expandedText = await expandFileMentions(line, process.cwd());
|
|
4638
|
+
const readOnlySystemPrompt = [
|
|
4639
|
+
activeReplySystemPrompt,
|
|
4640
|
+
'CodeWiki repository Q&A mode:',
|
|
4641
|
+
'- Answer questions about the current repository and generated CodeWiki/project-requirements report.',
|
|
4642
|
+
'- This is read-only. Do not modify files, update plans, run shell commands, delete anything, write memories, or ask to perform side effects.',
|
|
4643
|
+
'- Use only read-only project inspection tools when evidence is needed.',
|
|
4644
|
+
'- Be concise and cite relevant files or report sections when useful.'
|
|
4645
|
+
].join('\n\n');
|
|
4646
|
+
const transientSession = structuredClone(currentSession);
|
|
4647
|
+
const result = await askModel({
|
|
4648
|
+
text: expandedText,
|
|
4649
|
+
session: transientSession,
|
|
4650
|
+
config,
|
|
4651
|
+
model,
|
|
4652
|
+
systemPrompt: readOnlySystemPrompt,
|
|
4653
|
+
onAgentEvent,
|
|
4654
|
+
requestToolApproval: activeRequestToolApproval,
|
|
4655
|
+
executionMode: 'auto',
|
|
4656
|
+
alwaysAllowTools: CODEWIKI_READ_ONLY_TOOLS,
|
|
4657
|
+
allowedTools: CODEWIKI_READ_ONLY_TOOLS,
|
|
4658
|
+
persistSession: false,
|
|
4659
|
+
maxSteps: 32,
|
|
4660
|
+
skipAnalysisNudge: true,
|
|
4661
|
+
signal
|
|
4662
|
+
});
|
|
4663
|
+
return { type: 'assistant', text: result.text, aborted: !!result.aborted };
|
|
4664
|
+
}
|
|
4253
4665
|
if (parsedInput.type === 'shell') {
|
|
4254
4666
|
const shell = await handleShellInput(parsedInput.command, config);
|
|
4255
4667
|
return { type: 'shell', text: shell.text };
|
|
@@ -4259,12 +4671,12 @@ export async function createChatRuntime({
|
|
|
4259
4671
|
if (parsedInput.command === 'new') {
|
|
4260
4672
|
const fresh = await createSession();
|
|
4261
4673
|
currentSession = fresh;
|
|
4262
|
-
executionMode = config.execution?.mode || '
|
|
4674
|
+
executionMode = config.execution?.mode || 'normal';
|
|
4263
4675
|
compactState.backupMessages = null;
|
|
4264
4676
|
setResultDir(path.join(getSessionsDir(), String(fresh.id)));
|
|
4265
4677
|
historyIdCache = [fresh.id, ...historyIdCache.filter((id) => id !== fresh.id)];
|
|
4266
4678
|
historySessionCache = [
|
|
4267
|
-
{ id: fresh.id, messageCount: 0 },
|
|
4679
|
+
{ id: fresh.id, title: fresh.title || '', messageCount: 0 },
|
|
4268
4680
|
...historySessionCache.filter((s) => s.id !== fresh.id)
|
|
4269
4681
|
];
|
|
4270
4682
|
return {
|
|
@@ -4276,7 +4688,7 @@ export async function createChatRuntime({
|
|
|
4276
4688
|
if (parsedInput.command === 'help') {
|
|
4277
4689
|
return {
|
|
4278
4690
|
type: 'system',
|
|
4279
|
-
text: 'Commands: /help /exit /new /stop /commands /status /mode /compact /checkpoint /spec /plan /yes /no /edit /reject /agents /config /memory /capture /inbox /dream /reflect /history /debug /retry /<custom> !<shell>'
|
|
4691
|
+
text: 'Commands: /help /exit /new /stop /commands /status /model /mode /compact /checkpoint /spec /plan /yes /no /edit /reject /agents /config /memory /capture /inbox /dream /reflect /history /debug /retry /<custom> !<shell>'
|
|
4280
4692
|
};
|
|
4281
4693
|
}
|
|
4282
4694
|
if (parsedInput.command === 'status') {
|
|
@@ -4286,6 +4698,31 @@ export async function createChatRuntime({
|
|
|
4286
4698
|
text: `mode=${executionMode} | role=general | model=${model || config.model.name} | max_ctx=${effectiveMaxContextTokens(config)} | session=${currentSession.id} | todos=${todoCount}`
|
|
4287
4699
|
};
|
|
4288
4700
|
}
|
|
4701
|
+
if (parsedInput.command === 'model') {
|
|
4702
|
+
const sub = String(parsedInput.args[0] || 'current').trim().toLowerCase();
|
|
4703
|
+
const mainModel = resolveDefaultModel(config);
|
|
4704
|
+
const fastModel = resolveFastModel(config);
|
|
4705
|
+
if (sub === 'current' || sub === 'status') {
|
|
4706
|
+
return {
|
|
4707
|
+
type: 'system',
|
|
4708
|
+
text: `Current model: ${model || mainModel}\nDefault model: ${mainModel}\nFast model: ${fastModel}${config.model?.fast_name ? '' : ' (fallback to default; set /config set model.fast_name <name>)'}`
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4711
|
+
if (sub === 'main' || sub === 'default') {
|
|
4712
|
+
model = mainModel;
|
|
4713
|
+
} else if (sub === 'fast') {
|
|
4714
|
+
model = fastModel;
|
|
4715
|
+
} else if (sub === 'set') {
|
|
4716
|
+
const next = parsedInput.args.slice(1).join(' ').trim();
|
|
4717
|
+
if (!next) return { type: 'system', text: 'Usage: /model set <name>' };
|
|
4718
|
+
model = next;
|
|
4719
|
+
} else {
|
|
4720
|
+
return { type: 'system', text: 'Usage: /model current | /model main | /model fast | /model set <name>' };
|
|
4721
|
+
}
|
|
4722
|
+
currentSession.model = model;
|
|
4723
|
+
await saveSession(currentSession);
|
|
4724
|
+
return { type: 'system', text: `Model switched to: ${model}` };
|
|
4725
|
+
}
|
|
4289
4726
|
if (parsedInput.command === 'mode') {
|
|
4290
4727
|
const next = (parsedInput.args[0] || '').trim().toLowerCase();
|
|
4291
4728
|
if (!next) {
|
|
@@ -4340,9 +4777,13 @@ export async function createChatRuntime({
|
|
|
4340
4777
|
});
|
|
4341
4778
|
activeSubSession = null;
|
|
4342
4779
|
currentSession.planState = null;
|
|
4780
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
4343
4781
|
await removePlanFileIfPresent(planState);
|
|
4344
4782
|
executionMode = 'auto';
|
|
4345
|
-
await persistAssistantExchange(line, result.text || '', {
|
|
4783
|
+
await persistAssistantExchange(line, result.sessionText || result.text || '', {
|
|
4784
|
+
includeUser: false,
|
|
4785
|
+
extra: Array.isArray(result.transcript) ? { plan_transcript: result.transcript } : {}
|
|
4786
|
+
});
|
|
4346
4787
|
return { type: 'assistant', text: result.text, aborted: !!result.aborted };
|
|
4347
4788
|
}
|
|
4348
4789
|
if (parsedInput.command === 'edit') {
|
|
@@ -4391,6 +4832,15 @@ export async function createChatRuntime({
|
|
|
4391
4832
|
});
|
|
4392
4833
|
currentSession.planState = revised;
|
|
4393
4834
|
executionMode = 'plan';
|
|
4835
|
+
if (onAgentEvent) {
|
|
4836
|
+
onAgentEvent({
|
|
4837
|
+
type: 'plan:pending_approval',
|
|
4838
|
+
goal: currentSession.planState.goal,
|
|
4839
|
+
summary: currentSession.planState.finalSummary || currentSession.planState.summary,
|
|
4840
|
+
filePath: currentSession.planState.filePath,
|
|
4841
|
+
steps: currentSession.planState.steps
|
|
4842
|
+
});
|
|
4843
|
+
}
|
|
4394
4844
|
const text = `Plan revised.\n${buildPendingPlanApprovalMessage(currentSession.planState)}`;
|
|
4395
4845
|
await persistLocalExchange(line, text);
|
|
4396
4846
|
return { type: 'system', text };
|
|
@@ -4405,6 +4855,7 @@ export async function createChatRuntime({
|
|
|
4405
4855
|
}
|
|
4406
4856
|
if (hasPendingPlanApproval(currentSession)) {
|
|
4407
4857
|
currentSession.planState = null;
|
|
4858
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
4408
4859
|
executionMode = 'auto';
|
|
4409
4860
|
const text = 'Pending plan rejected and cleared.';
|
|
4410
4861
|
await persistLocalExchange(line, text, { includeUser: false });
|
|
@@ -4418,6 +4869,7 @@ export async function createChatRuntime({
|
|
|
4418
4869
|
}
|
|
4419
4870
|
const planState = { ...currentSession.planState };
|
|
4420
4871
|
currentSession.planState = null;
|
|
4872
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
4421
4873
|
await removePlanFileIfPresent(planState);
|
|
4422
4874
|
executionMode = 'auto';
|
|
4423
4875
|
const text = 'Pending plan rejected and cleared.';
|
|
@@ -4533,6 +4985,15 @@ export async function createChatRuntime({
|
|
|
4533
4985
|
steps: Array.isArray(auto.steps) ? auto.steps : []
|
|
4534
4986
|
};
|
|
4535
4987
|
executionMode = 'plan';
|
|
4988
|
+
if (onAgentEvent) {
|
|
4989
|
+
onAgentEvent({
|
|
4990
|
+
type: 'plan:pending_approval',
|
|
4991
|
+
goal: currentSession.planState.goal,
|
|
4992
|
+
summary: currentSession.planState.finalSummary || currentSession.planState.summary,
|
|
4993
|
+
filePath: currentSession.planState.filePath,
|
|
4994
|
+
steps: currentSession.planState.steps
|
|
4995
|
+
});
|
|
4996
|
+
}
|
|
4536
4997
|
const text = buildAutoPlanSystemSummary(auto);
|
|
4537
4998
|
await persistLocalExchange(line, text);
|
|
4538
4999
|
return {
|
|
@@ -4558,9 +5019,13 @@ export async function createChatRuntime({
|
|
|
4558
5019
|
});
|
|
4559
5020
|
activeSubSession = null;
|
|
4560
5021
|
currentSession.planState = null;
|
|
5022
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
4561
5023
|
await removePlanFileIfPresent(planState);
|
|
4562
5024
|
executionMode = 'auto';
|
|
4563
|
-
await persistAssistantExchange(line, result.text || '', {
|
|
5025
|
+
await persistAssistantExchange(line, result.sessionText || result.text || '', {
|
|
5026
|
+
includeUser: false,
|
|
5027
|
+
extra: Array.isArray(result.transcript) ? { plan_transcript: result.transcript } : {}
|
|
5028
|
+
});
|
|
4564
5029
|
return { type: 'assistant', text: result.text, aborted: !!result.aborted };
|
|
4565
5030
|
}
|
|
4566
5031
|
if (sub === 'stay') {
|
|
@@ -4667,6 +5132,7 @@ export async function createChatRuntime({
|
|
|
4667
5132
|
historyIdCache = sessions.map((s) => s.id);
|
|
4668
5133
|
historySessionCache = sessions.map((s) => ({
|
|
4669
5134
|
id: s.id,
|
|
5135
|
+
title: s.title || '',
|
|
4670
5136
|
messageCount: Number(s.messageCount || 0)
|
|
4671
5137
|
}));
|
|
4672
5138
|
if (sessions.length === 0) return { type: 'system', text: 'No sessions found' };
|
|
@@ -4692,7 +5158,7 @@ export async function createChatRuntime({
|
|
|
4692
5158
|
}
|
|
4693
5159
|
if (!historyIdCache.includes(targetId)) historyIdCache.unshift(targetId);
|
|
4694
5160
|
historySessionCache = [
|
|
4695
|
-
{ id: targetId, messageCount: Array.isArray(loaded.messages) ? loaded.messages.length : 0 },
|
|
5161
|
+
{ id: targetId, title: loaded.title || deriveSessionTitle(loaded.messages || []), messageCount: Array.isArray(loaded.messages) ? loaded.messages.length : 0 },
|
|
4696
5162
|
...historySessionCache.filter((s) => s.id !== targetId)
|
|
4697
5163
|
];
|
|
4698
5164
|
return {
|
|
@@ -5013,7 +5479,8 @@ export async function createChatRuntime({
|
|
|
5013
5479
|
let result;
|
|
5014
5480
|
try {
|
|
5015
5481
|
result = await askModel({
|
|
5016
|
-
text: rendered,
|
|
5482
|
+
text: custom.metadata.type === 'skill' ? line : rendered,
|
|
5483
|
+
modelText: custom.metadata.type === 'skill' ? rendered : undefined,
|
|
5017
5484
|
session: currentSession,
|
|
5018
5485
|
config,
|
|
5019
5486
|
model,
|
|
@@ -5059,8 +5526,12 @@ export async function createChatRuntime({
|
|
|
5059
5526
|
});
|
|
5060
5527
|
activeSubSession = null;
|
|
5061
5528
|
currentSession.planState = null;
|
|
5529
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
5062
5530
|
executionMode = 'auto';
|
|
5063
|
-
await persistAssistantExchange(line, result.text || '', {
|
|
5531
|
+
await persistAssistantExchange(line, result.sessionText || result.text || '', {
|
|
5532
|
+
includeUser: false,
|
|
5533
|
+
extra: Array.isArray(result.transcript) ? { plan_transcript: result.transcript } : {}
|
|
5534
|
+
});
|
|
5064
5535
|
return { type: 'assistant', text: result.text, aborted: !!result.aborted };
|
|
5065
5536
|
}
|
|
5066
5537
|
if (isStayInPlanText(parsedInput.text)) {
|
|
@@ -5070,6 +5541,7 @@ export async function createChatRuntime({
|
|
|
5070
5541
|
}
|
|
5071
5542
|
if (isRejectPlanText(parsedInput.text)) {
|
|
5072
5543
|
currentSession.planState = null;
|
|
5544
|
+
if (onAgentEvent) onAgentEvent({ type: 'plan:approval_cleared' });
|
|
5073
5545
|
executionMode = 'auto';
|
|
5074
5546
|
const text = 'Pending plan rejected and cleared.';
|
|
5075
5547
|
await persistLocalExchange(line, text);
|
|
@@ -5081,6 +5553,43 @@ export async function createChatRuntime({
|
|
|
5081
5553
|
};
|
|
5082
5554
|
}
|
|
5083
5555
|
|
|
5556
|
+
// Plan mode with no pending plan → auto-generate structured plan
|
|
5557
|
+
if (executionMode === 'plan') {
|
|
5558
|
+
const expandedPlanText = await expandFileMentions(parsedInput.text, process.cwd());
|
|
5559
|
+
await maybeAutoDreamFromRuntime();
|
|
5560
|
+
const auto = await buildAutoPlanAndRun({
|
|
5561
|
+
goal: expandedPlanText,
|
|
5562
|
+
session: currentSession,
|
|
5563
|
+
config,
|
|
5564
|
+
model,
|
|
5565
|
+
systemPrompt: activeReplySystemPrompt,
|
|
5566
|
+
onAgentEvent,
|
|
5567
|
+
sessionId: currentSession.id,
|
|
5568
|
+
taskClass: classifyPlanTaskClass(expandedPlanText)
|
|
5569
|
+
});
|
|
5570
|
+
currentSession.planState = {
|
|
5571
|
+
status: 'pending_approval',
|
|
5572
|
+
source: 'auto',
|
|
5573
|
+
goal: expandedPlanText,
|
|
5574
|
+
filePath: auto.filePath,
|
|
5575
|
+
summary: auto.summary || '',
|
|
5576
|
+
finalSummary: auto.finalSummary || auto.summary || '',
|
|
5577
|
+
steps: Array.isArray(auto.steps) ? auto.steps : []
|
|
5578
|
+
};
|
|
5579
|
+
if (onAgentEvent) {
|
|
5580
|
+
onAgentEvent({
|
|
5581
|
+
type: 'plan:pending_approval',
|
|
5582
|
+
goal: currentSession.planState.goal,
|
|
5583
|
+
summary: currentSession.planState.finalSummary || currentSession.planState.summary,
|
|
5584
|
+
filePath: currentSession.planState.filePath,
|
|
5585
|
+
steps: currentSession.planState.steps
|
|
5586
|
+
});
|
|
5587
|
+
}
|
|
5588
|
+
const text = buildAutoPlanSystemSummary(auto);
|
|
5589
|
+
await persistLocalExchange(line, text);
|
|
5590
|
+
return { type: 'system', text };
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5084
5593
|
if (compactState.autoEnabled) {
|
|
5085
5594
|
const currentTokens = estimateMessagesTokens(currentSession.messages);
|
|
5086
5595
|
const maxTokens = effectiveMaxContextTokens(config);
|
|
@@ -5185,6 +5694,18 @@ export async function createChatRuntime({
|
|
|
5185
5694
|
consumeStartupEvents: () => startupEvents.splice(0, startupEvents.length),
|
|
5186
5695
|
getInputHistory: () => loadInputHistory(),
|
|
5187
5696
|
getCurrentSessionId: () => currentSession.id,
|
|
5697
|
+
getSessionMessages: () => currentSession.messages || [],
|
|
5698
|
+
reloadConfig: async () => {
|
|
5699
|
+
config = await loadConfig();
|
|
5700
|
+
return config;
|
|
5701
|
+
},
|
|
5702
|
+
setExecutionMode: async (next) => {
|
|
5703
|
+
if (!['normal', 'auto', 'plan'].includes(next)) return false;
|
|
5704
|
+
executionMode = next;
|
|
5705
|
+
await setConfigValue('execution.mode', next);
|
|
5706
|
+
config = await loadConfig();
|
|
5707
|
+
return true;
|
|
5708
|
+
},
|
|
5188
5709
|
setRequestToolApproval: (handler) => {
|
|
5189
5710
|
activeRequestToolApproval = typeof handler === 'function' ? handler : null;
|
|
5190
5711
|
return true;
|