aws-runtime-bridge 1.9.90 → 1.9.92

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.
@@ -1,28 +1,28 @@
1
1
  import{spawn as V}from"node:child_process";import{promises as A}from"node:fs";import k from"node:path";import L from"axios";import{Router as X}from"express";import{validateToken as y}from"../middleware/auth.js";import{logger as h}from"../utils/logger.js";const P=X(),Z=1e4;function O(){const i=Number(process.env.AWS_RUNTIME_GIT_COMMAND_TIMEOUT_MS);return Number.isFinite(i)&&i>=1e3?i:Z}async function Q(i){let t;try{t=await A.stat(i)}catch(e){const a=e;throw a.code==="ENOENT"?new Error(`workspace path does not exist: ${i}`):new Error(`workspace path is not accessible: ${i}${a.message?` (${a.message})`:""}`)}if(!t.isDirectory())throw new Error(`workspace path is not a directory: ${i}`)}const tt=/^[0-9a-f]{40}$/i;function et(i,t,e,a){return i==="added"||i==="deleted"||i==="renamed"?!0:a||t>0||e>0}function rt(i){const t=String(i||"").toLowerCase();return t.includes("you do not have the initial commit yet")||t.includes("bad revision")&&t.includes("head")||t.includes("ambiguous argument")&&t.includes("head")}function st(){return"\u5F53\u524D Git \u4ED3\u5E93\u8FD8\u6CA1\u6709\u521D\u59CB\u63D0\u4EA4\uFF0C\u65E0\u6CD5\u521B\u5EFA\u5FEB\u7167\u3002\u8BF7\u5148\u63D0\u4EA4\u4E00\u6B21\u521D\u59CB\u63D0\u4EA4\u540E\u518D\u521B\u5EFA\u5FEB\u7167\u3002"}function ot(i){const t=String(i||"").toLowerCase();return t.includes("no local changes to save")||t.includes("no changes to save")||t.includes("\u6CA1\u6709\u672C\u5730\u53D8\u66F4\u9700\u8981\u4FDD\u5B58")}function it(i){const t=String(i||"").trim();return tt.test(t)?`refs/agentswork/stash-snapshots/${t.toLowerCase()}`:null}function W(i){const t=String(i||"").trim();if(!t)return null;const e=t.split("\0");if(e.length>=3){const s=e[0]?.trim(),o=e[1]?.trim(),l=e[2]?.trim()||o,c=e[3]?.trim()||null;if(!s||!o)return null;const u=I(l||"");return{ref:s,stashName:o,message:u.message,branch:u.branch,createdAt:c}}const a=t.match(/^(stash@\{\d+\})(?::\s*)?(.*)$/);if(!a)return null;const r=a[1],n=I(a[2]?.trim()||r);return{ref:r,stashName:r,message:n.message,branch:n.branch,createdAt:null}}function I(i){const t=String(i||"").trim(),e=t.match(/^(?:On|WIP on)\s+([^:]+):\s*(.*)$/);return e?{branch:e[1].trim(),message:e[2].trim()||t}:{branch:"",message:t}}function z(i){const t=String(i||"").split(`
2
- `).find(a=>a.trim());if(!t)return null;const e=W(t);return e?{ref:e.ref,stashName:e.stashName||e.ref,message:e.message||e.ref}:null}async function p(i,t){return new Promise(e=>{let a=!1,r=null;const n=c=>{a||(a=!0,r&&clearTimeout(r),e(c))},s=V("git",t,{cwd:i,stdio:["ignore","pipe","pipe"]});let o="",l="";s.stdout?.on("data",c=>{o+=String(c||"")}),s.stderr?.on("data",c=>{l+=String(c||"")}),r=setTimeout(()=>{const c=O();h.warn(`[runtime-bridge] git command timed out after ${c}ms: git ${t.join(" ")} (cwd=${i})`),s.kill("SIGKILL"),n({stdout:o,stderr:l||`git command timed out after ${c}ms`,exitCode:124})},O()),s.on("error",c=>{n({stdout:"",stderr:c.message,exitCode:1})}),s.on("close",c=>{n({stdout:o,stderr:l,exitCode:c??1})})})}async function _(i,t){const e=it(t);if(!e)return null;const a=await p(i,["update-ref",e,t]);return a.exitCode!==0?(h.warn(`[Git] \u6301\u4E45\u5316 stash \u5FEB\u7167 ref \u5931\u8D25: ref=${e}, error=${a.stderr||a.stdout}`),null):e}function S(i){return String(i||"").replace(/\\/g,"/").replace(/^\.\//,"").trim()}async function at(i){const t=k.join(i,".git");try{const e=await A.stat(t);return e.isDirectory()||e.isFile()}catch{return!1}}async function R(i){const t=k.resolve(String(i).trim());if(await Q(t),await at(t))return{workspacePath:t,repositoryRootPath:t,hasRepository:!0,isGitRepo:!0,usingParentGitRepo:!1,relativeWorkspacePath:""};const a=await p(t,["rev-parse","--show-toplevel"]);if(a.exitCode!==0)return{workspacePath:t,repositoryRootPath:null,hasRepository:!1,isGitRepo:!1,usingParentGitRepo:!1,relativeWorkspacePath:""};const r=k.resolve(a.stdout.trim()),n=S(k.relative(r,t));return{workspacePath:t,repositoryRootPath:r,hasRepository:!0,isGitRepo:!1,usingParentGitRepo:r!==t,relativeWorkspacePath:n}}function C(i,t){if(!t.relativeWorkspacePath)return[...i];const e=!i.includes("status");return[...i,...e?[`--relative=${t.relativeWorkspacePath}`]:[],"--",t.relativeWorkspacePath]}function N(i,t){const e=S(i);return t.relativeWorkspacePath?S(k.posix.join(t.relativeWorkspacePath,e)):e}function nt(i){const t=String(i||"").trim().toUpperCase();return t.startsWith("A")?"added":t.startsWith("D")?"deleted":t.startsWith("R")?"renamed":"modified"}function T(i){const t=S(i);if(!t.includes("=>"))return t;const e=t.match(/^(.*)\{([^{}]+)=>([^{}]+)\}(.*)$/);if(e){const r=e[1],n=e[3],s=e[4];return S(`${r}${n}${s}`)}const a=t.lastIndexOf("=>");return a>=0?S(t.slice(a+2)):t}function ct(i){const t=new Set,e=String(i||"").split(`
2
+ `).find(a=>a.trim());if(!t)return null;const e=W(t);return e?{ref:e.ref,stashName:e.stashName||e.ref,message:e.message||e.ref}:null}async function p(i,t){return new Promise(e=>{let a=!1,r=null;const n=c=>{a||(a=!0,r&&clearTimeout(r),e(c))},s=V("git",t,{cwd:i,stdio:["ignore","pipe","pipe"]});let o="",l="";s.stdout?.on("data",c=>{o+=String(c||"")}),s.stderr?.on("data",c=>{l+=String(c||"")}),r=setTimeout(()=>{const c=O();h.warn(`[runtime-bridge] git command timed out after ${c}ms: git ${t.join(" ")} (cwd=${i})`),s.kill("SIGKILL"),n({stdout:o,stderr:l||`git command timed out after ${c}ms`,exitCode:124})},O()),s.on("error",c=>{n({stdout:"",stderr:c.message,exitCode:1})}),s.on("close",c=>{n({stdout:o,stderr:l,exitCode:c??1})})})}async function _(i,t){const e=it(t);if(!e)return null;const a=await p(i,["update-ref",e,t]);return a.exitCode!==0?(h.warn(`[Git] \u6301\u4E45\u5316 stash \u5FEB\u7167 ref \u5931\u8D25: ref=${e}, error=${a.stderr||a.stdout}`),null):e}function S(i){return String(i||"").replace(/\\/g,"/").replace(/^\.\//,"").trim()}async function At(i){const t=k.join(i,".git");try{const e=await A.stat(t);return e.isDirectory()||e.isFile()}catch{return!1}}async function R(i){const t=k.resolve(String(i).trim());await Q(t);const e=await p(t,["rev-parse","--show-toplevel"]);if(e.exitCode!==0)return{workspacePath:t,repositoryRootPath:null,hasRepository:!1,isGitRepo:!1,usingParentGitRepo:!1,relativeWorkspacePath:""};const a=k.resolve(e.stdout.trim()),r=a===t,n=r?"":S(k.relative(a,t));return{workspacePath:t,repositoryRootPath:a,hasRepository:!0,isGitRepo:r,usingParentGitRepo:!r,relativeWorkspacePath:n}}function C(i,t){if(!t.relativeWorkspacePath)return[...i];const e=!i.includes("status");return[...i,...e?[`--relative=${t.relativeWorkspacePath}`]:[],"--",t.relativeWorkspacePath]}function N(i,t){const e=S(i);return t.relativeWorkspacePath?S(k.posix.join(t.relativeWorkspacePath,e)):e}function at(i){const t=String(i||"").trim().toUpperCase();return t.startsWith("A")?"added":t.startsWith("D")?"deleted":t.startsWith("R")?"renamed":"modified"}function T(i){const t=S(i);if(!t.includes("=>"))return t;const e=t.match(/^(.*)\{([^{}]+)=>([^{}]+)\}(.*)$/);if(e){const r=e[1],n=e[3],s=e[4];return S(`${r}${n}${s}`)}const a=t.lastIndexOf("=>");return a>=0?S(t.slice(a+2)):t}function nt(i){const t=new Set,e=String(i||"").split(`
3
3
  `).filter(a=>a.trim());for(const a of e){const r=a[0]||" ";if(r===" "||r==="?")continue;const n=a.slice(3).trim(),s=n.split(" -> "),o=T(s[s.length-1]||n);o&&t.add(o)}return t}function D(i,t,e=new Set,a=!1){const r=new Map,n=i.split(`
4
- `).filter(l=>l.trim());for(const l of n){const c=l.split(" ");if(c.length<2)continue;const u=nt(c[0]),f=u==="renamed"&&c.length>=3?2:1,d=T(c[f]);d&&r.set(d,u)}const s=[],o=t.split(`
5
- `).filter(l=>l.trim());for(const l of o){const c=l.split(" ");if(c.length<3)continue;const u=c[0]==="-"||c[1]==="-",f=c[0]==="-"?0:parseInt(c[0],10)||0,d=c[1]==="-"?0:parseInt(c[1],10)||0,m=T(c.slice(2).join(" ").trim()),g=r.get(m)||"modified";!m||!et(g,f,d,u)||s.push({path:m,status:g,additions:f,deletions:d,staged:a||e.has(m)})}return s}function lt(i){const t=[],e=String(i||"").split(`
6
- `).filter(a=>a.trim());for(const a of e)if(a.startsWith("?? ")){const r=a.slice(3).trim();r&&t.push(r.replace(/\/$/,""))}return t}async function ft(i,t,e,a=10){const r=[];async function n(s,o){if(o>a)return;const l=k.join(i,s);let c;try{c=await A.readdir(l,{withFileTypes:!0})}catch{return}for(const u of c){if(u.name===".git"||u.name==="node_modules")continue;const f=s?`${s}/${u.name}`:u.name;if(u.isDirectory())await n(f,o+1);else if(u.isFile()){const d=S(f);d&&!e.has(d)&&r.push({path:d,status:"added",additions:0,deletions:0,staged:!1})}}}for(const s of t){const o=S(s);if(!o)continue;const l=k.join(i,s);let c;try{c=await A.stat(l)}catch{continue}c.isFile()?e.has(o)||r.push({path:o,status:"added",additions:0,deletions:0,staged:!1}):c.isDirectory()&&await n(o,0)}return r}function ut(i,t){const e=new Map;for(const a of i)e.set(a.path,{...a});for(const a of t){const r=e.get(a.path);if(!r){e.set(a.path,{...a,staged:!0});continue}e.set(a.path,{...r,status:r.status==="modified"?a.status:r.status,additions:r.additions+a.additions,deletions:r.deletions+a.deletions,staged:!0})}return[...e.values()]}function q(i){return String(i||"").trim()}function dt(i){return String(i||"").trim()}function ht(i){return["--",i.relativeWorkspacePath||"."]}function G(i,t){return["--",N(i,t)]}function pt(i){const t=i.split("\0"),e=[];for(let a=0;a+4<t.length;a+=5){const r=t[a]?.trim();r&&e.push({hash:r,shortHash:t[a+1]?.trim()||r.slice(0,8),authorName:t[a+2]?.trim()||"unknown",authorDate:t[a+3]?.trim()||"",subject:t[a+4]?.trim()||r})}return e}P.post("/git/check",y,async(i,t)=>{const{workspacePath:e}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const a=await R(String(e).trim());t.json({ok:!0,isGitRepo:a.isGitRepo,hasRepository:a.hasRepository,usingParentGitRepo:a.usingParentGitRepo,workspacePath:a.workspacePath,repositoryRootPath:a.repositoryRootPath,relativeWorkspacePath:a.relativeWorkspacePath});return}catch(a){const r=a;t.status(500).json({error:r.message||"check git repo failed"})}}),P.post("/git/stash/create",y,async(i,t)=>{const{workspacePath:e,message:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=k.resolve(String(e).trim()),n=`\u5FEB\u7167\uFF08${new Date().toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}\uFF09`,s=a&&String(a).trim()?`\u5FEB\u7167: ${String(a).trim()}`:n,o=await p(r,["stash","push","-m",s]);if(ot(`${o.stdout}
4
+ `).filter(l=>l.trim());for(const l of n){const c=l.split(" ");if(c.length<2)continue;const u=at(c[0]),f=u==="renamed"&&c.length>=3?2:1,d=T(c[f]);d&&r.set(d,u)}const s=[],o=t.split(`
5
+ `).filter(l=>l.trim());for(const l of o){const c=l.split(" ");if(c.length<3)continue;const u=c[0]==="-"||c[1]==="-",f=c[0]==="-"?0:parseInt(c[0],10)||0,d=c[1]==="-"?0:parseInt(c[1],10)||0,m=T(c.slice(2).join(" ").trim()),g=r.get(m)||"modified";!m||!et(g,f,d,u)||s.push({path:m,status:g,additions:f,deletions:d,staged:a||e.has(m)})}return s}function ct(i){const t=[],e=String(i||"").split(`
6
+ `).filter(a=>a.trim());for(const a of e)if(a.startsWith("?? ")){const r=a.slice(3).trim();r&&t.push(r.replace(/\/$/,""))}return t}async function lt(i,t,e,a=10){const r=[];async function n(s,o){if(o>a)return;const l=k.join(i,s);let c;try{c=await A.readdir(l,{withFileTypes:!0})}catch{return}for(const u of c){if(u.name===".git"||u.name==="node_modules")continue;const f=s?`${s}/${u.name}`:u.name;if(u.isDirectory())await n(f,o+1);else if(u.isFile()){const d=S(f);d&&!e.has(d)&&r.push({path:d,status:"added",additions:0,deletions:0,staged:!1})}}}for(const s of t){const o=S(s);if(!o)continue;const l=k.join(i,s);let c;try{c=await A.stat(l)}catch{continue}c.isFile()?e.has(o)||r.push({path:o,status:"added",additions:0,deletions:0,staged:!1}):c.isDirectory()&&await n(o,0)}return r}function ft(i,t){const e=new Map;for(const a of i)e.set(a.path,{...a});for(const a of t){const r=e.get(a.path);if(!r){e.set(a.path,{...a,staged:!0});continue}e.set(a.path,{...r,status:r.status==="modified"?a.status:r.status,additions:r.additions+a.additions,deletions:r.deletions+a.deletions,staged:!0})}return[...e.values()]}function q(i){return String(i||"").trim()}function ut(i){return String(i||"").trim()}function dt(i){return["--",i.relativeWorkspacePath||"."]}function G(i,t){return["--",N(i,t)]}function ht(i){const t=i.split("\0"),e=[];for(let a=0;a+4<t.length;a+=5){const r=t[a]?.trim();r&&e.push({hash:r,shortHash:t[a+1]?.trim()||r.slice(0,8),authorName:t[a+2]?.trim()||"unknown",authorDate:t[a+3]?.trim()||"",subject:t[a+4]?.trim()||r})}return e}P.post("/git/check",y,async(i,t)=>{const{workspacePath:e}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const a=await R(String(e).trim());t.json({ok:!0,isGitRepo:a.isGitRepo,hasRepository:a.hasRepository,usingParentGitRepo:a.usingParentGitRepo,workspacePath:a.workspacePath,repositoryRootPath:a.repositoryRootPath,relativeWorkspacePath:a.relativeWorkspacePath});return}catch(a){const r=a;t.status(500).json({error:r.message||"check git repo failed"})}}),P.post("/git/stash/create",y,async(i,t)=>{const{workspacePath:e,message:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=k.resolve(String(e).trim()),n=`\u5FEB\u7167\uFF08${new Date().toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}\uFF09`,s=a&&String(a).trim()?`\u5FEB\u7167: ${String(a).trim()}`:n,o=await p(r,["stash","push","-m",s]);if(ot(`${o.stdout}
7
7
  ${o.stderr}`)){const d=await p(r,["stash","list","-n","1","--format=%H%x00%gd%x00%gs%x00%cr"]),m=d.exitCode===0?z(d.stdout):null,g=m?await _(r,m.ref):null;t.json({ok:!0,stashRef:g??m?.ref??null,stashName:m?.stashName??null,message:m?`\u6CA1\u6709\u672C\u5730\u53D8\u66F4\u9700\u8981\u4FDD\u5B58\uFF0C\u5DF2\u590D\u7528\u6700\u8FD1\u5FEB\u7167 ${m.stashName}`:"\u6CA1\u6709\u672C\u5730\u53D8\u66F4\u9700\u8981\u4FDD\u5B58",noChanges:!0,reusedLatestStash:!!m,workspacePath:r});return}if(o.exitCode!==0){if(rt(`${o.stdout}
8
8
  ${o.stderr}`)){t.status(400).json({error:st()});return}t.status(400).json({error:o.stderr||"git stash push failed"});return}const l=await p(r,["stash","list","-n","1","--format=%H%x00%gd%x00%gs%x00%cr"]),c=l.exitCode===0?z(l.stdout):null,f=(c?await _(r,c.ref):null)??c?.ref??"stash@{0}";t.json({ok:!0,stashRef:f,stashName:c?.stashName??null,message:s,workspacePath:r})}catch(r){const n=r;t.status(500).json({error:n.message||"create stash failed"})}}),P.post("/git/stash/list",y,async(i,t)=>{const{workspacePath:e,limit:a=20}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=k.resolve(String(e).trim()),n=Math.min(Math.max(1,Number(a)||20),100),s=await p(r,["stash","list","-n",String(n),"--format=%H%x00%gd%x00%gs%x00%cr"]);if(s.exitCode!==0){t.status(400).json({error:s.stderr||"git stash list failed"});return}const o=s.stdout.split(`
9
- `).map(W).filter(l=>l!==null);t.json({ok:!0,stashes:o,count:o.length,workspacePath:r})}catch(r){const n=r;t.status(500).json({error:n.message||"list stash failed"})}});async function H(i,t,e){const{workspacePath:a,ref:r}=i.body||{};if(!a||!String(a).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const n=k.resolve(String(a).trim()),s=r&&String(r).trim()?String(r).trim():"stash@{0}";await p(n,["checkout","--","."]);const o=await p(n,["stash",e,s]);if(o.exitCode!==0){if(o.stdout.includes("CONFLICT")||o.stderr.includes("CONFLICT")){t.json({ok:!1,hasConflict:!0,message:"\u6062\u590D\u65F6\u53D1\u751F\u51B2\u7A81\uFF0C\u8BF7\u624B\u52A8\u89E3\u51B3",details:o.stdout||o.stderr,workspacePath:n});return}if(o.stderr.includes("is not a valid reference")){t.status(404).json({error:`\u5FEB\u7167 ${s} \u4E0D\u5B58\u5728`});return}t.status(400).json({error:o.stderr||`git stash ${e} failed`});return}t.json({ok:!0,stashRef:s,message:e==="apply"?`\u5DF2\u5E94\u7528 ${s}`:`\u5DF2\u6062\u590D ${s}`,preservedStash:e==="apply",workspacePath:n})}catch(n){const s=n;t.status(500).json({error:s.message||`${e} stash failed`})}}P.post("/git/stash/apply",y,async(i,t)=>{await H(i,t,"apply")}),P.post("/git/stash/pop",y,async(i,t)=>{await H(i,t,"pop")}),P.post("/git/stash/drop",y,async(i,t)=>{const{workspacePath:e,ref:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=k.resolve(String(e).trim()),n=a&&String(a).trim()?String(a).trim():"stash@{0}",s=await p(r,["stash","drop",n]);if(s.exitCode!==0){if(s.stderr.includes("is not a valid reference")){t.status(404).json({error:`\u5FEB\u7167 ${n} \u4E0D\u5B58\u5728`});return}t.status(400).json({error:s.stderr||"git stash drop failed"});return}t.json({ok:!0,stashRef:n,message:`\u5DF2\u5220\u9664 ${n}`,workspacePath:r})}catch(r){const n=r;t.status(500).json({error:n.message||"drop stash failed"})}}),P.post("/git/diff",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=await R(String(a||e).trim());if(!r.hasRepository||!r.repositoryRootPath){t.json({ok:!0,isGitRepo:r.isGitRepo,hasRepository:!1,usingParentGitRepo:!1,hasChanges:!1,files:[],workspacePath:r.workspacePath,repositoryRootPath:null,relativeWorkspacePath:""});return}const n=await p(r.repositoryRootPath,C(["diff","--name-status"],r));if(n.exitCode!==0){t.status(400).json({error:n.stderr||"git diff failed"});return}const s=await p(r.repositoryRootPath,C(["diff","--numstat"],r));if(s.exitCode!==0){t.status(400).json({error:s.stderr||"git diff failed"});return}const o=await p(r.repositoryRootPath,C(["diff","--cached","--name-status"],r));if(o.exitCode!==0){t.status(400).json({error:o.stderr||"git staged diff failed"});return}const l=await p(r.repositoryRootPath,C(["diff","--cached","--numstat"],r));if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git staged diff failed"});return}const c=await p(r.repositoryRootPath,C(["status","--porcelain=v1"],r));if(c.exitCode!==0){t.status(400).json({error:c.stderr||"git status failed"});return}const u=ct(c.stdout),f=ut(D(n.stdout,s.stdout,u),D(o.stdout,l.stdout,u,!0)),d=lt(c.stdout);if(d.length>0){const m=new Set(f.map(x=>x.path)),g=await ft(r.repositoryRootPath,d,m);f.push(...g)}t.json({ok:!0,isGitRepo:r.isGitRepo,hasRepository:!0,usingParentGitRepo:r.usingParentGitRepo,hasChanges:f.length>0,files:f,workspacePath:r.workspacePath,repositoryRootPath:r.repositoryRootPath,relativeWorkspacePath:r.relativeWorkspacePath})}catch(r){const n=r;t.status(500).json({error:n.message||"git diff failed"})}});async function mt(i){const t=[],e=await p(i,["config","user.name"]);(e.exitCode!==0||!e.stdout.trim())&&t.push("-c","user.name=AgentsWork");const a=await p(i,["config","user.email"]);return(a.exitCode!==0||!a.stdout.trim())&&t.push("-c","user.email=agent@agentswork.com"),t}P.post("/git/commit",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,message:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=dt(r);if(!n){t.status(400).json({error:"commit message is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=ht(s),l=await p(s.repositoryRootPath,["add","--all",...o]);if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git add failed"});return}const c=await p(s.repositoryRootPath,["diff","--cached","--quiet",...o]);if(c.exitCode===0){t.status(400).json({error:"\u6CA1\u6709\u53EF\u63D0\u4EA4\u7684\u53D8\u66F4"});return}if(c.exitCode!==1){t.status(400).json({error:c.stderr||"git staged diff failed"});return}const u=await mt(s.repositoryRootPath),f=await p(s.repositoryRootPath,[...u,"commit","-m",n,...o]);if(f.exitCode!==0){t.status(400).json({error:f.stderr||f.stdout||"git commit failed"});return}t.json({ok:!0,message:"\u63D0\u4EA4\u5B8C\u6210",output:f.stdout,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git commit failed"})}}),P.post("/git/add-file",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePath:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=S(String(r||"").trim());if(!n){t.status(400).json({error:"filePath is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=await p(s.repositoryRootPath,["add",...G(n,s)]);if(o.exitCode!==0){t.status(400).json({error:o.stderr||"git add file failed"});return}t.json({ok:!0,filePath:n,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git add file failed"})}}),P.post("/git/add-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const l=s.flatMap(d=>G(d,o)),c=["add"],u=[];for(let d=0;d<l.length;d++)l[d]!=="--"&&u.push(l[d]);c.push("--",...u);const f=await p(o.repositoryRootPath,c);if(f.exitCode!==0){t.status(400).json({error:f.stderr||"git add files failed"});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git add files failed"})}}),P.post("/git/commits",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,limit:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const n=await R(String(a||e).trim());if(!n.hasRepository||!n.repositoryRootPath){t.json({ok:!0,commits:[],workspacePath:n.workspacePath,repositoryRootPath:null});return}const s=Number(r),o=Number.isInteger(s)&&s>0&&s<=100?s:30,l=await p(n.repositoryRootPath,["log",`-${o}`,"--date=iso-strict","--pretty=format:%H%x00%h%x00%an%x00%ad%x00%s%x00","--",n.relativeWorkspacePath||"."]);if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git log failed"});return}t.json({ok:!0,commits:pt(l.stdout),workspacePath:n.workspacePath,repositoryRootPath:n.repositoryRootPath,relativeWorkspacePath:n.relativeWorkspacePath})}catch(n){const s=n;t.status(500).json({error:s.message||"git commits failed"})}}),P.post("/git/commit-diff",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,commitHash:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=q(r);if(!n){t.status(400).json({error:"commitHash is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=["diff",`${n}^!`],l=await p(s.repositoryRootPath,C([...o,"--name-status"],s));if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git commit diff failed"});return}const c=await p(s.repositoryRootPath,C([...o,"--numstat"],s));if(c.exitCode!==0){t.status(400).json({error:c.stderr||"git commit diff failed"});return}const u=D(l.stdout,c.stdout);t.json({ok:!0,commitHash:n,isGitRepo:s.isGitRepo,hasRepository:!0,usingParentGitRepo:s.usingParentGitRepo,hasChanges:u.length>0,files:u,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git commit diff failed"})}}),P.post("/git/diff-file",y,async(i,t)=>{const{workspacePath:e,filePath:a,commitHash:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!a||!String(a).trim()){t.status(400).json({error:"filePath is required"});return}try{const n=await R(String(e).trim()),s=S(String(a).trim());if(!n.hasRepository||!n.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=N(s,n),l=q(r),c=l?["show","--format=","--no-ext-diff",l,"--",o]:["diff","HEAD","--",o];let u=await p(n.repositoryRootPath,c);if(!l&&u.exitCode!==0&&(u=await p(n.repositoryRootPath,["diff","--",o])),u.exitCode!==0){t.status(400).json({error:u.stderr||"git diff file failed"});return}if(!l&&!u.stdout.trim()){const f=await p(n.repositoryRootPath,["diff","--cached","--",o]);if(f.exitCode!==0){t.status(400).json({error:f.stderr||"git staged diff file failed"});return}u=f}if(!l&&!u.stdout.trim()){const f=k.join(n.repositoryRootPath,o);try{const d=await A.readFile(f,"utf-8");if(d){const m=d.split(`
9
+ `).map(W).filter(l=>l!==null);t.json({ok:!0,stashes:o,count:o.length,workspacePath:r})}catch(r){const n=r;t.status(500).json({error:n.message||"list stash failed"})}});async function H(i,t,e){const{workspacePath:a,ref:r}=i.body||{};if(!a||!String(a).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const n=k.resolve(String(a).trim()),s=r&&String(r).trim()?String(r).trim():"stash@{0}";await p(n,["checkout","--","."]);const o=await p(n,["stash",e,s]);if(o.exitCode!==0){if(o.stdout.includes("CONFLICT")||o.stderr.includes("CONFLICT")){t.json({ok:!1,hasConflict:!0,message:"\u6062\u590D\u65F6\u53D1\u751F\u51B2\u7A81\uFF0C\u8BF7\u624B\u52A8\u89E3\u51B3",details:o.stdout||o.stderr,workspacePath:n});return}if(o.stderr.includes("is not a valid reference")){t.status(404).json({error:`\u5FEB\u7167 ${s} \u4E0D\u5B58\u5728`});return}t.status(400).json({error:o.stderr||`git stash ${e} failed`});return}t.json({ok:!0,stashRef:s,message:e==="apply"?`\u5DF2\u5E94\u7528 ${s}`:`\u5DF2\u6062\u590D ${s}`,preservedStash:e==="apply",workspacePath:n})}catch(n){const s=n;t.status(500).json({error:s.message||`${e} stash failed`})}}P.post("/git/stash/apply",y,async(i,t)=>{await H(i,t,"apply")}),P.post("/git/stash/pop",y,async(i,t)=>{await H(i,t,"pop")}),P.post("/git/stash/drop",y,async(i,t)=>{const{workspacePath:e,ref:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=k.resolve(String(e).trim()),n=a&&String(a).trim()?String(a).trim():"stash@{0}",s=await p(r,["stash","drop",n]);if(s.exitCode!==0){if(s.stderr.includes("is not a valid reference")){t.status(404).json({error:`\u5FEB\u7167 ${n} \u4E0D\u5B58\u5728`});return}t.status(400).json({error:s.stderr||"git stash drop failed"});return}t.json({ok:!0,stashRef:n,message:`\u5DF2\u5220\u9664 ${n}`,workspacePath:r})}catch(r){const n=r;t.status(500).json({error:n.message||"drop stash failed"})}}),P.post("/git/diff",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const r=await R(String(a||e).trim());if(!r.hasRepository||!r.repositoryRootPath){t.json({ok:!0,isGitRepo:r.isGitRepo,hasRepository:!1,usingParentGitRepo:!1,hasChanges:!1,files:[],workspacePath:r.workspacePath,repositoryRootPath:null,relativeWorkspacePath:""});return}const n=await p(r.repositoryRootPath,C(["diff","--name-status"],r));if(n.exitCode!==0){t.status(400).json({error:n.stderr||"git diff failed"});return}const s=await p(r.repositoryRootPath,C(["diff","--numstat"],r));if(s.exitCode!==0){t.status(400).json({error:s.stderr||"git diff failed"});return}const o=await p(r.repositoryRootPath,C(["diff","--cached","--name-status"],r));if(o.exitCode!==0){t.status(400).json({error:o.stderr||"git staged diff failed"});return}const l=await p(r.repositoryRootPath,C(["diff","--cached","--numstat"],r));if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git staged diff failed"});return}const c=await p(r.repositoryRootPath,C(["status","--porcelain=v1"],r));if(c.exitCode!==0){t.status(400).json({error:c.stderr||"git status failed"});return}const u=nt(c.stdout),f=ft(D(n.stdout,s.stdout,u),D(o.stdout,l.stdout,u,!0)),d=ct(c.stdout);if(d.length>0){const m=new Set(f.map(x=>x.path)),g=await lt(r.repositoryRootPath,d,m);f.push(...g)}t.json({ok:!0,isGitRepo:r.isGitRepo,hasRepository:!0,usingParentGitRepo:r.usingParentGitRepo,hasChanges:f.length>0,files:f,workspacePath:r.workspacePath,repositoryRootPath:r.repositoryRootPath,relativeWorkspacePath:r.relativeWorkspacePath})}catch(r){const n=r;t.status(500).json({error:n.message||"git diff failed"})}});async function pt(i){const t=[],e=await p(i,["config","user.name"]);(e.exitCode!==0||!e.stdout.trim())&&t.push("-c","user.name=AgentsWork");const a=await p(i,["config","user.email"]);return(a.exitCode!==0||!a.stdout.trim())&&t.push("-c","user.email=agent@agentswork.com"),t}P.post("/git/commit",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,message:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=ut(r);if(!n){t.status(400).json({error:"commit message is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=dt(s),l=await p(s.repositoryRootPath,["add","--all",...o]);if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git add failed"});return}const c=await p(s.repositoryRootPath,["diff","--cached","--quiet",...o]);if(c.exitCode===0){t.status(400).json({error:"\u6CA1\u6709\u53EF\u63D0\u4EA4\u7684\u53D8\u66F4"});return}if(c.exitCode!==1){t.status(400).json({error:c.stderr||"git staged diff failed"});return}const u=await pt(s.repositoryRootPath),f=await p(s.repositoryRootPath,[...u,"commit","-m",n,...o]);if(f.exitCode!==0){t.status(400).json({error:f.stderr||f.stdout||"git commit failed"});return}t.json({ok:!0,message:"\u63D0\u4EA4\u5B8C\u6210",output:f.stdout,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git commit failed"})}}),P.post("/git/add-file",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePath:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=S(String(r||"").trim());if(!n){t.status(400).json({error:"filePath is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=await p(s.repositoryRootPath,["add",...G(n,s)]);if(o.exitCode!==0){t.status(400).json({error:o.stderr||"git add file failed"});return}t.json({ok:!0,filePath:n,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git add file failed"})}}),P.post("/git/add-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const l=s.flatMap(d=>G(d,o)),c=["add"],u=[];for(let d=0;d<l.length;d++)l[d]!=="--"&&u.push(l[d]);c.push("--",...u);const f=await p(o.repositoryRootPath,c);if(f.exitCode!==0){t.status(400).json({error:f.stderr||"git add files failed"});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git add files failed"})}}),P.post("/git/commits",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,limit:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}try{const n=await R(String(a||e).trim());if(!n.hasRepository||!n.repositoryRootPath){t.json({ok:!0,commits:[],workspacePath:n.workspacePath,repositoryRootPath:null});return}const s=Number(r),o=Number.isInteger(s)&&s>0&&s<=100?s:30,l=await p(n.repositoryRootPath,["log",`-${o}`,"--date=iso-strict","--pretty=format:%H%x00%h%x00%an%x00%ad%x00%s%x00","--",n.relativeWorkspacePath||"."]);if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git log failed"});return}t.json({ok:!0,commits:ht(l.stdout),workspacePath:n.workspacePath,repositoryRootPath:n.repositoryRootPath,relativeWorkspacePath:n.relativeWorkspacePath})}catch(n){const s=n;t.status(500).json({error:s.message||"git commits failed"})}}),P.post("/git/commit-diff",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,commitHash:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const n=q(r);if(!n){t.status(400).json({error:"commitHash is required"});return}try{const s=await R(String(a||e).trim());if(!s.hasRepository||!s.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=["diff",`${n}^!`],l=await p(s.repositoryRootPath,C([...o,"--name-status"],s));if(l.exitCode!==0){t.status(400).json({error:l.stderr||"git commit diff failed"});return}const c=await p(s.repositoryRootPath,C([...o,"--numstat"],s));if(c.exitCode!==0){t.status(400).json({error:c.stderr||"git commit diff failed"});return}const u=D(l.stdout,c.stdout);t.json({ok:!0,commitHash:n,isGitRepo:s.isGitRepo,hasRepository:!0,usingParentGitRepo:s.usingParentGitRepo,hasChanges:u.length>0,files:u,workspacePath:s.workspacePath,repositoryRootPath:s.repositoryRootPath,relativeWorkspacePath:s.relativeWorkspacePath})}catch(s){const o=s;t.status(500).json({error:o.message||"git commit diff failed"})}}),P.post("/git/diff-file",y,async(i,t)=>{const{workspacePath:e,filePath:a,commitHash:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!a||!String(a).trim()){t.status(400).json({error:"filePath is required"});return}try{const n=await R(String(e).trim()),s=S(String(a).trim());if(!n.hasRepository||!n.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}const o=N(s,n),l=q(r),c=l?["show","--format=","--no-ext-diff",l,"--",o]:["diff","HEAD","--",o];let u=await p(n.repositoryRootPath,c);if(!l&&u.exitCode!==0&&(u=await p(n.repositoryRootPath,["diff","--",o])),u.exitCode!==0){t.status(400).json({error:u.stderr||"git diff file failed"});return}if(!l&&!u.stdout.trim()){const f=await p(n.repositoryRootPath,["diff","--cached","--",o]);if(f.exitCode!==0){t.status(400).json({error:f.stderr||"git staged diff file failed"});return}u=f}if(!l&&!u.stdout.trim()){const f=k.join(n.repositoryRootPath,o);try{const d=await A.readFile(f,"utf-8");if(d){const m=d.split(`
10
10
  `).map(x=>`+${x}`).join(`
11
11
  `),g=d.split(`
12
12
  `).length;u={stdout:[`diff --git a/${o} b/${o}`,"new file mode 100644","--- /dev/null",`+++ b/${o}`,`@@ -0,0 +1,${g} @@`,m].join(`
13
13
  `),stderr:"",exitCode:0}}}catch{}}t.json({ok:!0,filePath:s,repositoryRelativeFilePath:o,commitHash:l||null,diffContent:u.stdout,workspacePath:n.workspacePath,repositoryRootPath:n.repositoryRootPath,usingParentGitRepo:n.usingParentGitRepo})}catch(n){const s=n;t.status(500).json({error:s.message||"git diff file failed"})}});const J=["STRICTLY act as a Git commit message generator. NEVER explain, narrate, or describe your task.",'NEVER start your reply with phrases like "\u6211\u4EEC\u88AB\u95EE\u5230", "\u4EE5\u4E0B\u662F", "\u597D\u7684", "Sure", "Here is", "I will", "I can", "Let me", "\u6839\u636E", "\u4E0B\u9762".',"NEVER include any meta-language or thinking out loud. Output ONLY the commit message text.","","Format (Conventional Commits, 1 line, optional body):"," <type>(<scope>): <description>","","Allowed types: feat, fix, refactor, test, docs, style, chore, perf, ci, build, revert.","First line MUST be <= 72 characters. <description> MUST be in Chinese.","Add a body (separated by a blank line) ONLY when the change needs more context."].join(`
14
14
  `);function U(i){return["\u8BF7\u76F4\u63A5\u8F93\u51FA\u4E0A\u8FF0\u683C\u5F0F\u7684\u63D0\u4EA4\u4FE1\u606F,\u4E0D\u8981\u4EFB\u4F55\u989D\u5916\u6587\u5B57\u3002","\u4EE5\u4E0B\u662F\u6682\u5B58\u533A diff:","",i].join(`
15
- `)}const B=/\b(?:feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)(?:\s*\([^)]*\))?\s*:/i,gt=/^(?:feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)\s*:/i;function yt(i){const t=i.split(`
16
- `)[0]?.trim()??"";if(!t||t.length<3)return!1;const e=(t.match(/[\u4e00-\u9fa5]/g)||[]).length,a=(t.match(/[a-zA-Z]{2,}/g)||[]).length;if(e===0&&a===0)return!1;const r=[/^以下是/,/^上面是/,/^生成的/,/^这是/,/^下面/,/^(?:Here|This|This is|That is)/i];for(const n of r)if(n.test(t))return!1;return e>=2||a>=2}const Pt=[/^\s*(?:我们|我)\s*(?:被\s*)?(?:问[到过]?|需要|要|将|来|先)[^.:\n]{0,60}?(?:提交信息|commit\s*message|[::,,。])/i,/^\s*(?:好的|好)\s*[,,::]/i,/^\s*(?:好的|好)\s*(?:以下是|上面是|提供|生成|给出)[^.:\n]{0,20}?[::]?/i,/^\s*是\s*[::]/i,/^\s*(?:Sure|Here(?:'s|\s+is)|We(?:'re| are)|I\s+(?:will|can|'ll)|Let\s+me|Certainly|Of\s+course)[^.:\n]{0,40}?[,,::.]/i,/^\s*根据\s*(?:您|你|您所|你所|所)?\s*(?:提供|上述|给[我您你])?\s*(?:的)?\s*diff\s*[,,::]?/i,/^\s*(?:以下|下面)[^,,::\n]{0,30}?提交信息\s*[,,::]?/i,/^\s*(?:以下|下面)\s*是\s*[,,::]/i,/^\s*生成\s*(?:一条|一个|了)?\s*(?:符合|新的)?\s*(?:conventional\s*commit|git)?\s*提交信息\s*[,,::]?/i,/^\s*```(?:text|markdown|bash|shell)?\s*\n?/i];function v(i){if(!i)return h.info("[Git/sanitize] \u8F93\u5165\u4E3A\u7A7A, \u8FD4\u56DE fallback"),"chore: update staged changes";let t=i.replace(/\r\n/g,`
17
- `).trim();const e=JSON.stringify(i.substring(0,120)),a=t.match(B);if(a&&a.index!==void 0&&a.index<=80)t=t.slice(a.index);else{for(let f=0;f<5;f+=1){const d=t;for(const m of Pt)t=t.replace(m,"");if(t=t.replace(/^[\s*\-`,,']+/,"").trim(),t===d)break}const s=t.split(`
18
- `)[0]?.trim()??"",o=!!t.match(B),l=!!t.match(gt),c=yt(t),u=s.length>100;if(!o&&!l&&!c&&!u)return h.info(`[Git/sanitize] \u5265\u79BB\u540E\u65E0\u6709\u6548\u5185\u5BB9, \u8FD4\u56DE fallback. raw=${e}, afterStrip=${JSON.stringify(t.substring(0,100))}`),"chore: update staged changes";!o&&(l||c||u)&&(t=s||t)}const r=t.search(/\n\s*\n/);if(r>0&&(t=t.slice(0,r)),t=t.replace(/\n+\s*```\s*$/g,"").trim(),!t)return h.info(`[Git/sanitize] \u622A\u65AD\u540E\u4E3A\u7A7A, \u8FD4\u56DE fallback. raw=${e}`),"chore: update staged changes";const n=t.split(`
19
- `)[0]?.trim()??"";return n.length>100?(h.info(`[Git/sanitize] \u9996\u884C\u8D85\u8FC7 100 \u5B57\u7B26, \u4EC5\u4FDD\u7559\u9996\u884C. raw=${e}, firstLine=${JSON.stringify(n.substring(0,100))}`),n):(h.info(`[Git/sanitize] \u7ED3\u679C: ${JSON.stringify(t.substring(0,120))} (from raw=${e})`),t)}function K(i){const t=i.split(/\r?\n/);let e="";for(const a of t){const r=a.trim();if(!r.startsWith("data:"))continue;const n=r.slice(5).trim();if(!(!n||n==="[DONE]"))try{const o=JSON.parse(n)?.choices?.[0]?.delta?.content;typeof o=="string"&&o.length>0&&(e+=o)}catch{}}return e}function wt(i,t){if(t>5)return;const e=i.split(/\r?\n/);for(const a of e){const r=a.trim();if(!r.startsWith("data:"))continue;const n=r.slice(5).trim();if(!(!n||n==="[DONE]"))try{const s=JSON.parse(n),o=Object.keys(s),l=s?.choices,c=Array.isArray(l)?l[0]:null,u=c?.delta?Object.keys(c.delta):null,f=c?.delta?.content;h.info(`[Git/extract] chunk#${t} structure: topKeys=${JSON.stringify(o)}, choicesLen=${Array.isArray(l)?l.length:typeof l}, deltaKeys=${JSON.stringify(u)}, content=${JSON.stringify(f?.substring(0,50))}, finishReason=${JSON.stringify(c?.finish_reason)}`)}catch{}}}async function St(i,t,e,a){const r=`${i.replace(/\/+$/,"")}/chat/completions`,o=(await L.post(r,{model:e,stream:!1,messages:[{role:"system",content:J},{role:"user",content:U(a)}],max_tokens:200,temperature:.2},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},timeout:3e4})).data?.choices?.[0]?.message?.content?.trim()||"";return v(o)}async function kt(i,t,e,a,r,n){const s=`${i.replace(/\/+$/,"")}/chat/completions`,l=(await L.post(s,{model:e,stream:!0,messages:[{role:"system",content:J},{role:"user",content:U(a)}],max_tokens:200,temperature:.2},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`,Accept:"text/event-stream"},timeout:Number(process.env.AWS_AI_STREAM_TIMEOUT_MS)||6e4,responseType:"stream",signal:n})).data;let c="",u="",f="",d=0,m=0;return h.info(`[Git/streamAi] AI \u6D41\u5F00\u59CB: aiModel=${e}`),await new Promise((g,x)=>{const b=w=>{l.removeAllListeners("data"),l.removeAllListeners("end"),l.removeAllListeners("error"),l.removeAllListeners("aborted"),h.info(`[Git/streamAi] AI \u6D41\u7ED3\u675F: totalChunks=${d}, totalDeltas=${m}, bufferLength=${c.length}, sanitized=${JSON.stringify(w).substring(0,200)}`),g(w)};l.on("data",w=>{const j=typeof w=="string"?w:w.toString("utf8");d++,f+=j,d<=3&&h.info(`[Git/streamAi] chunk#${d}: length=${j.length}, preview=${JSON.stringify(j.substring(0,80))}`),wt(j,d);const F=f.split(/\n\n/);f=F.pop()??"";for(const Y of F){const M=K(Y);M&&(m++,c+=M,u=v(c),r(M,u))}}),l.on("end",()=>{if(f.trim()){const w=K(f);w?(h.info(`[Git/streamAi] \u5C3E\u90E8\u6B8B\u7559 delta: length=${w.length}`),c+=w):h.info(`[Git/streamAi] \u5C3E\u90E8\u6B8B\u7559\u65E0 delta, pendingData=${JSON.stringify(f.substring(0,100))}`)}b(v(c))}),l.on("error",w=>{h.error(`[Git/streamAi] \u6D41\u9519\u8BEF: ${w.message}`),x(w)}),l.on("aborted",()=>{h.info(`[Git/streamAi] \u6D41\u88AB\u4E2D\u6B62, bufferLength=${c.length}`),b(v(c))})})}async function E(i,t,e){const a=await R(String(i||t).trim());if(!a.hasRepository||!a.repositoryRootPath)return h.warn(`[Git/collectDiff] \u4E0D\u5728 Git \u4ED3\u5E93\u4E2D: workspacePath=${t}`),{truncatedDiff:"",error:{status:400,message:"workspace is not inside a git repository"}};const r=e.map(c=>c.path).filter(Boolean);h.info(`[Git/collectDiff] \u5F00\u59CB\u6536\u96C6 ${r.length} \u4E2A\u6682\u5B58\u6587\u4EF6\u5DEE\u5F02: ${r.join(", ").substring(0,200)}`);const n=[];for(const c of r){const u=N(c,a),f=await p(a.repositoryRootPath,["diff","--cached","--",u]);f.exitCode===0&&f.stdout.trim()?n.push(`--- ${c} ---
15
+ `)}const B=/\b(?:feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)(?:\s*\([^)]*\))?\s*:/i,mt=/^(?:feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)\s*:/i;function gt(i){const t=i.split(`
16
+ `)[0]?.trim()??"";if(!t||t.length<3)return!1;const e=(t.match(/[\u4e00-\u9fa5]/g)||[]).length,a=(t.match(/[a-zA-Z]{2,}/g)||[]).length;if(e===0&&a===0)return!1;const r=[/^以下是/,/^上面是/,/^生成的/,/^这是/,/^下面/,/^(?:Here|This|This is|That is)/i];for(const n of r)if(n.test(t))return!1;return e>=2||a>=2}const yt=[/^\s*(?:我们|我)\s*(?:被\s*)?(?:问[到过]?|需要|要|将|来|先)[^.:\n]{0,60}?(?:提交信息|commit\s*message|[::,,。])/i,/^\s*(?:好的|好)\s*[,,::]/i,/^\s*(?:好的|好)\s*(?:以下是|上面是|提供|生成|给出)[^.:\n]{0,20}?[::]?/i,/^\s*是\s*[::]/i,/^\s*(?:Sure|Here(?:'s|\s+is)|We(?:'re| are)|I\s+(?:will|can|'ll)|Let\s+me|Certainly|Of\s+course)[^.:\n]{0,40}?[,,::.]/i,/^\s*根据\s*(?:您|你|您所|你所|所)?\s*(?:提供|上述|给[我您你])?\s*(?:的)?\s*diff\s*[,,::]?/i,/^\s*(?:以下|下面)[^,,::\n]{0,30}?提交信息\s*[,,::]?/i,/^\s*(?:以下|下面)\s*是\s*[,,::]/i,/^\s*生成\s*(?:一条|一个|了)?\s*(?:符合|新的)?\s*(?:conventional\s*commit|git)?\s*提交信息\s*[,,::]?/i,/^\s*```(?:text|markdown|bash|shell)?\s*\n?/i];function v(i){if(!i)return h.info("[Git/sanitize] \u8F93\u5165\u4E3A\u7A7A, \u8FD4\u56DE fallback"),"chore: update staged changes";let t=i.replace(/\r\n/g,`
17
+ `).trim();const e=JSON.stringify(i.substring(0,120)),a=t.match(B);if(a&&a.index!==void 0&&a.index<=80)t=t.slice(a.index);else{for(let f=0;f<5;f+=1){const d=t;for(const m of yt)t=t.replace(m,"");if(t=t.replace(/^[\s*\-`,,']+/,"").trim(),t===d)break}const s=t.split(`
18
+ `)[0]?.trim()??"",o=!!t.match(B),l=!!t.match(mt),c=gt(t),u=s.length>100;if(!o&&!l&&!c&&!u)return h.info(`[Git/sanitize] \u5265\u79BB\u540E\u65E0\u6709\u6548\u5185\u5BB9, \u8FD4\u56DE fallback. raw=${e}, afterStrip=${JSON.stringify(t.substring(0,100))}`),"chore: update staged changes";!o&&(l||c||u)&&(t=s||t)}const r=t.search(/\n\s*\n/);if(r>0&&(t=t.slice(0,r)),t=t.replace(/\n+\s*```\s*$/g,"").trim(),!t)return h.info(`[Git/sanitize] \u622A\u65AD\u540E\u4E3A\u7A7A, \u8FD4\u56DE fallback. raw=${e}`),"chore: update staged changes";const n=t.split(`
19
+ `)[0]?.trim()??"";return n.length>100?(h.info(`[Git/sanitize] \u9996\u884C\u8D85\u8FC7 100 \u5B57\u7B26, \u4EC5\u4FDD\u7559\u9996\u884C. raw=${e}, firstLine=${JSON.stringify(n.substring(0,100))}`),n):(h.info(`[Git/sanitize] \u7ED3\u679C: ${JSON.stringify(t.substring(0,120))} (from raw=${e})`),t)}function K(i){const t=i.split(/\r?\n/);let e="";for(const a of t){const r=a.trim();if(!r.startsWith("data:"))continue;const n=r.slice(5).trim();if(!(!n||n==="[DONE]"))try{const o=JSON.parse(n)?.choices?.[0]?.delta?.content;typeof o=="string"&&o.length>0&&(e+=o)}catch{}}return e}function Pt(i,t){if(t>5)return;const e=i.split(/\r?\n/);for(const a of e){const r=a.trim();if(!r.startsWith("data:"))continue;const n=r.slice(5).trim();if(!(!n||n==="[DONE]"))try{const s=JSON.parse(n),o=Object.keys(s),l=s?.choices,c=Array.isArray(l)?l[0]:null,u=c?.delta?Object.keys(c.delta):null,f=c?.delta?.content;h.info(`[Git/extract] chunk#${t} structure: topKeys=${JSON.stringify(o)}, choicesLen=${Array.isArray(l)?l.length:typeof l}, deltaKeys=${JSON.stringify(u)}, content=${JSON.stringify(f?.substring(0,50))}, finishReason=${JSON.stringify(c?.finish_reason)}`)}catch{}}}async function wt(i,t,e,a){const r=`${i.replace(/\/+$/,"")}/chat/completions`,o=(await L.post(r,{model:e,stream:!1,messages:[{role:"system",content:J},{role:"user",content:U(a)}],max_tokens:200,temperature:.2},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},timeout:3e4})).data?.choices?.[0]?.message?.content?.trim()||"";return v(o)}async function St(i,t,e,a,r,n){const s=`${i.replace(/\/+$/,"")}/chat/completions`,l=(await L.post(s,{model:e,stream:!0,messages:[{role:"system",content:J},{role:"user",content:U(a)}],max_tokens:200,temperature:.2},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`,Accept:"text/event-stream"},timeout:Number(process.env.AWS_AI_STREAM_TIMEOUT_MS)||6e4,responseType:"stream",signal:n})).data;let c="",u="",f="",d=0,m=0;return h.info(`[Git/streamAi] AI \u6D41\u5F00\u59CB: aiModel=${e}`),await new Promise((g,x)=>{const b=w=>{l.removeAllListeners("data"),l.removeAllListeners("end"),l.removeAllListeners("error"),l.removeAllListeners("aborted"),h.info(`[Git/streamAi] AI \u6D41\u7ED3\u675F: totalChunks=${d}, totalDeltas=${m}, bufferLength=${c.length}, sanitized=${JSON.stringify(w).substring(0,200)}`),g(w)};l.on("data",w=>{const j=typeof w=="string"?w:w.toString("utf8");d++,f+=j,d<=3&&h.info(`[Git/streamAi] chunk#${d}: length=${j.length}, preview=${JSON.stringify(j.substring(0,80))}`),Pt(j,d);const F=f.split(/\n\n/);f=F.pop()??"";for(const Y of F){const M=K(Y);M&&(m++,c+=M,u=v(c),r(M,u))}}),l.on("end",()=>{if(f.trim()){const w=K(f);w?(h.info(`[Git/streamAi] \u5C3E\u90E8\u6B8B\u7559 delta: length=${w.length}`),c+=w):h.info(`[Git/streamAi] \u5C3E\u90E8\u6B8B\u7559\u65E0 delta, pendingData=${JSON.stringify(f.substring(0,100))}`)}b(v(c))}),l.on("error",w=>{h.error(`[Git/streamAi] \u6D41\u9519\u8BEF: ${w.message}`),x(w)}),l.on("aborted",()=>{h.info(`[Git/streamAi] \u6D41\u88AB\u4E2D\u6B62, bufferLength=${c.length}`),b(v(c))})})}async function E(i,t,e){const a=await R(String(i||t).trim());if(!a.hasRepository||!a.repositoryRootPath)return h.warn(`[Git/collectDiff] \u4E0D\u5728 Git \u4ED3\u5E93\u4E2D: workspacePath=${t}`),{truncatedDiff:"",error:{status:400,message:"workspace is not inside a git repository"}};const r=e.map(c=>c.path).filter(Boolean);h.info(`[Git/collectDiff] \u5F00\u59CB\u6536\u96C6 ${r.length} \u4E2A\u6682\u5B58\u6587\u4EF6\u5DEE\u5F02: ${r.join(", ").substring(0,200)}`);const n=[];for(const c of r){const u=N(c,a),f=await p(a.repositoryRootPath,["diff","--cached","--",u]);f.exitCode===0&&f.stdout.trim()?n.push(`--- ${c} ---
20
20
  ${f.stdout.trim()}`):h.info(`[Git/collectDiff] \u6587\u4EF6\u65E0\u6682\u5B58\u5DEE\u5F02\u6216\u83B7\u53D6\u5931\u8D25: ${c}, exitCode=${f.exitCode}, stdout.length=${f.stdout.length}`)}if(n.length===0){h.info("[Git/collectDiff] \u9010\u6587\u4EF6 diff \u4E3A\u7A7A, \u56DE\u9000\u5230\u5168\u91CF diff --cached");const c=await p(a.repositoryRootPath,["diff","--cached"]);c.exitCode===0&&c.stdout.trim()?(n.push(c.stdout.trim()),h.info(`[Git/collectDiff] \u5168\u91CF diff \u83B7\u53D6\u6210\u529F: length=${c.stdout.trim().length}`)):h.info(`[Git/collectDiff] \u5168\u91CF diff \u4E5F\u4E3A\u7A7A, exitCode=${c.exitCode}`)}if(n.length===0)return h.info("[Git/collectDiff] \u6682\u5B58\u533A\u6CA1\u6709\u5DEE\u5F02\u5185\u5BB9 (diffParts \u4E3A\u7A7A)"),{truncatedDiff:""};const s=n.join(`
21
21
 
22
22
  `),o=15e3,l=s.length>o?`${s.slice(0,o)}
23
23
  ...(diff truncated due to length)`:s;return h.info(`[Git/collectDiff] \u6536\u96C6\u5B8C\u6210: diffContent.length=${s.length}, truncated=${l.length}`),{truncatedDiff:l}}function $(i,t,e){try{i.write(`event: ${t}
24
24
  `),i.write(`data: ${JSON.stringify(e)}
25
25
 
26
- `)}catch{}}P.post("/git/generate-commit-message",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r,aiBaseUrl:n,aiApiKey:s,aiModel:o}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}if(!n||!String(n).trim()||!s||!String(s).trim()||!o||!String(o).trim()){t.status(400).json({error:"aiBaseUrl, aiApiKey and aiModel are required"});return}try{const{truncatedDiff:l,error:c}=await E(String(a||""),String(e),r);if(c){t.status(c.status).json({error:c.message});return}if(!l){t.json({message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"});return}const u=await St(n,s,o,l);t.json({message:u})}catch(l){const c=l;h.error(`[Git] generate commit message failed: ${c.message}`),t.status(500).json({error:c.message||"generate commit message failed"})}}),P.post("/git/generate-commit-message-stream",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r,aiBaseUrl:n,aiApiKey:s,aiModel:o}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}if(!n||!String(n).trim()||!s||!String(s).trim()||!o||!String(o).trim()){t.status(400).json({error:"aiBaseUrl, aiApiKey and aiModel are required"});return}h.info(`[Git/SSE] \u6536\u5230 generate-commit-message-stream \u8BF7\u6C42: workspacePath=${String(e||"").substring(0,40)}, stagedFiles=${r?.length??0}, aiModel=${o}, aiBaseUrl=${n}`),t.status(200),t.setHeader("Content-Type","text/event-stream; charset=utf-8"),t.setHeader("Cache-Control","no-cache, no-transform"),t.setHeader("Connection","keep-alive"),t.setHeader("X-Accel-Buffering","no"),i.socket?.setNoDelay(!0),t.flushHeaders?.();let l=!1,c=null,u=!1;const f={delta:0},d=`${i.ip}:${i.socket?.remotePort??"?"}`;i.on("close",()=>{l||(l=!0,h.info(`[Git/SSE] \u5BA2\u6237\u7AEF\u65AD\u5F00\u8FDE\u63A5: workspacePath=${String(e||"").substring(0,40)}, deltaEventsSent=${f.delta}, peer=${d}`))}),$(t,"init",{status:"generating"});try{const{truncatedDiff:m,error:g}=await E(String(a||""),String(e),r);if(g){h.warn(`[Git/SSE] collectStagedDiffForAi \u8FD4\u56DE\u9519\u8BEF: ${g.message}`),$(t,"error",{message:g.message}),t.end();return}if(!m){h.info("[Git/SSE] \u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9, \u76F4\u63A5\u8FD4\u56DE done"),$(t,"delta",{contentDelta:"",message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"}),$(t,"done",{message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"}),t.end();return}h.info(`[Git/SSE] \u6536\u96C6\u5230 diff: truncatedDiff.length=${m.length}`),l&&h.info("[Git/SSE] \u5BA2\u6237\u7AEF\u5728 collectDiff \u671F\u95F4\u65AD\u5F00, \u4F46\u4ECD\u5C1D\u8BD5 AI \u8C03\u7528"),h.info(`[Git/SSE] \u5F00\u59CB\u8C03\u7528 AI streamAiForCommitMessage: aiModel=${o}`),c=new AbortController;let x="";const b=await kt(n,s,o,m,(w,j)=>{f.delta++,j!==x?(x=j,$(t,"delta",{contentDelta:w,message:j})):$(t,"delta",{contentDelta:w,message:j})},c.signal);h.info(`[Git/SSE] AI streamAiForCommitMessage \u5B8C\u6210: finalMessage=${JSON.stringify(b).substring(0,200)}, deltaEventsSent=${f.delta}`),l||$(t,"done",{message:b}),t.end()}catch(m){const g=m;h.error(`[Git/SSE] stream commit message failed: ${g.message}${g.stack?`
27
- `+g.stack:""}`),l||$(t,"error",{message:g.message||"generate commit message failed"}),t.end()}}),P.post("/git/unstage-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}let l="";for(const c of s){const u=G(c,o),f=await p(o.repositoryRootPath,["restore","--staged",...u]);f.exitCode!==0&&(l=f.stderr||`git restore --staged failed for ${c}`)}if(l){t.status(400).json({error:l});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git unstage files failed"})}}),P.post("/git/restore-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}let l="";for(const c of s){const u=G(c,o),f=await p(o.repositoryRootPath,["restore",...u]);f.exitCode!==0&&(l=f.stderr||`git restore failed for ${c}`)}if(l){t.status(400).json({error:l});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git restore files failed"})}}),P.post("/git/diff-content",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}try{const{truncatedDiff:n,error:s}=await E(String(a||""),String(e),r);if(s){t.status(s.status).json({error:s.message});return}t.json({ok:!0,diff:n||""})}catch(n){const s=n;h.error(`[Git/diff-content] \u83B7\u53D6\u6682\u5B58\u533A\u5DEE\u5F02\u5931\u8D25: ${s.message}`),t.status(500).json({error:s.message||"get diff content failed"})}});export{Q as assertGitWorkspacePathAccessible,St as callAiForCommitMessage,it as createAgentsWorkStashSnapshotRef,st as createMissingInitialCommitSnapshotError,G as createScopedFilePathspecArgs,ht as createScopedGitPathspecArgs,wt as debugAiStreamChunk,K as extractOpenAiStreamDelta,P as gitRouter,rt as isGitStashMissingInitialCommitError,ot as isGitStashNoChangesOutput,ut as mergeGitDiffSummaryFiles,dt as normalizeGitCommitMessage,D as parseGitDiffSummary,W as parseGitStashListLine,ct as parseGitStatusStagedPaths,lt as parseGitStatusUntrackedPaths,z as parseLatestGitStash,_ as persistAgentsWorkStashSnapshotRef,O as resolveGitCommandTimeoutMs,v as sanitizeCommitMessage,et as shouldIncludeGitDiffSummaryFile,kt as streamAiForCommitMessage};
26
+ `)}catch{}}P.post("/git/generate-commit-message",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r,aiBaseUrl:n,aiApiKey:s,aiModel:o}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}if(!n||!String(n).trim()||!s||!String(s).trim()||!o||!String(o).trim()){t.status(400).json({error:"aiBaseUrl, aiApiKey and aiModel are required"});return}try{const{truncatedDiff:l,error:c}=await E(String(a||""),String(e),r);if(c){t.status(c.status).json({error:c.message});return}if(!l){t.json({message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"});return}const u=await wt(n,s,o,l);t.json({message:u})}catch(l){const c=l;h.error(`[Git] generate commit message failed: ${c.message}`),t.status(500).json({error:c.message||"generate commit message failed"})}}),P.post("/git/generate-commit-message-stream",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r,aiBaseUrl:n,aiApiKey:s,aiModel:o}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}if(!n||!String(n).trim()||!s||!String(s).trim()||!o||!String(o).trim()){t.status(400).json({error:"aiBaseUrl, aiApiKey and aiModel are required"});return}h.info(`[Git/SSE] \u6536\u5230 generate-commit-message-stream \u8BF7\u6C42: workspacePath=${String(e||"").substring(0,40)}, stagedFiles=${r?.length??0}, aiModel=${o}, aiBaseUrl=${n}`),t.status(200),t.setHeader("Content-Type","text/event-stream; charset=utf-8"),t.setHeader("Cache-Control","no-cache, no-transform"),t.setHeader("Connection","keep-alive"),t.setHeader("X-Accel-Buffering","no"),i.socket?.setNoDelay(!0),t.flushHeaders?.();let l=!1,c=null,u=!1;const f={delta:0},d=`${i.ip}:${i.socket?.remotePort??"?"}`;i.on("close",()=>{l||(l=!0,h.info(`[Git/SSE] \u5BA2\u6237\u7AEF\u65AD\u5F00\u8FDE\u63A5: workspacePath=${String(e||"").substring(0,40)}, deltaEventsSent=${f.delta}, peer=${d}`))}),$(t,"init",{status:"generating"});try{const{truncatedDiff:m,error:g}=await E(String(a||""),String(e),r);if(g){h.warn(`[Git/SSE] collectStagedDiffForAi \u8FD4\u56DE\u9519\u8BEF: ${g.message}`),$(t,"error",{message:g.message}),t.end();return}if(!m){h.info("[Git/SSE] \u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9, \u76F4\u63A5\u8FD4\u56DE done"),$(t,"delta",{contentDelta:"",message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"}),$(t,"done",{message:"\u6682\u5B58\u533A\u6CA1\u6709\u53D8\u66F4\u5185\u5BB9"}),t.end();return}h.info(`[Git/SSE] \u6536\u96C6\u5230 diff: truncatedDiff.length=${m.length}`),l&&h.info("[Git/SSE] \u5BA2\u6237\u7AEF\u5728 collectDiff \u671F\u95F4\u65AD\u5F00, \u4F46\u4ECD\u5C1D\u8BD5 AI \u8C03\u7528"),h.info(`[Git/SSE] \u5F00\u59CB\u8C03\u7528 AI streamAiForCommitMessage: aiModel=${o}`),c=new AbortController;let x="";const b=await St(n,s,o,m,(w,j)=>{f.delta++,j!==x?(x=j,$(t,"delta",{contentDelta:w,message:j})):$(t,"delta",{contentDelta:w,message:j})},c.signal);h.info(`[Git/SSE] AI streamAiForCommitMessage \u5B8C\u6210: finalMessage=${JSON.stringify(b).substring(0,200)}, deltaEventsSent=${f.delta}`),l||$(t,"done",{message:b}),t.end()}catch(m){const g=m;h.error(`[Git/SSE] stream commit message failed: ${g.message}${g.stack?`
27
+ `+g.stack:""}`),l||$(t,"error",{message:g.message||"generate commit message failed"}),t.end()}}),P.post("/git/unstage-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}let l="";for(const c of s){const u=G(c,o),f=await p(o.repositoryRootPath,["restore","--staged",...u]);f.exitCode!==0&&(l=f.stderr||`git restore --staged failed for ${c}`)}if(l){t.status(400).json({error:l});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git unstage files failed"})}}),P.post("/git/restore-files",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,filePaths:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}const s=(Array.isArray(r)?r:[]).map(o=>S(String(o||"").trim())).filter(o=>o.length>0);if(s.length===0){t.status(400).json({error:"filePaths is required and must be a non-empty array"});return}try{const o=await R(String(a||e).trim());if(!o.hasRepository||!o.repositoryRootPath){t.status(400).json({error:"workspace is not inside a git repository"});return}let l="";for(const c of s){const u=G(c,o),f=await p(o.repositoryRootPath,["restore",...u]);f.exitCode!==0&&(l=f.stderr||`git restore failed for ${c}`)}if(l){t.status(400).json({error:l});return}t.json({ok:!0,filePaths:s,workspacePath:o.workspacePath,repositoryRootPath:o.repositoryRootPath,relativeWorkspacePath:o.relativeWorkspacePath})}catch(o){const l=o;t.status(500).json({error:l.message||"git restore files failed"})}}),P.post("/git/diff-content",y,async(i,t)=>{const{workspacePath:e,repositoryPath:a,stagedFiles:r}=i.body||{};if(!e||!String(e).trim()){t.status(400).json({error:"workspacePath is required"});return}if(!Array.isArray(r)||r.length===0){t.status(400).json({error:"stagedFiles is required and must be a non-empty array"});return}try{const{truncatedDiff:n,error:s}=await E(String(a||""),String(e),r);if(s){t.status(s.status).json({error:s.message});return}t.json({ok:!0,diff:n||""})}catch(n){const s=n;h.error(`[Git/diff-content] \u83B7\u53D6\u6682\u5B58\u533A\u5DEE\u5F02\u5931\u8D25: ${s.message}`),t.status(500).json({error:s.message||"get diff content failed"})}});export{Q as assertGitWorkspacePathAccessible,wt as callAiForCommitMessage,it as createAgentsWorkStashSnapshotRef,st as createMissingInitialCommitSnapshotError,G as createScopedFilePathspecArgs,dt as createScopedGitPathspecArgs,Pt as debugAiStreamChunk,K as extractOpenAiStreamDelta,P as gitRouter,rt as isGitStashMissingInitialCommitError,ot as isGitStashNoChangesOutput,ft as mergeGitDiffSummaryFiles,ut as normalizeGitCommitMessage,D as parseGitDiffSummary,W as parseGitStashListLine,nt as parseGitStatusStagedPaths,ct as parseGitStatusUntrackedPaths,z as parseLatestGitStash,_ as persistAgentsWorkStashSnapshotRef,O as resolveGitCommandTimeoutMs,v as sanitizeCommitMessage,et as shouldIncludeGitDiffSummaryFile,St as streamAiForCommitMessage};
28
28
 
