@qwen-code/qwen-code 0.19.2 → 0.19.3-nightly.20260630.e00fe6a27
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/bundled/extension-creator/SKILL.md +357 -0
- package/bundled/loop/SKILL.md +21 -7
- package/bundled/loop/SKILL.test.ts +41 -0
- package/bundled/loop/loop-task-file.test.ts +1064 -0
- package/bundled/loop/loop-task-file.ts +404 -0
- package/bundled/loop/loop-tick-resolver.test.ts +665 -0
- package/bundled/loop/loop-tick-resolver.ts +347 -0
- package/bundled/qc-helper/SKILL.md +26 -19
- package/bundled/qc-helper/docs/configuration/auth.md +11 -11
- package/bundled/qc-helper/docs/configuration/model-providers.md +13 -13
- package/bundled/qc-helper/docs/configuration/settings.md +76 -75
- package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
- package/bundled/qc-helper/docs/features/commands.md +108 -77
- package/bundled/qc-helper/docs/features/hooks.md +6 -1
- package/bundled/qc-helper/docs/features/memory.md +52 -0
- package/bundled/qc-helper/docs/qwen-serve.md +24 -2
- package/bundled/qc-helper/docs/support/tos-privacy.md +16 -3
- package/bundled/qc-helper/docs/support/troubleshooting.md +6 -0
- package/chunks/{MaxSizedBox-7RERNLFK.js → MaxSizedBox-T5X5MN5Q.js} +29 -27
- package/chunks/{StandaloneSessionPicker-S22XBSN6.js → StandaloneSessionPicker-P3E3WTOQ.js} +42 -37
- package/chunks/{acpAgent-4MCETHF2.js → acpAgent-QEP6DXFW.js} +864 -175
- package/chunks/{agent-K3ENVYSB.js → agent-UDANDUF7.js} +24 -23
- package/chunks/{agent-headless-HO3V3A3A.js → agent-headless-KYVSZHSO.js} +24 -23
- package/chunks/{anthropicContentGenerator-E3TQ5XJJ.js → anthropicContentGenerator-KWSJAQ7B.js} +33 -12
- package/chunks/{artifact-tool-QA4KRO3B.js → artifact-tool-D2X7G3C3.js} +2 -2
- package/chunks/{askUserQuestion-HMWXW6VN.js → askUserQuestion-UGETICJQ.js} +2 -2
- package/chunks/{bridge-4LV2HBH2.js → bridge-X42LXPTA.js} +31 -30
- package/chunks/{ca-7WC7ELX6.js → ca-IUFWESZL.js} +1 -0
- package/chunks/{chunk-JXQ23SNT.js → chunk-2JKEQWDZ.js} +623 -78
- package/chunks/{chunk-2TJ3YN6Q.js → chunk-2RJA6J57.js} +416 -401
- package/chunks/{chunk-3UALQ56H.js → chunk-3227DZO4.js} +1 -1
- package/chunks/{chunk-BGUDAULQ.js → chunk-3CPCDXFR.js} +5 -5
- package/chunks/{chunk-5RVSM6NW.js → chunk-3HUHAQF3.js} +1 -1
- package/chunks/{chunk-D5E5TMYH.js → chunk-3M4W4U5G.js} +16 -2
- package/chunks/{chunk-DBZUXSSV.js → chunk-4X7NIEQJ.js} +3 -3
- package/chunks/chunk-5GOVVXEV.js +73 -0
- package/chunks/{chunk-2BAQ3ACS.js → chunk-5SM4VT6V.js} +405 -5
- package/chunks/{chunk-NYOHZYHM.js → chunk-5XQ4A26L.js} +45 -3
- package/chunks/{chunk-CI5O6SQL.js → chunk-6FKEVYCD.js} +4 -4
- package/chunks/{chunk-ZD3NW5KL.js → chunk-7LM4XHPE.js} +63 -9
- package/chunks/chunk-7UNP2XM7.js +840 -0
- package/chunks/{chunk-OQHQHJRK.js → chunk-ARYCHZ4B.js} +151 -4775
- package/chunks/chunk-BC3C4F3Q.js +40 -0
- package/chunks/{chunk-CGEGHF2C.js → chunk-BKXBARJZ.js} +1 -1
- package/chunks/chunk-BMFMJINR.js +45 -0
- package/chunks/chunk-BOJWHRMX.js +11273 -0
- package/chunks/{chunk-CGOMICBE.js → chunk-BSZEQNUA.js} +34 -1
- package/chunks/{chunk-OIC6S73E.js → chunk-BUUQ5HPX.js} +1 -1
- package/chunks/{chunk-2BIF2NVV.js → chunk-BVSVIN45.js} +2 -2
- package/chunks/{chunk-TOEGRAVX.js → chunk-BX5YO7UW.js} +17 -5
- package/chunks/{chunk-4W4T77MO.js → chunk-BXVWV4GI.js} +109 -6
- package/chunks/{chunk-VQRYPFCV.js → chunk-CYHVPQYT.js} +10 -460
- package/chunks/{chunk-PRYMDRBV.js → chunk-DDMOU62Q.js} +1 -1
- package/chunks/{chunk-S566HKUS.js → chunk-DHXWNSJA.js} +15 -1
- package/chunks/{chunk-F6XNTYNE.js → chunk-E6XQPQXW.js} +30 -307
- package/chunks/{chunk-QBZ22PQX.js → chunk-EWALXUAD.js} +3 -1
- package/chunks/{chunk-EL5IHQON.js → chunk-EWYQFWYF.js} +6 -27
- package/chunks/{chunk-HG6YKEBI.js → chunk-F2DOT6UZ.js} +161 -30
- package/chunks/{chunk-JTYRZODB.js → chunk-FOOIZCWL.js} +16 -7
- package/chunks/{chunk-EX4W6ZYG.js → chunk-G5G4TFZ7.js} +1 -1
- package/chunks/{chunk-EW6C27XX.js → chunk-GEHVIWAT.js} +9 -3
- package/chunks/chunk-HEVBZSXG.js +4923 -0
- package/chunks/chunk-HFQ2XSE7.js +690 -0
- package/chunks/{chunk-PF523XJX.js → chunk-HPGTGMP3.js} +1 -1
- package/chunks/{chunk-OTBK43JR.js → chunk-HYCC3XM3.js} +1 -1
- package/chunks/{chunk-TMBPDHXD.js → chunk-I4H7PRWQ.js} +1 -1
- package/chunks/{chunk-EEEZIVFJ.js → chunk-JOLIREYR.js} +1 -1
- package/chunks/{chunk-TZM5JIAX.js → chunk-JYPQTRA3.js} +10 -7
- package/chunks/chunk-K5XU6E4T.js +167 -0
- package/chunks/{chunk-BS64PXY3.js → chunk-KFVU7ODN.js} +1 -1
- package/chunks/{chunk-3RJ3ZPPR.js → chunk-KKQWC6WS.js} +7 -7
- package/chunks/{chunk-3QFE4OTE.js → chunk-LBW7NW7X.js} +4 -4
- package/chunks/{chunk-Z7XXFPGP.js → chunk-LDWTYE33.js} +1 -1
- package/chunks/{chunk-EXMX5YHG.js → chunk-LP5E4YIH.js} +1 -1
- package/chunks/{chunk-ZUAXI2OA.js → chunk-M2U5NM24.js} +188 -11366
- package/chunks/{chunk-I5T6PIBQ.js → chunk-MBV2CTRL.js} +1010 -925
- package/chunks/{chunk-5JZLXFPD.js → chunk-MTHMXSNT.js} +11 -11
- package/chunks/{chunk-FPACXT7T.js → chunk-MTJVHQDP.js} +534 -164
- package/chunks/chunk-NDOC6M5S.js +481 -0
- package/chunks/{chunk-HGNSRCRB.js → chunk-NL4C3H6C.js} +1 -1
- package/chunks/{chunk-GZCJS5WH.js → chunk-O2VBQ3Y2.js} +2 -2
- package/chunks/{chunk-UN3C6GOR.js → chunk-PPFWEV7G.js} +10 -108
- package/chunks/{chunk-RS4HRC75.js → chunk-QI2CFVRF.js} +85 -8
- package/chunks/{chunk-XU5P23GN.js → chunk-QLDPRILK.js} +3 -3
- package/chunks/chunk-QYUE6W3T.js +123 -0
- package/chunks/{chunk-USGMPVOY.js → chunk-R3LHDWF2.js} +21 -12
- package/chunks/{chunk-BNXANYLH.js → chunk-RD6YJJJ6.js} +81 -1
- package/chunks/{chunk-PXFFKNCO.js → chunk-RIP623NO.js} +4877 -2469
- package/chunks/{chunk-XKBP7M7A.js → chunk-RYBSUGOR.js} +142 -30
- package/chunks/{chunk-BG4BIP7F.js → chunk-SBBN4BWR.js} +4 -2
- package/chunks/{chunk-T2VDEFUU.js → chunk-SKQZZVAV.js} +2 -2
- package/chunks/{chunk-5R4SBCX6.js → chunk-SL5MOGQH.js} +3 -3
- package/chunks/chunk-SMXULRAN.js +37 -0
- package/chunks/{chunk-WA5OJGFL.js → chunk-SS6WJMQK.js} +363 -76
- package/chunks/{chunk-UAARVVBI.js → chunk-TNWFHGN6.js} +1 -1
- package/chunks/{chunk-I2RFAW6Q.js → chunk-TT6Q3EN4.js} +7 -5
- package/chunks/chunk-UAKXW3DN.js +30 -0
- package/chunks/{chunk-C4K3FEQ2.js → chunk-UX4SGCGN.js} +32 -3
- package/chunks/{chunk-J6AW7O5D.js → chunk-WHDQZHRU.js} +2 -2
- package/chunks/{chunk-WGAEWQTF.js → chunk-WN6K47NR.js} +1 -2
- package/chunks/{chunk-UAARJR2G.js → chunk-WQT5SOI6.js} +2 -2
- package/chunks/{chunk-VYFMN7C6.js → chunk-WUMVIRTN.js} +225 -37
- package/chunks/{chunk-R36VMVEP.js → chunk-XJMKOTVV.js} +5 -5
- package/chunks/{chunk-TXVGVZYR.js → chunk-XJYUPHRC.js} +3 -3
- package/chunks/{chunk-2JD55C6G.js → chunk-Y6YMRS3U.js} +2 -2
- package/chunks/{chunk-LLFFKXZZ.js → chunk-YALKC62D.js} +56 -29
- package/chunks/{chunk-GYZQA2FO.js → chunk-YLZJCUH6.js} +1 -1
- package/chunks/chunk-YTFBURQD.js +313 -0
- package/chunks/{chunk-KBXLIVWQ.js → chunk-ZFPRYHWR.js} +2 -2
- package/chunks/{chunk-X6EDWN44.js → chunk-ZP6UKOPB.js} +1 -1
- package/chunks/{computer-use-6BBRNT6S.js → computer-use-LF2S6LUZ.js} +103 -49
- package/chunks/{contextCommand-UJAJ6N57.js → contextCommand-VPX5UG55.js} +26 -25
- package/chunks/{cron-create-4KQE6YLH.js → cron-create-SKEY55RG.js} +4 -4
- package/chunks/{cron-delete-THME66UP.js → cron-delete-I3NAT32Z.js} +6 -6
- package/chunks/{cron-list-7A54SJ5N.js → cron-list-6XRRL6TH.js} +5 -5
- package/chunks/{daemon-status-provider-CSL3BUOY.js → daemon-status-provider-5JAWZS4V.js} +34 -34
- package/chunks/{de-ACHALDED.js → de-EOW5PVHF.js} +1 -0
- package/chunks/{dist-BD27IA3L.js → dist-4FCNM6KJ.js} +2 -2
- package/chunks/{dist-OD2FY543.js → dist-O3H4PABL.js} +2 -2
- package/chunks/{dist-BOOH5JWN.js → dist-SCAAUWPS.js} +18 -4
- package/chunks/{dist-QHJRBCMP.js → dist-UKPWQJCL.js} +44 -2
- package/chunks/{dist-QFFZWACU.js → dist-VD7HXTML.js} +20 -9
- package/chunks/{earlyInputCapture-X6KMCSHD.js → earlyInputCapture-7FRQMU4P.js} +25 -24
- package/chunks/{edit-7J6WXARF.js → edit-REKJDIRL.js} +68 -27
- package/chunks/{en-NCUBOJOY.js → en-HPWEJBTR.js} +8 -0
- package/chunks/{enter-worktree-KULCKJPJ.js → enter-worktree-GBKUDCD3.js} +24 -23
- package/chunks/{enterPlanMode-H2CIOLMH.js → enterPlanMode-WB3Y4FGT.js} +24 -23
- package/chunks/{errors-6G2JYR54.js → errors-2XJDYO3M.js} +26 -25
- package/chunks/{exit-worktree-ECBWBVC5.js → exit-worktree-KKC7O2ZV.js} +24 -23
- package/chunks/{exitPlanMode-DQV56GTW.js → exitPlanMode-7HMS3TF7.js} +24 -23
- package/chunks/{fast-path-35JJFS3C.js → fast-path-XVNIYWGG.js} +4 -4
- package/chunks/{fast-path-settings-TSVI53EB.js → fast-path-settings-UQLRFDQP.js} +3 -2
- package/chunks/{fr-GVKZ27MF.js → fr-BN5NKSAC.js} +1 -0
- package/chunks/{gemini-NDTG7WAX.js → gemini-U5TPU3IQ.js} +210 -104
- package/chunks/{geminiContentGenerator-XTG6SFLA.js → geminiContentGenerator-ZVWRHXOO.js} +4 -4
- package/chunks/{glob-SJ2JBZK4.js → glob-FEJWIH2W.js} +24 -23
- package/chunks/{grep-BRMWFEWR.js → grep-KMP25IIA.js} +24 -23
- package/chunks/{headlessSafetyWarnings-LJ6FJX77.js → headlessSafetyWarnings-5DEDET4M.js} +24 -23
- package/chunks/{initializer-P5AXF7PV.js → initializer-FJTACLOH.js} +31 -28
- package/chunks/{ja-FKZ2WZ4D.js → ja-7DEUB2TS.js} +1 -0
- package/chunks/{keychain-token-storage-CSYMNRPP.js → keychain-token-storage-YLMDLKXT.js} +2 -2
- package/chunks/{list-6COK34BP.js → list-SCQXYJUW.js} +32 -29
- package/chunks/{loadedSettingsAdapter-XIUTN245.js → loadedSettingsAdapter-P6KPNAG7.js} +30 -27
- package/chunks/{loop-wakeup-33GPXJLA.js → loop-wakeup-FYEQEJUA.js} +7 -7
- package/chunks/{ls-BYQY7RVV.js → ls-R5WP4BGZ.js} +4 -4
- package/chunks/{lsp-X54RO4IV.js → lsp-GSICJMMW.js} +2 -2
- package/chunks/{monitor-DH7KFSJV.js → monitor-JU3HHHVY.js} +24 -23
- package/chunks/nonInteractiveCli-IZEKUHU3.js +100 -0
- package/chunks/{notebook-edit-D4R4ZLMA.js → notebook-edit-YHY3Z2QQ.js} +52 -23
- package/chunks/{openaiContentGenerator-F74IPQ6E.js → openaiContentGenerator-4WUVA3Q2.js} +13 -12
- package/chunks/{pt-SY5NCFGR.js → pt-TNZRNLQB.js} +1 -0
- package/chunks/{qwenContentGenerator-ATTK5P4D.js → qwenContentGenerator-MVYYR44B.js} +26 -25
- package/chunks/{qwenOAuth2-K4AASPCV.js → qwenOAuth2-6HNGHALT.js} +5 -4
- package/chunks/{read-file-767G23OY.js → read-file-NABEO2X4.js} +8 -8
- package/chunks/{read-mcp-resource-I5HCZJ6X.js → read-mcp-resource-DQQW7H7T.js} +2 -2
- package/chunks/{ripGrep-4OMMGSWX.js → ripGrep-YXLK6UTX.js} +24 -23
- package/chunks/{ru-FWNXJG4F.js → ru-NIAUBKCN.js} +1 -0
- package/chunks/{run-qwen-serve-REKSTYRA.js → run-qwen-serve-4B5QBMLQ.js} +144 -41
- package/chunks/{scheduler-UNTFDQLG.js → scheduler-XAKIYBDL.js} +24 -23
- package/chunks/{send-message-2DAFXEYP.js → send-message-EE4TWKVU.js} +2 -2
- package/chunks/{serve-KZ56QB5S.js → serve-4RXVLUKD.js} +30 -28
- package/chunks/{server-BV5TZUMU.js → server-7PA5QGIA.js} +11037 -8747
- package/chunks/{session-OIBXFSGD.js → session-WNVWRYAH.js} +194 -57
- package/chunks/{settings-WJTCBIRA.js → settings-YJH32TFF.js} +30 -27
- package/chunks/{shell-WC52IBHW.js → shell-YFLABOS5.js} +24 -23
- package/chunks/{skill-U7F7JR4M.js → skill-N3J7FUAY.js} +38 -11
- package/chunks/{spawnChannel-EI2E5BCW.js → spawnChannel-D6WVMFZJ.js} +26 -25
- package/chunks/{src-4F6FBZFI.js → src-IU5GDBEH.js} +88 -28
- package/chunks/{startInteractiveUI-SFRVB3CE.js → startInteractiveUI-QIPQTRT4.js} +2784 -2474
- package/chunks/{syntheticOutput-PPS3HDVA.js → syntheticOutput-T5YHQ6S2.js} +3 -3
- package/chunks/{task-create-OUYCA553.js → task-create-BLY7RHXX.js} +6 -6
- package/chunks/{task-list-WAX7I2IA.js → task-list-3QUYNVYR.js} +5 -5
- package/chunks/{task-stop-CAIL6FNH.js → task-stop-U4RATK2V.js} +2 -2
- package/chunks/{task-update-AHEO5OUT.js → task-update-U54O7KJX.js} +6 -6
- package/chunks/{team-create-3WC7CIIW.js → team-create-TP4CLLM3.js} +24 -23
- package/chunks/{team-delete-HGHFG23B.js → team-delete-LKBYPASD.js} +5 -5
- package/chunks/{theme-manager-DICFCT3P.js → theme-manager-N2TBIBZT.js} +25 -24
- package/chunks/{todoWrite-IFBMN3FH.js → todoWrite-OYXKTVYN.js} +4 -4
- package/chunks/{tool-search-L5K7HLER.js → tool-search-GBBSICYB.js} +101 -16
- package/chunks/trustedFolders-F7TBU5CD.js +76 -0
- package/chunks/types-QX5C3CHJ.js +12 -0
- package/chunks/{validateNonInterActiveAuth-GCH4Z6KI.js → validateNonInterActiveAuth-EQDQPSMI.js} +55 -50
- package/chunks/{web-fetch-B5IIQ5TT.js → web-fetch-PCVCML2X.js} +29 -15
- package/chunks/{workflow-OB3AND7I.js → workflow-ANJ4FYBK.js} +32 -30
- package/chunks/{workspace-providers-status-ZIR5EPOO.js → workspace-providers-status-462QQKQM.js} +32 -29
- package/chunks/workspace-service-VTG4G6CW.js +75 -0
- package/chunks/{write-file-SEXBNDZM.js → write-file-3P3WMQQW.js} +63 -27
- package/chunks/{zh-RBEGQVQT.js → zh-5EUYXASN.js} +8 -0
- package/chunks/{zh-TW-QGAVRXT3.js → zh-TW-TR3XYGE5.js} +8 -0
- package/cli-entry.js +20 -9
- package/cli.js +6 -6
- package/locales/ca.js +2 -0
- package/locales/de.js +2 -0
- package/locales/en.js +14 -0
- package/locales/fr.js +2 -0
- package/locales/ja.js +1 -0
- package/locales/pt.js +2 -0
- package/locales/ru.js +2 -0
- package/locales/zh-TW.js +12 -0
- package/locales/zh.js +12 -0
- package/node_modules/@qwen-code/audio-capture/dist/index.d.ts +35 -0
- package/node_modules/@qwen-code/audio-capture/dist/index.js +48 -0
- package/node_modules/@qwen-code/audio-capture/dist/index.js.map +1 -0
- package/node_modules/@qwen-code/audio-capture/dist/platform.d.ts +7 -0
- package/node_modules/@qwen-code/audio-capture/dist/platform.js +18 -0
- package/node_modules/@qwen-code/audio-capture/dist/platform.js.map +1 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/LICENSE +21 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/README.md +58 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/SECURITY.md +5 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/bin.js +84 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/build-test.js +19 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/index.js +6 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/node-gyp-build.js +207 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/optional.js +7 -0
- package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/package.json +43 -0
- package/node_modules/@qwen-code/audio-capture/package.json +30 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/linux-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/linux-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/package.json +18 -6
- package/patches/chrome-devtools-mcp+1.4.0.patch +31 -0
- package/postinstall.js +50 -0
- package/web-shell/assets/{arc-D_ae_Y9k.js → arc-DIemsO_F.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-BMLRjppa.js → architectureDiagram-3BPJPVTR-CTlUvIQv.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-qVDQC8KL.js → blockDiagram-GPEHLZMM-DG0jmIZK.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-CxWS6MBd.js → c4Diagram-AAUBKEIU-WljDBi55.js} +1 -1
- package/web-shell/assets/channel-CbzRbdpA.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-BtNuY5Yp.js → chunk-2J33WTMH-8nc6onr2.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BU-x368d.js → chunk-4BX2VUAB-EopXix8Z.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DRgTLvBu.js → chunk-55IACEB6-BE4Jz3N3.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-D2aElv7q.js → chunk-727SXJPM-C_eErgDN.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-BwHCMRQ0.js → chunk-AQP2D5EJ-DFtVW-Is.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-BMyPH-ku.js → chunk-FMBD7UC4-CJPyxIg9.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-BNKTstUf.js → chunk-ND2GUHAM-Bk-xgj6M.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-gD3vsFId.js → chunk-QZHKN3VN-p3Y4yaFB.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BFdyQ52h.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BFdyQ52h.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BG9FAsXE.js → cose-bilkent-S5V4N54A-BCMO6Js3.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-Cy1sR7om.js → dagre-BM42HDAG-DUMrwASf.js} +1 -1
- package/web-shell/assets/default-aEtf0G7-.svg +1 -0
- package/web-shell/assets/{diagram-2AECGRRQ-Bxi1I_Vu.js → diagram-2AECGRRQ-C5d7qJbL.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-BGCJjO6y.js → diagram-5GNKFQAL-CjLzMhbT.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CMTeLXp7.js → diagram-KO2AKTUF-RCoNWeAm.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BN1wyAGh.js → diagram-LMA3HP47-KThXjaNV.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-UYSG_zcp.js → diagram-OG6HWLK6-DKsC2BWz.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-DqXL08lw.js → erDiagram-TEJ5UH35-DJ2ukmq0.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BPJ9SFji.js → flowDiagram-I6XJVG4X-zzqaARRX.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BEd9Pnms.js → ganttDiagram-6RSMTGT7-kFUg-gqT.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-DrNRH3oi.js → gitGraphDiagram-PVQCEYII-C6JnMVzD.js} +1 -1
- package/web-shell/assets/index-B3XUm7dw.js +713 -0
- package/web-shell/assets/index-CHmzAWys.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CFYBrkVI.js → infoDiagram-5YYISTIA-XqPVhp89.js} +1 -1
- package/web-shell/assets/insert-DmRbh9Rv.svg +1 -0
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-Dxsddth7.js → ishikawaDiagram-YF4QCWOH-D2k8sGpf.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-DxaDK80t.js → journeyDiagram-JHISSGLW-CQEST1GE.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-Q0jQCOct.js → kanban-definition-UN3LZRKU-DZ7kqVBC.js} +1 -1
- package/web-shell/assets/{linear-DGGM2kcP.js → linear-B6C_6q_E.js} +1 -1
- package/web-shell/assets/{mermaid.core-ByoxnWut.js → mermaid.core-CsyNP1qt.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-C0ZseHsi.js → mindmap-definition-RKZ34NQL-B1VDIzJq.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-MQXNhl5A.js → pieDiagram-4H26LBE5-DN0E7Jwu.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DIR4ee2A.js → quadrantDiagram-W4KKPZXB-UKTQdHKm.js} +1 -1
- package/web-shell/assets/queue-DWpnpFgW.svg +1 -0
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BTR0UdYQ.js → requirementDiagram-4Y6WPE33-BRGceQvN.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-sfnhMELN.js → sankeyDiagram-5OEKKPKP-2DDyu41v.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DXczHOHH.js → sequenceDiagram-3UESZ5HK-CT5iE8ZU.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-DdE_KQFH.js → stateDiagram-AJRCARHV-CqMQ_s4G.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CamhV5pM.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DIc61uE8.js → timeline-definition-PNZ67QCA-Di37QSZU.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BF7ODmxB.js → vennDiagram-CIIHVFJN-DCXvpz5S.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-3pc1MEaw.js → wardley-L42UT6IY-CpUCk6OX.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-9jnPcZuP.js → wardleyDiagram-YWT4CUSO-D01pVEBg.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-DcthaZK6.js → xychartDiagram-2RQKCTM6-DOu5JDoz.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-B6HQGTYR.js +0 -410
- package/chunks/chunk-R2BXK7SX.js +0 -13
- package/chunks/chunk-RKIZXJMB.js +0 -13
- package/chunks/nonInteractiveCli-7575LBXP.js +0 -91
- package/chunks/workspace-service-OM5D4OI2.js +0 -60
- package/web-shell/assets/channel-DYPNiTww.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-p_g25Tni.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-p_g25Tni.js +0 -1
- package/web-shell/assets/index-CpOXWDPh.js +0 -714
- package/web-shell/assets/index-oVK7qhre.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BHUSEndU.js +0 -1
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Qwen
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { tildeifyPath } from '../../../utils/paths.js';
|
|
9
|
+
import {
|
|
10
|
+
LOOP_TASK_FILE_MAX_BYTES,
|
|
11
|
+
readLoopTaskFile,
|
|
12
|
+
type LoopTaskFileSource,
|
|
13
|
+
} from './loop-task-file.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Fire-time resolver for `.qwen/loop.md`-driven loops.
|
|
17
|
+
*
|
|
18
|
+
* A `/loop` whose scheduled prompt is one of these sentinels re-reads loop.md
|
|
19
|
+
* on every fire and gets either the FULL task block (first delivery, or whenever
|
|
20
|
+
* the file changed) or a one-line SHORT reminder (unchanged) — so the task list
|
|
21
|
+
* is paid for once into the cached message-prefix and later ticks stay cheap.
|
|
22
|
+
*
|
|
23
|
+
* Divergence from the upstream design this mirrors: the `lastContent` cache is
|
|
24
|
+
* held per Session instance (not a module singleton) so it scopes to one
|
|
25
|
+
* conversation and resets cleanly with that conversation's context (compaction).
|
|
26
|
+
* Change-detection is full content equality, not mtime/hash, so edit and
|
|
27
|
+
* delete→recreate both re-expand for free.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export const LOOP_SENTINEL_CRON = '<<loop.md>>';
|
|
31
|
+
export const LOOP_SENTINEL_DYNAMIC = '<<loop.md-dynamic>>';
|
|
32
|
+
|
|
33
|
+
export type LoopMode = 'cron' | 'dynamic';
|
|
34
|
+
|
|
35
|
+
export interface LoopTickResolverDeps {
|
|
36
|
+
/** Pass `config.getWorkingDir()` — loop.md is resolved against the cwd. */
|
|
37
|
+
projectRoot: string;
|
|
38
|
+
/** Home-candidate confinement root: `$QWEN_HOME` when set, else `$HOME`. */
|
|
39
|
+
homeDir: string;
|
|
40
|
+
/**
|
|
41
|
+
* QWEN_HOME-aware global dir holding the home `loop.md` (`Storage.getGlobalQwenDir()`).
|
|
42
|
+
* Omitted → defaults to `<homeDir>/.qwen` inside readLoopTaskFile.
|
|
43
|
+
*/
|
|
44
|
+
homeQwenDir?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Pass `() => config.isTrustedFolder()`. Re-evaluated on every `resolve()`,
|
|
47
|
+
* never captured once: `isTrustedFolder()` is not process-stable in IDE
|
|
48
|
+
* sessions (a workspace-trust update can flip it), and a trusted→untrusted
|
|
49
|
+
* flip must immediately stop reading the repo-controlled project
|
|
50
|
+
* `.qwen/loop.md` (the user-owned `~/.qwen/loop.md` still is read).
|
|
51
|
+
*/
|
|
52
|
+
allowProjectFile: () => boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface LoopTickResult {
|
|
56
|
+
/** Text to deliver to the model in place of the sentinel prompt. */
|
|
57
|
+
modelText: string;
|
|
58
|
+
/** True when the full task block was delivered (vs a short reminder). */
|
|
59
|
+
full: boolean;
|
|
60
|
+
/** Non-absolute label for the matched candidate (e.g. "project loop.md"),
|
|
61
|
+
* when present — safe for logs/UI that must not leak the absolute path, and
|
|
62
|
+
* doubles as the "a loop.md was found" flag for callers. */
|
|
63
|
+
sourceLabel?: string;
|
|
64
|
+
/** True ONLY for buildTransientErrorTick: a loop.md exists but could not be
|
|
65
|
+
* read THIS tick (a transient EACCES/EIO or editor/AV lock), as distinct from
|
|
66
|
+
* the genuinely-absent no-op (where this stays false). Lets the caller's echo
|
|
67
|
+
* say "temporarily unavailable" instead of "not present". Carries no errno or
|
|
68
|
+
* path — those stay in the modelText note and LOCAL debug logs only. */
|
|
69
|
+
transientError?: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const TRUNCATION_WARNING = `> WARNING: loop.md was truncated to ${LOOP_TASK_FILE_MAX_BYTES} bytes. Keep the task list concise.`;
|
|
73
|
+
|
|
74
|
+
const INTRO =
|
|
75
|
+
'The user configured a loop-tasks file. Work through the tasks defined below; these are the instructions for this tick and every subsequent tick (the reminder on later fires refers back to this message).';
|
|
76
|
+
|
|
77
|
+
// Mode-specific pacing guidance. Appended to BOTH the full block and the short
|
|
78
|
+
// reminder — the no-op/re-arm instruction applies on every tick.
|
|
79
|
+
const PACING_SUFFIX: Record<LoopMode, string> = {
|
|
80
|
+
cron: 'The recurring cron fires the next tick automatically — do not call LoopWakeup from this tick.',
|
|
81
|
+
dynamic: `You scheduled this tick via LoopWakeup (not a recurring cron). To keep the loop alive, call LoopWakeup again at the end of this turn with prompt set to the literal sentinel \`${LOOP_SENTINEL_DYNAMIC}\` — otherwise the loop ends after this tick.`,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Preamble for the UNCHANGED-tick reminder, which points back to the full block
|
|
85
|
+
// delivered on an earlier fire. NOT used on the first/changed full delivery,
|
|
86
|
+
// where the block is present in THIS message — there is no "earlier" to refer
|
|
87
|
+
// back to, so claiming the contents were established earlier would contradict
|
|
88
|
+
// the INTRO that sits right above them.
|
|
89
|
+
const SHORT_REMINDER_PREAMBLE =
|
|
90
|
+
'Work the tasks from the loop.md contents established earlier in this conversation. If you cannot find them, treat this as a no-op tick.';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The single H1 for every tick variant (full block, short reminder, absent), so
|
|
94
|
+
* they share one heading style and the dynamic-pacing suffix lives in one place.
|
|
95
|
+
* `sourceLabel` (set only on a full-block delivery) is a relative label like
|
|
96
|
+
* "project loop.md", never the absolute path — so the resolved file location
|
|
97
|
+
* isn't leaked to the model/API provider.
|
|
98
|
+
*/
|
|
99
|
+
function tickHeading(
|
|
100
|
+
mode: LoopMode,
|
|
101
|
+
opts: { sourceLabel?: string; absent?: boolean; unavailable?: boolean } = {},
|
|
102
|
+
): string {
|
|
103
|
+
// `unavailable` (transient read failure) is distinct from `absent`: the file
|
|
104
|
+
// exists but couldn't be read THIS tick, so the heading must not claim it's gone.
|
|
105
|
+
const subject = opts.unavailable
|
|
106
|
+
? 'loop.md unavailable'
|
|
107
|
+
: opts.absent
|
|
108
|
+
? 'loop.md absent'
|
|
109
|
+
: opts.sourceLabel
|
|
110
|
+
? `loop.md tasks from ${opts.sourceLabel}`
|
|
111
|
+
: 'loop.md tasks';
|
|
112
|
+
const base = `# /loop tick — ${subject}`;
|
|
113
|
+
return mode === 'dynamic' ? `${base} (dynamic pacing)` : base;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Model-safe relative label per source — exhaustive, so a new loop.md
|
|
117
|
+
* candidate added to readLoopTaskFile won't compile until it gets a label
|
|
118
|
+
* (rather than silently mislabelling it). */
|
|
119
|
+
const SOURCE_LABELS: Record<LoopTaskFileSource, string> = {
|
|
120
|
+
project: 'project loop.md',
|
|
121
|
+
home: 'home loop.md',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Per-mode tail of the absent reminder. The shared prefix (built in absentBody)
|
|
125
|
+
// names the candidate location(s) actually checked; only this no-op/re-arm
|
|
126
|
+
// guidance differs by mode.
|
|
127
|
+
const ABSENT_TAIL: Record<LoopMode, string> = {
|
|
128
|
+
cron: 'Treat this as a no-op tick; the recurring cron fires the next tick automatically.',
|
|
129
|
+
dynamic: `Treat this as a no-op tick. To pick it up if it is recreated, call LoopWakeup again with prompt set to the literal sentinel \`${LOOP_SENTINEL_DYNAMIC}\` — otherwise the loop ends after this tick.`,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Body of the absent reminder — the H1 is supplied by tickHeading() so the
|
|
133
|
+
// absent tick shares the same heading style as the full block and reminder.
|
|
134
|
+
// `locations` is LoopTickResolver.absentLocations(): the candidate path(s)
|
|
135
|
+
// ACTUALLY checked this tick (the project candidate is omitted on an untrusted
|
|
136
|
+
// folder), with a QWEN_HOME-aware home label that is never a raw absolute path.
|
|
137
|
+
function absentBody(mode: LoopMode, locations: string): string {
|
|
138
|
+
return `loop.md is not currently present at ${locations}. ${ABSENT_TAIL[mode]}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Detect whether a scheduled prompt is a loop.md sentinel, and which mode. */
|
|
142
|
+
export function detectLoopSentinel(prompt: string): LoopMode | null {
|
|
143
|
+
const trimmed = prompt.trim();
|
|
144
|
+
if (trimmed === LOOP_SENTINEL_DYNAMIC) {
|
|
145
|
+
return 'dynamic';
|
|
146
|
+
}
|
|
147
|
+
if (trimmed === LOOP_SENTINEL_CRON) {
|
|
148
|
+
return 'cron';
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Trim a truncated body back to its last full line before the warning tail. */
|
|
154
|
+
function cutToLastNewline(content: string): string {
|
|
155
|
+
const cut = content.lastIndexOf('\n');
|
|
156
|
+
// `> 0`, not `>= 0`: when the only newline is at index 0 (or there is none),
|
|
157
|
+
// there is no complete line to keep, so cutting would empty the body and leave
|
|
158
|
+
// the INTRO promising tasks that aren't there. Keep the (truncated) content
|
|
159
|
+
// instead — only a genuine trailing partial line (newline at index > 0) is
|
|
160
|
+
// dropped so the warning never glues onto a half-line.
|
|
161
|
+
return cut > 0 ? content.slice(0, cut) : content;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export class LoopTickResolver {
|
|
165
|
+
// What the model has actually received. Drives full-vs-reminder detection.
|
|
166
|
+
#lastContent: string | null = null;
|
|
167
|
+
// The most recent resolve()'s content, committed to #lastContent only once
|
|
168
|
+
// the caller confirms it reached the model (markDelivered) — so a tick that
|
|
169
|
+
// is aborted between resolve() and delivery can't poison the cache into
|
|
170
|
+
// sending a dangling short reminder next time.
|
|
171
|
+
#pendingContent: string | null = null;
|
|
172
|
+
// Instance-scoped fs.realpath cache for the confinement boundaries, handed to
|
|
173
|
+
// readLoopTaskFile. Tying it to the resolver (a fresh Map per /cd rebuild,
|
|
174
|
+
// cleared by resetCache) keeps the per-tick perf win while staying
|
|
175
|
+
// invalidatable — a module-global cache would pin a stale boundary in a
|
|
176
|
+
// long-lived process after a /cd or symlink re-point.
|
|
177
|
+
readonly #realDirCache = new Map<string, Promise<string>>();
|
|
178
|
+
|
|
179
|
+
constructor(private readonly deps: LoopTickResolverDeps) {}
|
|
180
|
+
|
|
181
|
+
/** Forget the delivered content so the next fire re-delivers the full block
|
|
182
|
+
* — called when the conversation is compacted (fresh context). */
|
|
183
|
+
resetCache(): void {
|
|
184
|
+
this.#lastContent = null;
|
|
185
|
+
this.#pendingContent = null;
|
|
186
|
+
// A reset may follow a /cd or symlink change, so drop the cached boundary
|
|
187
|
+
// realpaths too and re-resolve them on the next tick.
|
|
188
|
+
this.#realDirCache.clear();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Commit the last resolve()'s content once it has reached the model. */
|
|
192
|
+
markDelivered(): void {
|
|
193
|
+
if (this.#pendingContent !== null) {
|
|
194
|
+
this.#lastContent = this.#pendingContent;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** MODEL-FACING label for the home loop.md location. Mirrors
|
|
199
|
+
* readLoopTaskFile's home candidate (`<homeQwenDir>/loop.md`) so the absent
|
|
200
|
+
* reminder — and the caller's sanitized resolve-error — names the location
|
|
201
|
+
* actually checked (QWEN_HOME-aware), but must NEVER surface a raw absolute
|
|
202
|
+
* path: it flows into model/API text, leaking the host's filesystem layout.
|
|
203
|
+
* - under $HOME → tilde-abbreviated `~/.qwen/loop.md`;
|
|
204
|
+
* - relocated via $QWEN_HOME → the literal `$QWEN_HOME/loop.md`, not the
|
|
205
|
+
* resolved dir (`tildeifyPath` only abbreviates $HOME, so it's a no-op for
|
|
206
|
+
* a $QWEN_HOME outside $HOME and would otherwise pass the path through);
|
|
207
|
+
* - any other out-of-$HOME dir → a generic placeholder, never the path.
|
|
208
|
+
* The real absolute path stays in LOCAL debug logs only. */
|
|
209
|
+
homeLoopLabel(): string {
|
|
210
|
+
const homeQwenDir =
|
|
211
|
+
this.deps.homeQwenDir ?? path.join(this.deps.homeDir, '.qwen');
|
|
212
|
+
const homeLoopPath = path.join(homeQwenDir, 'loop.md');
|
|
213
|
+
|
|
214
|
+
const tildeified = tildeifyPath(homeLoopPath);
|
|
215
|
+
if (tildeified !== homeLoopPath) {
|
|
216
|
+
return tildeified;
|
|
217
|
+
}
|
|
218
|
+
// Outside $HOME: tildeifyPath was a no-op. When $QWEN_HOME relocated the
|
|
219
|
+
// global dir (homeQwenDir is its resolved value), report the literal env-var
|
|
220
|
+
// name — never the absolute path. The home candidate is always
|
|
221
|
+
// `<homeQwenDir>/loop.md`, so swap the whole resolved dir for `$QWEN_HOME` and
|
|
222
|
+
// re-attach the separator + basename directly. Deriving the tail from the
|
|
223
|
+
// resolved path's length instead mishandles edge dirs: a trailing slash
|
|
224
|
+
// (`$QWEN_HOME=/x/.qwen/`) over-counts the separator, and a filesystem-root
|
|
225
|
+
// homeQwenDir (`$QWEN_HOME=/` → homeLoopPath `/loop.md`, dirname `/`) drops the
|
|
226
|
+
// leading separator — both garbling the tail into `$QWEN_HOMEloop.md`.
|
|
227
|
+
if (process.env['QWEN_HOME']) {
|
|
228
|
+
return `$QWEN_HOME${path.sep}loop.md`;
|
|
229
|
+
}
|
|
230
|
+
return 'the configured global loop.md';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** The checked-candidate "where" string shared by the absent reminder and the
|
|
234
|
+
* caller's sanitized resolve-error. Names the project candidate ONLY when it
|
|
235
|
+
* was actually read (`projectChecked` — a trusted folder), so neither path can
|
|
236
|
+
* claim `.qwen/loop.md (project)` for an untrusted folder where the project
|
|
237
|
+
* file is skipped. The home label is the QWEN_HOME-aware, never-absolute
|
|
238
|
+
* homeLoopLabel(). Single source of truth so the two messages can't drift. */
|
|
239
|
+
absentLocations(projectChecked: boolean): string {
|
|
240
|
+
const homeLabel = this.homeLoopLabel();
|
|
241
|
+
return projectChecked
|
|
242
|
+
? `.qwen/loop.md (project) or ${homeLabel} (home)`
|
|
243
|
+
: `${homeLabel} (home)`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** A model-facing no-op tick (loop.md absent, or unreadable this tick). Clears
|
|
247
|
+
* the change-detection caches so a later successful tick re-delivers the FULL
|
|
248
|
+
* block instead of a dangling short reminder pointing at a block no longer
|
|
249
|
+
* guaranteed to be in context — absence (and a failed read) is itself a state
|
|
250
|
+
* change. */
|
|
251
|
+
#noOpTick(modelText: string, transientError = false): LoopTickResult {
|
|
252
|
+
this.#pendingContent = null;
|
|
253
|
+
this.#lastContent = null;
|
|
254
|
+
return { modelText, full: false, transientError };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* No-op tick for a transient, non-whitelisted read error (EACCES/EIO, or a
|
|
259
|
+
* Windows editor/AV briefly locking loop.md). Mirrors the absent tick — same
|
|
260
|
+
* heading + the mode's re-arm tail (ABSENT_TAIL) — so a `dynamic` loop still
|
|
261
|
+
* re-arms LoopWakeup and survives the hiccup instead of dying silently: its
|
|
262
|
+
* firing wakeup was already consumed by the scheduler, and only the
|
|
263
|
+
* end-of-turn re-arm keeps it alive, so a thrown turn ends the loop forever.
|
|
264
|
+
* `cron` callers don't use this (they re-fire on their own next interval).
|
|
265
|
+
* `projectChecked` is the trust captured for THIS tick (so the named candidate
|
|
266
|
+
* set matches what was probed); `code` is the errno only — never an absolute
|
|
267
|
+
* path — for a brief model-facing note.
|
|
268
|
+
*/
|
|
269
|
+
buildTransientErrorTick(
|
|
270
|
+
mode: LoopMode,
|
|
271
|
+
projectChecked: boolean,
|
|
272
|
+
code: string,
|
|
273
|
+
): LoopTickResult {
|
|
274
|
+
return this.#noOpTick(
|
|
275
|
+
// `unavailable`, not `absent`: the file exists but was unreadable this tick,
|
|
276
|
+
// so the heading mirrors the body instead of contradicting it.
|
|
277
|
+
`${tickHeading(mode, { unavailable: true })}\nloop.md at ${this.absentLocations(
|
|
278
|
+
projectChecked,
|
|
279
|
+
)} could not be read this tick (${code}). ${ABSENT_TAIL[mode]}`,
|
|
280
|
+
// Flag the tick as a transient read failure (file exists, unreadable this
|
|
281
|
+
// tick) so the caller's echo distinguishes it from a genuinely-absent file.
|
|
282
|
+
true,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* @param allowProjectFileOverride Trust captured once by the caller for this
|
|
288
|
+
* tick (see LoopTickResolverDeps.allowProjectFile). Threaded in — rather than
|
|
289
|
+
* re-reading the getter here — so the caller's error path can name the SAME
|
|
290
|
+
* candidate set that was probed even if `isTrustedFolder()` flips mid-tick.
|
|
291
|
+
* Omitted by direct callers, who fall back to the per-tick getter.
|
|
292
|
+
*/
|
|
293
|
+
async resolve(
|
|
294
|
+
mode: LoopMode,
|
|
295
|
+
allowProjectFileOverride?: boolean,
|
|
296
|
+
): Promise<LoopTickResult> {
|
|
297
|
+
// Re-read trust per tick (see LoopTickResolverDeps.allowProjectFile): a
|
|
298
|
+
// resolver built while trusted must skip the project file once trust flips.
|
|
299
|
+
// Captured so the absent reminder reflects what was ACTUALLY checked.
|
|
300
|
+
const allowProjectFile =
|
|
301
|
+
allowProjectFileOverride ?? this.deps.allowProjectFile();
|
|
302
|
+
const result = await readLoopTaskFile({
|
|
303
|
+
projectRoot: this.deps.projectRoot,
|
|
304
|
+
homeDir: this.deps.homeDir,
|
|
305
|
+
homeQwenDir: this.deps.homeQwenDir,
|
|
306
|
+
allowProjectFile,
|
|
307
|
+
realDirCache: this.#realDirCache,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (result.status === 'missing') {
|
|
311
|
+
// Absence is itself a state change: #noOpTick clears both caches so a
|
|
312
|
+
// later recreate — even with byte-identical content — re-expands the full
|
|
313
|
+
// block rather than sending a dangling short reminder.
|
|
314
|
+
return this.#noOpTick(
|
|
315
|
+
`${tickHeading(mode, { absent: true })}\n${absentBody(mode, this.absentLocations(allowProjectFile))}`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const content = result.truncated
|
|
320
|
+
? `${cutToLastNewline(result.content)}\n${TRUNCATION_WARNING}`
|
|
321
|
+
: result.content;
|
|
322
|
+
this.#pendingContent = content;
|
|
323
|
+
|
|
324
|
+
// Label by which candidate matched, never result.path (the absolute path),
|
|
325
|
+
// which would leak the OS username / dir layout to the API provider and to
|
|
326
|
+
// debug logs. The label alone is enough for the caller's UI and presence
|
|
327
|
+
// check, so the absolute path is not surfaced on the result at all.
|
|
328
|
+
const sourceLabel = SOURCE_LABELS[result.source];
|
|
329
|
+
|
|
330
|
+
if (this.#lastContent === content) {
|
|
331
|
+
return {
|
|
332
|
+
modelText: `${tickHeading(mode)}\n${SHORT_REMINDER_PREAMBLE} ${PACING_SUFFIX[mode]}`,
|
|
333
|
+
full: false,
|
|
334
|
+
sourceLabel,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// First/changed full delivery: INTRO + the block itself, then only the
|
|
339
|
+
// pacing suffix — no "established earlier" preamble, which would contradict
|
|
340
|
+
// the block sitting right here in this same message.
|
|
341
|
+
return {
|
|
342
|
+
modelText: `${tickHeading(mode, { sourceLabel })}\n${INTRO}\n${content}\n${PACING_SUFFIX[mode]}`,
|
|
343
|
+
full: true,
|
|
344
|
+
sourceLabel,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -47,20 +47,20 @@ Use this index to locate the right document for the user's question. Load only t
|
|
|
47
47
|
|
|
48
48
|
### Features
|
|
49
49
|
|
|
50
|
-
| Topic | Doc Path
|
|
51
|
-
| ------------------------------------------- |
|
|
52
|
-
| Approval mode (plan/default/auto_edit/yolo) | `docs/features/approval-mode.md`
|
|
53
|
-
| Auto mode (AI-driven approval) | `docs/features/auto-mode.md`
|
|
54
|
-
| Hooks (lifecycle hooks) | `docs/features/hooks.md`
|
|
55
|
-
| MCP (Model Context Protocol) | `docs/features/mcp.md`
|
|
56
|
-
| Memory | `docs/features/memory.md`
|
|
57
|
-
| Skills system | `docs/features/skills.md`
|
|
58
|
-
| Sub-agents | `docs/features/sub-agents.md`
|
|
59
|
-
| Sandbox / security | `docs/features/sandbox.md`
|
|
60
|
-
| Slash commands | `docs/features/commands.md`
|
|
61
|
-
| Headless / non-interactive mode | `docs/features/headless.md`
|
|
62
|
-
| LSP integration | `docs/features/lsp.md`
|
|
63
|
-
| Token caching | `docs/features/token-caching.md`
|
|
50
|
+
| Topic | Doc Path |
|
|
51
|
+
| ------------------------------------------- | --------------------------------------- |
|
|
52
|
+
| Approval mode (plan/default/auto_edit/yolo) | `docs/features/approval-mode.md` |
|
|
53
|
+
| Auto mode (AI-driven approval) | `docs/features/auto-mode.md` |
|
|
54
|
+
| Hooks (lifecycle hooks) | `docs/features/hooks.md` |
|
|
55
|
+
| MCP (Model Context Protocol) | `docs/features/mcp.md` |
|
|
56
|
+
| Memory | `docs/features/memory.md` |
|
|
57
|
+
| Skills system | `docs/features/skills.md` |
|
|
58
|
+
| Sub-agents | `docs/features/sub-agents.md` |
|
|
59
|
+
| Sandbox / security | `docs/features/sandbox.md` |
|
|
60
|
+
| Slash commands | `docs/features/commands.md` |
|
|
61
|
+
| Headless / non-interactive mode | `docs/features/headless.md` |
|
|
62
|
+
| LSP integration | `docs/features/lsp.md` |
|
|
63
|
+
| Token caching | `docs/features/token-caching.md` |
|
|
64
64
|
| Language / i18n | `docs/features/language.md` |
|
|
65
65
|
| Arena mode | `docs/features/arena.md` |
|
|
66
66
|
| Status line | `docs/features/status-line.md` |
|
|
@@ -75,6 +75,13 @@ Use this index to locate the right document for the user's question. Load only t
|
|
|
75
75
|
| Contextual tips | `docs/features/tips.md` |
|
|
76
76
|
| Channels (Telegram/WeChat/DingTalk/etc.) | `docs/features/channels/overview.md` |
|
|
77
77
|
|
|
78
|
+
### Daemon Mode
|
|
79
|
+
|
|
80
|
+
| Topic | Doc Path |
|
|
81
|
+
| --------------------------------- | --------------------------------- |
|
|
82
|
+
| qwen serve (daemon mode overview) | `docs/qwen-serve.md` |
|
|
83
|
+
| Local launch templates | `docs/qwen-serve-deploy-local.md` |
|
|
84
|
+
|
|
78
85
|
### IDE Integration
|
|
79
86
|
|
|
80
87
|
| Topic | Doc Path |
|
|
@@ -111,11 +118,11 @@ When the user asks about configuration, the primary reference is `docs/configura
|
|
|
111
118
|
|
|
112
119
|
### Config File Locations & Priority
|
|
113
120
|
|
|
114
|
-
| Level | Path
|
|
115
|
-
| ------- |
|
|
116
|
-
| User | `~/.qwen/settings.json`
|
|
117
|
-
| Project | `<project>/.qwen/settings.json`
|
|
118
|
-
| System | macOS: `/Library/Application Support/QwenCode/settings.json` | Admin-level config |
|
|
121
|
+
| Level | Path | Description |
|
|
122
|
+
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
|
123
|
+
| User | `~/.qwen/settings.json` | Personal global config |
|
|
124
|
+
| Project | `<project>/.qwen/settings.json` | Project-specific, overrides user level |
|
|
125
|
+
| System | Linux: `/etc/qwen-code/settings.json`<br>Windows: `C:\ProgramData\qwen-code\settings.json`<br>macOS: `/Library/Application Support/QwenCode/settings.json` | Admin-level config |
|
|
119
126
|
|
|
120
127
|
**Priority** (highest to lowest): CLI args > env vars > system settings > project settings > user settings > defaults
|
|
121
128
|
|
|
@@ -163,11 +163,11 @@ The key concept is **Model Providers** (`modelProviders`): Qwen Code supports mu
|
|
|
163
163
|
|
|
164
164
|
#### Supported protocols
|
|
165
165
|
|
|
166
|
-
| Protocol | `modelProviders` key | Environment variables
|
|
167
|
-
| ----------------- | -------------------- |
|
|
168
|
-
| OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL`
|
|
169
|
-
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL`
|
|
170
|
-
| Google GenAI | `gemini` | `GEMINI_API_KEY`, `GEMINI_MODEL`
|
|
166
|
+
| Protocol | `modelProviders` key | Environment variables | Providers |
|
|
167
|
+
| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
168
|
+
| OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL` | OpenAI, Azure OpenAI, OpenRouter, Requesty, ModelScope, Alibaba Cloud, any OpenAI-compatible endpoint |
|
|
169
|
+
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL` | Anthropic Claude |
|
|
170
|
+
| Google GenAI | `gemini` | `GEMINI_API_KEY`, `GEMINI_MODEL` | Google Gemini |
|
|
171
171
|
| Vertex AI | `vertex-ai` | `GOOGLE_API_KEY`, `GOOGLE_MODEL` (sets `GOOGLE_GENAI_USE_VERTEXAI=true`; uses the `gemini` protocol) | Google Vertex AI |
|
|
172
172
|
|
|
173
173
|
#### Step 1: Configure models and providers in `~/.qwen/settings.json`
|
|
@@ -224,13 +224,13 @@ Edit `~/.qwen/settings.json` (create it if it doesn't exist). You can mix multip
|
|
|
224
224
|
|
|
225
225
|
**`ModelConfig` fields (each entry inside `modelProviders`):**
|
|
226
226
|
|
|
227
|
-
| Field | Required | Description
|
|
228
|
-
| ------------------ | -------- |
|
|
229
|
-
| `id` | Yes | Model ID sent to the API (e.g. `gpt-4o`, `claude-sonnet-4-20250514`)
|
|
230
|
-
| `name` | No | Display name in the `/model` picker (defaults to `id`)
|
|
227
|
+
| Field | Required | Description |
|
|
228
|
+
| ------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
229
|
+
| `id` | Yes | Model ID sent to the API (e.g. `gpt-4o`, `claude-sonnet-4-20250514`) |
|
|
230
|
+
| `name` | No | Display name in the `/model` picker (defaults to `id`) |
|
|
231
231
|
| `envKey` | No | Environment variable name for the API key (e.g. `OPENAI_API_KEY`); optional/recommended — defaults to the auth type's default env key when omitted |
|
|
232
|
-
| `baseUrl` | No | API endpoint override (useful for proxies or custom endpoints)
|
|
233
|
-
| `generationConfig` | No | Fine-tune `timeout`, `maxRetries`, `samplingParams`, etc.
|
|
232
|
+
| `baseUrl` | No | API endpoint override (useful for proxies or custom endpoints) |
|
|
233
|
+
| `generationConfig` | No | Fine-tune `timeout`, `maxRetries`, `samplingParams`, etc. |
|
|
234
234
|
|
|
235
235
|
> [!note]
|
|
236
236
|
>
|
|
@@ -22,12 +22,12 @@ Below are comprehensive configuration examples for different authentication type
|
|
|
22
22
|
|
|
23
23
|
The `modelProviders` object keys must be valid `authType` values. Currently supported auth types are:
|
|
24
24
|
|
|
25
|
-
| Auth Type | Description
|
|
26
|
-
| ------------ |
|
|
27
|
-
| `openai` | OpenAI-compatible APIs (OpenAI, Azure OpenAI, local inference servers like vLLM/Ollama)
|
|
28
|
-
| `anthropic` | Anthropic Claude API
|
|
29
|
-
| `gemini` | Google Gemini API
|
|
30
|
-
| `qwen-oauth` | Qwen OAuth (hard-coded, cannot be overridden in `modelProviders`)
|
|
25
|
+
| Auth Type | Description |
|
|
26
|
+
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `openai` | OpenAI-compatible APIs (OpenAI, Azure OpenAI, local inference servers like vLLM/Ollama) |
|
|
28
|
+
| `anthropic` | Anthropic Claude API |
|
|
29
|
+
| `gemini` | Google Gemini API |
|
|
30
|
+
| `qwen-oauth` | Qwen OAuth (hard-coded, cannot be overridden in `modelProviders`) |
|
|
31
31
|
| `vertex-ai` | Google Vertex AI (uses the `gemini` protocol and the `@google/genai` SDK in Vertex AI mode; selecting it sets `GOOGLE_GENAI_USE_VERTEXAI=true`) |
|
|
32
32
|
|
|
33
33
|
> [!warning]
|
|
@@ -426,14 +426,14 @@ If you prefer to manually configure Coding Plan models, you can add them to your
|
|
|
426
426
|
|
|
427
427
|
The effective auth/model/credential values are chosen per field using the following precedence (first present wins). You can combine `--auth-type` with `--model` to point directly at a provider entry; these CLI flags run before other layers.
|
|
428
428
|
|
|
429
|
-
| Layer (highest → lowest) | authType | model | apiKey
|
|
430
|
-
| -------------------------- | ----------------------------------- | ----------------------------------------------- |
|
|
431
|
-
| Programmatic overrides | `/auth` | `/auth` input | `/auth` input
|
|
432
|
-
| Model provider selection | — | `modelProvider.id` | `env[modelProvider.envKey]`
|
|
429
|
+
| Layer (highest → lowest) | authType | model | apiKey | baseUrl | apiKeyEnvKey | proxy |
|
|
430
|
+
| -------------------------- | ----------------------------------- | ----------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------ | ---------------------- | --------------------------------- |
|
|
431
|
+
| Programmatic overrides | `/auth` | `/auth` input | `/auth` input | `/auth` input | — | — |
|
|
432
|
+
| Model provider selection | — | `modelProvider.id` | `env[modelProvider.envKey]` | `modelProvider.baseUrl` | `modelProvider.envKey` | — |
|
|
433
433
|
| CLI arguments | `--auth-type` | `--model` | `--openai-api-key` (or provider-specific equivalents) | `--openai-base-url` (or provider-specific equivalents) | — | — |
|
|
434
|
-
| Environment variables | — | Provider-specific mapping (e.g. `OPENAI_MODEL`) | Provider-specific mapping (e.g. `OPENAI_API_KEY`)
|
|
435
|
-
| Settings (`settings.json`) | `security.auth.selectedType` | `model.name` | `security.auth.apiKey`
|
|
436
|
-
| Default / computed | Falls back to `AuthType.QWEN_OAUTH` | Built-in default (OpenAI ⇒ `qwen3.5-plus`)
|
|
434
|
+
| Environment variables | — | Provider-specific mapping (e.g. `OPENAI_MODEL`) | Provider-specific mapping (e.g. `OPENAI_API_KEY`) | Provider-specific mapping (e.g. `OPENAI_BASE_URL`) | — | — |
|
|
435
|
+
| Settings (`settings.json`) | `security.auth.selectedType` | `model.name` | `security.auth.apiKey` | `security.auth.baseUrl` | — | — |
|
|
436
|
+
| Default / computed | Falls back to `AuthType.QWEN_OAUTH` | Built-in default (OpenAI ⇒ `qwen3.5-plus`) | — | — | — | `Config.getProxy()` if configured |
|
|
437
437
|
|
|
438
438
|
\*When present, CLI auth flags override settings. Otherwise, `security.auth.selectedType` or the implicit default determine the auth type. Qwen OAuth and OpenAI are the only auth types surfaced without extra configuration.
|
|
439
439
|
|