gsd-pi 2.52.0-dev.585e355 → 2.52.0-dev.655ad8a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -32
- package/dist/headless-query.js +1 -1
- package/dist/resources/extensions/get-secrets-from-user.js +7 -0
- package/dist/resources/extensions/gsd/auto/phases.js +28 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +5 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +70 -14
- package/dist/resources/extensions/gsd/auto.js +22 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -10
- package/dist/resources/extensions/gsd/guided-flow.js +4 -3
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
- package/dist/resources/extensions/gsd/state.js +5 -11
- package/dist/resources/extensions/shared/rtk.js +9 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-024d82be84800e52.js → webpack-bca0e732db0dcec3.js} +1 -1
- package/package.json +1 -1
- package/src/resources/extensions/get-secrets-from-user.ts +8 -0
- package/src/resources/extensions/gsd/auto/phases.ts +38 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +6 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +73 -14
- package/src/resources/extensions/gsd/auto.ts +21 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +4 -11
- package/src/resources/extensions/gsd/guided-flow.ts +4 -3
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
- package/src/resources/extensions/gsd/state.ts +5 -10
- package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +28 -27
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
- package/src/resources/extensions/shared/rtk.ts +10 -1
- package/dist/web/standalone/.next/static/chunks/4024.21054f459af5cc78.js +0 -9
- /package/dist/web/standalone/.next/static/{KTe1kB5nPLQFIIFz2OcmI → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KTe1kB5nPLQFIIFz2OcmI → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,a,f,c,d,b,t,r,o,n={},i={};function l(e){var a=i[e];if(void 0!==a)return a.exports;var f=i[e]={exports:{}},c=!0;try{n[e].call(f.exports,f,f.exports,l),c=!1}finally{c&&delete i[e]}return f.exports}l.m=n,e=[],l.O=(a,f,c,d)=>{if(f){d=d||0;for(var b=e.length;b>0&&e[b-1][2]>d;b--)e[b]=e[b-1];e[b]=[f,c,d];return}for(var t=1/0,b=0;b<e.length;b++){for(var[f,c,d]=e[b],r=!0,o=0;o<f.length;o++)(!1&d||t>=d)&&Object.keys(l.O).every(e=>l.O[e](f[o]))?f.splice(o--,1):(r=!1,d<t&&(t=d));if(r){e.splice(b--,1);var n=c();void 0!==n&&(a=n)}}return a},l.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return l.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,l.t=function(e,c){if(1&c&&(e=this(e)),8&c||"object"==typeof e&&e&&(4&c&&e.__esModule||16&c&&"function"==typeof e.then))return e;var d=Object.create(null);l.r(d);var b={};a=a||[null,f({}),f([]),f(f)];for(var t=2&c&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach(a=>b[a]=()=>e[a]);return b.default=()=>e,l.d(d,b),d},l.d=(e,a)=>{for(var f in a)l.o(a,f)&&!l.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},l.f={},l.e=e=>Promise.all(Object.keys(l.f).reduce((a,f)=>(l.f[f](e,a),a),[])),l.u=e=>4986===e?"static/chunks/4986-c2fc8845ce785303.js":"static/chunks/"+(({535:"4ca0cff5",1290:"cee15710",1630:"53c1bd3f",2577:"d1c28714",3879:"cfdf2ac7",3888:"e868780c",4763:"4402d2ac",4814:"799ebd4e",6079:"363642f4",6666:"570e4624",6814:"7d29de82",7442:"92e53eb0",8835:"ce16f5a9",9312:"1cd6e1d3"})[e]||e)+"."+({10:"6cf001c181ce1098",34:"ce581867cf95e24b",36:"b4a553bf2106f6d3",194:"76dbdc07cdc2311d",214:"f6bba63dfa159e01",252:"a9e22657cbf67b42",327:"8ecab0b86d52b597",376:"9e742ff6919b2b54",392:"3cad93691f1b7360",400:"59979e0d3ae126e4",425:"9a3434a28926566a",535:"07efe2bc8f09d72e",541:"cfa15b606745131a",579:"33fc87fb95163c6a",583:"b3efc73cb21097e2",624:"2dd909fbfce98c5e",640:"5bf1e25d0bddf875",698:"e0dda03fd303b96b",794:"06b1ae4fc9cc10a9",816:"f909c891b91aa79f",830:"e49b226c07876df4",840:"a9c535f8868cc4bd",862:"fe3b86ecfb9c0716",893:"c469257bbbbca4f5",966:"57e4cd93c2368d34",968:"237f19aca13543fe",1078:"02294b2934d5bf21",1142:"8248bfb76c695146",1161:"06b33878b495da50",1184:"e80a999422621ed9",1188:"1d4ce94ddc297119",1198:"2a5c215f01a8b74d",1215:"88ed89521e915107",1219:"e27b0bd10b029e40",1247:"64e212daa5bb3925",1248:"36af3903f037c1f5",1274:"ce6906b1fe2e04b8",1280:"1651bb5167170457",1290:"869cef5f741d40c2",1335:"716cc5924662708e",1365:"d7391145ca7f8791",1379:"03e1e0f31bdaa2cc",1410:"77acea37535dbbef",1413:"117c5958c59cc695",1453:"3c24c777a3deca2d",1456:"217c3832b3e76b7f",1501:"549af2c91a889a08",1534:"918a25b2e3daab22",1556:"96abc9ff91b0c383",1583:"03a06dbdde85ac56",1595:"ee61519fde230f60",1630:"2911e2bac119d910",1642:"8c00543baa1aef54",1656:"a9efc78185a5a85f",1664:"6d5b5e3112b66906",1898:"e07b2b1c5e789b06",1932:"b0aea9b52cabe5e8",1977:"a06c8e8d2198f765",2008:"817d0885545aaea9",2013:"598558c40e51e107",2031:"3877441c49bff5cd",2041:"00f4fa0ab26c6ba5",2062:"4a0ab3400fea0e34",2107:"c627112b02b9e1c8",2130:"441ae0f68863efeb",2160:"e38d781fd5c4cde0",2179:"1bf5fe315e6e132c",2215:"9d2d6fbe90ffcc80",2278:"0b14de1cb2041bfd",2349:"ca15d465c4260b4b",2374:"7560cc5c4b8ed6b0",2397:"0e4dce0a557ac7cf",2403:"3dda71b6482dce3b",2485:"3188870375e9fbee",2489:"fcc70bd67329a70e",2501:"4e65b56602faa956",2503:"bb9d3528c3c7ccae",2504:"159b28843e61aae9",2577:"f52cffdd449a2d14",2614:"8349e4b407470a30",2710:"fe0656d4ebae4d30",2728:"5fed9ac13dfcd1d1",2735:"5a3e65a580bd5af9",2747:"1d85d388314f2904",2765:"2c6d9772af50feed",2783:"e8bbf2c794ef9750",2812:"dcd8179a6b1d76c9",2839:"c9a657d5b4031a19",2895:"0339e755e79ee794",2937:"7e724516d5e6ce42",2954:"7d8daeae6410d4a4",2957:"2dd93db1a16e96b0",2964:"1a0e15f7327680a2",3072:"b6da96c10080c967",3074:"911584369786c26c",3077:"bf82c0c332cc9fec",3082:"159e4ab8f0572597",3095:"8cd478c42cee505a",3111:"1cf85db2faeb20cc",3175:"538ce7aec634bddb",3186:"3665756f8aae3eb7",3194:"5a331fb5e3dc34e9",3229:"5e91f7d0b135266b",3274:"858f7f9216c8b074",3286:"196c508356bb0b66",3288:"f23c8a5183e6b910",3290:"b5ba2646ad49c9fd",3304:"16305e84f4ff6598",3313:"471138e5504646a9",3324:"85e21e3313d0901c",3392:"460f5a753531f501",3419:"78b520dab7e2f96d",3437:"0ad1ecc8c5b8a679",3476:"246c30b47bded3b7",3483:"fc2a0b1185dbaa5d",3492:"ca55498822ad7796",3526:"24826331ab265b39",3606:"e5c833cdda239583",3633:"2526b2d018636ff0",3782:"8d7b66d0e37dbe76",3787:"78ebe68a043f50ce",3860:"be5b243bf7d6618c",3873:"72a9a21509f713f7",3879:"f50abf4e93e943ea",3888:"f7831045ac345aaa",3942:"085da8d58242eeab",3979:"cea8623f6e9f83ea",4024:"21054f459af5cc78",4053:"90d71fcbe4ffd852",4080:"08a21dae9e93c547",4163:"c6ebefdd9aa5c358",4174:"b6ff75dd91a2a32e",4223:"c10556cd92fc8018",4242:"3a66c58375424a5b",4275:"8f2e531757c2a813",4295:"6c0f4838b0c9c69d",4309:"a887a10e84c44f9e",4350:"b9d80827e8eee01a",4357:"ac4f251cdac34fbe",4358:"f89b14cf7a988731",4370:"ac13b62c811f7ede",4417:"0b5ee948c3518db3",4447:"f86b52aea068b189",4474:"053807fa34066566",4539:"559c223da16b0282",4540:"03df20c499bca840",4553:"ce3eab65a260353e",4567:"7dc81a6e1c7df565",4583:"2a5df6eb3a6ea30b",4593:"676ac488744e1af5",4608:"1ff246d6b4c771f8",4634:"0332a56fdb8e26c0",4650:"61aec912b756287b",4659:"0b14de1cb2041bfd",4678:"867dfae26694be02",4763:"d0d1b1777a45e0b2",4801:"17596dbc1818c262",4814:"ccb85c56e9216a38",4823:"907850963b2bcb70",4829:"402ec60139d36417",4846:"c563765de65a34c7",4900:"b723a916eafdf743",4903:"004f583a12223dac",4963:"0f6678151a159143",4969:"1cb10af9489ea295",4976:"8870319ffbd1c31f",5005:"73745d7fcae6989e",5025:"b597364f0cf8b85a",5061:"025d30c3123eeaf6",5136:"ac897c2a56ee392f",5183:"2e5c895a2be76262",5269:"2e771096652dc113",5320:"00f00028b9163a43",5326:"adc4bf49a22f4e67",5331:"4d5d42e5253dbee2",5347:"3192e0021174aaa8",5375:"ebc026e6140b52f1",5424:"4d62f7ee887cd8b9",5482:"0907421e6bf5eeec",5491:"5cc285c4b84dac30",5498:"117ef4b6035a90c5",5518:"6c3dc9afe81a566b",5520:"eab85d7487e77510",5553:"75df19e3cc1246d6",5575:"3d90c643343a1329",5645:"0b86853ae26d9ee3",5670:"2a1b27a6fdb7aa6b",5690:"d30877807cf5c7eb",5712:"574fca2d5f06483a",5728:"8ef773d61765855e",5750:"aa57d25b74640d23",5755:"00015c284ed6fb39",5920:"9db223329ee9e11a",5922:"ce56021f8cc6ebbc",5937:"0827b5b3eb831ff0",5968:"63d5869783fad06f",5997:"226c07d9e6c496e0",6046:"00d36aea7fd5b147",6079:"f9053a63f1b97508",6089:"2dd351186ec85cc3",6099:"43e6595fcf24fc33",6110:"5ce3f75fced27aaf",6144:"f967a8228bcdf663",6155:"19719cff570d6559",6166:"ecd82a9dcb484b97",6290:"e14cf4fc52dd4539",6293:"5914fa73a9f7e777",6311:"5b9c1f74df9a8f67",6331:"758f2f66b92cada9",6339:"bc9301cc22898be0",6360:"ff0a9063773daeeb",6402:"a0070d7688ed986b",6412:"089ee787a294d10b",6455:"12b78a2660d609eb",6563:"5d618b608750f4dc",6572:"ca2463823b9b01a0",6580:"75d53830b434451f",6588:"0fbca957af7d9e6a",6647:"584c5d5cd8dfdb5a",6666:"a82467c542429379",6686:"796c782c33ab8ca9",6701:"bff0efb979f71a17",6704:"f280f0ad0f5d8644",6729:"77a5381ac8f5c9ae",6741:"06fdaf122961074e",6814:"30ff86a90cbfd921",6846:"91283f709c40802c",6859:"bacad166ee995fe0",6887:"6c81234d73740fb9",6927:"aa3914b5fb0d14d4",6931:"3c90e9fe0f7f1e66",6938:"0ccf683bd8aa8410",6948:"2719ed8731963209",6959:"5a803faf27f88e9f",7021:"b71240b1d5f6fbe4",7040:"0b14de1cb2041bfd",7041:"174bf29bd837f06d",7082:"fc816f91214026d7",7113:"39704408fef3d26e",7130:"8d24694735826c22",7142:"dbd2cf8141eece5e",7152:"c7b7f1f5e9622f21",7227:"a6b2f01487bb3d9d",7258:"6cbe24c3bcb63d1d",7425:"8b47c8e398a12dd8",7442:"097194be4a0e7d55",7455:"71d54397710b923c",7465:"867e8ff655666413",7524:"9528295a19a5837a",7525:"f433aaf1fe40c90a",7557:"bdc743175125b3d8",7610:"b1439345dbcf285d",7625:"ab66bd50d2fb61a4",7635:"166d83de1d29e758",7636:"bf91320a9ff695af",7785:"1402a4110c300764",7799:"40b047a634f96a24",7819:"3c56f48c0dc5ad5d",7844:"2bb29faa262f313e",7846:"c9705c044ab8f87a",7884:"390ae2efbbf230c4",7889:"af3e581842f34c28",7921:"c361f794cc208e06",7977:"80e4daa080a79c39",8113:"907baefc7227cfb8",8132:"74491162f08af899",8192:"5918d83ac6a0e2dc",8243:"1450514f8390977e",8257:"dd8f651f1a43fee2",8288:"9bd1d26060cb00a1",8318:"81c7ac586fcbb728",8406:"955ccfbb4b70b8c3",8430:"b1f802dcffa41626",8432:"bd66ac287c569996",8457:"b61d96d8d30215fc",8496:"046efd6301dd804f",8545:"be0c9eea6aae5971",8555:"ab3ee6358f1d64da",8656:"2ceb4e5ff5df2fca",8670:"90ede75068758e82",8704:"a1003918da6654da",8773:"614f1f4f0f845c5e",8835:"5c7821b201f35593",8848:"7c6e47cca9f0059a",8921:"fb24a4d4d4d3265b",8947:"31d3d834d8281fd9",8977:"01b9c429327004e9",9005:"33cf91e617920d4f",9006:"11537833945ec4b8",9015:"c4e40321a6503a1b",9136:"191be42a2fee842c",9178:"48a90097ee3f0b0c",9186:"3af6fcd13ab752fa",9189:"3e9d29bf275ec462",9220:"bc767ebb5adb9f49",9224:"401f9320ee58570b",9240:"d38ddbe94e0bf128",9267:"fbfd65ea31e7448c",9294:"a20485f3282321b3",9302:"726b065f2df0323a",9312:"8121a74b2042bff3",9377:"f9db706e76f04afe",9382:"bc0e11ecc88dd62c",9421:"a5c1dbcfbfdd8f52",9448:"2668b3cd408e86de",9466:"c9d8f45d14235087",9521:"e1240eb862eb32dc",9547:"7729788fff21926f",9565:"8de0671f99d12abe",9569:"2f36b2b1c2f838d7",9605:"dfac539f89cea7a2",9615:"3b62c13af671f714",9648:"8235b6fea7087b3a",9666:"a515fa6d89a71f1c",9680:"d5ceac8967e0b6a8",9690:"7773c72f0eff6dec",9841:"422321143547591a",9842:"3b71b65b30d8ef2a",9996:"18b7bca2f0ab222e"})[e]+".js",l.miniCssF=e=>"static/css/659eccb5db697b76.css",l.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),l.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},l.l=(e,a,f,d)=>{if(c[e])return void c[e].push(a);if(void 0!==f)for(var b,t,r=document.getElementsByTagName("script"),o=0;o<r.length;o++){var n=r[o];if(n.getAttribute("src")==e||n.getAttribute("data-webpack")=="_N_E:"+f){b=n;break}}b||(t=!0,(b=document.createElement("script")).charset="utf-8",b.timeout=120,l.nc&&b.setAttribute("nonce",l.nc),b.setAttribute("data-webpack","_N_E:"+f),b.src=l.tu(e)),c[e]=[a];var i=(a,f)=>{b.onerror=b.onload=null,clearTimeout(u);var d=c[e];if(delete c[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach(e=>e(f)),a)return a(f)},u=setTimeout(i.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=i.bind(null,b.onerror),b.onload=i.bind(null,b.onload),t&&document.head.appendChild(b)},l.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.tt=()=>(void 0===d&&(d={createScriptURL:e=>e},"u">typeof trustedTypes&&trustedTypes.createPolicy&&(d=trustedTypes.createPolicy("nextjs#bundler",d))),d),l.tu=e=>l.tt().createScriptURL(e),l.p="/_next/",b={8068:0},l.f.miniCss=(e,a)=>{if(b[e])a.push(b[e]);else 0!==b[e]&&({1838:1})[e]&&a.push(b[e]=new Promise((a,f)=>{var c,d=l.miniCssF(e),b=l.p+d;if(((e,a)=>{for(var f=document.getElementsByTagName("link"),c=0;c<f.length;c++){var d=f[c],b=d.getAttribute("data-href")||d.getAttribute("href");if("stylesheet"===d.rel&&(b===e||b===a))return d}for(var t=document.getElementsByTagName("style"),c=0;c<t.length;c++){var d=t[c],b=d.getAttribute("data-href");if(b===e||b===a)return d}})(d,b))return a();(c=document.createElement("link")).rel="stylesheet",c.type="text/css",c.onerror=c.onload=d=>{if(c.onerror=c.onload=null,"load"===d.type)a();else{var t=d&&("load"===d.type?"missing":d.type),r=d&&d.target&&d.target.href||b,o=Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.type=t,o.request=r,c.parentNode.removeChild(c),f(o)}},c.href=b,function(e){if("function"==typeof _N_E_STYLE_LOAD){let{href:a,onload:f,onerror:c}=e;_N_E_STYLE_LOAD(0===a.indexOf(window.location.origin)?new URL(a).pathname:a).then(()=>null==f?void 0:f.call(e,{type:"load"}),()=>null==c?void 0:c.call(e,{}))}else document.head.appendChild(e)}(c)}).then(()=>{b[e]=0},a=>{throw delete b[e],a}))},t={8068:0,2557:0,7513:0},l.f.j=(e,a)=>{var f=l.o(t,e)?t[e]:void 0;if(0!==f)if(f)a.push(f[2]);else if(/^(1838|2557|7513|8068)$/.test(e))t[e]=0;else{var c=new Promise((a,c)=>f=t[e]=[a,c]);a.push(f[2]=c);var d=l.p+l.u(e),b=Error();l.l(d,a=>{if(l.o(t,e)&&(0!==(f=t[e])&&(t[e]=void 0),f)){var c=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;b.message="Loading chunk "+e+" failed.\n("+c+": "+d+")",b.name="ChunkLoadError",b.type=c,b.request=d,f[1](b)}},"chunk-"+e,e)}},l.O.j=e=>0===t[e],r=(e,a)=>{var f,c,[d,b,r]=a,o=0;if(d.some(e=>0!==t[e])){for(f in b)l.o(b,f)&&(l.m[f]=b[f]);if(r)var n=r(l)}for(e&&e(a);o<d.length;o++)c=d[o],l.o(t,c)&&t[c]&&t[c][0](),t[c]=0;return l.O(n)},(o=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(r.bind(null,0)),o.push=r.bind(null,o.push.bind(o)),l.nc=void 0})();
|
|
1
|
+
(()=>{"use strict";var e,a,f,c,d,b,t,r,o,n={},i={};function l(e){var a=i[e];if(void 0!==a)return a.exports;var f=i[e]={exports:{}},c=!0;try{n[e].call(f.exports,f,f.exports,l),c=!1}finally{c&&delete i[e]}return f.exports}l.m=n,e=[],l.O=(a,f,c,d)=>{if(f){d=d||0;for(var b=e.length;b>0&&e[b-1][2]>d;b--)e[b]=e[b-1];e[b]=[f,c,d];return}for(var t=1/0,b=0;b<e.length;b++){for(var[f,c,d]=e[b],r=!0,o=0;o<f.length;o++)(!1&d||t>=d)&&Object.keys(l.O).every(e=>l.O[e](f[o]))?f.splice(o--,1):(r=!1,d<t&&(t=d));if(r){e.splice(b--,1);var n=c();void 0!==n&&(a=n)}}return a},l.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return l.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,l.t=function(e,c){if(1&c&&(e=this(e)),8&c||"object"==typeof e&&e&&(4&c&&e.__esModule||16&c&&"function"==typeof e.then))return e;var d=Object.create(null);l.r(d);var b={};a=a||[null,f({}),f([]),f(f)];for(var t=2&c&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach(a=>b[a]=()=>e[a]);return b.default=()=>e,l.d(d,b),d},l.d=(e,a)=>{for(var f in a)l.o(a,f)&&!l.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},l.f={},l.e=e=>Promise.all(Object.keys(l.f).reduce((a,f)=>(l.f[f](e,a),a),[])),l.u=e=>4986===e?"static/chunks/4986-c2fc8845ce785303.js":"static/chunks/"+(({535:"4ca0cff5",1290:"cee15710",1630:"53c1bd3f",2577:"d1c28714",3879:"cfdf2ac7",3888:"e868780c",4763:"4402d2ac",4814:"799ebd4e",6079:"363642f4",6666:"570e4624",6814:"7d29de82",7442:"92e53eb0",8835:"ce16f5a9",9312:"1cd6e1d3"})[e]||e)+"."+({10:"6cf001c181ce1098",34:"ce581867cf95e24b",36:"b4a553bf2106f6d3",194:"76dbdc07cdc2311d",214:"f6bba63dfa159e01",252:"a9e22657cbf67b42",327:"8ecab0b86d52b597",376:"9e742ff6919b2b54",392:"3cad93691f1b7360",400:"59979e0d3ae126e4",425:"9a3434a28926566a",535:"07efe2bc8f09d72e",541:"cfa15b606745131a",579:"33fc87fb95163c6a",583:"b3efc73cb21097e2",624:"2dd909fbfce98c5e",640:"5bf1e25d0bddf875",698:"e0dda03fd303b96b",794:"06b1ae4fc9cc10a9",816:"f909c891b91aa79f",830:"e49b226c07876df4",840:"a9c535f8868cc4bd",862:"fe3b86ecfb9c0716",893:"c469257bbbbca4f5",966:"57e4cd93c2368d34",968:"237f19aca13543fe",1078:"02294b2934d5bf21",1142:"8248bfb76c695146",1161:"06b33878b495da50",1184:"e80a999422621ed9",1188:"1d4ce94ddc297119",1198:"2a5c215f01a8b74d",1215:"88ed89521e915107",1219:"e27b0bd10b029e40",1247:"64e212daa5bb3925",1248:"36af3903f037c1f5",1274:"ce6906b1fe2e04b8",1280:"1651bb5167170457",1290:"869cef5f741d40c2",1335:"716cc5924662708e",1365:"d7391145ca7f8791",1379:"03e1e0f31bdaa2cc",1410:"77acea37535dbbef",1413:"117c5958c59cc695",1453:"3c24c777a3deca2d",1456:"217c3832b3e76b7f",1501:"549af2c91a889a08",1534:"918a25b2e3daab22",1556:"96abc9ff91b0c383",1583:"03a06dbdde85ac56",1595:"ee61519fde230f60",1630:"2911e2bac119d910",1642:"8c00543baa1aef54",1656:"a9efc78185a5a85f",1664:"6d5b5e3112b66906",1898:"e07b2b1c5e789b06",1932:"b0aea9b52cabe5e8",1977:"a06c8e8d2198f765",2008:"817d0885545aaea9",2013:"598558c40e51e107",2031:"3877441c49bff5cd",2041:"00f4fa0ab26c6ba5",2062:"4a0ab3400fea0e34",2107:"c627112b02b9e1c8",2130:"441ae0f68863efeb",2160:"e38d781fd5c4cde0",2179:"1bf5fe315e6e132c",2215:"9d2d6fbe90ffcc80",2278:"0b14de1cb2041bfd",2349:"ca15d465c4260b4b",2374:"7560cc5c4b8ed6b0",2397:"0e4dce0a557ac7cf",2403:"3dda71b6482dce3b",2485:"3188870375e9fbee",2489:"fcc70bd67329a70e",2501:"4e65b56602faa956",2503:"bb9d3528c3c7ccae",2504:"159b28843e61aae9",2577:"f52cffdd449a2d14",2614:"8349e4b407470a30",2710:"fe0656d4ebae4d30",2728:"5fed9ac13dfcd1d1",2735:"5a3e65a580bd5af9",2747:"1d85d388314f2904",2765:"2c6d9772af50feed",2783:"e8bbf2c794ef9750",2812:"dcd8179a6b1d76c9",2839:"c9a657d5b4031a19",2895:"0339e755e79ee794",2937:"7e724516d5e6ce42",2954:"7d8daeae6410d4a4",2957:"2dd93db1a16e96b0",2964:"1a0e15f7327680a2",3072:"b6da96c10080c967",3074:"911584369786c26c",3077:"bf82c0c332cc9fec",3082:"159e4ab8f0572597",3095:"8cd478c42cee505a",3111:"1cf85db2faeb20cc",3175:"538ce7aec634bddb",3186:"3665756f8aae3eb7",3194:"5a331fb5e3dc34e9",3229:"5e91f7d0b135266b",3274:"858f7f9216c8b074",3286:"196c508356bb0b66",3288:"f23c8a5183e6b910",3290:"b5ba2646ad49c9fd",3304:"16305e84f4ff6598",3313:"471138e5504646a9",3324:"85e21e3313d0901c",3392:"460f5a753531f501",3419:"78b520dab7e2f96d",3437:"0ad1ecc8c5b8a679",3476:"246c30b47bded3b7",3483:"fc2a0b1185dbaa5d",3492:"ca55498822ad7796",3526:"24826331ab265b39",3606:"e5c833cdda239583",3633:"2526b2d018636ff0",3782:"8d7b66d0e37dbe76",3787:"78ebe68a043f50ce",3860:"be5b243bf7d6618c",3873:"72a9a21509f713f7",3879:"f50abf4e93e943ea",3888:"f7831045ac345aaa",3942:"085da8d58242eeab",3979:"cea8623f6e9f83ea",4024:"87fd909ae0110f50",4053:"90d71fcbe4ffd852",4080:"08a21dae9e93c547",4163:"c6ebefdd9aa5c358",4174:"b6ff75dd91a2a32e",4223:"c10556cd92fc8018",4242:"3a66c58375424a5b",4275:"8f2e531757c2a813",4295:"6c0f4838b0c9c69d",4309:"a887a10e84c44f9e",4350:"b9d80827e8eee01a",4357:"ac4f251cdac34fbe",4358:"f89b14cf7a988731",4370:"ac13b62c811f7ede",4417:"0b5ee948c3518db3",4447:"f86b52aea068b189",4474:"053807fa34066566",4539:"559c223da16b0282",4540:"03df20c499bca840",4553:"ce3eab65a260353e",4567:"7dc81a6e1c7df565",4583:"2a5df6eb3a6ea30b",4593:"676ac488744e1af5",4608:"1ff246d6b4c771f8",4634:"0332a56fdb8e26c0",4650:"61aec912b756287b",4659:"0b14de1cb2041bfd",4678:"867dfae26694be02",4763:"d0d1b1777a45e0b2",4801:"17596dbc1818c262",4814:"ccb85c56e9216a38",4823:"907850963b2bcb70",4829:"402ec60139d36417",4846:"c563765de65a34c7",4900:"b723a916eafdf743",4903:"004f583a12223dac",4963:"0f6678151a159143",4969:"1cb10af9489ea295",4976:"8870319ffbd1c31f",5005:"73745d7fcae6989e",5025:"b597364f0cf8b85a",5061:"025d30c3123eeaf6",5136:"ac897c2a56ee392f",5183:"2e5c895a2be76262",5269:"2e771096652dc113",5320:"00f00028b9163a43",5326:"adc4bf49a22f4e67",5331:"4d5d42e5253dbee2",5347:"3192e0021174aaa8",5375:"ebc026e6140b52f1",5424:"4d62f7ee887cd8b9",5482:"0907421e6bf5eeec",5491:"5cc285c4b84dac30",5498:"117ef4b6035a90c5",5518:"6c3dc9afe81a566b",5520:"eab85d7487e77510",5553:"75df19e3cc1246d6",5575:"3d90c643343a1329",5645:"0b86853ae26d9ee3",5670:"2a1b27a6fdb7aa6b",5690:"d30877807cf5c7eb",5712:"574fca2d5f06483a",5728:"8ef773d61765855e",5750:"aa57d25b74640d23",5755:"00015c284ed6fb39",5920:"9db223329ee9e11a",5922:"ce56021f8cc6ebbc",5937:"0827b5b3eb831ff0",5968:"63d5869783fad06f",5997:"226c07d9e6c496e0",6046:"00d36aea7fd5b147",6079:"f9053a63f1b97508",6089:"2dd351186ec85cc3",6099:"43e6595fcf24fc33",6110:"5ce3f75fced27aaf",6144:"f967a8228bcdf663",6155:"19719cff570d6559",6166:"ecd82a9dcb484b97",6290:"e14cf4fc52dd4539",6293:"5914fa73a9f7e777",6311:"5b9c1f74df9a8f67",6331:"758f2f66b92cada9",6339:"bc9301cc22898be0",6360:"ff0a9063773daeeb",6402:"a0070d7688ed986b",6412:"089ee787a294d10b",6455:"12b78a2660d609eb",6563:"5d618b608750f4dc",6572:"ca2463823b9b01a0",6580:"75d53830b434451f",6588:"0fbca957af7d9e6a",6647:"584c5d5cd8dfdb5a",6666:"a82467c542429379",6686:"796c782c33ab8ca9",6701:"bff0efb979f71a17",6704:"f280f0ad0f5d8644",6729:"77a5381ac8f5c9ae",6741:"06fdaf122961074e",6814:"30ff86a90cbfd921",6846:"91283f709c40802c",6859:"bacad166ee995fe0",6887:"6c81234d73740fb9",6927:"aa3914b5fb0d14d4",6931:"3c90e9fe0f7f1e66",6938:"0ccf683bd8aa8410",6948:"2719ed8731963209",6959:"5a803faf27f88e9f",7021:"b71240b1d5f6fbe4",7040:"0b14de1cb2041bfd",7041:"174bf29bd837f06d",7082:"fc816f91214026d7",7113:"39704408fef3d26e",7130:"8d24694735826c22",7142:"dbd2cf8141eece5e",7152:"c7b7f1f5e9622f21",7227:"a6b2f01487bb3d9d",7258:"6cbe24c3bcb63d1d",7425:"8b47c8e398a12dd8",7442:"097194be4a0e7d55",7455:"71d54397710b923c",7465:"867e8ff655666413",7524:"9528295a19a5837a",7525:"f433aaf1fe40c90a",7557:"bdc743175125b3d8",7610:"b1439345dbcf285d",7625:"ab66bd50d2fb61a4",7635:"166d83de1d29e758",7636:"bf91320a9ff695af",7785:"1402a4110c300764",7799:"40b047a634f96a24",7819:"3c56f48c0dc5ad5d",7844:"2bb29faa262f313e",7846:"c9705c044ab8f87a",7884:"390ae2efbbf230c4",7889:"af3e581842f34c28",7921:"c361f794cc208e06",7977:"80e4daa080a79c39",8113:"907baefc7227cfb8",8132:"74491162f08af899",8192:"5918d83ac6a0e2dc",8243:"1450514f8390977e",8257:"dd8f651f1a43fee2",8288:"9bd1d26060cb00a1",8318:"81c7ac586fcbb728",8406:"955ccfbb4b70b8c3",8430:"b1f802dcffa41626",8432:"bd66ac287c569996",8457:"b61d96d8d30215fc",8496:"046efd6301dd804f",8545:"be0c9eea6aae5971",8555:"ab3ee6358f1d64da",8656:"2ceb4e5ff5df2fca",8670:"90ede75068758e82",8704:"a1003918da6654da",8773:"614f1f4f0f845c5e",8835:"5c7821b201f35593",8848:"7c6e47cca9f0059a",8921:"fb24a4d4d4d3265b",8947:"31d3d834d8281fd9",8977:"01b9c429327004e9",9005:"33cf91e617920d4f",9006:"11537833945ec4b8",9015:"c4e40321a6503a1b",9136:"191be42a2fee842c",9178:"48a90097ee3f0b0c",9186:"3af6fcd13ab752fa",9189:"3e9d29bf275ec462",9220:"bc767ebb5adb9f49",9224:"401f9320ee58570b",9240:"d38ddbe94e0bf128",9267:"fbfd65ea31e7448c",9294:"a20485f3282321b3",9302:"726b065f2df0323a",9312:"8121a74b2042bff3",9377:"f9db706e76f04afe",9382:"bc0e11ecc88dd62c",9421:"a5c1dbcfbfdd8f52",9448:"2668b3cd408e86de",9466:"c9d8f45d14235087",9521:"e1240eb862eb32dc",9547:"7729788fff21926f",9565:"8de0671f99d12abe",9569:"2f36b2b1c2f838d7",9605:"dfac539f89cea7a2",9615:"3b62c13af671f714",9648:"8235b6fea7087b3a",9666:"a515fa6d89a71f1c",9680:"d5ceac8967e0b6a8",9690:"7773c72f0eff6dec",9841:"422321143547591a",9842:"3b71b65b30d8ef2a",9996:"18b7bca2f0ab222e"})[e]+".js",l.miniCssF=e=>"static/css/659eccb5db697b76.css",l.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),l.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},l.l=(e,a,f,d)=>{if(c[e])return void c[e].push(a);if(void 0!==f)for(var b,t,r=document.getElementsByTagName("script"),o=0;o<r.length;o++){var n=r[o];if(n.getAttribute("src")==e||n.getAttribute("data-webpack")=="_N_E:"+f){b=n;break}}b||(t=!0,(b=document.createElement("script")).charset="utf-8",b.timeout=120,l.nc&&b.setAttribute("nonce",l.nc),b.setAttribute("data-webpack","_N_E:"+f),b.src=l.tu(e)),c[e]=[a];var i=(a,f)=>{b.onerror=b.onload=null,clearTimeout(u);var d=c[e];if(delete c[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach(e=>e(f)),a)return a(f)},u=setTimeout(i.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=i.bind(null,b.onerror),b.onload=i.bind(null,b.onload),t&&document.head.appendChild(b)},l.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.tt=()=>(void 0===d&&(d={createScriptURL:e=>e},"u">typeof trustedTypes&&trustedTypes.createPolicy&&(d=trustedTypes.createPolicy("nextjs#bundler",d))),d),l.tu=e=>l.tt().createScriptURL(e),l.p="/_next/",b={8068:0},l.f.miniCss=(e,a)=>{if(b[e])a.push(b[e]);else 0!==b[e]&&({1838:1})[e]&&a.push(b[e]=new Promise((a,f)=>{var c,d=l.miniCssF(e),b=l.p+d;if(((e,a)=>{for(var f=document.getElementsByTagName("link"),c=0;c<f.length;c++){var d=f[c],b=d.getAttribute("data-href")||d.getAttribute("href");if("stylesheet"===d.rel&&(b===e||b===a))return d}for(var t=document.getElementsByTagName("style"),c=0;c<t.length;c++){var d=t[c],b=d.getAttribute("data-href");if(b===e||b===a)return d}})(d,b))return a();(c=document.createElement("link")).rel="stylesheet",c.type="text/css",c.onerror=c.onload=d=>{if(c.onerror=c.onload=null,"load"===d.type)a();else{var t=d&&("load"===d.type?"missing":d.type),r=d&&d.target&&d.target.href||b,o=Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.type=t,o.request=r,c.parentNode.removeChild(c),f(o)}},c.href=b,function(e){if("function"==typeof _N_E_STYLE_LOAD){let{href:a,onload:f,onerror:c}=e;_N_E_STYLE_LOAD(0===a.indexOf(window.location.origin)?new URL(a).pathname:a).then(()=>null==f?void 0:f.call(e,{type:"load"}),()=>null==c?void 0:c.call(e,{}))}else document.head.appendChild(e)}(c)}).then(()=>{b[e]=0},a=>{throw delete b[e],a}))},t={8068:0,2557:0,7513:0},l.f.j=(e,a)=>{var f=l.o(t,e)?t[e]:void 0;if(0!==f)if(f)a.push(f[2]);else if(/^(1838|2557|7513|8068)$/.test(e))t[e]=0;else{var c=new Promise((a,c)=>f=t[e]=[a,c]);a.push(f[2]=c);var d=l.p+l.u(e),b=Error();l.l(d,a=>{if(l.o(t,e)&&(0!==(f=t[e])&&(t[e]=void 0),f)){var c=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;b.message="Loading chunk "+e+" failed.\n("+c+": "+d+")",b.name="ChunkLoadError",b.type=c,b.request=d,f[1](b)}},"chunk-"+e,e)}},l.O.j=e=>0===t[e],r=(e,a)=>{var f,c,[d,b,r]=a,o=0;if(d.some(e=>0!==t[e])){for(f in b)l.o(b,f)&&(l.m[f]=b[f]);if(r)var n=r(l)}for(e&&e(a);o<d.length;o++)c=d[o],l.o(t,c)&&t[c]&&t[c][0](),t[c]=0;return l.O(n)},(o=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(r.bind(null,0)),o.push=r.bind(null,o.push.bind(o)),l.nc=void 0})();
|
package/package.json
CHANGED
|
@@ -47,6 +47,12 @@ function shellEscapeSingle(value: string): string {
|
|
|
47
47
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function hydrateProcessEnv(key: string, value: string): void {
|
|
51
|
+
// Make newly collected secrets immediately visible to the current session.
|
|
52
|
+
// Some extensions read process.env directly and do not reload .env on every call.
|
|
53
|
+
process.env[key] = value;
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
async function writeEnvKey(filePath: string, key: string, value: string): Promise<void> {
|
|
51
57
|
let content = "";
|
|
52
58
|
try {
|
|
@@ -312,6 +318,7 @@ async function applySecrets(
|
|
|
312
318
|
try {
|
|
313
319
|
await writeEnvKey(opts.envFilePath, key, value);
|
|
314
320
|
applied.push(key);
|
|
321
|
+
hydrateProcessEnv(key, value);
|
|
315
322
|
} catch (err: any) {
|
|
316
323
|
errors.push(`${key}: ${err.message}`);
|
|
317
324
|
}
|
|
@@ -330,6 +337,7 @@ async function applySecrets(
|
|
|
330
337
|
errors.push(`${key}: ${result.stderr.slice(0, 200)}`);
|
|
331
338
|
} else {
|
|
332
339
|
applied.push(key);
|
|
340
|
+
hydrateProcessEnv(key, value);
|
|
333
341
|
}
|
|
334
342
|
} catch (err: any) {
|
|
335
343
|
errors.push(`${key}: ${err.message}`);
|
|
@@ -36,6 +36,15 @@ import { writeUnitRuntimeRecord } from "../unit-runtime.js";
|
|
|
36
36
|
|
|
37
37
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the base path for milestone reports.
|
|
41
|
+
* Prefers originalBasePath (project root) over basePath (which may be a worktree).
|
|
42
|
+
* Exported for testing as _resolveReportBasePath.
|
|
43
|
+
*/
|
|
44
|
+
export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" | "basePath">): string {
|
|
45
|
+
return s.originalBasePath || s.basePath;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* Generate and write an HTML milestone report snapshot.
|
|
41
50
|
* Extracted from the milestone-transition block in autoLoop.
|
|
@@ -50,13 +59,15 @@ async function generateMilestoneReport(
|
|
|
50
59
|
const { writeReportSnapshot } = await importExtensionModule<typeof import("../reports.js")>(import.meta.url, "../reports.js");
|
|
51
60
|
const { basename } = await import("node:path");
|
|
52
61
|
|
|
53
|
-
const
|
|
62
|
+
const reportBasePath = _resolveReportBasePath(s);
|
|
63
|
+
|
|
64
|
+
const snapData = await loadVisualizerData(reportBasePath);
|
|
54
65
|
const completedMs = snapData.milestones.find(
|
|
55
66
|
(m: { id: string }) => m.id === milestoneId,
|
|
56
67
|
);
|
|
57
68
|
const msTitle = completedMs?.title ?? milestoneId;
|
|
58
69
|
const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
|
|
59
|
-
const projName = basename(
|
|
70
|
+
const projName = basename(reportBasePath);
|
|
60
71
|
const doneSlices = snapData.milestones.reduce(
|
|
61
72
|
(acc: number, m: { slices: { done: boolean }[] }) =>
|
|
62
73
|
acc + m.slices.filter((sl: { done: boolean }) => sl.done).length,
|
|
@@ -67,10 +78,10 @@ async function generateMilestoneReport(
|
|
|
67
78
|
0,
|
|
68
79
|
);
|
|
69
80
|
const outPath = writeReportSnapshot({
|
|
70
|
-
basePath:
|
|
81
|
+
basePath: reportBasePath,
|
|
71
82
|
html: generateHtmlReport(snapData, {
|
|
72
83
|
projectName: projName,
|
|
73
|
-
projectPath:
|
|
84
|
+
projectPath: reportBasePath,
|
|
74
85
|
gsdVersion,
|
|
75
86
|
milestoneId,
|
|
76
87
|
indexRelPath: "index.html",
|
|
@@ -79,7 +90,7 @@ async function generateMilestoneReport(
|
|
|
79
90
|
milestoneTitle: msTitle,
|
|
80
91
|
kind: "milestone",
|
|
81
92
|
projectName: projName,
|
|
82
|
-
projectPath:
|
|
93
|
+
projectPath: reportBasePath,
|
|
83
94
|
gsdVersion,
|
|
84
95
|
totalCost: snapData.totals?.cost ?? 0,
|
|
85
96
|
totalTokens: snapData.totals?.tokens.total ?? 0,
|
|
@@ -250,8 +261,14 @@ export async function runPreDispatch(
|
|
|
250
261
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
251
262
|
return { action: "break", reason: "merge-conflict" };
|
|
252
263
|
}
|
|
253
|
-
// Non-conflict merge errors —
|
|
254
|
-
|
|
264
|
+
// Non-conflict merge errors — stop auto to avoid advancing with unmerged work
|
|
265
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
266
|
+
ctx.ui.notify(
|
|
267
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
268
|
+
"error",
|
|
269
|
+
);
|
|
270
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
271
|
+
return { action: "break", reason: "merge-failed" };
|
|
255
272
|
}
|
|
256
273
|
|
|
257
274
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -344,6 +361,13 @@ export async function runPreDispatch(
|
|
|
344
361
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
345
362
|
return { action: "break", reason: "merge-conflict" };
|
|
346
363
|
}
|
|
364
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
365
|
+
ctx.ui.notify(
|
|
366
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
367
|
+
"error",
|
|
368
|
+
);
|
|
369
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
370
|
+
return { action: "break", reason: "merge-failed" };
|
|
347
371
|
}
|
|
348
372
|
|
|
349
373
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -441,6 +465,13 @@ export async function runPreDispatch(
|
|
|
441
465
|
await deps.stopAuto(ctx, pi, `Merge conflict on milestone ${s.currentMilestoneId}`);
|
|
442
466
|
return { action: "break", reason: "merge-conflict" };
|
|
443
467
|
}
|
|
468
|
+
logError("engine", "Milestone merge failed with non-conflict error", { milestone: s.currentMilestoneId!, error: String(mergeErr) });
|
|
469
|
+
ctx.ui.notify(
|
|
470
|
+
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /gsd auto to resume.`,
|
|
471
|
+
"error",
|
|
472
|
+
);
|
|
473
|
+
await deps.stopAuto(ctx, pi, `Merge error on milestone ${s.currentMilestoneId}: ${String(mergeErr)}`);
|
|
474
|
+
return { action: "break", reason: "merge-failed" };
|
|
444
475
|
}
|
|
445
476
|
|
|
446
477
|
// PR creation (auto_pr) is handled inside mergeMilestoneToMain (#2302)
|
|
@@ -677,9 +677,14 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
677
677
|
if (validationPath) {
|
|
678
678
|
const validationContent = await loadFile(validationPath);
|
|
679
679
|
if (validationContent) {
|
|
680
|
-
|
|
680
|
+
// Accept either the structured template format (table with MET/N/A)
|
|
681
|
+
// or prose evidence patterns the validation agent may emit.
|
|
682
|
+
const structuredMatch =
|
|
681
683
|
validationContent.includes("Operational") &&
|
|
682
684
|
(validationContent.includes("MET") || validationContent.includes("N/A"));
|
|
685
|
+
const proseMatch =
|
|
686
|
+
/[Oo]perational[\s:][^\n]*(?:pass|verified|confirmed|met|complete|true|yes|addressed|covered|n\/a|not\s+applicable)/i.test(validationContent);
|
|
687
|
+
const hasOperationalCheck = structuredMatch || proseMatch;
|
|
683
688
|
if (!hasOperationalCheck) {
|
|
684
689
|
return {
|
|
685
690
|
action: "stop" as const,
|
|
@@ -157,6 +157,25 @@ function clearProjectRootStateFiles(basePath: string, milestoneId: string): void
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
// ─── Build Artifact Auto-Resolve ─────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
/** Patterns for machine-generated build artifacts that can be safely
|
|
163
|
+
* auto-resolved by accepting --theirs during merge. These files are
|
|
164
|
+
* regenerable and never contain meaningful manual edits. */
|
|
165
|
+
export const SAFE_AUTO_RESOLVE_PATTERNS: RegExp[] = [
|
|
166
|
+
/\.tsbuildinfo$/,
|
|
167
|
+
/\.pyc$/,
|
|
168
|
+
/\/__pycache__\//,
|
|
169
|
+
/\.DS_Store$/,
|
|
170
|
+
/\.map$/,
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
/** Returns true if the file path is safe to auto-resolve during merge.
|
|
174
|
+
* Covers `.gsd/` state files and common build artifacts. */
|
|
175
|
+
export const isSafeToAutoResolve = (filePath: string): boolean =>
|
|
176
|
+
filePath.startsWith(".gsd/") ||
|
|
177
|
+
SAFE_AUTO_RESOLVE_PATTERNS.some((re) => re.test(filePath));
|
|
178
|
+
|
|
160
179
|
// ─── Dispatch-Level Sync (project root ↔ worktree) ──────────────────────────
|
|
161
180
|
|
|
162
181
|
/**
|
|
@@ -1408,30 +1427,30 @@ export function mergeMilestoneToMain(
|
|
|
1408
1427
|
: nativeConflictFiles(originalBasePath_);
|
|
1409
1428
|
|
|
1410
1429
|
if (conflictedFiles.length > 0) {
|
|
1411
|
-
// Separate
|
|
1412
|
-
// GSD state files
|
|
1413
|
-
//
|
|
1414
|
-
//
|
|
1415
|
-
const
|
|
1430
|
+
// Separate auto-resolvable conflicts (GSD state files + build artifacts)
|
|
1431
|
+
// from real code conflicts. GSD state files diverge between branches
|
|
1432
|
+
// during normal operation. Build artifacts are machine-generated and
|
|
1433
|
+
// regenerable. Both are safe to accept from the milestone branch.
|
|
1434
|
+
const autoResolvable = conflictedFiles.filter(isSafeToAutoResolve);
|
|
1416
1435
|
const codeConflicts = conflictedFiles.filter(
|
|
1417
|
-
(f) => !f
|
|
1436
|
+
(f) => !isSafeToAutoResolve(f),
|
|
1418
1437
|
);
|
|
1419
1438
|
|
|
1420
|
-
// Auto-resolve
|
|
1421
|
-
if (
|
|
1422
|
-
for (const
|
|
1439
|
+
// Auto-resolve safe conflicts by accepting the milestone branch version
|
|
1440
|
+
if (autoResolvable.length > 0) {
|
|
1441
|
+
for (const safeFile of autoResolvable) {
|
|
1423
1442
|
try {
|
|
1424
|
-
nativeCheckoutTheirs(originalBasePath_, [
|
|
1425
|
-
nativeAddPaths(originalBasePath_, [
|
|
1443
|
+
nativeCheckoutTheirs(originalBasePath_, [safeFile]);
|
|
1444
|
+
nativeAddPaths(originalBasePath_, [safeFile]);
|
|
1426
1445
|
} catch {
|
|
1427
1446
|
// If checkout --theirs fails, try removing the file from the merge
|
|
1428
1447
|
// (it's a runtime file that shouldn't be committed anyway)
|
|
1429
|
-
nativeRmForce(originalBasePath_, [
|
|
1448
|
+
nativeRmForce(originalBasePath_, [safeFile]);
|
|
1430
1449
|
}
|
|
1431
1450
|
}
|
|
1432
1451
|
}
|
|
1433
1452
|
|
|
1434
|
-
// If there are still
|
|
1453
|
+
// If there are still real code conflicts, escalate
|
|
1435
1454
|
if (codeConflicts.length > 0) {
|
|
1436
1455
|
// Pop stash before throwing so local work is not lost (#2151).
|
|
1437
1456
|
if (stashed) {
|
|
@@ -1480,7 +1499,47 @@ export function mergeMilestoneToMain(
|
|
|
1480
1499
|
encoding: "utf-8",
|
|
1481
1500
|
});
|
|
1482
1501
|
} catch {
|
|
1483
|
-
// Stash pop
|
|
1502
|
+
// Stash pop after squash merge can conflict on .gsd/ state files that
|
|
1503
|
+
// diverged between branches. Left unresolved, these UU entries block
|
|
1504
|
+
// every subsequent merge. Auto-resolve them the same way we handle
|
|
1505
|
+
// .gsd/ conflicts during the merge itself: accept HEAD (the just-committed
|
|
1506
|
+
// version) and drop the now-applied stash.
|
|
1507
|
+
const uu = nativeConflictFiles(originalBasePath_);
|
|
1508
|
+
const gsdUU = uu.filter((f) => f.startsWith(".gsd/"));
|
|
1509
|
+
const nonGsdUU = uu.filter((f) => !f.startsWith(".gsd/"));
|
|
1510
|
+
|
|
1511
|
+
if (gsdUU.length > 0) {
|
|
1512
|
+
for (const f of gsdUU) {
|
|
1513
|
+
try {
|
|
1514
|
+
// Accept the committed (HEAD) version of the state file
|
|
1515
|
+
execFileSync("git", ["checkout", "HEAD", "--", f], {
|
|
1516
|
+
cwd: originalBasePath_,
|
|
1517
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1518
|
+
encoding: "utf-8",
|
|
1519
|
+
});
|
|
1520
|
+
nativeAddPaths(originalBasePath_, [f]);
|
|
1521
|
+
} catch {
|
|
1522
|
+
// Last resort: remove the conflicted state file
|
|
1523
|
+
nativeRmForce(originalBasePath_, [f]);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
if (nonGsdUU.length === 0) {
|
|
1529
|
+
// All conflicts were .gsd/ files — safe to drop the stash
|
|
1530
|
+
try {
|
|
1531
|
+
execFileSync("git", ["stash", "drop"], {
|
|
1532
|
+
cwd: originalBasePath_,
|
|
1533
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1534
|
+
encoding: "utf-8",
|
|
1535
|
+
});
|
|
1536
|
+
} catch { /* stash may already be consumed */ }
|
|
1537
|
+
} else {
|
|
1538
|
+
// Non-.gsd conflicts remain — leave stash for manual resolution
|
|
1539
|
+
logWarning("reconcile", "Stash pop conflict on non-.gsd files after merge", {
|
|
1540
|
+
files: nonGsdUU.join(", "),
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1484
1543
|
}
|
|
1485
1544
|
}
|
|
1486
1545
|
|
|
@@ -414,6 +414,13 @@ export function stopAutoRemote(projectRoot: string): {
|
|
|
414
414
|
const lock = readCrashLock(projectRoot);
|
|
415
415
|
if (!lock) return { found: false };
|
|
416
416
|
|
|
417
|
+
// Never SIGTERM ourselves — a stale lock with our own PID is not a remote
|
|
418
|
+
// session, it is leftover from a prior loop exit in this process. (#2730)
|
|
419
|
+
if (lock.pid === process.pid) {
|
|
420
|
+
clearLock(projectRoot);
|
|
421
|
+
return { found: false };
|
|
422
|
+
}
|
|
423
|
+
|
|
417
424
|
if (!isLockProcessAlive(lock)) {
|
|
418
425
|
// Stale lock — clean it up
|
|
419
426
|
clearLock(projectRoot);
|
|
@@ -445,6 +452,10 @@ export function checkRemoteAutoSession(projectRoot: string): {
|
|
|
445
452
|
const lock = readCrashLock(projectRoot);
|
|
446
453
|
if (!lock) return { running: false };
|
|
447
454
|
|
|
455
|
+
// Our own PID is not a "remote" session — it is a stale lock left by this
|
|
456
|
+
// process (e.g. after step-mode exit without full cleanup). (#2730)
|
|
457
|
+
if (lock.pid === process.pid) return { running: false };
|
|
458
|
+
|
|
448
459
|
if (!isLockProcessAlive(lock)) {
|
|
449
460
|
// Stale lock from a dead process — not a live remote session
|
|
450
461
|
return { running: false };
|
|
@@ -548,6 +559,16 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
548
559
|
s.active = false;
|
|
549
560
|
clearUnitTimeout();
|
|
550
561
|
|
|
562
|
+
// Clear crash lock and release session lock so the next `/gsd next` does
|
|
563
|
+
// not see a stale lock with the current PID and treat it as a "remote"
|
|
564
|
+
// session (which would cause it to SIGTERM itself). (#2730)
|
|
565
|
+
try {
|
|
566
|
+
if (lockBase()) clearLock(lockBase());
|
|
567
|
+
if (lockBase()) releaseSessionLock(lockBase());
|
|
568
|
+
} catch {
|
|
569
|
+
/* best-effort — mirror stopAuto cleanup */
|
|
570
|
+
}
|
|
571
|
+
|
|
551
572
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
552
573
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
553
574
|
ctx.ui.setFooter(undefined);
|
|
@@ -107,16 +107,9 @@ export async function handleAgentEnd(
|
|
|
107
107
|
ctx.ui.notify(`Network retries exhausted for ${currentModelId}. Attempting model fallback.`, "warning");
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
// ---
|
|
111
|
-
// Rate
|
|
112
|
-
|
|
113
|
-
if (cls.kind === "rate-limit") {
|
|
114
|
-
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, true);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// --- Server/connection/stream errors: try model fallback first ---
|
|
119
|
-
if (cls.kind === "network" || cls.kind === "server" || cls.kind === "connection" || cls.kind === "stream") {
|
|
110
|
+
// --- Transient errors: try model fallback first, then pause ---
|
|
111
|
+
// Rate limits are often per-model, so switching models can bypass them.
|
|
112
|
+
if (cls.kind === "rate-limit" || cls.kind === "network" || cls.kind === "server" || cls.kind === "connection" || cls.kind === "stream") {
|
|
120
113
|
// Try model fallback
|
|
121
114
|
const dash = getAutoDashboardData();
|
|
122
115
|
if (dash.currentUnit) {
|
|
@@ -161,7 +154,7 @@ export async function handleAgentEnd(
|
|
|
161
154
|
|
|
162
155
|
// --- Transient fallback: pause with auto-resume ---
|
|
163
156
|
if (isTransient(cls)) {
|
|
164
|
-
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail,
|
|
157
|
+
await pauseTransientWithBackoff(cls, pi, ctx, errorDetail, cls.kind === "rate-limit");
|
|
165
158
|
return;
|
|
166
159
|
}
|
|
167
160
|
|
|
@@ -517,8 +517,9 @@ export async function showDiscuss(
|
|
|
517
517
|
|
|
518
518
|
const state = await deriveState(basePath);
|
|
519
519
|
|
|
520
|
-
// No active milestone
|
|
521
|
-
|
|
520
|
+
// No active milestone (or corrupted milestone with undefined id) —
|
|
521
|
+
// check for pending milestones to discuss instead
|
|
522
|
+
if (!state.activeMilestone?.id) {
|
|
522
523
|
const pendingMilestones = state.registry.filter(m => m.status === "pending");
|
|
523
524
|
if (pendingMilestones.length === 0) {
|
|
524
525
|
ctx.ui.notify("No active milestone. Run /gsd to create one first.", "warning");
|
|
@@ -1043,7 +1044,7 @@ export async function showSmartEntry(
|
|
|
1043
1044
|
|
|
1044
1045
|
const state = await deriveState(basePath);
|
|
1045
1046
|
|
|
1046
|
-
if (!state.activeMilestone) {
|
|
1047
|
+
if (!state.activeMilestone?.id) {
|
|
1047
1048
|
// Guard: if a discuss session is already in flight, don't re-inject the prompt.
|
|
1048
1049
|
// Both /gsd and /gsd auto reach this branch when no milestone exists yet.
|
|
1049
1050
|
// Without this guard, every subsequent /gsd call overwrites pendingAutoStart
|
|
@@ -196,7 +196,17 @@ function appendWorkerLog(basePath: string, milestoneId: string, chunk: string):
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
function restoreRuntimeState(basePath: string): boolean {
|
|
199
|
-
if (state?.active)
|
|
199
|
+
if (state?.active) {
|
|
200
|
+
// Verify at least one worker is alive — if all are in terminal states,
|
|
201
|
+
// the cached state is stale and we should fall through to cleanup.
|
|
202
|
+
const hasLiveWorker = [...state.workers.values()].some(
|
|
203
|
+
(w) => w.state !== "error" && w.state !== "stopped",
|
|
204
|
+
);
|
|
205
|
+
if (hasLiveWorker) return true;
|
|
206
|
+
|
|
207
|
+
// All workers dead — clear stale state so restoreState() can clean up.
|
|
208
|
+
state = null;
|
|
209
|
+
}
|
|
200
210
|
|
|
201
211
|
const restored = restoreState(basePath);
|
|
202
212
|
if (restored && restored.workers.length > 0) {
|
|
@@ -932,6 +942,18 @@ export function refreshWorkerStatuses(
|
|
|
932
942
|
state.totalCost += worker.cost;
|
|
933
943
|
}
|
|
934
944
|
|
|
945
|
+
// If all workers are in a terminal state (error/stopped), the orchestration
|
|
946
|
+
// is finished — deactivate and clean up so zombie workers don't persist.
|
|
947
|
+
const allDead = [...state.workers.values()].every(
|
|
948
|
+
(w) => w.state === "error" || w.state === "stopped",
|
|
949
|
+
);
|
|
950
|
+
if (allDead) {
|
|
951
|
+
state.active = false;
|
|
952
|
+
removeStateFile(basePath);
|
|
953
|
+
state = null;
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
|
|
935
957
|
// Persist updated state for crash recovery
|
|
936
958
|
persistState(basePath);
|
|
937
959
|
}
|
|
@@ -90,18 +90,13 @@ export function isMilestoneComplete(roadmap: Roadmap): boolean {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Check whether a VALIDATION file's verdict is terminal
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* Check whether a VALIDATION file's verdict is terminal.
|
|
94
|
+
* Any successfully extracted verdict (pass, needs-attention, needs-remediation,
|
|
95
|
+
* fail, etc.) means validation completed. Only return false when no verdict
|
|
96
|
+
* could be parsed — i.e. extractVerdict() returns undefined (#2769).
|
|
96
97
|
*/
|
|
97
98
|
export function isValidationTerminal(validationContent: string): boolean {
|
|
98
|
-
|
|
99
|
-
if (!v) return false;
|
|
100
|
-
// 'pass' and 'needs-attention' are always terminal.
|
|
101
|
-
// 'needs-remediation' is treated as terminal to prevent infinite loops
|
|
102
|
-
// when no remediation slices exist in the roadmap (#832). The validation
|
|
103
|
-
// report is preserved on disk for manual review.
|
|
104
|
-
return v === 'pass' || v === 'needs-attention' || v === 'needs-remediation';
|
|
99
|
+
return extractVerdict(validationContent) != null;
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
// ─── State Derivation ──────────────────────────────────────────────────────
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #2773 — activeMilestone.id guard
|
|
3
|
+
*
|
|
4
|
+
* When activeMilestone is a non-null object with `id: undefined` (corrupted
|
|
5
|
+
* state), the old `!state.activeMilestone` truthiness check passed through,
|
|
6
|
+
* causing a downstream crash when code assumed `.id` was a valid string.
|
|
7
|
+
*
|
|
8
|
+
* The fix uses optional chaining (`!state.activeMilestone?.id`) so all three
|
|
9
|
+
* "no usable milestone" shapes are caught:
|
|
10
|
+
* 1. activeMilestone === null
|
|
11
|
+
* 2. activeMilestone === undefined
|
|
12
|
+
* 3. activeMilestone === { id: undefined, title: "..." }
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it } from 'node:test'
|
|
16
|
+
import assert from 'node:assert/strict'
|
|
17
|
+
|
|
18
|
+
import type { GSDState, ActiveRef } from '../types.ts'
|
|
19
|
+
|
|
20
|
+
// ─── Guard Under Test ────────────────────────────────────────────────────────
|
|
21
|
+
// Extracted guard logic identical to headless-query.ts (line 74) and
|
|
22
|
+
// guided-flow.ts (lines 522, 1047).
|
|
23
|
+
|
|
24
|
+
function activeMilestoneIsUsable(activeMilestone: ActiveRef | null | undefined): boolean {
|
|
25
|
+
return !!activeMilestone?.id
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
describe('activeMilestone?.id guard (#2773)', () => {
|
|
31
|
+
it('rejects null activeMilestone', () => {
|
|
32
|
+
assert.equal(activeMilestoneIsUsable(null), false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('rejects undefined activeMilestone', () => {
|
|
36
|
+
assert.equal(activeMilestoneIsUsable(undefined), false)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('rejects malformed activeMilestone with id: undefined', () => {
|
|
40
|
+
// This is the crash case from #2773 — object exists but id is undefined
|
|
41
|
+
const malformed = { id: undefined, title: 'Ghost Milestone' } as unknown as ActiveRef
|
|
42
|
+
assert.equal(activeMilestoneIsUsable(malformed), false)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('rejects malformed activeMilestone with id: empty string', () => {
|
|
46
|
+
const malformed = { id: '', title: 'Empty ID Milestone' } as unknown as ActiveRef
|
|
47
|
+
assert.equal(activeMilestoneIsUsable(malformed), false)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('accepts valid activeMilestone with a real id', () => {
|
|
51
|
+
const valid: ActiveRef = { id: 'M001', title: 'Real Milestone' }
|
|
52
|
+
assert.equal(activeMilestoneIsUsable(valid), true)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('headless-query stop behavior with corrupted milestone', () => {
|
|
57
|
+
// Simulates the decision logic from handleQuery (headless-query.ts:74-78)
|
|
58
|
+
function deriveNextAction(activeMilestone: ActiveRef | null | undefined, phase: string) {
|
|
59
|
+
if (!activeMilestone?.id) {
|
|
60
|
+
return {
|
|
61
|
+
action: 'stop' as const,
|
|
62
|
+
reason: phase === 'complete' ? 'All milestones complete.' : 'No active milestone.',
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { action: 'dispatch' as const, unitId: activeMilestone.id }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
it('returns stop when activeMilestone is null', () => {
|
|
69
|
+
const result = deriveNextAction(null, 'pre-planning')
|
|
70
|
+
assert.equal(result.action, 'stop')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('returns stop when activeMilestone has undefined id', () => {
|
|
74
|
+
const corrupted = { id: undefined, title: 'Corrupted' } as unknown as ActiveRef
|
|
75
|
+
const result = deriveNextAction(corrupted, 'executing')
|
|
76
|
+
assert.equal(result.action, 'stop')
|
|
77
|
+
assert.equal(result.reason, 'No active milestone.')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('returns dispatch with valid milestone id', () => {
|
|
81
|
+
const valid: ActiveRef = { id: 'M001', title: 'Valid' }
|
|
82
|
+
const result = deriveNextAction(valid, 'executing')
|
|
83
|
+
assert.equal(result.action, 'dispatch')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('returns correct stop reason when phase is complete', () => {
|
|
87
|
+
const result = deriveNextAction(null, 'complete')
|
|
88
|
+
assert.equal(result.action, 'stop')
|
|
89
|
+
assert.equal(result.reason, 'All milestones complete.')
|
|
90
|
+
})
|
|
91
|
+
})
|