@@ -1,7 +1,7 @@
1
- import{spawnSync as P}from"node:child_process";import{createInterface as q}from"node:readline/promises";import{existsSync as l,mkdirSync as p,readFileSync as Y,rmSync as J,unlinkSync as M,writeFileSync as N}from"node:fs";import o from"node:path";import S from"node:os";import{fileURLToPath as O}from"node:url";import{configureStartupConfig as z,printConfigExampleCommand as Q}from"./startup-config-wizard.js";import{createWindowsServiceManager as X,isNodeWindowsAvailable as Z}from"./windows-service-manager.js";const m="awsb.service",j=`/etc/systemd/system/${m}`,H="awsb",x=`${H}.exe`,F=o.join(S.homedir(),".aws-bridge","log"),B=o.join(F,"awsb.out.log"),T="com.agentsworkstudio.awsb",_=o.join(S.homedir(),"Library","LaunchAgents",`${T}.plist`),ee=o.join(S.homedir(),".aws-bridge","log"),W=o.join(ee,"awsb.out.log");function re(){const e=O(import.meta.url);return o.resolve(o.dirname(e),"..","..")}function te(e=re()){const r=o.join(e,"package.json");return JSON.parse(Y(r,"utf-8")).version||"unknown"}function I(e,r){const n=P(e,r,{shell:process.platform==="win32",stdio:"inherit"});return{status:n.status,error:n.error}}function ne(){try{const e=P("npm",["root","-g"],{shell:process.platform==="win32",encoding:"utf-8",stdio:["ignore","pipe","ignore"]});if(e.status===0&&e.stdout){const r=e.stdout.trim();if(r)return r}}catch{}return null}function ae(e){process.stdout.write(`${e}
2
- `)}function se(e){process.stderr.write(`${e}
3
- `)}function ie(e){return e==="-v"||e==="--version"||e==="version"}function ue(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function de(){return process.argv[1]?o.resolve(process.argv[1]):O(import.meta.url)}function oe(e){return["[Unit]","Description=AgentsWorkStudio Runtime Bridge","After=network-online.target","Wants=network-online.target","","[Service]","Type=simple","Environment=AWS_BRIDGE_SKIP_SETUP=true",`ExecStart=${[process.execPath,e].map(n=>ue(n)).join(" ")}`,"Restart=on-failure","RestartSec=5s","","[Install]","WantedBy=multi-user.target",""].join(`
4
- `)}function v(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function ce(e,r={}){const n=r.userHomeDir??S.homedir(),s=r.logPath??W,a=s.replace(/\.out\.log$/,".err.log");return['<?xml version="1.0" encoding="UTF-8"?>','<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">','<plist version="1.0">',"<dict>"," <key>Label</key>",` <string>${v(T)}</string>`," <key>ProgramArguments</key>"," <array>",` <string>${v(process.execPath)}</string>`,` <string>${v(e)}</string>`," </array>"," <key>EnvironmentVariables</key>"," <dict>"," <key>AWS_BRIDGE_SKIP_SETUP</key>"," <string>true</string>"," <key>AWS_RUNTIME_HOME_DIR</key>",` <string>${v(n)}</string>`," </dict>"," <key>RunAtLoad</key>"," <true/>"," <key>KeepAlive</key>"," <true/>"," <key>StandardOutPath</key>",` <string>${v(s)}</string>`," <key>StandardErrorPath</key>",` <string>${v(a)}</string>`,"</dict>","</plist>",""].join(`
5
- `)}function f(e,r){return e("systemctl",r)}function g(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Csystemctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function d(e){return!e.error&&e.status===0}function E(e,r){return e==="linux"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd \u73AF\u5883\u3002"),!1)}function k(e,r){return e==="darwin"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 macOS launchd \u73AF\u5883\u3002"),!1)}function G(e){e("Usage: awsb service <install|uninstall|start|stop|restart>")}function le(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=oe(e.executablePath);try{p(o.dirname(e.serviceUnitPath),{recursive:!0}),N(e.serviceUnitPath,r,{encoding:"utf-8",mode:420})}catch(t){const i=t instanceof Error?t:new Error(String(t));return e.stderr(`[runtime-bridge] \u5199\u5165 systemd unit \u5931\u8D25: ${i.message}`),{handled:!0,exitCode:1}}const n=f(e.runCommand,["daemon-reload"]);if(!d(n))return e.stderr(g("\u91CD\u8F7D systemd",n)),{handled:!0,exitCode:n.status??1};const s=f(e.runCommand,["enable",m]);if(!d(s))return e.stderr(g("\u542F\u7528 awsb \u5F00\u673A\u81EA\u542F",s)),{handled:!0,exitCode:s.status??1};const a=f(e.runCommand,["is-active","--quiet",m]);if(a.error)return e.stderr(g("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",a)),{handled:!0,exitCode:1};if(a.status!==0){const t=f(e.runCommand,["start",m]);return d(t)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u3001\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\u5E76\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(g("\u542F\u52A8 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}return e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF1B\u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u3002"),{handled:!0,exitCode:0}}function me(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=l(e.serviceUnitPath),n=f(e.runCommand,["is-active","--quiet",m]);if(n.error)return e.stderr(g("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",n)),{handled:!0,exitCode:1};if(n.status===0){const t=f(e.runCommand,["stop",m]);if(!d(t))return e.stderr(g("\u505C\u6B62 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1}}const s=f(e.runCommand,["disable",m]);if(s.error||s.status!==0&&r)return e.stderr(g("\u7981\u7528 awsb \u5F00\u673A\u81EA\u542F",s)),{handled:!0,exitCode:s.status??1};if(r)try{M(e.serviceUnitPath)}catch(t){const i=t instanceof Error?t:new Error(String(t));return e.stderr(`[runtime-bridge] \u5220\u9664 systemd unit \u5931\u8D25: ${i.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb systemd unit \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");const a=f(e.runCommand,["daemon-reload"]);return d(a)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(g("\u91CD\u8F7D systemd",a)),{handled:!0,exitCode:a.status??1})}function fe(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!l(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=f(e.runCommand,["restart",m]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(g("\u91CD\u542F awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function ge(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!l(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=f(e.runCommand,["start",m]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(g("\u542F\u52A8 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function he(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!l(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=f(e.runCommand,["stop",m]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(g("\u505C\u6B62 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function be(e){return e(`[runtime-bridge] \u672A\u68C0\u6D4B\u5230 node-windows \u6A21\u5757\u3002\u8BF7\u91CD\u65B0\u5B89\u88C5 aws-runtime-bridge\uFF1A
6
- npm install -g aws-runtime-bridge`),{handled:!0,exitCode:1}}async function we(e){const r=e.windowsServiceManager;if(!r&&!Z())return be(e.stderr);const n=e.windowsServiceLogPath||B,s=o.dirname(e.executablePath),a=S.homedir();try{await(r||X()).install({name:H,description:"awsb runtime bridge",script:e.executablePath,workingDirectory:s,env:[{name:"AWS_BRIDGE_SKIP_SETUP",value:"true"},{name:"AWS_RUNTIME_HOME_DIR",value:a}],logpath:F})}catch(i){const h=i instanceof Error?i:new Error(String(i));return e.stderr(`[runtime-bridge] \u5B89\u88C5 Windows \u670D\u52A1\u5931\u8D25: ${h.message}`),{handled:!0,exitCode:1}}const t=e.runCommand("sc.exe",["start",x]);return d(t)?(e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${n}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1})}function Ce(e){const r=s=>e.runCommand("sc.exe",s);r(["stop",x]);const n=r(["delete",x]);return d(n)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u5378\u8F7D Windows \u670D\u52A1\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}`),{handled:!0,exitCode:n.status??1})}function xe(e){const r=s=>e.runCommand("sc.exe",s);r(["stop",x]);const n=r(["start",x]);return d(n)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u91CD\u542F Windows \u670D\u52A1\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}`),{handled:!0,exitCode:n.status??1})}function Pe(e){const r=e.runCommand("sc.exe",["start",x]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function Se(e){const r=e.runCommand("sc.exe",["stop",x]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u505C\u6B62 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function ve(){return`gui/${process.getuid?.()??0}`}function R(e){return e.launchdDomainTarget||ve()}function L(e){return`${e}/${T}`}function D(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Claunchctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function ye(e){if(!k(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||_,n=e.launchdLogPath||W,s=ce(e.executablePath,{userHomeDir:S.homedir(),logPath:n});try{p(o.dirname(r),{recursive:!0}),p(o.dirname(n),{recursive:!0}),N(r,s,{encoding:"utf-8",mode:420})}catch(i){const h=i instanceof Error?i:new Error(String(i));return e.stderr(`[runtime-bridge] \u5199\u5165 launchd plist \u5931\u8D25: ${h.message}`),{handled:!0,exitCode:1}}const a=R(e);e.runCommand("launchctl",["bootout",L(a)]);const t=e.runCommand("launchctl",["bootstrap",a,r]);return d(t)?(e.stdout(`[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${n}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(D("\u5B89\u88C5 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}function $e(e){if(!k(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||_,n=R(e),s=L(n),a=e.runCommand("launchctl",["bootout",s]);if(a.error)return e.stderr(D("\u5378\u8F7D awsb \u670D\u52A1",a)),{handled:!0,exitCode:1};if(l(r))try{M(r)}catch(t){const i=t instanceof Error?t:new Error(String(t));return e.stderr(`[runtime-bridge] \u5220\u9664 launchd plist \u5931\u8D25: ${i.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb launchd plist \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}}function Ee(e){if(!k(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||_;if(!l(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const n=R(e),s=L(n),a=e.runCommand("launchctl",["kickstart",s]);if(d(a))return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0};const t=e.runCommand("launchctl",["bootstrap",n,r]);return d(t)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u542F\u52A8 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}function ke(e){if(!k(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=R(e),n=e.runCommand("launchctl",["bootout",L(r)]);return d(n)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u505C\u6B62 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function Re(e){if(!k(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||_;if(!l(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const n=R(e);e.runCommand("launchctl",["bootout",L(n)]);const s=e.runCommand("launchctl",["bootstrap",n,r]);return d(s)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(D("\u91CD\u542F awsb \u670D\u52A1",s)),{handled:!0,exitCode:s.status??1})}async function Le(e,r,n,s){const a=e[1];if(!a||a==="-h"||a==="--help"||a==="help")return G(n),{handled:!0,exitCode:a?0:1};const t={stdout:n,stderr:s,runCommand:r.runCommand||I,platform:r.platform||process.platform,serviceUnitPath:r.serviceUnitPath||j,executablePath:r.executablePath||de(),windowsServiceManager:r.windowsServiceManager,launchdPlistPath:r.launchdPlistPath,launchdLogPath:r.launchdLogPath,launchdDomainTarget:r.launchdDomainTarget};return t.platform!=="linux"&&t.platform!=="win32"&&t.platform!=="darwin"?(s("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}):a==="install"?t.platform==="win32"?await we(t):t.platform==="darwin"?ye(t):le(t):a==="uninstall"?t.platform==="win32"?Ce(t):t.platform==="darwin"?$e(t):me(t):a==="restart"?t.platform==="win32"?xe(t):t.platform==="darwin"?Re(t):fe(t):a==="start"?t.platform==="win32"?Pe(t):t.platform==="darwin"?Ee(t):ge(t):a==="stop"?t.platform==="win32"?Se(t):t.platform==="darwin"?ke(t):he(t):(s(`[runtime-bridge] \u672A\u77E5 service \u5B50\u547D\u4EE4: ${a}`),G(n),{handled:!0,exitCode:1})}function V(e){return e?e.split(/\r?\n/).map(r=>r.trim()).filter(r=>/^\d+$/.test(r)).map(Number):[]}function De(e){try{if(e==="win32"){const n=P("powershell",["-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -like '*aws-runtime-bridge*' -and $_.ProcessId -ne ${process.pid} } | ForEach-Object { $_.ProcessId }`],{encoding:"utf-8"});return V(n.stdout)}const r=P("pgrep",["-f","aws-runtime-bridge"],{encoding:"utf-8"});return V(r.stdout).filter(n=>n!==process.pid)}catch{return[]}}function _e(e,r){if(r==="win32"){P("taskkill",["/PID",String(e),"/F","/T"],{stdio:"ignore"});return}P("kill",["-9",String(e)],{stdio:"ignore"})}function pe(e){if(!process.stdin.isTTY)return Promise.resolve("n");const r=q({input:process.stdin,output:process.stdout});return r.question(e).finally(()=>r.close())}async function Te(e,r,n){const s=e.runCommand||I,a=e.platform||process.platform,t=e.findRunningBridgeProcesses||De,i=e.prompt||pe,h=e.killBridgeProcess||_e,u=e.globalModulePath||ne;r("[runtime-bridge] \u6B63\u5728\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C...");const c=t(a).filter(w=>w!==process.pid);let b=!1;if(c.length>0){r(`[runtime-bridge] \u68C0\u6D4B\u5230 aws-runtime-bridge \u6B63\u5728\u8FD0\u884C (PID: ${c.join(", ")})\uFF0C\u66F4\u65B0\u65F6\u8FD9\u4E9B\u8FDB\u7A0B\u53EF\u80FD\u5360\u7528\u6587\u4EF6\u5BFC\u81F4\u8986\u76D6\u5931\u8D25\u3002`);const w=(await i("\u662F\u5426\u5173\u95ED\u4E0A\u8FF0\u8FDB\u7A0B\u4EE5\u7EE7\u7EED\u66F4\u65B0? (y/N) ")).trim().toLowerCase();if(w==="y"||w==="yes")for(const C of c)try{h(C,a),r(`[runtime-bridge] \u5DF2\u5173\u95ED\u8FDB\u7A0B PID: ${C}`)}catch($){const K=$ instanceof Error?$:new Error(String($));n(`[runtime-bridge] \u5173\u95ED\u8FDB\u7A0B PID ${C} \u5931\u8D25: ${K.message}`)}else b=!0,r("[runtime-bridge] \u5DF2\u9009\u62E9\u4E0D\u5173\u95ED\u8FDB\u7A0B\uFF0C\u5C06\u4EE5 --force \u65B9\u5F0F\u5F3A\u5236\u5B89\u88C5\uFF08\u82E5\u6587\u4EF6\u4ECD\u88AB\u5360\u7528\u53EF\u80FD\u4F1A\u6709\u8B66\u544A\uFF09\u3002")}const U=u();if(U){const w=o.join(U,"aws-runtime-bridge");if(l(w)){r("[runtime-bridge] \u6E05\u7406\u65E7\u7248\u672C\u6B8B\u7559\u76EE\u5F55...");try{J(w,{recursive:!0,force:!0})}catch(C){const $=C instanceof Error?C:new Error(String(C));n(`[runtime-bridge] \u6E05\u7406\u6B8B\u7559\u76EE\u5F55\u5931\u8D25\uFF08\u5C06\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09: ${$.message}`)}}}const A=["install","-g","aws-runtime-bridge@latest","--omit=optional"];b&&A.push("--force");const y=s("npm",A);return y.error?(n(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25: ${y.error.message}`),{handled:!0,exitCode:1}):y.status!==0?(n(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${y.status??"unknown"}`),{handled:!0,exitCode:y.status??1}):(r("[runtime-bridge] \u66F4\u65B0\u5B8C\u6210\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C awsb -v \u67E5\u770B\u5F53\u524D\u7248\u672C\u3002"),{handled:!0,exitCode:0})}function We(e,r,n){const a=(e.argv||process.argv.slice(2)).slice(1).some(u=>u==="--follow"||u==="-f"),t=e.platform||process.platform,i=e.runCommand||I,h=e.serviceUnitPath||j;if(t==="linux"){if(!l(h))return n("[runtime-bridge] awsb \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF08awsb service install\uFF09\uFF0C\u65E0\u65E5\u5FD7\u53EF\u67E5\u770B\u3002"),{handled:!0,exitCode:1};const u=["-u",m];a?u.push("-f"):u.push("-n","200","--no-pager");const c=i("journalctl",u);return c.error?(n(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${c.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:c.status??0}}if(t==="win32"){const u=e.windowsServiceLogPath||B;if(!l(u))return n(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const c=`Get-Content -Encoding UTF8 -Tail 200 "${u}"`+(a?" -Wait":""),b=i("powershell",["-NoProfile","-Command",c]);return b.error?(n(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${b.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:b.status??0}}if(t==="darwin"){const u=e.launchdLogPath||W;if(!l(u))return n(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const b=i("tail",a?["-f",u]:["-n","200",u]);return b.error?(n(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${b.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:b.status??0}}return n("[runtime-bridge] awsb log \u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}}async function Fe(e={}){const r=e.argv||process.argv.slice(2),n=r[0],s=e.stdout||ae,a=e.stderr||se;if(ie(n))return s(`aws-runtime-bridge ${te(e.packageRoot)}`),{handled:!0,exitCode:0};if(n==="update")return await Te(e,s,a);if(n==="config"){const t=r[1];if(t==="example"||t==="minimal"||t==="--minimal"||t==="-m")return{handled:!0,exitCode:await(e.configureExample||Q)()==="created"?0:1};const h=await(e.configure||z)();return{handled:!0,exitCode:h==="configured"||h==="created"?0:1}}return n==="service"?await Le(r,e,s,a):n==="log"?We(e,s,a):{handled:!1,exitCode:0}}export{ce as createLaunchdPlistContent,oe as createSystemdUnitContent,Fe as handleCliCommand,te as readPackageVersion};
1
+ import{spawnSync as v}from"node:child_process";import{createInterface as J}from"node:readline/promises";import{existsSync as m,mkdirSync as p,readFileSync as z,rmSync as Q,unlinkSync as N,writeFileSync as O}from"node:fs";import c from"node:path";import P from"node:os";import{fileURLToPath as j}from"node:url";import{configureStartupConfig as X,printConfigExampleCommand as Z}from"./startup-config-wizard.js";import{createWindowsServiceManager as ee,isNodeWindowsAvailable as re}from"./windows-service-manager.js";const f="awsb.service",T=`/etc/systemd/system/${f}`,H="awsb",C=`${H}.exe`,F=c.join(P.homedir(),".aws-bridge","log"),B=c.join(F,"awsb.out.log"),I="com.agentsworkstudio.awsb",D=c.join(P.homedir(),"Library","LaunchAgents",`${I}.plist`),te=c.join(P.homedir(),".aws-bridge","log"),U=c.join(te,"awsb.out.log");function ne(){const e=j(import.meta.url);return c.resolve(c.dirname(e),"..","..")}function ae(e=ne()){const r=c.join(e,"package.json");return JSON.parse(z(r,"utf-8")).version||"unknown"}function _(e,r){const t=v(e,r,{shell:process.platform==="win32",stdio:"inherit"});return{status:t.status,error:t.error}}function ie(){try{const e=v("npm",["root","-g"],{shell:process.platform==="win32",encoding:"utf-8",stdio:["ignore","pipe","ignore"]});if(e.status===0&&e.stdout){const r=e.stdout.trim();if(r)return r}}catch{}return null}function se(e){process.stdout.write(`${e}
2
+ `)}function ue(e){process.stderr.write(`${e}
3
+ `)}function de(e){return e==="-v"||e==="--version"||e==="version"}function oe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function G(){return process.argv[1]?c.resolve(process.argv[1]):j(import.meta.url)}function ce(e){return["[Unit]","Description=AgentsWorkStudio Runtime Bridge","After=network-online.target","Wants=network-online.target","","[Service]","Type=simple","Environment=AWS_BRIDGE_SKIP_SETUP=true",`ExecStart=${[process.execPath,e].map(t=>oe(t)).join(" ")}`,"Restart=on-failure","RestartSec=5s","","[Install]","WantedBy=multi-user.target",""].join(`
4
+ `)}function S(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function le(e,r={}){const t=r.userHomeDir??P.homedir(),i=r.logPath??U,a=i.replace(/\.out\.log$/,".err.log");return['<?xml version="1.0" encoding="UTF-8"?>','<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">','<plist version="1.0">',"<dict>"," <key>Label</key>",` <string>${S(I)}</string>`," <key>ProgramArguments</key>"," <array>",` <string>${S(process.execPath)}</string>`,` <string>${S(e)}</string>`," </array>"," <key>EnvironmentVariables</key>"," <dict>"," <key>AWS_BRIDGE_SKIP_SETUP</key>"," <string>true</string>"," <key>AWS_RUNTIME_HOME_DIR</key>",` <string>${S(t)}</string>`," </dict>"," <key>RunAtLoad</key>"," <true/>"," <key>KeepAlive</key>"," <true/>"," <key>StandardOutPath</key>",` <string>${S(i)}</string>`," <key>StandardErrorPath</key>",` <string>${S(a)}</string>`,"</dict>","</plist>",""].join(`
5
+ `)}function g(e,r){return e("systemctl",r)}function h(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Csystemctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function d(e){return!e.error&&e.status===0}function E(e,r){return e==="linux"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd \u73AF\u5883\u3002"),!1)}function R(e,r){return e==="darwin"?!0:(r("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 macOS launchd \u73AF\u5883\u3002"),!1)}function V(e){e("Usage: awsb service <install|uninstall|start|stop|restart>")}function me(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=ce(e.executablePath);try{p(c.dirname(e.serviceUnitPath),{recursive:!0}),O(e.serviceUnitPath,r,{encoding:"utf-8",mode:420})}catch(n){const s=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5199\u5165 systemd unit \u5931\u8D25: ${s.message}`),{handled:!0,exitCode:1}}const t=g(e.runCommand,["daemon-reload"]);if(!d(t))return e.stderr(h("\u91CD\u8F7D systemd",t)),{handled:!0,exitCode:t.status??1};const i=g(e.runCommand,["enable",f]);if(!d(i))return e.stderr(h("\u542F\u7528 awsb \u5F00\u673A\u81EA\u542F",i)),{handled:!0,exitCode:i.status??1};const a=g(e.runCommand,["is-active","--quiet",f]);if(a.error)return e.stderr(h("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",a)),{handled:!0,exitCode:1};if(a.status!==0){const n=g(e.runCommand,["start",f]);return d(n)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u3001\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\u5E76\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(h("\u542F\u52A8 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}return e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF1B\u670D\u52A1\u5DF2\u5728\u8FD0\u884C\u3002"),{handled:!0,exitCode:0}}function fe(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=m(e.serviceUnitPath),t=g(e.runCommand,["is-active","--quiet",f]);if(t.error)return e.stderr(h("\u68C0\u67E5 awsb \u670D\u52A1\u72B6\u6001",t)),{handled:!0,exitCode:1};if(t.status===0){const n=g(e.runCommand,["stop",f]);if(!d(n))return e.stderr(h("\u505C\u6B62 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1}}const i=g(e.runCommand,["disable",f]);if(i.error||i.status!==0&&r)return e.stderr(h("\u7981\u7528 awsb \u5F00\u673A\u81EA\u542F",i)),{handled:!0,exitCode:i.status??1};if(r)try{N(e.serviceUnitPath)}catch(n){const s=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5220\u9664 systemd unit \u5931\u8D25: ${s.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb systemd unit \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");const a=g(e.runCommand,["daemon-reload"]);return d(a)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(h("\u91CD\u8F7D systemd",a)),{handled:!0,exitCode:a.status??1})}function ge(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!m(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=g(e.runCommand,["restart",f]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(h("\u91CD\u542F awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function he(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!m(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=g(e.runCommand,["start",f]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(h("\u542F\u52A8 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function we(e){if(!E(e.platform,e.stderr))return{handled:!0,exitCode:1};if(!m(e.serviceUnitPath))return e.stderr("[runtime-bridge] awsb systemd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const r=g(e.runCommand,["stop",f]);return d(r)?(e.stdout("[runtime-bridge] awsb systemd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(h("\u505C\u6B62 awsb \u670D\u52A1",r)),{handled:!0,exitCode:r.status??1})}function be(e){return e(`[runtime-bridge] \u672A\u68C0\u6D4B\u5230 node-windows \u6A21\u5757\u3002\u8BF7\u91CD\u65B0\u5B89\u88C5 aws-runtime-bridge\uFF1A
6
+ npm install -g aws-runtime-bridge`),{handled:!0,exitCode:1}}async function q(e){const r=e.windowsServiceManager;if(!r&&!re())return be(e.stderr);const t=e.windowsServiceLogPath||B,i=c.dirname(e.executablePath),a=P.homedir();try{await(r||ee()).install({name:H,description:"awsb runtime bridge",script:e.executablePath,workingDirectory:i,env:[{name:"AWS_BRIDGE_SKIP_SETUP",value:"true"},{name:"AWS_RUNTIME_HOME_DIR",value:a}],logpath:F})}catch(s){const o=s instanceof Error?s:new Error(String(s));return e.stderr(`[runtime-bridge] \u5B89\u88C5 Windows \u670D\u52A1\u5931\u8D25: ${o.message}`),{handled:!0,exitCode:1}}const n=e.runCommand("sc.exe",["start",C]);return d(n)?(e.stdout(`[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}`),{handled:!0,exitCode:n.status??1})}function Ce(e){const r=i=>e.runCommand("sc.exe",i);r(["stop",C]);const t=r(["delete",C]);return d(t)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u5378\u8F7D Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1})}function xe(e){const r=i=>e.runCommand("sc.exe",i);r(["stop",C]);const t=r(["start",C]);return d(t)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u91CD\u542F Windows \u670D\u52A1\u5931\u8D25: ${t.error?.message??`\u9000\u51FA\u7801 ${t.status??"unknown"}`}`),{handled:!0,exitCode:t.status??1})}function ve(e){const r=e.runCommand("sc.exe",["start",C]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u542F\u52A8 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function Pe(e){const r=e.runCommand("sc.exe",["stop",C]);return d(r)?(e.stdout("[runtime-bridge] awsb Windows \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(`[runtime-bridge] \u505C\u6B62 Windows \u670D\u52A1\u5931\u8D25: ${r.error?.message??`\u9000\u51FA\u7801 ${r.status??"unknown"}`}`),{handled:!0,exitCode:r.status??1})}function Se(){return`gui/${process.getuid?.()??0}`}function k(e){return e.launchdDomainTarget||Se()}function W(e){return`${e}/${I}`}function L(e,r){return r.error?`[runtime-bridge] ${e}\u5931\u8D25: ${r.error.message}`:`[runtime-bridge] ${e}\u5931\u8D25\uFF0Claunchctl \u9000\u51FA\u7801: ${r.status??"unknown"}`}function ye(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D,t=e.launchdLogPath||U,i=le(e.executablePath,{userHomeDir:P.homedir(),logPath:t});try{p(c.dirname(r),{recursive:!0}),p(c.dirname(t),{recursive:!0}),O(r,i,{encoding:"utf-8",mode:420})}catch(s){const o=s instanceof Error?s:new Error(String(s));return e.stderr(`[runtime-bridge] \u5199\u5165 launchd plist \u5931\u8D25: ${o.message}`),{handled:!0,exitCode:1}}const a=k(e);e.runCommand("launchctl",["bootout",W(a)]);const n=e.runCommand("launchctl",["bootstrap",a,r]);return d(n)?(e.stdout(`[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5B89\u88C5\u5E76\u5DF2\u542F\u52A8\uFF08\u65E5\u5FD7: ${t}\uFF09\u3002`),{handled:!0,exitCode:0}):(e.stderr(L("\u5B89\u88C5 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function $e(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D,t=k(e),i=W(t),a=e.runCommand("launchctl",["bootout",i]);if(a.error)return e.stderr(L("\u5378\u8F7D awsb \u670D\u52A1",a)),{handled:!0,exitCode:1};if(m(r))try{N(r)}catch(n){const s=n instanceof Error?n:new Error(String(n));return e.stderr(`[runtime-bridge] \u5220\u9664 launchd plist \u5931\u8D25: ${s.message}`),{handled:!0,exitCode:1}}else e.stdout("[runtime-bridge] awsb launchd plist \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u5220\u9664\u3002");return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u5378\u8F7D\u3002"),{handled:!0,exitCode:0}}function Ee(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D;if(!m(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=k(e),i=W(t),a=e.runCommand("launchctl",["kickstart",i]);if(d(a))return e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0};const n=e.runCommand("launchctl",["bootstrap",t,r]);return d(n)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u542F\u52A8\u3002"),{handled:!0,exitCode:0}):(e.stderr(L("\u542F\u52A8 awsb \u670D\u52A1",n)),{handled:!0,exitCode:n.status??1})}function Re(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=k(e),t=e.runCommand("launchctl",["bootout",W(r)]);return d(t)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u505C\u6B62\u3002"),{handled:!0,exitCode:0}):(e.stderr(L("\u505C\u6B62 awsb \u670D\u52A1",t)),{handled:!0,exitCode:t.status??1})}function ke(e){if(!R(e.platform,e.stderr))return{handled:!0,exitCode:1};const r=e.launchdPlistPath||D;if(!m(r))return e.stderr("[runtime-bridge] awsb launchd \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF0C\u8BF7\u5148\u6267\u884C `awsb service install`\u3002"),{handled:!0,exitCode:1};const t=k(e);e.runCommand("launchctl",["bootout",W(t)]);const i=e.runCommand("launchctl",["bootstrap",t,r]);return d(i)?(e.stdout("[runtime-bridge] awsb launchd \u670D\u52A1\u5DF2\u91CD\u542F\u3002"),{handled:!0,exitCode:0}):(e.stderr(L("\u91CD\u542F awsb \u670D\u52A1",i)),{handled:!0,exitCode:i.status??1})}async function We(e,r,t,i){const a=e[1];if(!a||a==="-h"||a==="--help"||a==="help")return V(t),{handled:!0,exitCode:a?0:1};const n={stdout:t,stderr:i,runCommand:r.runCommand||_,platform:r.platform||process.platform,serviceUnitPath:r.serviceUnitPath||T,executablePath:r.executablePath||G(),windowsServiceManager:r.windowsServiceManager,launchdPlistPath:r.launchdPlistPath,launchdLogPath:r.launchdLogPath,launchdDomainTarget:r.launchdDomainTarget};return n.platform!=="linux"&&n.platform!=="win32"&&n.platform!=="darwin"?(i("[runtime-bridge] service \u547D\u4EE4\u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}):a==="install"?n.platform==="win32"?await q(n):n.platform==="darwin"?ye(n):me(n):a==="uninstall"?n.platform==="win32"?Ce(n):n.platform==="darwin"?$e(n):fe(n):a==="restart"?n.platform==="win32"?xe(n):n.platform==="darwin"?ke(n):ge(n):a==="start"?n.platform==="win32"?ve(n):n.platform==="darwin"?Ee(n):he(n):a==="stop"?n.platform==="win32"?Pe(n):n.platform==="darwin"?Re(n):we(n):(i(`[runtime-bridge] \u672A\u77E5 service \u5B50\u547D\u4EE4: ${a}`),V(t),{handled:!0,exitCode:1})}function K(e){return e?e.split(/\r?\n/).map(r=>r.trim()).filter(r=>/^\d+$/.test(r)).map(Number):[]}function Le(e){try{if(e==="win32"){const t=v("powershell",["-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -like '*aws-runtime-bridge*' -and $_.ProcessId -ne ${process.pid} } | ForEach-Object { $_.ProcessId }`],{encoding:"utf-8"});return K(t.stdout)}const r=v("pgrep",["-f","aws-runtime-bridge"],{encoding:"utf-8"});return K(r.stdout).filter(t=>t!==process.pid)}catch{return[]}}function De(e,r){if(r==="win32"){v("taskkill",["/PID",String(e),"/F","/T"],{stdio:"ignore"});return}v("kill",["-9",String(e)],{stdio:"ignore"})}function _e(e){if(!process.stdin.isTTY)return Promise.resolve("n");const r=J({input:process.stdin,output:process.stdout});return r.question(e).finally(()=>r.close())}async function pe(e,r,t){const i=e.runCommand||_,a=e.platform||process.platform,n=e.findRunningBridgeProcesses||Le,s=e.prompt||_e,o=e.killBridgeProcess||De,u=e.globalModulePath||ie;r("[runtime-bridge] \u6B63\u5728\u66F4\u65B0 aws-runtime-bridge \u5230\u6700\u65B0\u7248\u672C...");const l=n(a).filter(b=>b!==process.pid);let w=!1;if(l.length>0){r(`[runtime-bridge] \u68C0\u6D4B\u5230 aws-runtime-bridge \u6B63\u5728\u8FD0\u884C (PID: ${l.join(", ")})\uFF0C\u66F4\u65B0\u65F6\u8FD9\u4E9B\u8FDB\u7A0B\u53EF\u80FD\u5360\u7528\u6587\u4EF6\u5BFC\u81F4\u8986\u76D6\u5931\u8D25\u3002`);const b=(await s("\u662F\u5426\u5173\u95ED\u4E0A\u8FF0\u8FDB\u7A0B\u4EE5\u7EE7\u7EED\u66F4\u65B0? (y/N) ")).trim().toLowerCase();if(b==="y"||b==="yes")for(const x of l)try{o(x,a),r(`[runtime-bridge] \u5DF2\u5173\u95ED\u8FDB\u7A0B PID: ${x}`)}catch($){const Y=$ instanceof Error?$:new Error(String($));t(`[runtime-bridge] \u5173\u95ED\u8FDB\u7A0B PID ${x} \u5931\u8D25: ${Y.message}`)}else w=!0,r("[runtime-bridge] \u5DF2\u9009\u62E9\u4E0D\u5173\u95ED\u8FDB\u7A0B\uFF0C\u5C06\u4EE5 --force \u65B9\u5F0F\u5F3A\u5236\u5B89\u88C5\uFF08\u82E5\u6587\u4EF6\u4ECD\u88AB\u5360\u7528\u53EF\u80FD\u4F1A\u6709\u8B66\u544A\uFF09\u3002")}const A=u();if(A){const b=c.join(A,"aws-runtime-bridge");if(m(b)){r("[runtime-bridge] \u6E05\u7406\u65E7\u7248\u672C\u6B8B\u7559\u76EE\u5F55...");try{Q(b,{recursive:!0,force:!0})}catch(x){const $=x instanceof Error?x:new Error(String(x));t(`[runtime-bridge] \u6E05\u7406\u6B8B\u7559\u76EE\u5F55\u5931\u8D25\uFF08\u5C06\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09: ${$.message}`)}}}const M=["install","-g","aws-runtime-bridge@latest","--omit=optional"];w&&M.push("--force");const y=i("npm",M);if(y.error)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25: ${y.error.message}`),{handled:!0,exitCode:1};if(y.status!==0)return t(`[runtime-bridge] \u66F4\u65B0\u5931\u8D25\uFF0Cnpm \u9000\u51FA\u7801: ${y.status??"unknown"}`),{handled:!0,exitCode:y.status??1};if(a==="win32"){const b=await Te(e,r,t);if(b.exitCode!==0)return b}return r("[runtime-bridge] \u66F4\u65B0\u5B8C\u6210\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C awsb -v \u67E5\u770B\u5F53\u524D\u7248\u672C\u3002"),{handled:!0,exitCode:0}}async function Te(e,r,t){const i=e.runCommand||_,a=i("sc.exe",["query",C]);if(!d(a))return{handled:!0,exitCode:0};r("[runtime-bridge] \u68C0\u6D4B\u5230 Windows \u670D\u52A1\u5DF2\u6CE8\u518C\uFF0C\u6B63\u5728\u91CD\u5EFA\u670D\u52A1\u6587\u4EF6\uFF08daemon/winsw.exe\uFF09..."),i("sc.exe",["stop",C]);const n=i("sc.exe",["delete",C]);d(n)||t(`[runtime-bridge] \u5220\u9664\u65E7 SCM \u8BB0\u5F55\u5931\u8D25: ${n.error?.message??`\u9000\u51FA\u7801 ${n.status??"unknown"}`}\uFF08\u5C1D\u8BD5\u7EE7\u7EED\u5B89\u88C5\uFF09`);const s={stdout:r,stderr:t,runCommand:i,platform:"win32",serviceUnitPath:e.serviceUnitPath||T,executablePath:e.executablePath||G(),windowsServiceManager:e.windowsServiceManager};try{return(await q(s)).exitCode!==0?(t("[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5931\u8D25\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C `awsb service uninstall && awsb service install` \u4FEE\u590D\u670D\u52A1\u3002"),{handled:!0,exitCode:0}):(r("[runtime-bridge] Windows \u670D\u52A1\u6587\u4EF6\u5DF2\u91CD\u5EFA\u3002"),{handled:!0,exitCode:0})}catch(o){const u=o instanceof Error?o:new Error(String(o));return t(`[runtime-bridge] \u91CD\u5EFA Windows \u670D\u52A1\u6587\u4EF6\u5F02\u5E38: ${u.message}\u3002\u5305\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6267\u884C \`awsb service uninstall && awsb service install\` \u4FEE\u590D\u670D\u52A1\u3002`),{handled:!0,exitCode:0}}}function Ie(e,r,t){const a=(e.argv||process.argv.slice(2)).slice(1).some(u=>u==="--follow"||u==="-f"),n=e.platform||process.platform,s=e.runCommand||_,o=e.serviceUnitPath||T;if(n==="linux"){if(!m(o))return t("[runtime-bridge] awsb \u670D\u52A1\u5C1A\u672A\u5B89\u88C5\uFF08awsb service install\uFF09\uFF0C\u65E0\u65E5\u5FD7\u53EF\u67E5\u770B\u3002"),{handled:!0,exitCode:1};const u=["-u",f];a?u.push("-f"):u.push("-n","200","--no-pager");const l=s("journalctl",u);return l.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${l.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:l.status??0}}if(n==="win32"){const u=e.windowsServiceLogPath||B;if(!m(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const l=`Get-Content -Encoding UTF8 -Tail 200 "${u}"`+(a?" -Wait":""),w=s("powershell",["-NoProfile","-Command",l]);return w.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${w.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:w.status??0}}if(n==="darwin"){const u=e.launchdLogPath||U;if(!m(u))return t(`[runtime-bridge] \u5C1A\u672A\u751F\u6210\u65E5\u5FD7\u6587\u4EF6: ${u}\u3002\u8BF7\u5148\u6267\u884C \`awsb service install\` \u5E76\u8FD0\u884C\u670D\u52A1\u3002`),{handled:!0,exitCode:1};const w=s("tail",a?["-f",u]:["-n","200",u]);return w.error?(t(`[runtime-bridge] \u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${w.error.message}`),{handled:!0,exitCode:1}):{handled:!0,exitCode:w.status??0}}return t("[runtime-bridge] awsb log \u4EC5\u652F\u6301 Linux systemd\u3001Windows \u670D\u52A1\u4E0E macOS launchd \u73AF\u5883\u3002"),{handled:!0,exitCode:1}}async function Be(e={}){const r=e.argv||process.argv.slice(2),t=r[0],i=e.stdout||se,a=e.stderr||ue;if(de(t))return i(`aws-runtime-bridge ${ae(e.packageRoot)}`),{handled:!0,exitCode:0};if(t==="update")return await pe(e,i,a);if(t==="config"){const n=r[1];if(n==="example"||n==="minimal"||n==="--minimal"||n==="-m")return{handled:!0,exitCode:await(e.configureExample||Z)()==="created"?0:1};const o=await(e.configure||X)();return{handled:!0,exitCode:o==="configured"||o==="created"?0:1}}return t==="service"?await We(r,e,i,a):t==="log"?Ie(e,i,a):{handled:!1,exitCode:0}}export{le as createLaunchdPlistContent,ce as createSystemdUnitContent,Be as handleCliCommand,ae as readPackageVersion};
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-runtime-bridge",
3
- "version": "1.9.90",
3
+ "version": "1.9.92",
4
4
  "description": "AgentsWorkStudio runtime bridge service for machine-level agent runtime integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",