@qwen-code/qwen-code 0.19.3 → 0.19.4-nightly.20260702.46814e4f1
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/loop/SKILL.md +22 -3
- package/bundled/loop/SKILL.test.ts +20 -0
- package/bundled/loop/autonomous-loop.test.ts +59 -0
- package/bundled/loop/autonomous-loop.ts +102 -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 +906 -0
- package/bundled/loop/loop-tick-resolver.ts +416 -0
- package/bundled/qc-helper/SKILL.md +12 -5
- package/bundled/qc-helper/docs/configuration/auth.md +1 -1
- package/bundled/qc-helper/docs/configuration/settings.md +62 -32
- package/bundled/qc-helper/docs/features/approval-mode.md +3 -0
- package/bundled/qc-helper/docs/features/auto-mode.md +40 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +81 -18
- package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
- package/bundled/qc-helper/docs/features/code-review.md +17 -61
- package/bundled/qc-helper/docs/features/commands.md +42 -40
- package/bundled/qc-helper/docs/features/headless.md +19 -18
- package/bundled/qc-helper/docs/features/hooks.md +6 -1
- package/bundled/qc-helper/docs/features/mcp.md +3 -1
- package/bundled/qc-helper/docs/features/memory.md +1 -1
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +10 -0
- package/bundled/qc-helper/docs/features/status-line.md +3 -3
- package/bundled/qc-helper/docs/ide-integration/ide-integration.md +4 -4
- package/bundled/qc-helper/docs/qwen-serve.md +53 -0
- package/bundled/qc-helper/docs/support/troubleshooting.md +11 -0
- package/bundled/review/DESIGN.md +21 -26
- package/bundled/review/SKILL.md +45 -129
- package/chunks/MaxSizedBox-GHGRQ2OS.js +69 -0
- package/chunks/{StandaloneSessionPicker-Z52JTYST.js → StandaloneSessionPicker-G7YTTM27.js} +49 -42
- package/chunks/{acpAgent-7RZUOWOM.js → acpAgent-SDOILBSU.js} +1325 -365
- package/chunks/{agent-4FG7WTHJ.js → agent-NTSXGV4L.js} +31 -25
- package/chunks/agent-headless-WYURMSAB.js +62 -0
- package/chunks/{anthropicContentGenerator-PFITVL7Y.js → anthropicContentGenerator-WL3LJOUB.js} +110 -31
- package/chunks/{artifact-tool-D2X7G3C3.js → artifact-tool-W76WC2JX.js} +3 -3
- package/chunks/{askUserQuestion-UGETICJQ.js → askUserQuestion-J3P6TH3V.js} +2 -2
- package/chunks/bridge-AMOL4W4P.js +73 -0
- package/chunks/{ca-IUFWESZL.js → ca-HCMB2I54.js} +10 -9
- package/chunks/channel-worker-supervisor-C3IB63V7.js +659 -0
- package/chunks/{chunk-STUWFKGD.js → chunk-26JIREA5.js} +466 -543
- package/chunks/{chunk-SLNKLLEO.js → chunk-2MRV62AU.js} +37 -8
- package/chunks/{chunk-ODLIHNOY.js → chunk-2U4HUMOL.js} +1 -1
- package/chunks/{chunk-CKQA6AWF.js → chunk-4D73HUOP.js} +1 -1
- package/chunks/{chunk-M2U5NM24.js → chunk-54YZOP7P.js} +309 -72
- package/chunks/{chunk-J7FA27RO.js → chunk-5LKL3PAU.js} +3 -3
- package/chunks/chunk-5P5XGNYH.js +93 -0
- package/chunks/{chunk-UFLGERMB.js → chunk-6JE32BRB.js} +178 -124
- package/chunks/{chunk-FKAVULLM.js → chunk-75AVTQJ2.js} +74 -10
- package/chunks/{chunk-I2LYBGNI.js → chunk-7IOMIYOE.js} +1 -1
- package/chunks/{chunk-4LUZAKMK.js → chunk-7KXAGQJ2.js} +1 -1
- package/chunks/{chunk-BXSHL2SF.js → chunk-7LUOQJ3D.js} +1 -1
- package/chunks/{chunk-YAINVQ3Q.js → chunk-A5OPLHFM.js} +18693 -17055
- package/chunks/chunk-AHNXYU4O.js +24 -0
- package/chunks/{chunk-UX4SGCGN.js → chunk-AVQDCKNF.js} +96 -22
- package/chunks/{chunk-HYCC3XM3.js → chunk-B236XPGF.js} +1 -1
- package/chunks/chunk-B6SZLQAZ.js +3523 -0
- package/chunks/{chunk-5DWXLGOM.js → chunk-BJBWRCSK.js} +1 -1
- package/chunks/chunk-BPFJQGY7.js +193 -0
- package/chunks/{chunk-SKQZZVAV.js → chunk-BZHLWC6T.js} +2 -2
- package/chunks/{chunk-U3KSMM7G.js → chunk-D5KISTLW.js} +339 -383
- package/chunks/{chunk-GT2FGICD.js → chunk-DE7YXUR7.js} +1 -1
- package/chunks/{chunk-BUUQ5HPX.js → chunk-DG573EOO.js} +1 -1
- package/chunks/{chunk-VVLOGDB6.js → chunk-DX3TKXNT.js} +2 -2
- package/chunks/chunk-E5A7LHNN.js +51 -0
- package/chunks/{chunk-3PJXIDKI.js → chunk-E6US47KI.js} +3 -27
- package/chunks/{chunk-QBZ22PQX.js → chunk-EWALXUAD.js} +3 -1
- package/chunks/{chunk-PDE7CSDS.js → chunk-FXKI7OW6.js} +2 -2
- package/chunks/{chunk-F3ZYSEY6.js → chunk-FY4TT4L4.js} +3 -3
- package/chunks/{chunk-QLDPRILK.js → chunk-G7OQ3RFJ.js} +3 -3
- package/chunks/{chunk-R2BXK7SX.js → chunk-GHOTR7HL.js} +6 -1
- package/chunks/{chunk-KMGMKW5Q.js → chunk-GLPV75ES.js} +9 -3
- package/chunks/{chunk-LD2XBG6Z.js → chunk-GO6LNQXT.js} +1 -39
- package/chunks/{chunk-CNLEDYE3.js → chunk-H6TNLOLM.js} +5 -5
- package/chunks/{chunk-JVHEVCAU.js → chunk-HLW4EGKR.js} +31 -6
- package/chunks/{chunk-I4H7PRWQ.js → chunk-HTWHAN44.js} +1 -1
- package/chunks/{chunk-QE6KJYLT.js → chunk-IPYE5BIS.js} +123 -25
- package/chunks/{chunk-EJYJYJZ2.js → chunk-IRJWHZWU.js} +3 -70
- package/chunks/{chunk-EDMZZFDU.js → chunk-J3YPTTNL.js} +930 -798
- package/chunks/{chunk-GGBIN5K7.js → chunk-JGAJMIJZ.js} +1 -1
- package/chunks/{chunk-N4EJFBN5.js → chunk-JVLP5US5.js} +427 -263
- package/chunks/{chunk-R5OP2ATH.js → chunk-JZG7VB6C.js} +11 -11
- package/chunks/{chunk-QI7GOGJR.js → chunk-KKQWC6WS.js} +1 -1
- package/chunks/{chunk-ADCIHOQZ.js → chunk-KX5QZRW2.js} +142 -30
- package/chunks/{chunk-SBBN4BWR.js → chunk-L7OJ3ZO3.js} +1 -1
- package/chunks/{chunk-NDOC6M5S.js → chunk-L7QPM2YD.js} +2 -2
- package/chunks/{chunk-BVSVIN45.js → chunk-LKWAVAB5.js} +3 -3
- package/chunks/{chunk-T4T2FNV4.js → chunk-LOW52WYZ.js} +2 -2
- package/chunks/{chunk-4QK3O43S.js → chunk-LU7BIVWC.js} +4 -4
- package/chunks/{chunk-ZP6UKOPB.js → chunk-LWGLBVWA.js} +1 -1
- package/chunks/{chunk-L7OKCI7T.js → chunk-M7BLWURA.js} +15 -1
- package/chunks/{chunk-PR32FRT6.js → chunk-MIM62IXS.js} +3 -3
- package/chunks/{chunk-RD6YJJJ6.js → chunk-MOUXUCXQ.js} +1 -1
- package/chunks/{chunk-VBZ452JT.js → chunk-MSNGFH6L.js} +494 -114
- package/chunks/{chunk-BX5YO7UW.js → chunk-MTNTVOJR.js} +542 -370
- package/chunks/chunk-MX2YXRER.js +44 -0
- package/chunks/chunk-NIOPRZNN.js +27 -0
- package/chunks/{chunk-SMYQZVZ3.js → chunk-NOGSPTLJ.js} +1 -1
- package/chunks/{chunk-DDMOU62Q.js → chunk-NPQWQYU6.js} +1 -1
- package/chunks/{chunk-MNF6S5PR.js → chunk-P5THQV6A.js} +4 -4
- package/chunks/{chunk-6V4NZFUS.js → chunk-PCYOT4PK.js} +5 -5
- package/chunks/{chunk-CF6BB3LT.js → chunk-PPFWEV7G.js} +10 -1
- package/chunks/{chunk-FXKVLFFY.js → chunk-PSFDB5FZ.js} +3 -3
- package/chunks/{chunk-XJYUPHRC.js → chunk-QOMAHFYI.js} +3 -3
- package/chunks/{chunk-J37FGIOA.js → chunk-QXPI7FEC.js} +38 -4
- package/chunks/{chunk-RRFZXMYP.js → chunk-QZDBHNMV.js} +691 -164
- package/chunks/{chunk-S7AKE7HL.js → chunk-R6RI2HIC.js} +63 -9
- package/chunks/{chunk-HZT4UCFB.js → chunk-RB7S52NJ.js} +4 -4
- package/chunks/{chunk-J33ZR6OJ.js → chunk-RK22ACPP.js} +16 -16
- package/chunks/chunk-RM3PGSGL.js +66 -0
- package/chunks/chunk-RNBYOUGV.js +42 -0
- package/chunks/chunk-S6RLAIUR.js +23 -0
- package/chunks/{chunk-3TV3HUWZ.js → chunk-SCYK2YLI.js} +81 -30
- package/chunks/{chunk-HPZTOP4I.js → chunk-SEKRT4SD.js} +133 -23
- package/chunks/chunk-SEZC2725.js +36 -0
- package/chunks/chunk-SIUQ3YYX.js +78 -0
- package/chunks/{chunk-O2VBQ3Y2.js → chunk-SJBIFVD2.js} +2 -2
- package/chunks/chunk-SYCJMSIJ.js +82 -0
- package/chunks/{chunk-JE5FVRPC.js → chunk-T22H4V4R.js} +48 -23
- package/chunks/{chunk-3227DZO4.js → chunk-T42ACHFI.js} +1 -1
- package/chunks/{chunk-UO5GVXQE.js → chunk-TENOUWY2.js} +3 -3
- package/chunks/{chunk-JOLIREYR.js → chunk-TOAUDIS7.js} +1 -1
- package/chunks/{chunk-QNKBEJO2.js → chunk-UA6XBZT7.js} +2776 -1289
- package/chunks/{chunk-O75BHFQW.js → chunk-UQTYK5SS.js} +2 -2
- package/chunks/{chunk-Y6YMRS3U.js → chunk-UY2TCIZS.js} +17 -3
- package/chunks/{chunk-FNJ7BDPH.js → chunk-UY7ZAYTY.js} +10 -7
- package/chunks/{chunk-UYT3MWEB.js → chunk-UYHWM24C.js} +30 -2
- package/chunks/{chunk-SMXULRAN.js → chunk-VXGPYF7U.js} +1 -1
- package/chunks/{chunk-BTLJ2MF5.js → chunk-W7CG5HPC.js} +3 -3
- package/chunks/{chunk-JJXWTVSK.js → chunk-XHZKDN7M.js} +34 -1
- package/chunks/{chunk-K5XU6E4T.js → chunk-XKSCTXPK.js} +2 -2
- package/chunks/chunk-Y4LITCRB.js +367 -0
- package/chunks/chunk-YHTNWGRR.js +239 -0
- package/chunks/{chunk-BKXBARJZ.js → chunk-YPCPZSZB.js} +1 -1
- package/chunks/{chunk-QWFNTRH4.js → chunk-YSM24SCE.js} +1 -1
- package/chunks/chunk-YTFBURQD.js +313 -0
- package/chunks/{chunk-NL4C3H6C.js → chunk-YXK4GPYO.js} +1 -1
- package/chunks/{chunk-RYLJU2DY.js → chunk-ZN5T4BHI.js} +1 -1
- package/chunks/{computer-use-JGB36FDW.js → computer-use-MTSVPLPY.js} +34 -28
- package/chunks/contextCommand-VGJ3BPTK.js +67 -0
- package/chunks/{cron-create-SKEY55RG.js → cron-create-6YTCOX6P.js} +4 -4
- package/chunks/{cron-delete-I3NAT32Z.js → cron-delete-E3NIFSUK.js} +4 -4
- package/chunks/{cron-list-6XRRL6TH.js → cron-list-Q64MNQNE.js} +4 -4
- package/chunks/daemon-EEB2RYOL.js +8453 -0
- package/chunks/daemon-status-provider-H5SNMK42.js +71 -0
- package/chunks/{de-EOW5PVHF.js → de-PLLFDERI.js} +10 -9
- package/chunks/{dist-NHEYYB2B.js → dist-ADMIQGHI.js} +2 -2
- package/chunks/{dist-J37VXPLD.js → dist-BCQ7INM7.js} +40 -15
- package/chunks/{dist-663NZ6MI.js → dist-KNZFCY5F.js} +116 -11
- package/chunks/{dist-LB6OGPVM.js → dist-LHUWC3K6.js} +26 -5
- package/chunks/{dist-PQPZ5Q4N.js → dist-WBBZ76JZ.js} +20 -9
- package/chunks/{earlyInputCapture-44RISVVJ.js → earlyInputCapture-U4ZIQSQU.js} +32 -26
- package/chunks/{edit-NN6GM5DT.js → edit-SYIQ2KBI.js} +41 -38
- package/chunks/{en-HPWEJBTR.js → en-M4EBUBNU.js} +32 -10
- package/chunks/{enter-worktree-PB3O2C7D.js → enter-worktree-HPPOO244.js} +31 -25
- package/chunks/{enterPlanMode-YQFNNSUA.js → enterPlanMode-56YYO52U.js} +41 -25
- package/chunks/{errors-LS7XU5DZ.js → errors-EO4SXCFP.js} +33 -27
- package/chunks/{exit-worktree-E2FTNSBK.js → exit-worktree-UDM7E6XH.js} +31 -25
- package/chunks/{exitPlanMode-GLYK2BUB.js → exitPlanMode-M6P3AWLJ.js} +149 -33
- package/chunks/{fast-path-WQ6M7LI7.js → fast-path-42P4QYWI.js} +33 -14
- package/chunks/{fast-path-settings-OAGU3X5H.js → fast-path-settings-UQLRFDQP.js} +2 -2
- package/chunks/{fr-BN5NKSAC.js → fr-MBMNQSQ6.js} +10 -9
- package/chunks/{gemini-2YFLVA2M.js → gemini-NRLXS5J7.js} +84 -70
- package/chunks/{geminiContentGenerator-XV6SV6CD.js → geminiContentGenerator-DLJPYYPA.js} +41 -5
- package/chunks/{glob-2H6CDDMK.js → glob-JPY3F74Y.js} +31 -25
- package/chunks/{grep-VXIUXM3C.js → grep-HW23YES5.js} +31 -25
- package/chunks/initializer-HWOZTC4A.js +67 -0
- package/chunks/{ja-7DEUB2TS.js → ja-HFV5QCHR.js} +10 -9
- package/chunks/{keychain-token-storage-YLMDLKXT.js → keychain-token-storage-GPAKRDKQ.js} +2 -2
- package/chunks/list-OZGAGRDG.js +71 -0
- package/chunks/loadedSettingsAdapter-RUTZVVIA.js +66 -0
- package/chunks/{loop-wakeup-CITGGQHA.js → loop-wakeup-G2EHBRGR.js} +5 -5
- package/chunks/{ls-R5WP4BGZ.js → ls-IDHUVSAG.js} +4 -4
- package/chunks/{lsp-GSICJMMW.js → lsp-FSRYXGFT.js} +2 -2
- package/chunks/{monitor-HKLRS2HQ.js → monitor-QVWEIXU3.js} +33 -26
- package/chunks/nonInteractiveCli-RV2WYPML.js +109 -0
- package/chunks/{notebook-edit-Y6SKSGTT.js → notebook-edit-B26W3FFH.js} +37 -34
- package/chunks/{openaiContentGenerator-J7G2FYJT.js → openaiContentGenerator-6TH7AZGQ.js} +15 -13
- package/chunks/pidfile-KW2QQJZI.js +73 -0
- package/chunks/{pt-TNZRNLQB.js → pt-2THT3YHA.js} +10 -9
- package/chunks/{qwenContentGenerator-5XIEM5GV.js → qwenContentGenerator-5IQAC7RN.js} +33 -27
- package/chunks/{qwenOAuth2-AG3PFFLZ.js → qwenOAuth2-LWLA6MQG.js} +5 -4
- package/chunks/{read-file-J7D552ZJ.js → read-file-CWFAHOI2.js} +11 -10
- package/chunks/{read-mcp-resource-DQQW7H7T.js → read-mcp-resource-PIJF24RO.js} +2 -2
- package/chunks/ripGrep-FTZGDKY4.js +60 -0
- package/chunks/{ru-NIAUBKCN.js → ru-Z67YJHBG.js} +10 -9
- package/chunks/{run-qwen-serve-SGEEVMXD.js → run-qwen-serve-FN2SW5ZI.js} +545 -97
- package/chunks/{scheduler-7CQI3S4Q.js → scheduler-BMS23O3I.js} +31 -25
- package/chunks/{send-message-EE4TWKVU.js → send-message-33PYFMCT.js} +20 -4
- package/chunks/serve-PXFYKL65.js +71 -0
- package/chunks/{server-4QMUWXPW.js → server-BRKALJ4F.js} +4132 -1175
- package/chunks/{session-NRO7UFOY.js → session-AQMISBP4.js} +205 -64
- package/chunks/{settings-SGWRDQSC.js → settings-JCPVUZMB.js} +35 -29
- package/chunks/{shell-62ANGIHL.js → shell-POHCRVN2.js} +31 -25
- package/chunks/{skill-VWAQAWW6.js → skill-QPEVHS6H.js} +13 -12
- package/chunks/spawnChannel-V3QT62TE.js +69 -0
- package/chunks/{src-KUV5J5Q2.js → src-IZSP7L6Y.js} +127 -32
- package/chunks/{startInteractiveUI-6EYJN3JV.js → startInteractiveUI-63KATISO.js} +16762 -16075
- package/chunks/{syntheticOutput-T5YHQ6S2.js → syntheticOutput-YOSWIHDJ.js} +3 -3
- package/chunks/{task-create-BLY7RHXX.js → task-create-NHS2NGB3.js} +9 -7
- package/chunks/{task-list-3QUYNVYR.js → task-list-5UIB564R.js} +7 -6
- package/chunks/{task-stop-U4RATK2V.js → task-stop-HGXZ2VZ3.js} +2 -2
- package/chunks/{task-update-U54O7KJX.js → task-update-IYYWUILG.js} +40 -7
- package/chunks/{team-create-LPOGCPM7.js → team-create-E5O2F3CA.js} +31 -25
- package/chunks/{team-delete-LKBYPASD.js → team-delete-FEKJCU4P.js} +7 -6
- package/chunks/team-plan-approval-2TU4YROB.js +202 -0
- package/chunks/theme-manager-37KOGPJL.js +64 -0
- package/chunks/{todoWrite-OYXKTVYN.js → todoWrite-TKMVZ2HT.js} +4 -4
- package/chunks/{tool-search-YPUFJ3ZQ.js → tool-search-4ZTGNSFI.js} +38 -11
- package/chunks/{trustedFolders-5B24TMEA.js → trustedFolders-RJ5WXJ6L.js} +32 -26
- package/chunks/{validateNonInterActiveAuth-BTDTYOVT.js → validateNonInterActiveAuth-ZWMHZAOK.js} +66 -55
- package/chunks/{web-fetch-EEB5LZYU.js → web-fetch-J4PIW36Q.js} +5 -4
- package/chunks/{workflow-LAWIW5LI.js → workflow-6PG2PC5M.js} +68 -39
- package/chunks/workspace-providers-status-4QIZN2W4.js +68 -0
- package/chunks/workspace-service-CYMCOEIO.js +78 -0
- package/chunks/{write-file-PCV226DJ.js → write-file-R354LGQF.js} +41 -40
- package/chunks/{zh-5EUYXASN.js → zh-SLZNSSZB.js} +32 -10
- package/chunks/{zh-TW-TR3XYGE5.js → zh-TW-P53C2SL5.js} +32 -10
- package/cli.js +6 -6
- package/locales/ca.js +15 -13
- package/locales/de.js +15 -13
- package/locales/en.js +52 -15
- package/locales/fr.js +15 -14
- package/locales/ja.js +15 -14
- package/locales/pt.js +15 -13
- package/locales/ru.js +15 -13
- package/locales/zh-TW.js +50 -14
- package/locales/zh.js +50 -14
- package/node_modules/@qwen-code/audio-capture/package.json +1 -1
- 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/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/package.json +15 -6
- package/patches/chrome-devtools-mcp+1.4.0.patch +31 -0
- package/postinstall.js +50 -0
- package/web-shell/assets/{arc-DA7r8Ueo.js → arc-Bd3048nX.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-ZDUxPtZ2.js → architectureDiagram-3BPJPVTR-DyzbzABx.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-vrtOf1kJ.js → blockDiagram-GPEHLZMM-CTjxm9Sy.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BHFjzIi4.js → c4Diagram-AAUBKEIU-DSOFWNU6.js} +1 -1
- package/web-shell/assets/channel-oVoup_Ci.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-mdeQVz59.js → chunk-2J33WTMH-D_PFdjo2.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BkKMlwBX.js → chunk-4BX2VUAB-52eG6wOT.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-B7bnXNfu.js → chunk-55IACEB6-CGTZfKkC.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-DGz8Mm6i.js → chunk-727SXJPM-CZ-qfRUm.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-BQAydUNk.js → chunk-AQP2D5EJ-B2dSDcqM.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-GHr2LN_p.js → chunk-FMBD7UC4-Cfy3tyA0.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-7R91lnUx.js → chunk-ND2GUHAM-CApNUpUq.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-aTJD3lSQ.js → chunk-QZHKN3VN-CVBG8kgg.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-B8WsaT2G.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B8WsaT2G.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BTf8t1RL.js → cose-bilkent-S5V4N54A-URd77-_-.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-_sgp3WuA.js → dagre-BM42HDAG-C07H4G9-.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CROtRy1w.js → diagram-2AECGRRQ-CYbpXrSn.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-BqGRzwSc.js → diagram-5GNKFQAL-SI8s6fjX.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CMrcEtA7.js → diagram-KO2AKTUF-mBkC4RTW.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BRydGNW5.js → diagram-LMA3HP47-CyBPDzWJ.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-D0ilgNjV.js → diagram-OG6HWLK6-DwK7kBCu.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-2lnQeJUM.js → erDiagram-TEJ5UH35-Ds1StEUd.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-C_ZMdQiC.js → flowDiagram-I6XJVG4X-BDC4-jHO.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-Dw9V_Ny0.js → ganttDiagram-6RSMTGT7-CV2aHQqf.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-HDXI-F1B.js → gitGraphDiagram-PVQCEYII-B8RcuV_L.js} +1 -1
- package/web-shell/assets/index-B5WZ0qP1.js +717 -0
- package/web-shell/assets/index-CYE1IMd1.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CuB8Ebua.js → infoDiagram-5YYISTIA-DUPoTf50.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-D_tyhVwh.js → ishikawaDiagram-YF4QCWOH-FDYOx9rf.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-CgCwJQNU.js → journeyDiagram-JHISSGLW-C5_ohMRp.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-PZUtcbPx.js → kanban-definition-UN3LZRKU-Bn4UnOMG.js} +1 -1
- package/web-shell/assets/{linear-CZqRdJIU.js → linear-Bl0pKQtY.js} +1 -1
- package/web-shell/assets/{mermaid.core-CPW_4UEF.js → mermaid.core-sevQFoji.js} +72 -72
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-D_Y75ID7.js → mindmap-definition-RKZ34NQL-DSH4JZF9.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Q4dTyLeF.js → pieDiagram-4H26LBE5-acWvdQTD.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-ckw329Ft.js → quadrantDiagram-W4KKPZXB-DlggX4Sm.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-DbVDm4It.js → requirementDiagram-4Y6WPE33--mMqwmV8.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CHuZ_ecH.js → sankeyDiagram-5OEKKPKP-BtV9tZ77.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DU2YSpq-.js → sequenceDiagram-3UESZ5HK-iDQzPFlj.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CA9PEBUo.js → stateDiagram-AJRCARHV-CsCyQLZ3.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CPapECG9.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-Bhlo4WVc.js → timeline-definition-PNZ67QCA-Dl0rnKvr.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-6xtPLsyl.js → vennDiagram-CIIHVFJN-qF7nTZzA.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-3eozmXPf.js → wardley-L42UT6IY-fWoK9i7F.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BOn6hKss.js → wardleyDiagram-YWT4CUSO-pHGfkMnc.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-BsP4-I_y.js → xychartDiagram-2RQKCTM6-3Doc4Trz.js} +1 -1
- package/web-shell/index.html +18 -2
- package/chunks/MaxSizedBox-QNF3EIGU.js +0 -63
- package/chunks/agent-headless-RQ5BTX3G.js +0 -56
- package/chunks/bridge-JL2PMCIW.js +0 -66
- package/chunks/chunk-5GOVVXEV.js +0 -73
- package/chunks/chunk-BC3C4F3Q.js +0 -40
- package/chunks/chunk-BW4KCQFD.js +0 -1103
- package/chunks/chunk-RKIZXJMB.js +0 -13
- package/chunks/contextCommand-WYU6OQ2F.js +0 -61
- package/chunks/daemon-status-provider-HH2EC5FI.js +0 -65
- package/chunks/headlessSafetyWarnings-TBE35GJ4.js +0 -55
- package/chunks/initializer-2Y7SLOKV.js +0 -61
- package/chunks/list-ZAFHZ7OS.js +0 -65
- package/chunks/loadedSettingsAdapter-6KJXD6M3.js +0 -60
- package/chunks/nonInteractiveCli-5W4GIZQM.js +0 -96
- package/chunks/ripGrep-IEIFIWP4.js +0 -54
- package/chunks/serve-V6GVZR6U.js +0 -65
- package/chunks/spawnChannel-3VHW5EPY.js +0 -63
- package/chunks/theme-manager-LYLGAERF.js +0 -58
- package/chunks/workspace-providers-status-PIAFVYHA.js +0 -62
- package/chunks/workspace-service-YAIOD4HG.js +0 -71
- package/web-shell/assets/channel-iRo68q4Q.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-iHF24a8X.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-iHF24a8X.js +0 -1
- package/web-shell/assets/index-CHmzAWys.css +0 -5
- package/web-shell/assets/index-w6GTOHh1.js +0 -713
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-t1LRI0oY.js +0 -1
|
@@ -0,0 +1,416 @@
|
|
|
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
|
+
import {
|
|
15
|
+
AUTONOMOUS_PREAMBLE,
|
|
16
|
+
AUTONOMOUS_PREAMBLE_MARKER,
|
|
17
|
+
CRON_REARM,
|
|
18
|
+
autonomousTickText,
|
|
19
|
+
keepAliveRearm,
|
|
20
|
+
type LoopMode,
|
|
21
|
+
} from './autonomous-loop.js';
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
AUTONOMOUS_SENTINEL_CRON,
|
|
25
|
+
AUTONOMOUS_SENTINEL_DYNAMIC,
|
|
26
|
+
AutonomousLoopTickResolver,
|
|
27
|
+
detectAutonomousSentinel,
|
|
28
|
+
} from './autonomous-loop.js';
|
|
29
|
+
export type { LoopMode } from './autonomous-loop.js';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fire-time resolver for `.qwen/loop.md`-driven loops.
|
|
33
|
+
*
|
|
34
|
+
* A `/loop` whose scheduled prompt is one of these sentinels re-reads loop.md
|
|
35
|
+
* on every fire and gets either the FULL task block (first delivery, or whenever
|
|
36
|
+
* the file changed) or a one-line SHORT reminder (unchanged) — so the task list
|
|
37
|
+
* is paid for once into the cached message-prefix and later ticks stay cheap.
|
|
38
|
+
*
|
|
39
|
+
* Divergence from the upstream design this mirrors: the `lastContent` cache is
|
|
40
|
+
* held per Session instance (not a module singleton) so it scopes to one
|
|
41
|
+
* conversation and resets cleanly with that conversation's context (compaction).
|
|
42
|
+
* Change-detection is full content equality, not mtime/hash, so edit and
|
|
43
|
+
* delete→recreate both re-expand for free.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
export const LOOP_SENTINEL_CRON = '<<loop.md>>';
|
|
47
|
+
export const LOOP_SENTINEL_DYNAMIC = '<<loop.md-dynamic>>';
|
|
48
|
+
|
|
49
|
+
export interface LoopTickResolverDeps {
|
|
50
|
+
/** Pass `config.getWorkingDir()` — loop.md is resolved against the cwd. */
|
|
51
|
+
projectRoot: string;
|
|
52
|
+
/** Home-candidate confinement root: `$QWEN_HOME` when set, else `$HOME`. */
|
|
53
|
+
homeDir: string;
|
|
54
|
+
/**
|
|
55
|
+
* QWEN_HOME-aware global dir holding the home `loop.md` (`Storage.getGlobalQwenDir()`).
|
|
56
|
+
* Omitted → defaults to `<homeDir>/.qwen` inside readLoopTaskFile.
|
|
57
|
+
*/
|
|
58
|
+
homeQwenDir?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Pass `() => config.isTrustedFolder()`. Re-evaluated on every `resolve()`,
|
|
61
|
+
* never captured once: `isTrustedFolder()` is not process-stable in IDE
|
|
62
|
+
* sessions (a workspace-trust update can flip it), and a trusted→untrusted
|
|
63
|
+
* flip must immediately stop reading the repo-controlled project
|
|
64
|
+
* `.qwen/loop.md` (the user-owned `~/.qwen/loop.md` still is read).
|
|
65
|
+
*/
|
|
66
|
+
allowProjectFile: () => boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface LoopTickResult {
|
|
70
|
+
/** Text to deliver to the model in place of the sentinel prompt. */
|
|
71
|
+
modelText: string;
|
|
72
|
+
/** True when the full task block was delivered (vs a short reminder). */
|
|
73
|
+
full: boolean;
|
|
74
|
+
/** Non-absolute label for the matched candidate (e.g. "project loop.md"),
|
|
75
|
+
* when present — safe for logs/UI that must not leak the absolute path, and
|
|
76
|
+
* doubles as the "a loop.md was found" flag for callers. */
|
|
77
|
+
sourceLabel?: string;
|
|
78
|
+
/** True ONLY for buildTransientErrorTick: a loop.md exists but could not be
|
|
79
|
+
* read THIS tick (a transient EACCES/EIO or editor/AV lock), as distinct from
|
|
80
|
+
* the genuinely-absent no-op (where this stays false). Lets the caller's echo
|
|
81
|
+
* say "temporarily unavailable" instead of "not present". Carries no errno or
|
|
82
|
+
* path — those stay in the modelText note and LOCAL debug logs only. */
|
|
83
|
+
transientError?: boolean;
|
|
84
|
+
/** True when this tick is an autonomous-mode tick (a `<<autonomous-loop*>>`
|
|
85
|
+
* fire, or a loop.md sentinel whose file is gone and has converged on the
|
|
86
|
+
* autonomous preamble). Lets the caller's echo label it distinctly. */
|
|
87
|
+
autonomous?: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const TRUNCATION_WARNING = `> WARNING: loop.md was truncated to ${LOOP_TASK_FILE_MAX_BYTES} bytes. Keep the task list concise.`;
|
|
91
|
+
|
|
92
|
+
const INTRO =
|
|
93
|
+
'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).';
|
|
94
|
+
|
|
95
|
+
// Mode-specific pacing guidance. Appended to BOTH the full block and the short
|
|
96
|
+
// reminder — the no-op/re-arm instruction applies on every tick.
|
|
97
|
+
const PACING_SUFFIX: Record<LoopMode, string> = {
|
|
98
|
+
cron: CRON_REARM,
|
|
99
|
+
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.`,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Preamble for the UNCHANGED-tick reminder, which points back to the full block
|
|
103
|
+
// delivered on an earlier fire. NOT used on the first/changed full delivery,
|
|
104
|
+
// where the block is present in THIS message — there is no "earlier" to refer
|
|
105
|
+
// back to, so claiming the contents were established earlier would contradict
|
|
106
|
+
// the INTRO that sits right above them.
|
|
107
|
+
const SHORT_REMINDER_PREAMBLE =
|
|
108
|
+
'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.';
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The single H1 for every tick variant (full block, short reminder, absent), so
|
|
112
|
+
* they share one heading style and the dynamic-pacing suffix lives in one place.
|
|
113
|
+
* `sourceLabel` (set only on a full-block delivery) is a relative label like
|
|
114
|
+
* "project loop.md", never the absolute path — so the resolved file location
|
|
115
|
+
* isn't leaked to the model/API provider.
|
|
116
|
+
*/
|
|
117
|
+
function tickHeading(
|
|
118
|
+
mode: LoopMode,
|
|
119
|
+
opts: { sourceLabel?: string; absent?: boolean; unavailable?: boolean } = {},
|
|
120
|
+
): string {
|
|
121
|
+
// `unavailable` (transient read failure) is distinct from `absent`: the file
|
|
122
|
+
// exists but couldn't be read THIS tick, so the heading must not claim it's gone.
|
|
123
|
+
const subject = opts.unavailable
|
|
124
|
+
? 'loop.md unavailable'
|
|
125
|
+
: opts.absent
|
|
126
|
+
? 'loop.md absent'
|
|
127
|
+
: opts.sourceLabel
|
|
128
|
+
? `loop.md tasks from ${opts.sourceLabel}`
|
|
129
|
+
: 'loop.md tasks';
|
|
130
|
+
const base = `# /loop tick — ${subject}`;
|
|
131
|
+
return mode === 'dynamic' ? `${base} (dynamic pacing)` : base;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Model-safe relative label per source — exhaustive, so a new loop.md
|
|
135
|
+
* candidate added to readLoopTaskFile won't compile until it gets a label
|
|
136
|
+
* (rather than silently mislabelling it). */
|
|
137
|
+
const SOURCE_LABELS: Record<LoopTaskFileSource, string> = {
|
|
138
|
+
project: 'project loop.md',
|
|
139
|
+
home: 'home loop.md',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Per-mode tail for a TRANSIENT-failure no-op tick (buildTransientErrorTick):
|
|
143
|
+
// "treat this as a no-op" + the mode's re-arm. A genuinely-absent loop.md does
|
|
144
|
+
// NOT use this — it converges on absentAutonomousTickText (run the autonomous
|
|
145
|
+
// check, not a no-op).
|
|
146
|
+
const ABSENT_TAIL: Record<LoopMode, string> = {
|
|
147
|
+
cron: 'Treat this as a no-op tick; the recurring cron fires the next tick automatically.',
|
|
148
|
+
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.`,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/** Detect whether a scheduled prompt is a loop.md sentinel, and which mode. */
|
|
152
|
+
export function detectLoopSentinel(prompt: string): LoopMode | null {
|
|
153
|
+
const trimmed = prompt.trim();
|
|
154
|
+
if (trimmed === LOOP_SENTINEL_DYNAMIC) {
|
|
155
|
+
return 'dynamic';
|
|
156
|
+
}
|
|
157
|
+
if (trimmed === LOOP_SENTINEL_CRON) {
|
|
158
|
+
return 'cron';
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Shared self-paced re-arm instruction; the loop.md and autonomous dynamic ticks
|
|
164
|
+
// differ only in the sentinel the model re-arms with, so build both from one
|
|
165
|
+
// template to keep them in lockstep.
|
|
166
|
+
// `keepAliveRearm` itself lives in autonomous-loop.ts so the interactive TUI
|
|
167
|
+
// path can expand autonomous sentinels without importing loop.md file readers.
|
|
168
|
+
|
|
169
|
+
// Re-arm guidance for an absent-loop.md tick that has converged on autonomous
|
|
170
|
+
// mode: re-arm the LOOP.MD sentinel (not the autonomous one) so a recreated file
|
|
171
|
+
// is picked up on the next fire.
|
|
172
|
+
const ABSENT_AUTONOMOUS_REARM: Record<LoopMode, string> = {
|
|
173
|
+
cron: PACING_SUFFIX.cron,
|
|
174
|
+
dynamic: keepAliveRearm(
|
|
175
|
+
LOOP_SENTINEL_DYNAMIC,
|
|
176
|
+
'To pick up loop.md if it is recreated',
|
|
177
|
+
),
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/** The tick text for an absent loop.md that converges on autonomous mode — like
|
|
181
|
+
* a pure autonomous tick but headed "loop.md absent" and re-arming the loop.md
|
|
182
|
+
* sentinel so a recreated file is picked up. It says "run the autonomous check",
|
|
183
|
+
* NOT an unconditional no-op: the no-op wording would contradict the preamble
|
|
184
|
+
* prepended on the first fire (and the dedup tick that follows it). */
|
|
185
|
+
function absentAutonomousTickText(mode: LoopMode, locations: string): string {
|
|
186
|
+
return `${tickHeading(mode, { absent: true })}\nloop.md is not currently present at ${locations}. Run the autonomous check using the loop instructions established earlier in this conversation. If you cannot find them, treat this as a no-op tick and stop immediately. ${ABSENT_AUTONOMOUS_REARM[mode]}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Trim a truncated body back to its last full line before the warning tail. */
|
|
190
|
+
function cutToLastNewline(content: string): string {
|
|
191
|
+
const cut = content.lastIndexOf('\n');
|
|
192
|
+
// `> 0`, not `>= 0`: when the only newline is at index 0 (or there is none),
|
|
193
|
+
// there is no complete line to keep, so cutting would empty the body and leave
|
|
194
|
+
// the INTRO promising tasks that aren't there. Keep the (truncated) content
|
|
195
|
+
// instead — only a genuine trailing partial line (newline at index > 0) is
|
|
196
|
+
// dropped so the warning never glues onto a half-line.
|
|
197
|
+
return cut > 0 ? content.slice(0, cut) : content;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export class LoopTickResolver {
|
|
201
|
+
// What the model has actually received. Drives full-vs-reminder detection.
|
|
202
|
+
#lastContent: string | typeof AUTONOMOUS_PREAMBLE_MARKER | null = null;
|
|
203
|
+
// The most recent resolve()'s content, committed to #lastContent only once
|
|
204
|
+
// the caller confirms it reached the model (markDelivered) — so a tick that
|
|
205
|
+
// is aborted between resolve() and delivery can't poison the cache into
|
|
206
|
+
// sending a dangling short reminder next time.
|
|
207
|
+
#pendingContent: string | typeof AUTONOMOUS_PREAMBLE_MARKER | null = null;
|
|
208
|
+
// Instance-scoped fs.realpath cache for the confinement boundaries, handed to
|
|
209
|
+
// readLoopTaskFile. Tying it to the resolver (a fresh Map per /cd rebuild,
|
|
210
|
+
// cleared by resetCache) keeps the per-tick perf win while staying
|
|
211
|
+
// invalidatable — a module-global cache would pin a stale boundary in a
|
|
212
|
+
// long-lived process after a /cd or symlink re-point.
|
|
213
|
+
readonly #realDirCache = new Map<string, Promise<string>>();
|
|
214
|
+
|
|
215
|
+
constructor(private readonly deps: LoopTickResolverDeps) {}
|
|
216
|
+
|
|
217
|
+
/** Forget the delivered content so the next fire re-delivers the full block
|
|
218
|
+
* — called when the conversation is compacted (fresh context). */
|
|
219
|
+
resetCache(): void {
|
|
220
|
+
this.#lastContent = null;
|
|
221
|
+
this.#pendingContent = null;
|
|
222
|
+
// A reset may follow a /cd or symlink change, so drop the cached boundary
|
|
223
|
+
// realpaths too and re-resolve them on the next tick.
|
|
224
|
+
this.#realDirCache.clear();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Commit the last resolve()'s content once it has reached the model. */
|
|
228
|
+
markDelivered(): void {
|
|
229
|
+
if (this.#pendingContent !== null) {
|
|
230
|
+
this.#lastContent = this.#pendingContent;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Expand an autonomous tick: the full preamble + tick text on the first
|
|
235
|
+
* delivery, then only the short tick text once the preamble was committed
|
|
236
|
+
* (markDelivered sets #lastContent to the shared marker). Shared by a pure
|
|
237
|
+
* autonomous fire and the absent-loop.md convergence in resolve(), so the
|
|
238
|
+
* preamble is delivered once across both. */
|
|
239
|
+
#autonomousTick(tickText: string): LoopTickResult {
|
|
240
|
+
// Set the marker in BOTH branches (like resolve() sets #pendingContent above
|
|
241
|
+
// its short/full split): the short branch must also refresh it, or a stale
|
|
242
|
+
// value left by a previously-aborted full tick would be committed by the next
|
|
243
|
+
// markDelivered() and poison a later fire into a dangling short reminder.
|
|
244
|
+
this.#pendingContent = AUTONOMOUS_PREAMBLE_MARKER;
|
|
245
|
+
if (this.#lastContent === AUTONOMOUS_PREAMBLE_MARKER) {
|
|
246
|
+
return { modelText: tickText, full: false, autonomous: true };
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
modelText: `${AUTONOMOUS_PREAMBLE}\n${tickText}`,
|
|
250
|
+
full: true,
|
|
251
|
+
autonomous: true,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Resolve an autonomous-loop sentinel fire (a bare `/loop`, no loop.md).
|
|
256
|
+
* Synchronous — the preamble is static; only the dedup state is consulted. */
|
|
257
|
+
resolveAutonomous(mode: LoopMode): LoopTickResult {
|
|
258
|
+
return this.#autonomousTick(autonomousTickText(mode));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** MODEL-FACING label for the home loop.md location. Mirrors
|
|
262
|
+
* readLoopTaskFile's home candidate (`<homeQwenDir>/loop.md`) so the absent
|
|
263
|
+
* reminder — and the caller's sanitized resolve-error — names the location
|
|
264
|
+
* actually checked (QWEN_HOME-aware), but must NEVER surface a raw absolute
|
|
265
|
+
* path: it flows into model/API text, leaking the host's filesystem layout.
|
|
266
|
+
* - under $HOME → tilde-abbreviated `~/.qwen/loop.md`;
|
|
267
|
+
* - relocated via $QWEN_HOME → the literal `$QWEN_HOME/loop.md`, not the
|
|
268
|
+
* resolved dir (`tildeifyPath` only abbreviates $HOME, so it's a no-op for
|
|
269
|
+
* a $QWEN_HOME outside $HOME and would otherwise pass the path through);
|
|
270
|
+
* - any other out-of-$HOME dir → a generic placeholder, never the path.
|
|
271
|
+
* The real absolute path stays in LOCAL debug logs only. */
|
|
272
|
+
homeLoopLabel(): string {
|
|
273
|
+
const homeQwenDir =
|
|
274
|
+
this.deps.homeQwenDir ?? path.join(this.deps.homeDir, '.qwen');
|
|
275
|
+
const homeLoopPath = path.join(homeQwenDir, 'loop.md');
|
|
276
|
+
|
|
277
|
+
const tildeified = tildeifyPath(homeLoopPath);
|
|
278
|
+
if (tildeified !== homeLoopPath) {
|
|
279
|
+
return tildeified.replace(/\\/g, '/');
|
|
280
|
+
}
|
|
281
|
+
// Outside $HOME: tildeifyPath was a no-op. When $QWEN_HOME relocated the
|
|
282
|
+
// global dir (homeQwenDir is its resolved value), report the literal env-var
|
|
283
|
+
// name — never the absolute path. The home candidate is always
|
|
284
|
+
// `<homeQwenDir>/loop.md`, so swap the whole resolved dir for `$QWEN_HOME` and
|
|
285
|
+
// re-attach the user-facing POSIX slash + basename directly. Deriving the tail from the
|
|
286
|
+
// resolved path's length instead mishandles edge dirs: a trailing slash
|
|
287
|
+
// (`$QWEN_HOME=/x/.qwen/`) over-counts the separator, and a filesystem-root
|
|
288
|
+
// homeQwenDir (`$QWEN_HOME=/` → homeLoopPath `/loop.md`, dirname `/`) drops the
|
|
289
|
+
// leading separator — both garbling the tail into `$QWEN_HOMEloop.md`.
|
|
290
|
+
if (process.env['QWEN_HOME']) {
|
|
291
|
+
return '$QWEN_HOME/loop.md';
|
|
292
|
+
}
|
|
293
|
+
return 'the configured global loop.md';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** The checked-candidate "where" string shared by the absent reminder and the
|
|
297
|
+
* caller's sanitized resolve-error. Names the project candidate ONLY when it
|
|
298
|
+
* was actually read (`projectChecked` — a trusted folder), so neither path can
|
|
299
|
+
* claim `.qwen/loop.md (project)` for an untrusted folder where the project
|
|
300
|
+
* file is skipped. The home label is the QWEN_HOME-aware, never-absolute
|
|
301
|
+
* homeLoopLabel(). Single source of truth so the two messages can't drift. */
|
|
302
|
+
absentLocations(projectChecked: boolean): string {
|
|
303
|
+
const homeLabel = this.homeLoopLabel();
|
|
304
|
+
return projectChecked
|
|
305
|
+
? `.qwen/loop.md (project) or ${homeLabel} (home)`
|
|
306
|
+
: `${homeLabel} (home)`;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** A model-facing no-op tick for a loop.md that is unreadable THIS tick (a
|
|
310
|
+
* transient read failure — see buildTransientErrorTick). Clears the
|
|
311
|
+
* change-detection caches so a later successful tick re-delivers the FULL block
|
|
312
|
+
* instead of a dangling short reminder. A genuinely-absent loop.md no longer
|
|
313
|
+
* routes here — it converges on the autonomous preamble in resolve(). */
|
|
314
|
+
#noOpTick(modelText: string, transientError = false): LoopTickResult {
|
|
315
|
+
this.#pendingContent = null;
|
|
316
|
+
if (this.#lastContent !== AUTONOMOUS_PREAMBLE_MARKER) {
|
|
317
|
+
this.#lastContent = null;
|
|
318
|
+
}
|
|
319
|
+
return { modelText, full: false, transientError };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* No-op tick for a transient, non-whitelisted read error (EACCES/EIO, or a
|
|
324
|
+
* Windows editor/AV briefly locking loop.md). Mirrors the absent tick — same
|
|
325
|
+
* heading + the mode's re-arm tail (ABSENT_TAIL) — so a `dynamic` loop still
|
|
326
|
+
* re-arms LoopWakeup and survives the hiccup instead of dying silently: its
|
|
327
|
+
* firing wakeup was already consumed by the scheduler, and only the
|
|
328
|
+
* end-of-turn re-arm keeps it alive, so a thrown turn ends the loop forever.
|
|
329
|
+
* `cron` callers don't use this (they re-fire on their own next interval).
|
|
330
|
+
* `projectChecked` is the trust captured for THIS tick (so the named candidate
|
|
331
|
+
* set matches what was probed); `code` is the errno only — never an absolute
|
|
332
|
+
* path — for a brief model-facing note.
|
|
333
|
+
*/
|
|
334
|
+
buildTransientErrorTick(
|
|
335
|
+
mode: LoopMode,
|
|
336
|
+
projectChecked: boolean,
|
|
337
|
+
code: string,
|
|
338
|
+
): LoopTickResult {
|
|
339
|
+
return this.#noOpTick(
|
|
340
|
+
// `unavailable`, not `absent`: the file exists but was unreadable this tick,
|
|
341
|
+
// so the heading mirrors the body instead of contradicting it.
|
|
342
|
+
`${tickHeading(mode, { unavailable: true })}\nloop.md at ${this.absentLocations(
|
|
343
|
+
projectChecked,
|
|
344
|
+
)} could not be read this tick (${code}). ${ABSENT_TAIL[mode]}`,
|
|
345
|
+
// Flag the tick as a transient read failure (file exists, unreadable this
|
|
346
|
+
// tick) so the caller's echo distinguishes it from a genuinely-absent file.
|
|
347
|
+
true,
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* @param allowProjectFileOverride Trust captured once by the caller for this
|
|
353
|
+
* tick (see LoopTickResolverDeps.allowProjectFile). Threaded in — rather than
|
|
354
|
+
* re-reading the getter here — so the caller's error path can name the SAME
|
|
355
|
+
* candidate set that was probed even if `isTrustedFolder()` flips mid-tick.
|
|
356
|
+
* Omitted by direct callers, who fall back to the per-tick getter.
|
|
357
|
+
*/
|
|
358
|
+
async resolve(
|
|
359
|
+
mode: LoopMode,
|
|
360
|
+
allowProjectFileOverride?: boolean,
|
|
361
|
+
): Promise<LoopTickResult> {
|
|
362
|
+
// Re-read trust per tick (see LoopTickResolverDeps.allowProjectFile): a
|
|
363
|
+
// resolver built while trusted must skip the project file once trust flips.
|
|
364
|
+
// Captured so the absent reminder reflects what was ACTUALLY checked.
|
|
365
|
+
const allowProjectFile =
|
|
366
|
+
allowProjectFileOverride ?? this.deps.allowProjectFile();
|
|
367
|
+
const result = await readLoopTaskFile({
|
|
368
|
+
projectRoot: this.deps.projectRoot,
|
|
369
|
+
homeDir: this.deps.homeDir,
|
|
370
|
+
homeQwenDir: this.deps.homeQwenDir,
|
|
371
|
+
allowProjectFile,
|
|
372
|
+
realDirCache: this.#realDirCache,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
if (result.status === 'missing') {
|
|
376
|
+
// Absent loop.md converges on autonomous mode: prepend the autonomous
|
|
377
|
+
// preamble (once, deduped via the shared marker) so a file-less loop keeps
|
|
378
|
+
// working autonomously instead of no-op'ing forever. The tick text says
|
|
379
|
+
// "run the autonomous check" (NOT an unconditional no-op, which would
|
|
380
|
+
// contradict the prepended preamble) and keeps the loop.md-absent heading +
|
|
381
|
+
// a loop.md-sentinel re-arm so a recreated file is still picked up (its
|
|
382
|
+
// content can never equal the marker, so it re-delivers full).
|
|
383
|
+
return this.#autonomousTick(
|
|
384
|
+
absentAutonomousTickText(mode, this.absentLocations(allowProjectFile)),
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const content = result.truncated
|
|
389
|
+
? `${cutToLastNewline(result.content)}\n${TRUNCATION_WARNING}`
|
|
390
|
+
: result.content;
|
|
391
|
+
this.#pendingContent = content;
|
|
392
|
+
|
|
393
|
+
// Label by which candidate matched, never result.path (the absolute path),
|
|
394
|
+
// which would leak the OS username / dir layout to the API provider and to
|
|
395
|
+
// debug logs. The label alone is enough for the caller's UI and presence
|
|
396
|
+
// check, so the absolute path is not surfaced on the result at all.
|
|
397
|
+
const sourceLabel = SOURCE_LABELS[result.source];
|
|
398
|
+
|
|
399
|
+
if (this.#lastContent === content) {
|
|
400
|
+
return {
|
|
401
|
+
modelText: `${tickHeading(mode)}\n${SHORT_REMINDER_PREAMBLE} ${PACING_SUFFIX[mode]}`,
|
|
402
|
+
full: false,
|
|
403
|
+
sourceLabel,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// First/changed full delivery: INTRO + the block itself, then only the
|
|
408
|
+
// pacing suffix — no "established earlier" preamble, which would contradict
|
|
409
|
+
// the block sitting right here in this same message.
|
|
410
|
+
return {
|
|
411
|
+
modelText: `${tickHeading(mode, { sourceLabel })}\n${INTRO}\n${content}\n${PACING_SUFFIX[mode]}`,
|
|
412
|
+
full: true,
|
|
413
|
+
sourceLabel,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -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
|
|
|
@@ -165,7 +165,7 @@ The key concept is **Model Providers** (`modelProviders`): Qwen Code supports mu
|
|
|
165
165
|
|
|
166
166
|
| Protocol | `modelProviders` key | Environment variables | Providers |
|
|
167
167
|
| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
168
|
-
| OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL`
|
|
168
|
+
| OpenAI-compatible | `openai` | `OPENAI_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_MODEL` (alias: `QWEN_MODEL`) | OpenAI, Azure OpenAI, OpenRouter, Requesty, ModelScope, Alibaba Cloud, any OpenAI-compatible endpoint |
|
|
169
169
|
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL` | Anthropic Claude |
|
|
170
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 |
|