@askexenow/exe-os 0.9.407 → 0.9.409
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/deploy/compose/erp-nginx/nginx.conf +8 -2
- package/deploy/compose/sso-edge/default.conf.template +55 -0
- package/deploy/hosted/public-demo-compose.yml +52 -0
- package/deploy/stack-manifests/v0.9.json +1339 -1
- package/dist/.dist-verified.json +3 -3
- package/dist/{active-agent-U6JYIXZD.js → active-agent-2AMJC3SC.js} +6 -5
- package/dist/{active-agent-2OMOWJXI.js → active-agent-5AKPW2N7.js} +6 -5
- package/dist/{agent-defs-generator-TZC3QFTT.js → agent-defs-generator-QN3J6FVJ.js} +5 -5
- package/dist/{agent-loop-OQUZUGQU.js → agent-loop-FMOA2MG2.js} +1 -1
- package/dist/{agentic-ontology-GJI54CFX.js → agentic-ontology-6RS7A7KP.js} +1 -1
- package/dist/{artifact-backup-4GCKVN3V.js → artifact-backup-6O4FNYPS.js} +3 -3
- package/dist/{backfill-metadata-EVJEKCY3.js → backfill-metadata-6YX6LGPJ.js} +8 -8
- package/dist/{backup-verify-PIH5GXLV.js → backup-verify-QIAQ63VC.js} +1 -1
- package/dist/{behavior-injection-TKQETCCW.js → behavior-injection-NRXTNROW.js} +11 -11
- package/dist/{behavior-promotion-TB53MVMQ.js → behavior-promotion-MW7OQ72V.js} +10 -10
- package/dist/{behaviors-2XKHIDUD.js → behaviors-7AOK44QK.js} +9 -9
- package/dist/bin/agentic-ontology-backfill.js +9 -9
- package/dist/bin/agentic-reflection-backfill.js +10 -10
- package/dist/bin/agentic-semantic-label.js +9 -9
- package/dist/bin/backfill-conversations.js +8 -8
- package/dist/bin/backfill-responses.js +8 -8
- package/dist/bin/backfill-vectors.js +8 -8
- package/dist/bin/bulk-sync-postgres.js +17 -17
- package/dist/bin/cc-doctor.js +12 -11
- package/dist/bin/cleanup-stale-review-tasks.js +19 -19
- package/dist/bin/cli.js +24 -24
- package/dist/bin/deferred-daemon-restart.js +104 -103
- package/dist/bin/exe-agent-config.js +5 -5
- package/dist/bin/exe-agent.js +10 -10
- package/dist/bin/exe-assign.js +9 -9
- package/dist/bin/exe-boot.js +44 -43
- package/dist/bin/exe-call.js +9 -9
- package/dist/bin/exe-cloud.js +18 -18
- package/dist/bin/exe-config-dump.js +5 -5
- package/dist/bin/exe-dispatch.js +20 -20
- package/dist/bin/exe-doctor.js +7 -7
- package/dist/bin/exe-export-behaviors.js +13 -13
- package/dist/bin/exe-forget.js +11 -11
- package/dist/bin/exe-gateway.js +9 -9
- package/dist/bin/exe-grant.js +6 -6
- package/dist/bin/exe-healthcheck.js +12 -11
- package/dist/bin/exe-heartbeat.js +25 -25
- package/dist/bin/exe-kill.js +25 -25
- package/dist/bin/exe-launch-agent.js +34 -34
- package/dist/bin/exe-mcp.js +7 -6
- package/dist/bin/exe-memory-reads.js +8 -8
- package/dist/bin/exe-new-employee.js +11 -11
- package/dist/bin/exe-os-mcp-proxy.js +7 -6
- package/dist/bin/exe-pending-messages.js +20 -20
- package/dist/bin/exe-pending-notifications.js +19 -19
- package/dist/bin/exe-pending-reviews.js +20 -20
- package/dist/bin/exe-rename.js +7 -7
- package/dist/bin/exe-review.js +24 -24
- package/dist/bin/exe-search.js +10 -10
- package/dist/bin/exe-session-cleanup.js +26 -26
- package/dist/bin/exe-settings.js +19 -19
- package/dist/bin/exe-start-codex.js +20 -20
- package/dist/bin/exe-start-opencode.js +18 -18
- package/dist/bin/exe-status.js +21 -21
- package/dist/bin/exe-support.js +3 -3
- package/dist/bin/exe-team.js +5 -5
- package/dist/bin/git-sweep.js +21 -21
- package/dist/bin/graph-backfill.js +9 -9
- package/dist/bin/graph-export.js +9 -9
- package/dist/bin/hooks-cli.js +4 -4
- package/dist/bin/import-history.js +14 -13
- package/dist/bin/install.js +106 -105
- package/dist/bin/intercom-check.js +5 -5
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +5 -5
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/pre-publish.js +1 -1
- package/dist/bin/reconcile-backlog.js +2 -2
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/repair-document-chunks.js +8 -8
- package/dist/bin/scan-tasks.js +20 -20
- package/dist/bin/setup.js +3 -3
- package/dist/bin/shard-migrate.js +9 -9
- package/dist/bin/stack-update.js +4 -4
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{boot-generation-34GD265Q.js → boot-generation-HG6LLZLY.js} +4 -4
- package/dist/{boot-review-sections-JYDDUJH5.js → boot-review-sections-STZ5EAIL.js} +18 -18
- package/dist/{bug-landed-reconciler-ORYLGRQI.js → bug-landed-reconciler-EO72HUI2.js} +7 -7
- package/dist/build-info.json +3 -3
- package/dist/build-manifest.json +970 -970
- package/dist/{capability-cards-IOFJOGID.js → capability-cards-C3SMHB2E.js} +3 -3
- package/dist/{capacity-monitor-CJSDRDLR.js → capacity-monitor-UI553HRL.js} +20 -20
- package/dist/{catchup-brief-ELSYIYVL.js → catchup-brief-VE2X4HML.js} +26 -26
- package/dist/{chunk-HBOSSJWS.js → chunk-23XUZHB7.js} +5 -5
- package/dist/{chunk-BG52IECQ.js → chunk-3AL2LO3L.js} +1 -1
- package/dist/{chunk-HPDR3EL7.js → chunk-3MDUKF3N.js} +4 -4
- package/dist/{chunk-BHKCSRJG.js → chunk-4M24XCTI.js} +663 -68
- package/dist/{chunk-RGPEUXOE.js → chunk-4MK6LOD6.js} +27 -3
- package/dist/{chunk-ZB34E2OV.js → chunk-4O7OUBEX.js} +10 -10
- package/dist/{chunk-Z5ERWCOL.js → chunk-4Q7H3TO7.js} +1 -1
- package/dist/{chunk-YTP6L76N.js → chunk-4RQ62XXK.js} +5 -5
- package/dist/{chunk-VDSAXP3N.js → chunk-4S6H2NWS.js} +4 -4
- package/dist/{chunk-DXZRXNIC.js → chunk-4W7Y67B5.js} +1 -1
- package/dist/{chunk-SS3FTK77.js → chunk-52Z435PH.js} +8 -3
- package/dist/{chunk-77EIMVAX.js → chunk-5N34MMKS.js} +1 -1
- package/dist/{chunk-UMLDPQ24.js → chunk-6EY6OFBC.js} +2 -2
- package/dist/{chunk-IMI5ZAOA.js → chunk-6JLVCMKH.js} +1 -1
- package/dist/{chunk-ZGRLIQLE.js → chunk-6RRPVE5O.js} +3 -3
- package/dist/{chunk-6SJ4SKWZ.js → chunk-6TB7UXCA.js} +1 -1
- package/dist/{chunk-342ZBEDI.js → chunk-6ZW6BRI4.js} +2 -2
- package/dist/{chunk-5QJEJA5H.js → chunk-7I6KVKFF.js} +3 -3
- package/dist/{chunk-4SLKFUA7.js → chunk-7LTAA55U.js} +5 -1
- package/dist/{chunk-FKANX6A7.js → chunk-7P2TDFZL.js} +1 -1
- package/dist/{chunk-SLJDYBLE.js → chunk-7R7KDRKV.js} +1 -1
- package/dist/{chunk-NRLJOV7M.js → chunk-7YX73K2R.js} +97 -58
- package/dist/{chunk-R5YD5DIP.js → chunk-APVU4Q5B.js} +16 -16
- package/dist/{chunk-7OX2AACL.js → chunk-B3ISLIKE.js} +2 -2
- package/dist/{chunk-CP6XE35Z.js → chunk-BHDDDNC6.js} +2 -2
- package/dist/{chunk-TEHJ5TOU.js → chunk-BIV4IHED.js} +12 -12
- package/dist/{chunk-5GYA4ERO.js → chunk-BM467PZN.js} +1 -1
- package/dist/{chunk-BER2YLZT.js → chunk-BPBEJD7U.js} +1 -1
- package/dist/{chunk-T4IDLAZM.js → chunk-BYP3DOUU.js} +13 -0
- package/dist/{chunk-U7A2EACP.js → chunk-C426MZMD.js} +3 -3
- package/dist/{chunk-TRZXFWRO.js → chunk-DACRR362.js} +6 -6
- package/dist/{chunk-232YVOFB.js → chunk-DE2V7547.js} +2 -2
- package/dist/{chunk-QHQW3VHV.js → chunk-DIKLSAJE.js} +1 -1
- package/dist/{chunk-XC6EXJBA.js → chunk-DM4VTXM6.js} +4 -4
- package/dist/{chunk-EEY77PKF.js → chunk-DMYJVGQM.js} +1 -1
- package/dist/{chunk-ZSZVJ2FR.js → chunk-E2Z3F26R.js} +1 -1
- package/dist/{chunk-GRIGIKC4.js → chunk-EHILXBVT.js} +3 -3
- package/dist/{chunk-AIDYWH4D.js → chunk-EIM7OGTD.js} +2 -2
- package/dist/{chunk-7E4KZIX7.js → chunk-ESO5JDOT.js} +1 -1
- package/dist/{chunk-SPHPROWZ.js → chunk-F5ZRHLG5.js} +2 -2
- package/dist/{chunk-BIBBNDM3.js → chunk-FBZ32BD4.js} +1 -1
- package/dist/{chunk-FBB2YMKB.js → chunk-FJKUFMNF.js} +1 -1
- package/dist/{chunk-MNEVSKUY.js → chunk-FZT4VQP7.js} +1 -1
- package/dist/{chunk-ZLMVXK4O.js → chunk-G3ZYXXO7.js} +11 -11
- package/dist/{chunk-6RWTLW75.js → chunk-GEQQGN3J.js} +7 -7
- package/dist/{chunk-7NR6LMGH.js → chunk-GG73NHZD.js} +2 -2
- package/dist/{chunk-VGP4T2L6.js → chunk-GKPPLIMJ.js} +5 -5
- package/dist/{chunk-ERIXGUSV.js → chunk-GPWXUU3L.js} +1 -1
- package/dist/{chunk-OAP66FCX.js → chunk-GRAMRMWS.js} +2 -2
- package/dist/{chunk-IVX4CW6I.js → chunk-GTRB6DGI.js} +2 -2
- package/dist/{chunk-WQ7YIU4M.js → chunk-HFSFWMID.js} +3 -3
- package/dist/{chunk-5FOJ6N3V.js → chunk-HFXBL7XE.js} +1 -1
- package/dist/{chunk-36QUBTID.js → chunk-HK7HIDXP.js} +2 -2
- package/dist/{chunk-323DU3UM.js → chunk-HNGAM3U4.js} +3 -3
- package/dist/{chunk-XIJIFRPA.js → chunk-HRKN3DQE.js} +8 -8
- package/dist/{chunk-AO2HCOE6.js → chunk-HRYWB4TO.js} +3 -3
- package/dist/{chunk-Q2RTUZXB.js → chunk-HUMNRJZE.js} +4 -4
- package/dist/{chunk-KAKURNNS.js → chunk-IPANAGA3.js} +1 -1
- package/dist/{chunk-RZTSXHWF.js → chunk-IPBNHPTE.js} +9 -9
- package/dist/{chunk-SDJ3TONY.js → chunk-IUBCS6TA.js} +3 -3
- package/dist/{chunk-C7SKFVXQ.js → chunk-IURGBN5B.js} +4 -4
- package/dist/{chunk-GWAN2BDB.js → chunk-IVXELUEQ.js} +25 -12
- package/dist/{chunk-DG3DWHYJ.js → chunk-IZ24HRDC.js} +3 -3
- package/dist/{chunk-G3ABALZ7.js → chunk-JJYAETCO.js} +4 -4
- package/dist/{chunk-6XJYUC7K.js → chunk-JR3GTBV3.js} +1 -1
- package/dist/{chunk-MLIRYXZ2.js → chunk-K7DAE2HO.js} +1 -1
- package/dist/{chunk-ZGNMI2WJ.js → chunk-KBHK2WNO.js} +1 -1
- package/dist/{chunk-MAY4VWEG.js → chunk-KCRSJ3VU.js} +3 -3
- package/dist/{chunk-NF7JS7XW.js → chunk-KIJRAZWR.js} +1 -1
- package/dist/{chunk-35PGCSNN.js → chunk-KPLMY2GT.js} +4 -4
- package/dist/{chunk-USZHUBHT.js → chunk-L4ISXVC5.js} +1 -1
- package/dist/{chunk-UNNOYMQI.js → chunk-L5CPS34O.js} +1 -1
- package/dist/{chunk-SJTFU3YJ.js → chunk-LE3DIA25.js} +3 -3
- package/dist/{chunk-DEBKL7WW.js → chunk-LMF2YC5C.js} +4 -4
- package/dist/{chunk-LDYQPD5H.js → chunk-LVEMYNYH.js} +3 -3
- package/dist/{chunk-G4MVORCE.js → chunk-M4N7I2H5.js} +5 -5
- package/dist/{chunk-5F74HGSQ.js → chunk-M7774YLB.js} +1 -1
- package/dist/{chunk-3AOPBH5S.js → chunk-ME733Y2F.js} +1 -1
- package/dist/{chunk-CCY37D3C.js → chunk-N3JEYUDV.js} +2 -2
- package/dist/{chunk-3X733RHO.js → chunk-NDCW4G55.js} +1 -1
- package/dist/{chunk-Y73MI7UH.js → chunk-NFNM64A7.js} +12 -12
- package/dist/{chunk-3AC6WJNP.js → chunk-NHQWPKX7.js} +2 -2
- package/dist/{chunk-YB5IW32Y.js → chunk-NK4JHJNP.js} +4 -4
- package/dist/{chunk-IZWMWJZT.js → chunk-NVM3SKJ4.js} +1 -1
- package/dist/{chunk-VSJ3Y26C.js → chunk-OE7TAEOG.js} +1 -1
- package/dist/{chunk-D6PNMFPF.js → chunk-OEHZ46WQ.js} +2 -2
- package/dist/{chunk-4MQDDFRN.js → chunk-OFT5KSBM.js} +1 -1
- package/dist/{chunk-FEJK36FV.js → chunk-OISOA6NX.js} +2 -2
- package/dist/{chunk-L23CONP7.js → chunk-PCFYNK7V.js} +3 -3
- package/dist/{chunk-OMMQNLFE.js → chunk-PKM456D2.js} +1 -1
- package/dist/{chunk-G66AOAYN.js → chunk-PZDAPIQL.js} +1 -1
- package/dist/{chunk-QZJY4RMF.js → chunk-Q4GS5VW7.js} +3 -3
- package/dist/{chunk-DOO6M2XM.js → chunk-QK3Z4TKQ.js} +5 -5
- package/dist/{chunk-KZSBPAEJ.js → chunk-QPMKVSHU.js} +2 -2
- package/dist/{chunk-ZL3D7XTR.js → chunk-QUK3UDZV.js} +3 -3
- package/dist/{chunk-4U2TAOW7.js → chunk-QYIR64RR.js} +1 -1
- package/dist/{chunk-QWXBLCVK.js → chunk-R6CKQLEA.js} +2 -2
- package/dist/{chunk-X6HOIDIR.js → chunk-R7QZXQPU.js} +3 -3
- package/dist/{chunk-G6D6U2EY.js → chunk-RZ23QQCI.js} +4 -4
- package/dist/{chunk-PYS43F2X.js → chunk-RZBSVTOL.js} +1 -1
- package/dist/{chunk-RHEIOXVL.js → chunk-SA66WRBT.js} +1 -1
- package/dist/{chunk-KVPCFVAH.js → chunk-SFGFNJBR.js} +1 -1
- package/dist/{chunk-S5OI42DL.js → chunk-SGR4ZQAV.js} +3 -3
- package/dist/{chunk-IQI5LAEK.js → chunk-SY53PYLU.js} +1 -1
- package/dist/{chunk-7DG3WBGN.js → chunk-SYUJCVJG.js} +1 -1
- package/dist/{chunk-HJ2DJJIK.js → chunk-T2PAFWRK.js} +8 -8
- package/dist/{chunk-AWNX33WP.js → chunk-TBYWOHTE.js} +1 -1
- package/dist/{chunk-DDAOY3DL.js → chunk-TCV3WA5I.js} +1 -1
- package/dist/{chunk-3VW5ZP2F.js → chunk-UWGQNJIE.js} +1 -1
- package/dist/{chunk-3DIP37BT.js → chunk-UXJAW4IQ.js} +2 -2
- package/dist/{chunk-QJTG3DN7.js → chunk-VLAENYCN.js} +1 -1
- package/dist/{chunk-TLELTVAN.js → chunk-VYKXRSHU.js} +1 -1
- package/dist/{chunk-VFUMCL6H.js → chunk-W2VDJKTB.js} +1 -1
- package/dist/{chunk-PCLIU4BP.js → chunk-W5XAB2SW.js} +154 -152
- package/dist/{chunk-6GBGKSNQ.js → chunk-WYNIWJRN.js} +5 -5
- package/dist/{chunk-7VSPHUIB.js → chunk-XAGIZVYI.js} +26 -26
- package/dist/{chunk-XT7ZZJVD.js → chunk-XCPD7NGP.js} +1 -1
- package/dist/{chunk-52JOFQOK.js → chunk-XFGS22VE.js} +1 -1
- package/dist/{chunk-YV5JIEYI.js → chunk-XGPBHKU3.js} +2 -2
- package/dist/{chunk-WJ53NNEV.js → chunk-Y5LJYDX4.js} +1 -0
- package/dist/{chunk-GVVWEBTD.js → chunk-YLWKWEJJ.js} +3 -3
- package/dist/{chunk-6Y7TK4EA.js → chunk-YUAOQJVV.js} +2 -2
- package/dist/{chunk-KP3J52RW.js → chunk-YVS77JPW.js} +3 -3
- package/dist/{chunk-XA5FPMYR.js → chunk-ZEHBSA25.js} +2 -2
- package/dist/{chunk-6ENEX5UH.js → chunk-ZYOIH5NY.js} +6 -6
- package/dist/{cleanup-graph-garbage-M5OYEPRR.js → cleanup-graph-garbage-NKAJSCWZ.js} +9 -9
- package/dist/{cli-shutdown-AY2FMXD6.js → cli-shutdown-F3DFDCB5.js} +1 -1
- package/dist/{cloud-sync-command-PRC4GV62.js → cloud-sync-command-3YBLSMAL.js} +2 -2
- package/dist/{cloud-sync-db-init-IYXPCNSJ.js → cloud-sync-db-init-JWSPAFKY.js} +1 -1
- package/dist/{cloud-sync-shutdown-3F6XASFF.js → cloud-sync-shutdown-4R6RIO67.js} +3 -3
- package/dist/{co-activation-LB56BYW2.js → co-activation-2ZRANV3Q.js} +3 -3
- package/dist/{co-occurrence-TKPZB3IR.js → co-occurrence-6EELW2L2.js} +7 -7
- package/dist/{consent-passphrase-YQLAAPPC.js → consent-passphrase-TDR263MC.js} +2 -2
- package/dist/{content-extractor-XCS6QGM4.js → content-extractor-OVD7PTSN.js} +2 -2
- package/dist/{conversation-entity-extractor-J2UZGFG3.js → conversation-entity-extractor-KUJN3MOH.js} +4 -4
- package/dist/{crdt-sync-GE6DVV2F.js → crdt-sync-IX43KVQ3.js} +4 -4
- package/dist/{crm-webhook-6HXNLEQV.js → crm-webhook-GSCIW6CE.js} +2 -2
- package/dist/{cto-delegation-gate-QSWDPH67.js → cto-delegation-gate-ZWD4EFRR.js} +20 -19
- package/dist/{daemon-orchestration-YJ4GMHVM.js → daemon-orchestration-WL6V4QL4.js} +24 -24
- package/dist/{doc-graph-extractor-XLAUARWE.js → doc-graph-extractor-NJ7ZZC2C.js} +7 -7
- package/dist/{documents-SZ76YQ3Q.js → documents-O7WYZFFE.js} +9 -9
- package/dist/{dreaming-ZQGMOZ2E.js → dreaming-TUESPDT3.js} +24 -24
- package/dist/{employee-boot-brief-SV5JHCJL.js → employee-boot-brief-UCP6QLN4.js} +28 -28
- package/dist/{entity-boost-KTADWOGJ.js → entity-boost-TK43XT24.js} +1 -1
- package/dist/{exe-drift-CT36U5DX.js → exe-drift-QD6LUZT2.js} +4 -4
- package/dist/{exe-export-EJ4B74OU.js → exe-export-QIUNHFSS.js} +11 -11
- package/dist/{exe-import-UA6OIZ4C.js → exe-import-3UFOLHEW.js} +11 -11
- package/dist/{exe-key-SKOOVJCT.js → exe-key-D5NDKGHT.js} +104 -103
- package/dist/{exe-org-WQARAD3U.js → exe-org-UWDJBOCV.js} +32 -32
- package/dist/{exe-snapshot-2OXDANU3.js → exe-snapshot-P6SFODEN.js} +27 -27
- package/dist/{fast-db-init-YFUMI4NH.js → fast-db-init-SD7JZSEC.js} +1 -1
- package/dist/{founder-context-DMWIIDJ2.js → founder-context-QIXDZIJX.js} +2 -2
- package/dist/{founder-monitor-envelope-JYFWXZQ4.js → founder-monitor-envelope-TLOC4UYG.js} +4 -4
- package/dist/gateway/index.js +11 -11
- package/dist/{gateway-client-ELHI2DWX.js → gateway-client-CQTSYJLP.js} +1 -1
- package/dist/{git-staleness-K7HHMBWI.js → git-staleness-JSQTHB4Z.js} +3 -3
- package/dist/{global-procedures-ERZJFJUA.js → global-procedures-T3RKI4QX.js} +6 -6
- package/dist/{graph-auto-extract-LUQ6QZ4P.js → graph-auto-extract-V75GSTNX.js} +7 -7
- package/dist/{graph-query-KRNMWF77.js → graph-query-VAQN2RK3.js} +1 -1
- package/dist/{graph-rag-2W26GEGZ.js → graph-rag-GBA5E3QC.js} +4 -4
- package/dist/{hook-integrity-QFBZE5FK.js → hook-integrity-II6QK6Y4.js} +1 -1
- package/dist/{hook-prefetch-WP3PEE4H.js → hook-prefetch-5EHPOYY3.js} +19 -19
- package/dist/hooks/bug-report-worker.js +23 -23
- package/dist/hooks/codex-stop-task-finalizer.js +25 -25
- package/dist/hooks/commit-complete.js +23 -23
- package/dist/hooks/error-recall.js +14 -13
- package/dist/hooks/exe-heartbeat-hook.js +7 -6
- package/dist/hooks/ingest-worker.js +35 -9
- package/dist/hooks/ingest.js +16 -15
- package/dist/hooks/instructions-loaded.js +9 -8
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +8 -7
- package/dist/hooks/post-compact.js +7 -6
- package/dist/hooks/post-tool-combined.js +13 -13
- package/dist/hooks/pre-compact.js +24 -23
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prompt-submit.js +43 -42
- package/dist/hooks/session-end.js +29 -28
- package/dist/hooks/session-start.js +18 -18
- package/dist/hooks/stop.js +27 -26
- package/dist/hooks/subagent-stop.js +28 -27
- package/dist/hooks/summary-worker.js +27 -27
- package/dist/index.js +31 -31
- package/dist/{installer-ADGJLDVY.js → installer-ILYC4LI5.js} +9 -8
- package/dist/{installer-HCFVVQ6F.js → installer-MPVQ5L22.js} +9 -8
- package/dist/{installer-ZNP4S32U.js → installer-XEEZSF3V.js} +9 -8
- package/dist/{intercom-queue-NRECOZFL.js → intercom-queue-QGHAW2KO.js} +18 -18
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +17 -17
- package/dist/lib/consolidation.js +10 -10
- package/dist/lib/crypto.js +3 -3
- package/dist/lib/database.js +3 -3
- package/dist/lib/db-backup.js +1 -1
- package/dist/lib/db-write-worker.js +3 -3
- package/dist/lib/db.js +3 -3
- package/dist/lib/device-registry.js +1 -1
- package/dist/lib/employee-templates.js +7 -7
- package/dist/lib/employees.js +3 -3
- package/dist/lib/exe-daemon.js +90 -90
- package/dist/lib/hybrid-search.js +10 -10
- package/dist/lib/identity.js +3 -3
- package/dist/lib/keychain.js +1 -1
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +19 -19
- package/dist/lib/post-tool-memory.js +46 -7
- package/dist/lib/registry-proxy.js +1 -1
- package/dist/lib/reminders.js +4 -4
- package/dist/lib/runtime-table.js +1 -1
- package/dist/lib/schedules.js +9 -9
- package/dist/lib/session-registry.js +5 -5
- package/dist/lib/skill-learning.js +10 -10
- package/dist/lib/store.js +8 -8
- package/dist/lib/task-router.js +4 -4
- package/dist/lib/tasks.js +20 -20
- package/dist/lib/tmux-routing.js +18 -18
- package/dist/lib/token-spend.js +4 -4
- package/dist/lib/ws-client.js +1 -1
- package/dist/{license-gate-CB2OCT2G.js → license-gate-CARN6AB6.js} +3 -3
- package/dist/{license-recheck-ZAEPWMY7.js → license-recheck-7Z3LS6YS.js} +1 -1
- package/dist/{license-sync-UW4UH7F5.js → license-sync-PUQV3HSZ.js} +2 -2
- package/dist/{local-secret-inventory-2DVUEFKD.js → local-secret-inventory-5J7P24ZR.js} +2 -2
- package/dist/mcp/register-tools.js +103 -102
- package/dist/mcp/server.js +103 -102
- package/dist/mcp/tools/complete-reminder.js +5 -5
- package/dist/mcp/tools/create-reminder.js +5 -5
- package/dist/mcp/tools/create-task.js +24 -23
- package/dist/mcp/tools/deactivate-behavior.js +13 -12
- package/dist/mcp/tools/list-reminders.js +5 -5
- package/dist/mcp/tools/list-tasks.js +24 -23
- package/dist/mcp/tools/send-message.js +23 -22
- package/dist/mcp/tools/update-task.js +21 -21
- package/dist/{mcp-http-config-IPXCT6Y5.js → mcp-http-config-RJKTZPHZ.js} +7 -6
- package/dist/{mcp-session-identity-GRKQ6X6M.js → mcp-session-identity-HN444A3G.js} +18 -18
- package/dist/{memory-cards-JN32U2KA.js → memory-cards-AT3QCCWU.js} +8 -8
- package/dist/{memory-graph-extractor-3LN2GSMZ.js → memory-graph-extractor-B43UWGV5.js} +8 -8
- package/dist/{memory-maintenance-YTNSNHD5.js → memory-maintenance-WDLL3ZX3.js} +2 -2
- package/dist/{memory-poisoning-defense-ISKHR76K.js → memory-poisoning-defense-TS4WNW4S.js} +3 -3
- package/dist/{memory-pressure-watchdog-P4QHXE3Z.js → memory-pressure-watchdog-6YH7S6W7.js} +19 -19
- package/dist/{memory-reflection-R6TAIUOR.js → memory-reflection-N6NSYW6S.js} +8 -8
- package/dist/{memory-write-repository-JTJE3AG4.js → memory-write-repository-D35RDO62.js} +1 -1
- package/dist/{monitor-grants-KX5J6AQ7.js → monitor-grants-FH4PNYN5.js} +3 -3
- package/dist/{monitor-identity-WXIGBLYH.js → monitor-identity-LK5ZCCND.js} +2 -2
- package/dist/{notification-ledger-DKHZKGZX.js → notification-ledger-3WJYJGGS.js} +19 -19
- package/dist/{notifications-ZQVBRXG5.js → notifications-T5C2CVB3.js} +18 -18
- package/dist/{orchestration-events-B3OHNBR4.js → orchestration-events-73VEJT7Q.js} +4 -4
- package/dist/{orchestrator-OG6BEUHS.js → orchestrator-3O657734.js} +20 -20
- package/dist/{org-brief-session-MHDLBUO4.js → org-brief-session-EGB35QLM.js} +15 -15
- package/dist/{org-consent-policy-OP5L627O.js → org-consent-policy-MSVSRI53.js} +5 -5
- package/dist/{org-join-H3PBH7US.js → org-join-4BK2XJJI.js} +9 -9
- package/dist/{org-key-admin-UEDWV3F4.js → org-key-admin-EUSSGXQ3.js} +11 -11
- package/dist/{org-key-epoch-BW72L7RI.js → org-key-epoch-NMEWDT5L.js} +5 -5
- package/dist/{org-key-pin-XBLJOF4A.js → org-key-pin-HUSXGINB.js} +3 -3
- package/dist/{org-membership-UHVIK3UH.js → org-membership-B74IWEM5.js} +4 -4
- package/dist/{org-partner-config-G3BGVBQT.js → org-partner-config-5FJTJABN.js} +8 -8
- package/dist/{org-partner-runtime-H6MROHM7.js → org-partner-runtime-GN4GFWI2.js} +15 -15
- package/dist/{org-row-visibility-JK5REXVH.js → org-row-visibility-PBZ2TSCR.js} +1 -1
- package/dist/{pipeline-router-7L7AV55A.js → pipeline-router-2IELBSVJ.js} +4 -4
- package/dist/{plan-limits-RKGJXYKE.js → plan-limits-4GXK5PFT.js} +6 -6
- package/dist/{platform-procedures-RTD5E3BD.js → platform-procedures-QP3W2NLH.js} +1 -1
- package/dist/{pre-tool-use-impl-Q3JG5RNT.js → pre-tool-use-impl-CY73PRJP.js} +42 -42
- package/dist/{project-name-KQUBSY5O.js → project-name-337ERIAX.js} +4 -4
- package/dist/{projection-worker-LGELT4E6.js → projection-worker-W476IG6V.js} +2 -2
- package/dist/{prospective-memory-ZESC2I6H.js → prospective-memory-5INB7NUL.js} +3 -3
- package/dist/{push-notifications-YL2DRTGQ.js → push-notifications-YVOP4KGN.js} +19 -19
- package/dist/{reproject-worktree-memories-VPZRYPQM.js → reproject-worktree-memories-OGBR3CMO.js} +18 -18
- package/dist/{reranker-XC2LXYD3.js → reranker-W7WCJH6Y.js} +1 -1
- package/dist/{retrieval-health-H4QJN3UZ.js → retrieval-health-R6MGXLTP.js} +1 -1
- package/dist/{review-polling-67WTTJHH.js → review-polling-TKAWVY6G.js} +19 -19
- package/dist/runtime/index.js +23 -23
- package/dist/{session-events-7XFO27M5.js → session-events-HUCZ7TOR.js} +19 -19
- package/dist/{session-kill-telemetry-2F5INRA6.js → session-kill-telemetry-RWRWOW4C.js} +19 -19
- package/dist/{session-scope-GEXQAEYT.js → session-scope-5CDRHV75.js} +18 -18
- package/dist/{setup-wizard-NQI6GC2N.js → setup-wizard-RBTJAZOP.js} +3 -3
- package/dist/{shard-manager-TJ323N7P.js → shard-manager-LRPAAQA4.js} +2 -2
- package/dist/{skill-refinement-EQ3YVAGM.js → skill-refinement-MDXKDCY6.js} +4 -4
- package/dist/{skill-retrieval-LABSBPVT.js → skill-retrieval-OWY6MTCX.js} +12 -12
- package/dist/{skill-usage-WNCOURZY.js → skill-usage-GNV737U5.js} +4 -4
- package/dist/{stack-generate-manifest-RKQBTLEY.js → stack-generate-manifest-S4SBLKBY.js} +4 -4
- package/dist/{stack-promote-ZVOIMFRF.js → stack-promote-U4EZNLOV.js} +4 -4
- package/dist/{stack-release-ZCHLWJXF.js → stack-release-4VBGOYGK.js} +5 -5
- package/dist/{stack-update-AP6OC7LU.js → stack-update-C5YKHE7A.js} +3 -3
- package/dist/{steward-gate-BNI4K3GP.js → steward-gate-QFPXQBUZ.js} +4 -4
- package/dist/{subagent-brief-injection-ZXKMB5TZ.js → subagent-brief-injection-GDXO5WNS.js} +33 -32
- package/dist/{subagent-spawn-ledger-OI23OT4I.js → subagent-spawn-ledger-PDICC43I.js} +2 -1
- package/dist/{support-bug-actions-OYM3K4RU.js → support-bug-actions-4XEKXIIO.js} +4 -4
- package/dist/{support-inbox-2JOCSJUT.js → support-inbox-Y7AFCOGM.js} +17 -16
- package/dist/{support-outbox-6AE2NQTA.js → support-outbox-2WYS3HWR.js} +2 -2
- package/dist/{task-enforcement-LUXQXSE6.js → task-enforcement-CN3Q4PEH.js} +19 -19
- package/dist/{task-request-inbox-4TOOJ6IR.js → task-request-inbox-AY3C6DND.js} +5 -5
- package/dist/{task-scope-OEA6KUTX.js → task-scope-AMR3Z3DJ.js} +18 -18
- package/dist/{tasks-crud-GBNROE5E.js → tasks-crud-2GHKIZOM.js} +18 -18
- package/dist/{tasks-notify-FMSTX6Q5.js → tasks-notify-Z53446KM.js} +19 -19
- package/dist/{tasks-review-EAOT3SKK.js → tasks-review-APRNSHMQ.js} +18 -18
- package/dist/{telemetry-upload-OFNKPITF.js → telemetry-upload-5XR42SQN.js} +8 -8
- package/dist/{token-budget-7K5PMPP2.js → token-budget-TTNJXI7W.js} +4 -4
- package/dist/{tool-telemetry-HC7NHNWD.js → tool-telemetry-36ST422N.js} +1 -1
- package/dist/tui/App.js +30 -30
- package/dist/{tui-data-C6STFM4Z.js → tui-data-AP5TPUOQ.js} +22 -22
- package/dist/{update-support-KOJIIKHY.js → update-support-SFTI2PUD.js} +15 -14
- package/dist/{whatsapp-JDAZGYPN.js → whatsapp-5CXE3JHG.js} +2 -2
- package/dist/{wiki-acl-7JCCDS7U.js → wiki-acl-N754BC2W.js} +1 -1
- package/dist/{work-claims-MDJ3JEUD.js → work-claims-OAICQBWO.js} +4 -4
- package/dist/{work-state-heartbeat-GFPR5OVW.js → work-state-heartbeat-MTTUGMPU.js} +1 -1
- package/dist/{workflow-engine-YYR2DNFP.js → workflow-engine-RID3QL2U.js} +2 -2
- package/dist/{worktree-XJITSSNN.js → worktree-XWVNDBRD.js} +5 -5
- package/dist/{worktree-sweep-3FJSAGNK.js → worktree-sweep-6VEHGH7U.js} +6 -6
- package/package.json +6 -5
- package/release-notes.json +9 -10
- package/stack.release.json +3 -3
- package/dist/{chunk-ZWQWLUZA.js → chunk-33PG3KNY.js} +0 -0
- package/dist/{chunk-MY6P4E5J.js → chunk-64UAHPXA.js} +0 -0
- package/dist/{chunk-7GCPTNHK.js → chunk-CLV7ALXV.js} +0 -0
- package/dist/{chunk-7QIEF6OZ.js → chunk-EZQ4W3WW.js} +0 -0
- package/dist/{chunk-DHRIW7RJ.js → chunk-FLO24BNN.js} +0 -0
- package/dist/{chunk-USDMXIPZ.js → chunk-FUZHMV7K.js} +0 -0
- package/dist/{chunk-E5RCYOLD.js → chunk-LDHJX4TZ.js} +0 -0
- package/dist/{chunk-3NHFXUWK.js → chunk-OEEHLATI.js} +0 -0
- package/dist/{chunk-HEEKYE6D.js → chunk-OLMLA377.js} +0 -0
- package/dist/{chunk-QYCRJ76J.js → chunk-WIDOLS7T.js} +0 -0
- package/dist/{chunk-FLC2S4BD.js → chunk-YBB43SXC.js} +0 -0
- package/dist/{chunk-GVTIDG37.js → chunk-YG4DZZ6J.js} +0 -0
- package/dist/{core-memory-DQ5A24DD.js → core-memory-WR7I7DIP.js} +0 -0
- package/dist/{hook-tamper-log-ARGWCXKJ.js → hook-tamper-log-HTWEP37U.js} +3 -3
- /package/dist/{memory-isolation-2M3GFNWG.js → memory-isolation-4RQJ5RCK.js} +0 -0
- /package/dist/{oauth-server-NWVJ26NL.js → oauth-server-VBDMZIEV.js} +0 -0
- /package/dist/{project-boot-JAGN65MZ.js → project-boot-G7T5WHO6.js} +0 -0
|
@@ -7,17 +7,17 @@ import {
|
|
|
7
7
|
supportProductSchema,
|
|
8
8
|
supportTaskIdSchema,
|
|
9
9
|
supportVersionSchema
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-HK7HIDXP.js";
|
|
11
11
|
import {
|
|
12
12
|
queueSupportStatusUpdateSync
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-L4ISXVC5.js";
|
|
14
14
|
import {
|
|
15
15
|
assessAttribution,
|
|
16
16
|
assessDisposition,
|
|
17
17
|
buildVerificationArtifact,
|
|
18
18
|
isPlaceholderIdentity,
|
|
19
19
|
isUnresolvedIdentity
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-4MK6LOD6.js";
|
|
21
21
|
import {
|
|
22
22
|
SUPPORT_REPORT_SENT_MARKER
|
|
23
23
|
} from "./chunk-MMRUBN3I.js";
|
|
@@ -34,14 +34,14 @@ import {
|
|
|
34
34
|
sanitizeUpstreamId,
|
|
35
35
|
sanitizeVersionField,
|
|
36
36
|
sanitizedUpstreamBody
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-BYP3DOUU.js";
|
|
38
38
|
import {
|
|
39
39
|
getActiveAgent
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-OISOA6NX.js";
|
|
41
41
|
import {
|
|
42
42
|
loadLicense,
|
|
43
43
|
readCachedLicenseToken
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-DIKLSAJE.js";
|
|
45
45
|
import {
|
|
46
46
|
EXE_AI_DIR,
|
|
47
47
|
loadConfig
|
|
@@ -51,8 +51,8 @@ import {
|
|
|
51
51
|
import { z as z3 } from "zod";
|
|
52
52
|
import { readFileSync } from "fs";
|
|
53
53
|
import { readFile as readFile2 } from "fs/promises";
|
|
54
|
-
import { join } from "path";
|
|
55
|
-
import { homedir } from "os";
|
|
54
|
+
import { join as join2 } from "path";
|
|
55
|
+
import { homedir as homedir2 } from "os";
|
|
56
56
|
|
|
57
57
|
// src/mcp/tools/update-bug-report.ts
|
|
58
58
|
import { z as z2 } from "zod";
|
|
@@ -120,6 +120,7 @@ function resolveRef(ref, cwd) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
var MODEL_HELP = "Set ANTHROPIC_MODEL (employee sessions get it automatically at launch) or pass attribution_model explicitly. It is NOT guessed: a wrong model on the record is worse than no record at all, because it points at the wrong suspect.";
|
|
123
|
+
var ACCOUNTABILITY_PURPOSES = /* @__PURE__ */ new Set(["verdict", "routing_verdict"]);
|
|
123
124
|
function resolveAttribution(purpose, input = {}) {
|
|
124
125
|
const stated = input.agent?.trim() ?? "";
|
|
125
126
|
let observed = "";
|
|
@@ -129,24 +130,24 @@ function resolveAttribution(purpose, input = {}) {
|
|
|
129
130
|
observed = "";
|
|
130
131
|
}
|
|
131
132
|
let agent;
|
|
132
|
-
if (purpose
|
|
133
|
+
if (ACCOUNTABILITY_PURPOSES.has(purpose)) {
|
|
133
134
|
const observedIsReal = observed !== "" && !isUnresolvedIdentity(observed);
|
|
134
135
|
if (observedIsReal && stated && stated.toLowerCase() !== observed.toLowerCase()) {
|
|
135
136
|
return {
|
|
136
137
|
ok: false,
|
|
137
138
|
code: "attribution_agent_conflict",
|
|
138
|
-
message: `Refused locally [attribution_agent_conflict]: attribution_agent was given as "${stated}", but this session resolves to "${observed}". A verdict is signed by whoever actually made it \u2014 attribution_agent is a fallback for a session that cannot observe its own identity (the MCP daemon), not a way to record the call under another employee's name. Omit attribution_agent to sign as "${observed}", or make the call from that employee's session.`
|
|
139
|
+
message: `Refused locally [attribution_agent_conflict]: attribution_agent was given as "${stated}", but this session resolves to "${observed}". A ${purpose === "verdict" ? "verdict" : "close"} is signed by whoever actually made it \u2014 attribution_agent is a fallback for a session that cannot observe its own identity (the MCP daemon), not a way to record the call under another employee's name. Omit attribution_agent to sign as "${observed}", or make the call from that employee's session.`
|
|
139
140
|
};
|
|
140
141
|
}
|
|
141
142
|
agent = observedIsReal ? observed : stated;
|
|
142
143
|
} else {
|
|
143
144
|
agent = stated || observed;
|
|
144
145
|
}
|
|
145
|
-
if (purpose
|
|
146
|
+
if (ACCOUNTABILITY_PURPOSES.has(purpose) && isUnresolvedIdentity(agent)) {
|
|
146
147
|
agent = "";
|
|
147
148
|
}
|
|
148
149
|
if (!agent) {
|
|
149
|
-
const message = purpose
|
|
150
|
+
const message = ACCOUNTABILITY_PURPOSES.has(purpose) ? `Refused locally [attribution_agent_missing]: could not resolve which agent is producing this ${purpose === "verdict" ? "verdict" : "close"}, and it will not be invented. The MCP tools run in the launchd daemon, which carries no active-agent marker, no tmux session and no AGENT_ID, so the session identity is not observable from there. Pass attribution_agent with your own employee name exactly as it appears in the roster \u2014 never a role like 'admin'.` : `Refused locally [attribution_agent_missing]: could not resolve which agent is producing this ${purpose}, and it will not be invented. Restore the active-agent marker or set AGENT_ID to your real employee name.`;
|
|
150
151
|
return {
|
|
151
152
|
ok: false,
|
|
152
153
|
code: "attribution_agent_missing",
|
|
@@ -225,11 +226,14 @@ var verificationArtifactInputSchema = {
|
|
|
225
226
|
parent_result: z.enum(["fail", "pass", "error"]).optional().describe("regression_test only: the result you OBSERVED running that test at the parent commit. Must be 'fail' \u2014 a test that already passed does not detect the defect."),
|
|
226
227
|
fix_result: z.enum(["fail", "pass", "error"]).optional().describe("regression_test only: the result you OBSERVED running that test at the fix commit. Must be 'pass'."),
|
|
227
228
|
verifier: z.string().optional().describe("manual and ops_transcript: the identity of the person or employee who confirmed the defect is gone. Checked server-side against the bug's filer and assignee \u2014 it may not be either. Placeholders ('me', 'agent') are refused."),
|
|
228
|
-
disposition: z.enum(["fixed", "not_a_defect", "superseded", "wontfix"]).optional().describe(
|
|
229
|
-
"WHY the record is closing. Omit (or 'fixed') for the normal case: a defect was repaired, and a verification artifact is required. Use 'not_a_defect' when there was nothing to fix (a smoke-test record, a misfiled report), 'superseded' when another record covers it, 'wontfix' when it is a deliberate decline
|
|
229
|
+
disposition: z.enum(["fixed", "not_a_defect", "superseded", "wontfix", "migrated"]).optional().describe(
|
|
230
|
+
"WHY the record is closing. Omit (or 'fixed') for the normal case: a defect was repaired, and a verification artifact is required. Use 'not_a_defect' when there was nothing to fix (a smoke-test record, a misfiled report), 'superseded' when another record covers it, 'wontfix' when it is a deliberate decline, 'migrated' when the bug was moved to GitHub Issues (requires github_issue_url, NOT disposition_reason). All of these require NO fix_commit \u2014 and they are recorded as closed, not as fixed, because asserting a repair that never happened is its own kind of false record."
|
|
230
231
|
),
|
|
231
232
|
disposition_reason: z.string().optional().describe(
|
|
232
|
-
"REQUIRED for any disposition other than 'fixed': what makes this record a non-defect. Explain the call \u2014 a bare label or a hedge is refused."
|
|
233
|
+
"REQUIRED for any disposition other than 'fixed'/'migrated': what makes this record a non-defect. Explain the call \u2014 a bare label or a hedge is refused."
|
|
234
|
+
),
|
|
235
|
+
github_issue_url: z.string().optional().describe(
|
|
236
|
+
"REQUIRED for disposition='migrated': the GitHub Issue this bug was moved to, https://github.com/AskExe/<repo>/issues/<n>. Also usable on its own (no status/disposition at all) to back-link an ALREADY fixed/closed record to its GitHub issue without changing its status."
|
|
233
237
|
),
|
|
234
238
|
superseded_by: z.string().optional().describe("REQUIRED for disposition='superseded': the id of the record that replaces this one, so the claim is checkable."),
|
|
235
239
|
superseded_coverage: z.string().optional().describe(
|
|
@@ -262,7 +266,8 @@ var verificationArtifactInputSchema = {
|
|
|
262
266
|
delivery_proof: z.string().optional().describe('Optional JSON delivery declaration, e.g. {"channel":"npm","version":"0.9.364","tarball_shasum":"\u2026","fix_path_published":true}. Recorded, not required \u2014 delivery does not gate closing. A declaration that is present must still be true.')
|
|
263
267
|
};
|
|
264
268
|
function buildVerdictAttribution(input) {
|
|
265
|
-
|
|
269
|
+
const purpose = input.disposition === "migrated" ? "routing_verdict" : "verdict";
|
|
270
|
+
return resolveAttribution(purpose, {
|
|
266
271
|
agent: input.attribution_agent,
|
|
267
272
|
model: input.attribution_model,
|
|
268
273
|
observed_at: input.observed_at,
|
|
@@ -295,6 +300,7 @@ var DEFERRAL_BLOCKING = {
|
|
|
295
300
|
superseded_by: true,
|
|
296
301
|
disposition_verifier: true,
|
|
297
302
|
superseded_coverage: true,
|
|
303
|
+
github_issue_url: true,
|
|
298
304
|
// Attribution inputs — the client turns these into `attribution`, which it likewise
|
|
299
305
|
// does not build on the deferral branch.
|
|
300
306
|
attribution_agent: true,
|
|
@@ -403,6 +409,7 @@ function resolveVerificationArtifact(status, input, context = {}) {
|
|
|
403
409
|
superseded_by: input.superseded_by,
|
|
404
410
|
disposition_verifier: input.disposition_verifier,
|
|
405
411
|
superseded_coverage: input.superseded_coverage,
|
|
412
|
+
github_issue_url: input.github_issue_url,
|
|
406
413
|
symptoms: input.symptoms,
|
|
407
414
|
context
|
|
408
415
|
});
|
|
@@ -705,7 +712,7 @@ function registerUpdateBugReport(server) {
|
|
|
705
712
|
content: [{ type: "text", text: describeOversizeRefusal(oversize) }]
|
|
706
713
|
};
|
|
707
714
|
}
|
|
708
|
-
const attestsByIdentity = verification.verification_kind === "manual" || verification.verification_kind === "ops_transcript" || verification.disposition !== void 0 && verification.disposition !== "fixed";
|
|
715
|
+
const attestsByIdentity = verification.verification_kind === "manual" || verification.verification_kind === "ops_transcript" || verification.disposition !== void 0 && verification.disposition !== "fixed" && verification.disposition !== "migrated";
|
|
709
716
|
let resolvedVerification = resolveVerificationArtifact(gatedStatus, verification, { sendUpstream: send_upstream });
|
|
710
717
|
if (resolvedVerification.ok && isVerifiedStatus(gatedStatus) && attestsByIdentity) {
|
|
711
718
|
const authorIdentities = await collectBugAuthorIdentities(id);
|
|
@@ -797,6 +804,7 @@ These do not match \u2014 not updating to avoid mutating the wrong bug. Verify t
|
|
|
797
804
|
if (verification.superseded_by) payload.superseded_by = verification.superseded_by;
|
|
798
805
|
if (verification.disposition_verifier) payload.disposition_verifier = verification.disposition_verifier;
|
|
799
806
|
if (verification.superseded_coverage) payload.superseded_coverage = verification.superseded_coverage;
|
|
807
|
+
if (verification.github_issue_url) payload.github_issue_url = verification.github_issue_url;
|
|
800
808
|
if (verification.symptoms) payload.symptoms = verification.symptoms;
|
|
801
809
|
if (resolvedVerification.attribution) payload.attribution = resolvedVerification.attribution;
|
|
802
810
|
} else {
|
|
@@ -932,6 +940,487 @@ Upstream status: ${upstreamStatus}`
|
|
|
932
940
|
);
|
|
933
941
|
}
|
|
934
942
|
|
|
943
|
+
// src/lib/support-github-issue.ts
|
|
944
|
+
import { execFile } from "child_process";
|
|
945
|
+
import { closeSync, mkdirSync, openSync, statSync, unlinkSync, writeSync } from "fs";
|
|
946
|
+
import { randomUUID } from "crypto";
|
|
947
|
+
import { homedir } from "os";
|
|
948
|
+
import { join } from "path";
|
|
949
|
+
var GITHUB_ORG = "AskExe";
|
|
950
|
+
var PRODUCT_REPO_ROUTE = {
|
|
951
|
+
"exe-os": "exe-os",
|
|
952
|
+
"exe-create": "exe-create",
|
|
953
|
+
"exe-wiki": "exe-wiki",
|
|
954
|
+
"exe-gateway": "exe-gateway",
|
|
955
|
+
"exe-build": "exe-build",
|
|
956
|
+
"exe-chat": "exe-chat",
|
|
957
|
+
"exe-auth": "exe-auth",
|
|
958
|
+
"exe-monitor": "exe-monitor",
|
|
959
|
+
"exe-db": "exe-db",
|
|
960
|
+
"exe-crm": "exe-infra",
|
|
961
|
+
"exe-erp": "exe-infra"
|
|
962
|
+
};
|
|
963
|
+
var EXE_INFRA_REPO = `${GITHUB_ORG}/exe-infra`;
|
|
964
|
+
function routeRepoForProduct(product) {
|
|
965
|
+
if (!product) return null;
|
|
966
|
+
const repo = PRODUCT_REPO_ROUTE[product];
|
|
967
|
+
return repo ? `${GITHUB_ORG}/${repo}` : null;
|
|
968
|
+
}
|
|
969
|
+
var EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|
|
970
|
+
function scrubEmail(value) {
|
|
971
|
+
return value == null ? "" : String(value).replace(EMAIL_RE, "[redacted-email]");
|
|
972
|
+
}
|
|
973
|
+
function sanitizeIssueText(value) {
|
|
974
|
+
const raw = value == null ? "" : String(value);
|
|
975
|
+
const { text } = redactSecrets(raw);
|
|
976
|
+
return neutralizeHtmlComments(scrubEmail(text));
|
|
977
|
+
}
|
|
978
|
+
function neutralizeHtmlComments(value) {
|
|
979
|
+
return value.replaceAll("<!--", "<!--").replaceAll("-->", "-->");
|
|
980
|
+
}
|
|
981
|
+
function neutralizeBody(body, repo, product) {
|
|
982
|
+
const parts = body.split(/(```[\s\S]*?```|`[^`\n]*`)/g);
|
|
983
|
+
return parts.map((seg, i) => {
|
|
984
|
+
if (i % 2 === 1) return seg;
|
|
985
|
+
let out = seg.replace(/(^|[^\w`/.])@([A-Za-z0-9][A-Za-z0-9-]{0,38})/g, (_m, pre, name) => `${pre}\`@${name}\``);
|
|
986
|
+
if (repo === EXE_INFRA_REPO && product) {
|
|
987
|
+
out = out.replace(/(^|[^\w/])#(\d+)\b/g, (_m, pre, n) => `${pre}${GITHUB_ORG}/${product}#${n}`);
|
|
988
|
+
}
|
|
989
|
+
return out;
|
|
990
|
+
}).join("");
|
|
991
|
+
}
|
|
992
|
+
function truncateTitle(title) {
|
|
993
|
+
const t = String(title || "Untitled bug report").trim();
|
|
994
|
+
return t.length > 250 ? `${t.slice(0, 249)}\u2026` : t;
|
|
995
|
+
}
|
|
996
|
+
function fmt(d) {
|
|
997
|
+
return d ? String(d).replace("T", " ").replace(/\.\d+Z$/, " UTC") : "\u2014";
|
|
998
|
+
}
|
|
999
|
+
function issueMarker(bugId) {
|
|
1000
|
+
return `<!-- exe-support-bug-id: ${bugId} -->`;
|
|
1001
|
+
}
|
|
1002
|
+
function bodyOwnedBy(body, bugId) {
|
|
1003
|
+
return typeof body === "string" && body.trimEnd().endsWith(issueMarker(bugId));
|
|
1004
|
+
}
|
|
1005
|
+
function cell(v) {
|
|
1006
|
+
const s = sanitizeIssueText(v == null ? "" : String(v)).replace(/\|/g, "\\|").replace(/\r?\n/g, " ").trim();
|
|
1007
|
+
return s || "\u2014";
|
|
1008
|
+
}
|
|
1009
|
+
function jsonArray(v) {
|
|
1010
|
+
if (Array.isArray(v)) return v;
|
|
1011
|
+
if (typeof v !== "string" || !v.trim()) return [];
|
|
1012
|
+
try {
|
|
1013
|
+
const parsed = JSON.parse(v);
|
|
1014
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1015
|
+
} catch {
|
|
1016
|
+
return [v];
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
function entryText(e) {
|
|
1020
|
+
if (e == null) return "";
|
|
1021
|
+
if (typeof e === "string") return e;
|
|
1022
|
+
if (typeof e === "object") {
|
|
1023
|
+
const o = e;
|
|
1024
|
+
const when = typeof o.at === "string" ? o.at : typeof o.timestamp === "string" ? o.timestamp : "";
|
|
1025
|
+
const text = typeof o.note === "string" ? o.note : typeof o.text === "string" ? o.text : JSON.stringify(o);
|
|
1026
|
+
return when ? `${when}: ${text}` : text;
|
|
1027
|
+
}
|
|
1028
|
+
return String(e);
|
|
1029
|
+
}
|
|
1030
|
+
function section(L, heading, value) {
|
|
1031
|
+
const text = sanitizeIssueText(value == null ? "" : String(value)).trim();
|
|
1032
|
+
if (text) L.push(`### ${heading}`, "", "```", text, "```", "");
|
|
1033
|
+
}
|
|
1034
|
+
function persistedIssueNumber(url, repo) {
|
|
1035
|
+
if (typeof url !== "string") return null;
|
|
1036
|
+
const m = /^https:\/\/github\.com\/([A-Za-z0-9._-]+\/[A-Za-z0-9._-]+)\/issues\/([1-9][0-9]*)$/.exec(url);
|
|
1037
|
+
if (!m || m[1] !== repo) return null;
|
|
1038
|
+
return Number(m[2]);
|
|
1039
|
+
}
|
|
1040
|
+
function renderIssueBody(bug) {
|
|
1041
|
+
const L = [];
|
|
1042
|
+
L.push("## Summary", "", sanitizeIssueText(bug.summary) || "_No summary recorded._", "");
|
|
1043
|
+
L.push(`Reported via exe-support (${cell(bug.license_plan || "unknown")} plan)`, "");
|
|
1044
|
+
pushFactsTable(L, bug);
|
|
1045
|
+
pushEvidenceSections(L, bug);
|
|
1046
|
+
L.push("---", "", `Migrated from exe-support bug ${bug.id}`, "", issueMarker(bug.id));
|
|
1047
|
+
return L.join("\n");
|
|
1048
|
+
}
|
|
1049
|
+
async function recheckCanonical(repo, canonical, bug) {
|
|
1050
|
+
const view = JSON.parse(await gh(["issue", "view", String(canonical.number), "-R", repo, "--json", "state"]) || "{}");
|
|
1051
|
+
const state = String(view.state ?? "").toUpperCase();
|
|
1052
|
+
if (state !== "OPEN" && state !== "CLOSED") {
|
|
1053
|
+
throw new Error(`Could not verify GitHub issue ${repo}#${canonical.number} before migrating (state: ${state || "unknown"}). The support record was left untouched.`);
|
|
1054
|
+
}
|
|
1055
|
+
if (state !== "CLOSED") return canonical;
|
|
1056
|
+
const fresh = await searchMarkerIssues(repo, bug.id);
|
|
1057
|
+
const others = fresh.filter((i) => i.number !== canonical.number);
|
|
1058
|
+
if (others.length === 0) {
|
|
1059
|
+
await gh(["issue", "reopen", String(canonical.number), "-R", repo]);
|
|
1060
|
+
return { ...canonical, state: "OPEN" };
|
|
1061
|
+
}
|
|
1062
|
+
const survivor = await reconcileMarkerIssues(repo, others);
|
|
1063
|
+
await syncTriageToIssue(repo, survivor, bug);
|
|
1064
|
+
return survivor;
|
|
1065
|
+
}
|
|
1066
|
+
function pushFactsTable(L, bug) {
|
|
1067
|
+
L.push("### Facts", "", "| Field | Value |", "| --- | --- |");
|
|
1068
|
+
L.push(`| Severity | ${cell(bug.severity)} |`);
|
|
1069
|
+
L.push(`| Product | ${cell(bug.product)} |`);
|
|
1070
|
+
L.push(`| Classification | ${cell(bug.classification)} |`);
|
|
1071
|
+
L.push(`| Cluster | ${cell(bug.cluster)} |`);
|
|
1072
|
+
L.push(`| Reported | ${cell(fmt(bug.created_at))} |`);
|
|
1073
|
+
L.push(`| Triaged | ${cell(fmt(bug.triaged_at))} |`);
|
|
1074
|
+
L.push(`| Fixed version | ${cell(bug.fixed_version)} |`);
|
|
1075
|
+
L.push(`| Package version | ${cell(bug.package_version)} |`);
|
|
1076
|
+
L.push("");
|
|
1077
|
+
}
|
|
1078
|
+
var MANAGED_LABEL_PREFIXES = ["cluster:", "severity:", "product:"];
|
|
1079
|
+
async function syncLabels(repo, issueNumber, bug) {
|
|
1080
|
+
const want = buildLabels(bug, repo);
|
|
1081
|
+
const view = JSON.parse(await gh(["issue", "view", String(issueNumber), "-R", repo, "--json", "labels"]) || "{}");
|
|
1082
|
+
const have = (view.labels ?? []).map((l) => l.name ?? "").filter(Boolean);
|
|
1083
|
+
const add = want.filter((l) => !have.includes(l));
|
|
1084
|
+
const remove = have.filter((l) => MANAGED_LABEL_PREFIXES.some((p) => l.startsWith(p)) && !want.includes(l));
|
|
1085
|
+
if (add.length === 0 && remove.length === 0) return;
|
|
1086
|
+
if (add.length) await ensureLabelsExist(repo, add);
|
|
1087
|
+
const args = ["issue", "edit", String(issueNumber), "-R", repo];
|
|
1088
|
+
if (add.length) args.push("--add-label", add.join(","));
|
|
1089
|
+
if (remove.length) args.push("--remove-label", remove.join(","));
|
|
1090
|
+
await gh(args);
|
|
1091
|
+
}
|
|
1092
|
+
function pushEvidenceSections(L, bug) {
|
|
1093
|
+
if (bug.observed_kind || bug.evidence_pointer) {
|
|
1094
|
+
section(L, "Filing evidence", `${bug.observed_kind ? `Kind: ${bug.observed_kind}
|
|
1095
|
+
` : ""}${bug.evidence_pointer ? `Pointer: ${bug.evidence_pointer}` : ""}`);
|
|
1096
|
+
}
|
|
1097
|
+
section(L, "Customer impact", bug.customer_impact);
|
|
1098
|
+
section(L, "Local patch supplied by the reporter", bug.local_patch_diff);
|
|
1099
|
+
const steps = jsonArray(bug.reproduction_steps).map(entryText).filter((s) => s.trim());
|
|
1100
|
+
if (steps.length) {
|
|
1101
|
+
L.push("### Reproduction steps", "", "```", sanitizeIssueText(steps.map((s, i) => `${i + 1}. ${s}`).join("\n")), "```", "");
|
|
1102
|
+
}
|
|
1103
|
+
section(L, "Expected", bug.expected);
|
|
1104
|
+
section(L, "Actual", bug.actual);
|
|
1105
|
+
section(L, "Workaround", bug.workaround);
|
|
1106
|
+
section(L, "Triage notes", bug.triage_notes);
|
|
1107
|
+
const progress = jsonArray(bug.progress_log).map(entryText).filter((s) => s.trim());
|
|
1108
|
+
if (progress.length) section(L, "Progress log", progress.join("\n"));
|
|
1109
|
+
section(L, "Triage note (this triage)", bug.add_note);
|
|
1110
|
+
}
|
|
1111
|
+
function buildLabels(bug, repo) {
|
|
1112
|
+
const labels = ["bug", "from:exe-support", `severity:${bug.severity || "p3"}`, "status:triaged"];
|
|
1113
|
+
if (bug.cluster) labels.push(`cluster:${bug.cluster}`);
|
|
1114
|
+
if (repo === EXE_INFRA_REPO && bug.product) labels.push(`product:${bug.product}`);
|
|
1115
|
+
return labels;
|
|
1116
|
+
}
|
|
1117
|
+
var GithubCliUnavailableError = class extends Error {
|
|
1118
|
+
constructor(message) {
|
|
1119
|
+
super(message);
|
|
1120
|
+
this.name = "GithubCliUnavailableError";
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
function execGh(args, stdin) {
|
|
1124
|
+
return new Promise((resolve, reject) => {
|
|
1125
|
+
const child = execFile(
|
|
1126
|
+
"gh",
|
|
1127
|
+
args,
|
|
1128
|
+
{ maxBuffer: 16 * 1024 * 1024 },
|
|
1129
|
+
(err, stdout, stderr) => {
|
|
1130
|
+
if (err) {
|
|
1131
|
+
const e = err;
|
|
1132
|
+
e.stdout = stdout;
|
|
1133
|
+
e.stderr = stderr;
|
|
1134
|
+
reject(e);
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
resolve(stdout);
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
child.stdin?.on?.("error", (streamErr) => {
|
|
1141
|
+
const e = streamErr;
|
|
1142
|
+
e.message = `gh stdin write failed: ${streamErr.message}`;
|
|
1143
|
+
reject(e);
|
|
1144
|
+
});
|
|
1145
|
+
if (stdin !== void 0) child.stdin?.end(stdin);
|
|
1146
|
+
else child.stdin?.end();
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
async function gh(args, stdin) {
|
|
1150
|
+
try {
|
|
1151
|
+
return await execGh(args, stdin);
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
const e = err;
|
|
1154
|
+
if (e.code === "ENOENT") {
|
|
1155
|
+
throw new GithubCliUnavailableError(
|
|
1156
|
+
"GitHub CLI (`gh`) is not installed. Install it from https://cli.github.com to push triaged bugs to GitHub, or pass push_to_github: false to skip."
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
const out = `${e.stderr || ""}${e.stdout || ""}`;
|
|
1160
|
+
if (/not logged into any github hosts|gh auth login|authentication required|http 401/i.test(out)) {
|
|
1161
|
+
throw new GithubCliUnavailableError(
|
|
1162
|
+
"GitHub CLI (`gh`) is not authenticated. Run `gh auth login`, or pass push_to_github: false to skip."
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
throw new Error(`gh ${args[0] ?? ""} failed: ${(out || e.message || String(err)).slice(0, 2e3)}`);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
async function searchMarkerIssues(repo, bugId) {
|
|
1169
|
+
const out = await gh([
|
|
1170
|
+
"issue",
|
|
1171
|
+
"list",
|
|
1172
|
+
"-R",
|
|
1173
|
+
repo,
|
|
1174
|
+
"--state",
|
|
1175
|
+
"all",
|
|
1176
|
+
"--search",
|
|
1177
|
+
`"${bugId}" in:body`,
|
|
1178
|
+
"--json",
|
|
1179
|
+
"number,url,body,state",
|
|
1180
|
+
"--limit",
|
|
1181
|
+
"20"
|
|
1182
|
+
]);
|
|
1183
|
+
let issues;
|
|
1184
|
+
try {
|
|
1185
|
+
issues = JSON.parse(out || "[]");
|
|
1186
|
+
} catch {
|
|
1187
|
+
issues = [];
|
|
1188
|
+
}
|
|
1189
|
+
return issues.filter((i) => bodyOwnedBy(i.body, bugId)).map((i) => ({ number: i.number, url: i.url, state: i.state }));
|
|
1190
|
+
}
|
|
1191
|
+
async function verifyPersistedIssueMarker(repo, number, url, bugId) {
|
|
1192
|
+
let out;
|
|
1193
|
+
try {
|
|
1194
|
+
out = await gh(["issue", "view", String(number), "-R", repo, "--json", "number,url,state,body"]);
|
|
1195
|
+
} catch (err) {
|
|
1196
|
+
process.stderr.write(
|
|
1197
|
+
`[support-github-issue] persisted github_issue_url ${url} (issue #${number} in ${repo}) could not be verified (${err instanceof Error ? err.message : String(err)}) \u2014 dropped as a reconciliation candidate.
|
|
1198
|
+
`
|
|
1199
|
+
);
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
let parsed;
|
|
1203
|
+
try {
|
|
1204
|
+
parsed = JSON.parse(out);
|
|
1205
|
+
} catch {
|
|
1206
|
+
process.stderr.write(
|
|
1207
|
+
`[support-github-issue] persisted github_issue_url ${url} (issue #${number} in ${repo}) returned unparseable JSON from \`gh issue view\` \u2014 dropped as a reconciliation candidate.
|
|
1208
|
+
`
|
|
1209
|
+
);
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1212
|
+
if (!bodyOwnedBy(parsed.body, bugId)) {
|
|
1213
|
+
process.stderr.write(
|
|
1214
|
+
`[support-github-issue] persisted github_issue_url ${url} does not carry bug ${bugId}'s exact marker as its final content \u2014 dropped as a reconciliation candidate (it may have been set to an unrelated issue, e.g. via an admin back-link).
|
|
1215
|
+
`
|
|
1216
|
+
);
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|
|
1219
|
+
return { number: parsed.number, url: parsed.url, state: parsed.state };
|
|
1220
|
+
}
|
|
1221
|
+
async function closeDuplicateIssue(repo, number, canonicalNumber) {
|
|
1222
|
+
await gh([
|
|
1223
|
+
"issue",
|
|
1224
|
+
"close",
|
|
1225
|
+
String(number),
|
|
1226
|
+
"-R",
|
|
1227
|
+
repo,
|
|
1228
|
+
"--reason",
|
|
1229
|
+
"not planned",
|
|
1230
|
+
"--comment",
|
|
1231
|
+
`Duplicate of #${canonicalNumber} (concurrent triage)`
|
|
1232
|
+
]);
|
|
1233
|
+
}
|
|
1234
|
+
async function reconcileMarkerIssues(repo, candidates) {
|
|
1235
|
+
const byNumber = /* @__PURE__ */ new Map();
|
|
1236
|
+
for (const candidate of candidates) if (!byNumber.has(candidate.number)) byNumber.set(candidate.number, candidate);
|
|
1237
|
+
const unique = [...byNumber.values()];
|
|
1238
|
+
const canonical = unique.reduce((lowest, hit) => hit.number < lowest.number ? hit : lowest, unique[0]);
|
|
1239
|
+
for (const candidate of unique) {
|
|
1240
|
+
if (candidate.number === canonical.number) continue;
|
|
1241
|
+
try {
|
|
1242
|
+
await closeDuplicateIssue(repo, candidate.number, canonical.number);
|
|
1243
|
+
} catch {
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return canonical;
|
|
1247
|
+
}
|
|
1248
|
+
async function createIssue(repo, title, body, labels) {
|
|
1249
|
+
const out = await gh(
|
|
1250
|
+
["issue", "create", "-R", repo, "--title", title, "--body-file", "-", "--label", labels.join(",")],
|
|
1251
|
+
body
|
|
1252
|
+
);
|
|
1253
|
+
const url = out.trim().split("\n").filter(Boolean).pop() || "";
|
|
1254
|
+
const number = Number(url.match(/\/issues\/(\d+)/)?.[1]);
|
|
1255
|
+
if (!url || !Number.isFinite(number)) {
|
|
1256
|
+
throw new Error(`gh issue create returned an unexpected result: ${out.slice(0, 300)}`);
|
|
1257
|
+
}
|
|
1258
|
+
return { number, url, state: "OPEN" };
|
|
1259
|
+
}
|
|
1260
|
+
var knownRepoLabels = /* @__PURE__ */ new Map();
|
|
1261
|
+
var LABEL_COLORS = {
|
|
1262
|
+
bug: "d73a4a",
|
|
1263
|
+
"from:exe-support": "fbca04",
|
|
1264
|
+
"severity:p0": "b60205",
|
|
1265
|
+
"severity:p1": "d93f0b",
|
|
1266
|
+
"severity:p2": "fbca04",
|
|
1267
|
+
"severity:p3": "cccccc",
|
|
1268
|
+
"status:triaged": "1d76db",
|
|
1269
|
+
default: "5319e7"
|
|
1270
|
+
};
|
|
1271
|
+
function labelColor(label) {
|
|
1272
|
+
return LABEL_COLORS[label] ?? LABEL_COLORS.default;
|
|
1273
|
+
}
|
|
1274
|
+
function labelDescription(label) {
|
|
1275
|
+
if (label.startsWith("cluster:")) return "exe-support cluster";
|
|
1276
|
+
if (label.startsWith("product:")) return "exe-support product";
|
|
1277
|
+
return "created by exe-support triage";
|
|
1278
|
+
}
|
|
1279
|
+
async function listRepoLabels(repo) {
|
|
1280
|
+
const out = await gh(["label", "list", "-R", repo, "--limit", "1000", "--json", "name"]);
|
|
1281
|
+
let items;
|
|
1282
|
+
try {
|
|
1283
|
+
items = JSON.parse(out || "[]");
|
|
1284
|
+
} catch {
|
|
1285
|
+
items = [];
|
|
1286
|
+
}
|
|
1287
|
+
return new Set(items.map((i) => i.name));
|
|
1288
|
+
}
|
|
1289
|
+
async function ensureLabelsExist(repo, labels) {
|
|
1290
|
+
let known = knownRepoLabels.get(repo);
|
|
1291
|
+
if (!known) {
|
|
1292
|
+
known = await listRepoLabels(repo);
|
|
1293
|
+
knownRepoLabels.set(repo, known);
|
|
1294
|
+
}
|
|
1295
|
+
for (const label of labels) {
|
|
1296
|
+
if (known.has(label)) continue;
|
|
1297
|
+
try {
|
|
1298
|
+
await gh(["label", "create", label, "-R", repo, "--color", labelColor(label), "--description", labelDescription(label)]);
|
|
1299
|
+
} catch (err) {
|
|
1300
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1301
|
+
if (!/already exists/i.test(message)) throw err;
|
|
1302
|
+
}
|
|
1303
|
+
known.add(label);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
async function syncTriageToIssue(repo, canonical, bug) {
|
|
1307
|
+
const wasClosed = !!canonical.state && canonical.state.toUpperCase() === "CLOSED";
|
|
1308
|
+
if (wasClosed) await gh(["issue", "reopen", String(canonical.number), "-R", repo]);
|
|
1309
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1310
|
+
const summary = sanitizeIssueText(bug.summary) || "_No summary recorded._";
|
|
1311
|
+
const lines = [
|
|
1312
|
+
wasClosed ? `Re-triaged from exe-support on ${date} \u2014 reported again, reopening.` : `Re-triaged from exe-support on ${date} \u2014 updated triage details.`,
|
|
1313
|
+
"",
|
|
1314
|
+
"### Summary",
|
|
1315
|
+
"",
|
|
1316
|
+
summary
|
|
1317
|
+
];
|
|
1318
|
+
lines.push("");
|
|
1319
|
+
pushFactsTable(lines, bug);
|
|
1320
|
+
pushEvidenceSections(lines, bug);
|
|
1321
|
+
const commentBody = neutralizeBody(lines.join("\n"), repo, bug.product ?? null);
|
|
1322
|
+
await syncLabels(repo, canonical.number, bug);
|
|
1323
|
+
await gh(["issue", "comment", String(canonical.number), "-R", repo, "--body-file", "-"], commentBody);
|
|
1324
|
+
}
|
|
1325
|
+
async function pushBugToGithub(bug) {
|
|
1326
|
+
const repo = routeRepoForProduct(bug.product);
|
|
1327
|
+
if (!repo) {
|
|
1328
|
+
throw new Error(
|
|
1329
|
+
`No GitHub route configured for product '${bug.product ?? "unknown"}'. Pass push_to_github: false to skip, or triage with a supported product.`
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
const persistedNumber = persistedIssueNumber(bug.github_issue_url, repo);
|
|
1333
|
+
const persistedCandidate = persistedNumber !== null ? await verifyPersistedIssueMarker(repo, persistedNumber, bug.github_issue_url, bug.id) : null;
|
|
1334
|
+
const markerIssues = await searchMarkerIssues(repo, bug.id);
|
|
1335
|
+
const preCreateCandidates = persistedCandidate ? [persistedCandidate, ...markerIssues] : markerIssues;
|
|
1336
|
+
if (preCreateCandidates.length > 0) {
|
|
1337
|
+
const canonical2 = await reconcileMarkerIssues(repo, preCreateCandidates);
|
|
1338
|
+
await syncTriageToIssue(repo, canonical2, bug);
|
|
1339
|
+
const settled2 = await recheckCanonical(repo, canonical2, bug);
|
|
1340
|
+
return { issueUrl: settled2.url, issueNumber: settled2.number, repo, adopted: true };
|
|
1341
|
+
}
|
|
1342
|
+
const body = neutralizeBody(renderIssueBody(bug), repo, bug.product ?? null);
|
|
1343
|
+
const title = truncateTitle(sanitizeIssueText(bug.title || bug.summary));
|
|
1344
|
+
const labels = buildLabels(bug, repo);
|
|
1345
|
+
await ensureLabelsExist(repo, labels);
|
|
1346
|
+
const created = await createIssue(repo, title, body, labels);
|
|
1347
|
+
const postCreateMarkerIssues = await searchMarkerIssues(repo, bug.id);
|
|
1348
|
+
const canonical = await reconcileMarkerIssues(repo, [...postCreateMarkerIssues, created]);
|
|
1349
|
+
if (canonical.number !== created.number) await syncTriageToIssue(repo, canonical, bug);
|
|
1350
|
+
const settled = await recheckCanonical(repo, canonical, bug);
|
|
1351
|
+
return { issueUrl: settled.url, issueNumber: settled.number, repo, adopted: settled.number !== created.number };
|
|
1352
|
+
}
|
|
1353
|
+
function locksDir() {
|
|
1354
|
+
return join(process.env.EXE_OS_DIR ?? join(homedir(), ".exe-os"), "locks");
|
|
1355
|
+
}
|
|
1356
|
+
function lockPath(bugId) {
|
|
1357
|
+
const safe = bugId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
1358
|
+
return join(locksDir(), `support-github-${safe}.lock`);
|
|
1359
|
+
}
|
|
1360
|
+
var LOCK_WAIT_TIMEOUT_MS = 6e4;
|
|
1361
|
+
var LOCK_POLL_MS = 250;
|
|
1362
|
+
var GithubLockTimeoutError = class extends Error {
|
|
1363
|
+
constructor(message) {
|
|
1364
|
+
super(message);
|
|
1365
|
+
this.name = "GithubLockTimeoutError";
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
function sleep(ms) {
|
|
1369
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1370
|
+
}
|
|
1371
|
+
async function acquireBugLock(bugId) {
|
|
1372
|
+
mkdirSync(locksDir(), { recursive: true });
|
|
1373
|
+
const path2 = lockPath(bugId);
|
|
1374
|
+
const deadline = Date.now() + LOCK_WAIT_TIMEOUT_MS;
|
|
1375
|
+
const myToken = `${process.pid}:${randomUUID()}`;
|
|
1376
|
+
for (; ; ) {
|
|
1377
|
+
try {
|
|
1378
|
+
const fd = openSync(path2, "wx");
|
|
1379
|
+
try {
|
|
1380
|
+
writeSync(fd, myToken);
|
|
1381
|
+
} finally {
|
|
1382
|
+
closeSync(fd);
|
|
1383
|
+
}
|
|
1384
|
+
return () => {
|
|
1385
|
+
try {
|
|
1386
|
+
unlinkSync(path2);
|
|
1387
|
+
} catch (err) {
|
|
1388
|
+
const e = err;
|
|
1389
|
+
if (e.code !== "ENOENT") {
|
|
1390
|
+
process.stderr.write(
|
|
1391
|
+
`[support-github-issue] could not release bug lock for bug ${bugId} at ${path2}: ${e.code ?? e.message}
|
|
1392
|
+
`
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
const e = err;
|
|
1399
|
+
if (e.code !== "EEXIST") throw err;
|
|
1400
|
+
if (Date.now() >= deadline) {
|
|
1401
|
+
let ageText;
|
|
1402
|
+
try {
|
|
1403
|
+
ageText = `${Math.round((Date.now() - statSync(path2).mtimeMs) / 1e3)}s old`;
|
|
1404
|
+
} catch {
|
|
1405
|
+
ageText = "age unknown";
|
|
1406
|
+
}
|
|
1407
|
+
throw new GithubLockTimeoutError(
|
|
1408
|
+
`Could not push bug ${bugId} to GitHub: the per-bug lock ${path2} (${ageText}) was still held after ${LOCK_WAIT_TIMEOUT_MS / 1e3}s. Either another triage call for this bug is in progress on this host \u2014 wait for it to finish and retry \u2014 or a previous call crashed and left its lock behind, in which case delete that file and retry. Nothing was changed here.`
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
await sleep(Math.min(LOCK_POLL_MS, Math.max(0, deadline - Date.now())));
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
async function withBugGithubLock(bugId, fn) {
|
|
1416
|
+
const release = await acquireBugLock(bugId);
|
|
1417
|
+
try {
|
|
1418
|
+
return await fn();
|
|
1419
|
+
} finally {
|
|
1420
|
+
release();
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
|
|
935
1424
|
// src/mcp/tools/support-inbox.ts
|
|
936
1425
|
var DEFAULT_ENDPOINT = "https://api.askexe.com/admin/support/bug-reports";
|
|
937
1426
|
var DEFAULT_OWNER_ENDPOINT = "https://api.askexe.com/v1/support/bug-reports";
|
|
@@ -948,7 +1437,7 @@ function adminToken() {
|
|
|
948
1437
|
if (process.env.ASKEXE_SUPPORT_ADMIN_TOKEN) return process.env.ASKEXE_SUPPORT_ADMIN_TOKEN;
|
|
949
1438
|
if (process.env.EXE_SUPPORT_ADMIN_TOKEN) return process.env.EXE_SUPPORT_ADMIN_TOKEN;
|
|
950
1439
|
try {
|
|
951
|
-
const configPath =
|
|
1440
|
+
const configPath = join2(process.env.EXE_OS_DIR ?? join2(homedir2(), ".exe-os"), "config.json");
|
|
952
1441
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
953
1442
|
return config.support?.adminToken || config.support?.admin_token;
|
|
954
1443
|
} catch {
|
|
@@ -962,7 +1451,7 @@ function ownerEndpoint() {
|
|
|
962
1451
|
const routerUrl = process.env.API_ROUTER_URL?.replace(/\/+$/, "");
|
|
963
1452
|
let configured;
|
|
964
1453
|
try {
|
|
965
|
-
const configPath =
|
|
1454
|
+
const configPath = join2(process.env.EXE_OS_DIR ?? join2(homedir2(), ".exe-os"), "config.json");
|
|
966
1455
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
967
1456
|
configured = config.support?.bugReportEndpoint;
|
|
968
1457
|
} catch {
|
|
@@ -973,7 +1462,7 @@ function ownerEndpoint() {
|
|
|
973
1462
|
function ownerAuthHeaders() {
|
|
974
1463
|
let cloudApiKey;
|
|
975
1464
|
try {
|
|
976
|
-
const configPath =
|
|
1465
|
+
const configPath = join2(process.env.EXE_OS_DIR ?? join2(homedir2(), ".exe-os"), "config.json");
|
|
977
1466
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
978
1467
|
cloudApiKey = config.cloud?.apiKey;
|
|
979
1468
|
} catch {
|
|
@@ -1356,63 +1845,169 @@ function registerTriageBugReport(server) {
|
|
|
1356
1845
|
"unclear"
|
|
1357
1846
|
]).optional().describe("Triage classification: upstream_bug, customer_customization, emergency_hotfix, unclear"),
|
|
1358
1847
|
cluster: supportClusterClearableSchema.optional().describe("Root-cause class this bug belongs to \u2014 a kebab-case slug (feature d0970342). Fixes are dispatched per cluster; use list_bugs(cluster=...) to find every bug sharing one. Pass an empty string to CLEAR a mis-triaged cluster back to unset."),
|
|
1848
|
+
push_to_github: z3.boolean().optional().describe(
|
|
1849
|
+
"Feature d7ea536b: when status is set to 'triaged' (the moment a bug moves from the untriaged inbox onto the roadmap), file (or adopt) a GitHub Issue in the routed AskExe repo and immediately close this support record with disposition='migrated' + the issue URL \u2014 GitHub becomes the system of record. Defaults to true whenever status='triaged'. Pass false to just set status='triaged' the old way, with no GitHub push."
|
|
1850
|
+
),
|
|
1359
1851
|
...verificationArtifactInputSchema
|
|
1360
1852
|
}
|
|
1361
1853
|
},
|
|
1362
|
-
async ({ id, status, triage_notes, add_note, linked_task_id, linked_commit, fixed_version, product, classification, cluster, ...verification }) => {
|
|
1854
|
+
async ({ id, status, triage_notes, add_note, linked_task_id, linked_commit, fixed_version, product, classification, cluster, push_to_github, ...verification }) => {
|
|
1363
1855
|
const bugUrl = `${endpoint()}/${encodeURIComponent(sanitizeUpstreamId(id))}`;
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1856
|
+
const wantsGithubPush = status === "triaged" && push_to_github !== false;
|
|
1857
|
+
const errorResult = (text) => ({ isError: true, content: [{ type: "text", text }] });
|
|
1858
|
+
const finishClose = async (effectiveStatus, verificationFinal, githubPush) => {
|
|
1859
|
+
const attestsByIdentity = verificationFinal.verification_kind === "manual" || verificationFinal.verification_kind === "ops_transcript" || verificationFinal.disposition !== void 0 && verificationFinal.disposition !== "fixed" && verificationFinal.disposition !== "migrated";
|
|
1860
|
+
let authorIdentities = [];
|
|
1861
|
+
if (isVerifiedStatus(effectiveStatus) && attestsByIdentity) {
|
|
1862
|
+
try {
|
|
1863
|
+
const row = await requestJson(bugUrl);
|
|
1864
|
+
authorIdentities = [row?.agent_id, row?.license_email];
|
|
1865
|
+
} catch {
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
const resolved = resolveVerificationArtifact(effectiveStatus, verificationFinal, { authorIdentities });
|
|
1869
|
+
if (!resolved.ok) {
|
|
1870
|
+
return errorResult(resolved.message);
|
|
1871
|
+
}
|
|
1872
|
+
const attribution = assertVerdictAttribution(effectiveStatus, resolved);
|
|
1873
|
+
if (!attribution.ok) {
|
|
1874
|
+
return errorResult(attribution.message);
|
|
1875
|
+
}
|
|
1876
|
+
const delivery = parseDeliveryProof(verificationFinal.delivery_proof);
|
|
1877
|
+
if (!delivery.ok) {
|
|
1878
|
+
return errorResult(delivery.message);
|
|
1879
|
+
}
|
|
1880
|
+
const data = await requestJson(bugUrl, {
|
|
1881
|
+
method: "PATCH",
|
|
1882
|
+
body: sanitizedUpstreamBody({
|
|
1883
|
+
status: effectiveStatus,
|
|
1884
|
+
triage_notes,
|
|
1885
|
+
add_note,
|
|
1886
|
+
linked_task_id,
|
|
1887
|
+
linked_commit,
|
|
1888
|
+
fixed_version,
|
|
1889
|
+
product,
|
|
1890
|
+
classification,
|
|
1891
|
+
cluster,
|
|
1892
|
+
verification_artifact: resolved.artifact,
|
|
1893
|
+
delivery_proof: delivery.value,
|
|
1894
|
+
// The disposition travels with the close: the server gates on it, and stores
|
|
1895
|
+
// it so the record reads as "closed because there was nothing to fix" rather
|
|
1896
|
+
// than as an unexplained close.
|
|
1897
|
+
disposition: verificationFinal.disposition,
|
|
1898
|
+
disposition_reason: verificationFinal.disposition_reason,
|
|
1899
|
+
superseded_by: verificationFinal.superseded_by,
|
|
1900
|
+
disposition_verifier: verificationFinal.disposition_verifier,
|
|
1901
|
+
superseded_coverage: verificationFinal.superseded_coverage,
|
|
1902
|
+
github_issue_url: verificationFinal.github_issue_url,
|
|
1903
|
+
symptoms: verificationFinal.symptoms,
|
|
1904
|
+
attribution: resolved.attribution
|
|
1905
|
+
}, "support-inbox:triage_bug")
|
|
1906
|
+
});
|
|
1907
|
+
let response = fixed_version && !status ? withStatusNotice(
|
|
1908
|
+
data,
|
|
1909
|
+
`fixed_version ${fixed_version} recorded. Status was not changed and the bug was NOT closed. To close it, pass status: "closed" explicitly.`
|
|
1910
|
+
) : data;
|
|
1911
|
+
if (githubPush && response && typeof response === "object" && !Array.isArray(response)) {
|
|
1912
|
+
response = {
|
|
1913
|
+
...response,
|
|
1914
|
+
github_issue_url: githubPush.issueUrl,
|
|
1915
|
+
github_issue_repo: githubPush.repo,
|
|
1916
|
+
github_issue_adopted: githubPush.adopted
|
|
1917
|
+
};
|
|
1371
1918
|
}
|
|
1919
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1920
|
+
};
|
|
1921
|
+
if (!wantsGithubPush) {
|
|
1922
|
+
return finishClose(status, verification);
|
|
1372
1923
|
}
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1924
|
+
let row1;
|
|
1925
|
+
try {
|
|
1926
|
+
row1 = await requestJson(bugUrl);
|
|
1927
|
+
} catch (err) {
|
|
1928
|
+
return errorResult(
|
|
1929
|
+
`Could not push bug ${id} to GitHub: failed to fetch the bug record first (${err instanceof Error ? err.message : String(err)}). Nothing was changed.`
|
|
1930
|
+
);
|
|
1376
1931
|
}
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1932
|
+
const canonicalId = row1.id?.trim() || id;
|
|
1933
|
+
const effectiveProduct = product ?? row1.product;
|
|
1934
|
+
const repo = routeRepoForProduct(effectiveProduct);
|
|
1935
|
+
if (!repo) {
|
|
1936
|
+
return errorResult(
|
|
1937
|
+
`No GitHub route configured for product '${effectiveProduct ?? "unknown"}'. Pass push_to_github: false to skip, or triage with a supported product.`
|
|
1938
|
+
);
|
|
1380
1939
|
}
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1383
|
-
|
|
1940
|
+
const placeholderIssueUrl = `https://github.com/${repo}/issues/1`;
|
|
1941
|
+
const precheckVerification = { ...verification };
|
|
1942
|
+
precheckVerification.disposition = "migrated";
|
|
1943
|
+
precheckVerification.github_issue_url = placeholderIssueUrl;
|
|
1944
|
+
const precheckResolved = resolveVerificationArtifact("closed", precheckVerification, { authorIdentities: [] });
|
|
1945
|
+
if (!precheckResolved.ok) {
|
|
1946
|
+
return errorResult(precheckResolved.message);
|
|
1947
|
+
}
|
|
1948
|
+
const precheckAttribution = assertVerdictAttribution("closed", precheckResolved);
|
|
1949
|
+
if (!precheckAttribution.ok) {
|
|
1950
|
+
return errorResult(precheckAttribution.message);
|
|
1951
|
+
}
|
|
1952
|
+
const precheckDelivery = parseDeliveryProof(verification.delivery_proof);
|
|
1953
|
+
if (!precheckDelivery.ok) {
|
|
1954
|
+
return errorResult(precheckDelivery.message);
|
|
1955
|
+
}
|
|
1956
|
+
try {
|
|
1957
|
+
return await withBugGithubLock(canonicalId, async () => {
|
|
1958
|
+
let row2;
|
|
1959
|
+
try {
|
|
1960
|
+
row2 = await requestJson(bugUrl);
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
return errorResult(
|
|
1963
|
+
`Could not push bug ${id} to GitHub: failed to re-fetch the bug record inside the lock (${err instanceof Error ? err.message : String(err)}). Nothing was changed.`
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
const bugForIssue = {
|
|
1967
|
+
id: canonicalId,
|
|
1968
|
+
title: row2.title ?? void 0,
|
|
1969
|
+
summary: row2.summary ?? void 0,
|
|
1970
|
+
severity: row2.severity ?? void 0,
|
|
1971
|
+
product: product ?? row2.product,
|
|
1972
|
+
classification: classification ?? row2.classification,
|
|
1973
|
+
cluster: cluster ?? row2.cluster,
|
|
1974
|
+
created_at: row2.created_at ?? void 0,
|
|
1975
|
+
triaged_at: row2.triaged_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1976
|
+
fixed_version: fixed_version ?? row2.fixed_version,
|
|
1977
|
+
package_version: row2.package_version ?? void 0,
|
|
1978
|
+
license_plan: row2.license_plan ?? void 0,
|
|
1979
|
+
triage_notes: triage_notes ?? row2.triage_notes,
|
|
1980
|
+
github_issue_url: row2.github_issue_url ?? void 0,
|
|
1981
|
+
customer_impact: row2.customer_impact ?? void 0,
|
|
1982
|
+
reproduction_steps: row2.reproduction_steps_json ?? void 0,
|
|
1983
|
+
expected: row2.expected ?? void 0,
|
|
1984
|
+
actual: row2.actual ?? void 0,
|
|
1985
|
+
workaround: row2.workaround ?? void 0,
|
|
1986
|
+
progress_log: row2.progress_log ?? void 0,
|
|
1987
|
+
add_note: add_note ?? void 0,
|
|
1988
|
+
observed_kind: row2.observed_kind ?? void 0,
|
|
1989
|
+
evidence_pointer: row2.evidence_pointer ?? void 0,
|
|
1990
|
+
local_patch_diff: row2.local_patch_diff ?? void 0
|
|
1991
|
+
};
|
|
1992
|
+
let githubPush;
|
|
1993
|
+
try {
|
|
1994
|
+
githubPush = await pushBugToGithub(bugForIssue);
|
|
1995
|
+
} catch (err) {
|
|
1996
|
+
return errorResult(
|
|
1997
|
+
`Could not push bug ${id} to GitHub: ${err instanceof Error ? err.message : String(err)}. The record was left at its current status; nothing was closed.`
|
|
1998
|
+
);
|
|
1999
|
+
}
|
|
2000
|
+
const finalVerification = { ...verification };
|
|
2001
|
+
finalVerification.disposition = "migrated";
|
|
2002
|
+
finalVerification.github_issue_url = githubPush.issueUrl;
|
|
2003
|
+
return finishClose("closed", finalVerification, githubPush);
|
|
2004
|
+
});
|
|
2005
|
+
} catch (err) {
|
|
2006
|
+
if (err instanceof GithubLockTimeoutError) {
|
|
2007
|
+
return errorResult(err.message);
|
|
2008
|
+
}
|
|
2009
|
+
throw err;
|
|
1384
2010
|
}
|
|
1385
|
-
const data = await requestJson(bugUrl, {
|
|
1386
|
-
method: "PATCH",
|
|
1387
|
-
body: sanitizedUpstreamBody({
|
|
1388
|
-
status,
|
|
1389
|
-
triage_notes,
|
|
1390
|
-
add_note,
|
|
1391
|
-
linked_task_id,
|
|
1392
|
-
linked_commit,
|
|
1393
|
-
fixed_version,
|
|
1394
|
-
product,
|
|
1395
|
-
classification,
|
|
1396
|
-
cluster,
|
|
1397
|
-
verification_artifact: resolved.artifact,
|
|
1398
|
-
delivery_proof: delivery.value,
|
|
1399
|
-
// The disposition travels with the close: the server gates on it, and stores
|
|
1400
|
-
// it so the record reads as "closed because there was nothing to fix" rather
|
|
1401
|
-
// than as an unexplained close.
|
|
1402
|
-
disposition: verification.disposition,
|
|
1403
|
-
disposition_reason: verification.disposition_reason,
|
|
1404
|
-
superseded_by: verification.superseded_by,
|
|
1405
|
-
disposition_verifier: verification.disposition_verifier,
|
|
1406
|
-
superseded_coverage: verification.superseded_coverage,
|
|
1407
|
-
symptoms: verification.symptoms,
|
|
1408
|
-
attribution: resolved.attribution
|
|
1409
|
-
}, "support-inbox:triage_bug")
|
|
1410
|
-
});
|
|
1411
|
-
const response = fixed_version && !status ? withStatusNotice(
|
|
1412
|
-
data,
|
|
1413
|
-
`fixed_version ${fixed_version} recorded. Status was not changed and the bug was NOT closed. To close it, pass status: "closed" explicitly.`
|
|
1414
|
-
) : data;
|
|
1415
|
-
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1416
2011
|
}
|
|
1417
2012
|
);
|
|
1418
2013
|
}
|