chainlesschain 0.45.70 → 0.45.74

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.
Files changed (89) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/Analytics-B4OM8S8X.css +1 -0
  4. package/src/assets/web-panel/assets/Analytics-sBrYoc3A.js +3 -0
  5. package/src/assets/web-panel/assets/AppLayout-BhJ3YFWt.js +1 -0
  6. package/src/assets/web-panel/assets/AppLayout-Cr2lWhF-.css +1 -0
  7. package/src/assets/web-panel/assets/Backup-D68fenbD.js +1 -0
  8. package/src/assets/web-panel/assets/Backup-fZqtfC1m.css +1 -0
  9. package/src/assets/web-panel/assets/{Chat-DXtvKoM0.js → Chat-DaxTP3x8.js} +1 -1
  10. package/src/assets/web-panel/assets/{Cron-BJ4ODHOy.js → Cron-CNs03iHJ.js} +2 -2
  11. package/src/assets/web-panel/assets/{Dashboard-BZd4wDPQ.js → Dashboard-CjlX4CrX.js} +2 -2
  12. package/src/assets/web-panel/assets/Git-CCMVr3Y8.js +2 -0
  13. package/src/assets/web-panel/assets/Git-DGcuBXST.css +1 -0
  14. package/src/assets/web-panel/assets/{Logs-CSeKZEG_.js → Logs-BY6A0UNG.js} +2 -2
  15. package/src/assets/web-panel/assets/{McpTools-BYQAK11r.js → McpTools-CrBVYlg6.js} +2 -2
  16. package/src/assets/web-panel/assets/{Memory-gkUAPyuZ.js → Memory-CWx3SpUt.js} +2 -2
  17. package/src/assets/web-panel/assets/{Notes-bjNrQgAo.js → Notes-1LcGD49x.js} +2 -2
  18. package/src/assets/web-panel/assets/Organization-DdOOM4ic.css +1 -0
  19. package/src/assets/web-panel/assets/Organization-Dx2DhbkM.js +4 -0
  20. package/src/assets/web-panel/assets/P2P-B16fjqfJ.js +2 -0
  21. package/src/assets/web-panel/assets/P2P-OEzOeMZX.css +1 -0
  22. package/src/assets/web-panel/assets/Permissions-BQbC9FzG.js +4 -0
  23. package/src/assets/web-panel/assets/Permissions-C9WlkGl-.css +1 -0
  24. package/src/assets/web-panel/assets/Projects-CjhZbNYm.js +2 -0
  25. package/src/assets/web-panel/assets/Projects-DxKelI5h.css +1 -0
  26. package/src/assets/web-panel/assets/Providers-BEakqcO5.css +1 -0
  27. package/src/assets/web-panel/assets/Providers-ivOAQtHM.js +2 -0
  28. package/src/assets/web-panel/assets/RssFeed-BlFC20eg.css +1 -0
  29. package/src/assets/web-panel/assets/RssFeed-BrsErdrU.js +3 -0
  30. package/src/assets/web-panel/assets/Security-DnEvJU5h.js +4 -0
  31. package/src/assets/web-panel/assets/Security-Dwxw7rfP.css +1 -0
  32. package/src/assets/web-panel/assets/{Services-CS0oMdxh.js → Services-7jQywNbl.js} +2 -2
  33. package/src/assets/web-panel/assets/Skills-BCvgBkD3.js +1 -0
  34. package/src/assets/web-panel/assets/{Tasks-qULws8pc.js → Tasks-CmJBC1cf.js} +1 -1
  35. package/src/assets/web-panel/assets/Templates-DOY_oZnm.css +1 -0
  36. package/src/assets/web-panel/assets/Templates-RXT8-DNk.js +1 -0
  37. package/src/assets/web-panel/assets/Wallet-3iYASEx_.js +4 -0
  38. package/src/assets/web-panel/assets/Wallet-DnIumafl.css +1 -0
  39. package/src/assets/web-panel/assets/WebAuthn-CNPl2VQR.css +1 -0
  40. package/src/assets/web-panel/assets/WebAuthn-s3Hzd9db.js +5 -0
  41. package/src/assets/web-panel/assets/{antd-CJSBocer.js → antd-gZyc63Qr.js} +114 -114
  42. package/src/assets/web-panel/assets/chat-BmwHBi9M.js +1 -0
  43. package/src/assets/web-panel/assets/index-DrmEk9S3.js +2 -0
  44. package/src/assets/web-panel/assets/{markdown-Bo5cVN4u.js → markdown-Bv7nG63L.js} +1 -1
  45. package/src/assets/web-panel/assets/ws-CU7Gvoom.js +1 -0
  46. package/src/assets/web-panel/index.html +2 -2
  47. package/src/commands/doctor.js +33 -151
  48. package/src/commands/mcp.js +1 -1
  49. package/src/commands/plugin.js +1 -1
  50. package/src/commands/session.js +106 -7
  51. package/src/commands/status.js +39 -69
  52. package/src/gateways/ws/session-protocol.js +1 -1
  53. package/src/gateways/ws/ws-agent-handler.js +484 -0
  54. package/src/gateways/ws/ws-server.js +758 -4
  55. package/src/gateways/ws/ws-session-gateway.js +1432 -1
  56. package/src/harness/mcp-client.js +417 -0
  57. package/src/harness/mock-llm-provider.js +167 -0
  58. package/src/harness/plugin-manager.js +434 -0
  59. package/src/lib/agent-core.js +25 -1902
  60. package/src/lib/hashline.js +208 -0
  61. package/src/lib/jsonl-session-store.js +11 -0
  62. package/src/lib/mcp-client.js +14 -412
  63. package/src/lib/plugin-manager.js +29 -428
  64. package/src/lib/prompt-compressor.js +11 -0
  65. package/src/lib/session-hooks.js +61 -0
  66. package/src/lib/skill-loader.js +4 -0
  67. package/src/lib/skill-mcp.js +190 -0
  68. package/src/lib/workflow-state-reader.js +94 -0
  69. package/src/lib/ws-agent-handler.js +8 -472
  70. package/src/lib/ws-server.js +12 -756
  71. package/src/lib/ws-session-manager.js +8 -1417
  72. package/src/repl/agent-repl.js +27 -3
  73. package/src/runtime/agent-core.js +1760 -0
  74. package/src/runtime/agent-runtime.js +3 -1
  75. package/src/runtime/coding-agent-contract-shared.cjs +496 -0
  76. package/src/runtime/coding-agent-contract.js +49 -229
  77. package/src/runtime/coding-agent-policy.cjs +54 -5
  78. package/src/runtime/diagnostics.js +317 -0
  79. package/src/runtime/index.js +3 -0
  80. package/src/tools/index.js +3 -0
  81. package/src/tools/legacy-agent-tools.js +5 -0
  82. package/src/assets/web-panel/assets/AppLayout-B_tkw3Pn.js +0 -1
  83. package/src/assets/web-panel/assets/AppLayout-CFP4dGIJ.css +0 -1
  84. package/src/assets/web-panel/assets/Providers-Brm-S_hS.css +0 -1
  85. package/src/assets/web-panel/assets/Providers-Dbf57Tbv.js +0 -1
  86. package/src/assets/web-panel/assets/Skills-B2fgruv8.js +0 -1
  87. package/src/assets/web-panel/assets/chat-DnH09sSR.js +0 -1
  88. package/src/assets/web-panel/assets/index-IK-oro0g.js +0 -2
  89. package/src/assets/web-panel/assets/ws-DjelKkD6.js +0 -1
@@ -0,0 +1 @@
1
+ import{V as j,f as g,r as w}from"./vendor-CN0Iv_qZ.js";import{u as f}from"./ws-CU7Gvoom.js";const S="新对话",T="新 Agent",M={"assistant.delta":"response-token","assistant.final":"response-complete","assistant.message":"response-complete","tool.call.started":"tool-executing","tool.call.completed":"tool-result","tool.call.failed":"tool-result","slot.filling":"question","approval.requested":"question",error:"error"},N=j("chat",()=>{const c=g([]),p=g(null),i=w({}),a=w({}),m=w({}),d=g(!1);let q=null;function y(t){return i[t]||(i[t]=[]),i[t]}function h(t){if(!t?.id)return;const e=c.value.find(o=>o.id===t.id);if(e){Object.assign(e,t);return}c.value.unshift(t)}function A(t,e=f()){i[t]||(i[t]=[]),a[t]||(a[t]={content:"",active:!1}),e.onSession(t,o=>E(t,o))}function v(t=f()){q||(q=t.onRuntimeEvent(e=>{const o=e.payload||{},s=o.record||{};if(e.type==="session:start"){const n=o.sessionType||s.type||"chat";h({id:o.sessionId,type:n,provider:s.provider||null,model:s.model||null,projectRoot:s.projectRoot||null,status:s.status||"created",title:n==="chat"?S:T,createdAt:Date.now(),messageCount:s.messageCount??0})}else if(e.type==="session:resume"){const n=o.sessionId;if(!n)return;Array.isArray(o.history)&&(i[n]=o.history.map(r=>({role:r.role,content:r.content,timestamp:r.timestamp||Date.now()}))),a[n]||(a[n]={content:"",active:!1}),h({id:n,type:s.type||null,provider:s.provider||null,model:s.model||null,projectRoot:s.projectRoot||null,status:s.status||"resumed",messageCount:s.messageCount??(Array.isArray(o.history)?o.history.length:0)})}else if(e.type==="session:end"){const n=o.sessionId;c.value=c.value.filter(r=>r.id!==n),p.value===n&&(p.value=c.value[0]?.id||null)}}))}async function C(){const t=f();v(t),c.value=await t.listSessions()}async function D(t="chat"){const e=f();v(e);const o=await e.createSession(t);return h({id:o,type:t,title:t==="chat"?S:T,createdAt:Date.now(),messageCount:0}),A(o,e),p.value=o,o}function E(t,e){const o=y(t),s=M[e.type]||e.type,n=e.payload||{};if(s==="response-token"){a[t]||(a[t]={content:"",active:!0});const r=e.token||n.token||n.delta||n.content||"";a[t].content+=r,a[t].active=!0}else if(s==="response-complete"){const r=e.content||n.content||a[t]?.content||"";o.push({role:"assistant",content:r,timestamp:Date.now()}),a[t]&&(a[t].content="",a[t].active=!1);const l=c.value.find(u=>u.id===t);if(l&&(l.title===S||l.title===T)){const u=o.find(L=>L.role==="user");u&&(l.title=u.content.slice(0,30))}l&&(l.messageCount=o.filter(u=>u.role!=="tool").length),d.value=!1}else if(s==="tool-executing")o.push({role:"tool",tool:e.tool||n.tool||n.toolName||"unknown",input:e.input||n.input||n.args||null,status:"running",timestamp:Date.now()});else if(s==="tool-result"){const r=e.tool||n.tool||n.toolName||"unknown",l=[...o].reverse().find(u=>u.role==="tool"&&u.tool===r);l&&(l.result=e.result||n.result||n.output||null,l.status="done")}else if(s==="question")m[t]={requestId:e.requestId||n.requestId||e.id,question:e.question||n.question||n.message||"",choices:e.choices||n.choices||n.options||[]};else if(s==="error"){const r=e.message||n.message||"Unknown error";o.push({role:"assistant",content:`Error: ${r}`,timestamp:Date.now()}),d.value=!1,a[t]&&(a[t].active=!1)}}async function k(t,e){const o=f();v(o),y(t).push({role:"user",content:e,timestamp:Date.now()}),a[t]||(a[t]={content:"",active:!1}),a[t].active=!0,d.value=!0,o.sendSessionMessage(t,e)}function _(t,e){const o=f(),s=m[t];s&&(o.answerQuestion(t,s.requestId,e),delete m[t])}async function R(t){const e=f();if(v(e),p.value=t,A(t,e),!i[t]||i[t].length===0)try{await e.resumeSession(t)}catch{}}return{sessions:c,currentSessionId:p,messages:i,streaming:a,pendingQuestion:m,isLoading:d,loadSessions:C,createSession:D,sendMessage:k,answerQuestion:_,switchSession:R,getMessages:y}});export{N as u};
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./AppLayout-BhJ3YFWt.js","./vendor-CN0Iv_qZ.js","./ws-CU7Gvoom.js","./_plugin-vue_export-helper-DlAUqK2U.js","./antd-gZyc63Qr.js","./AppLayout-Cr2lWhF-.css","./Dashboard-CjlX4CrX.js","./chat-BmwHBi9M.js","./Dashboard-CKeMmCoT.css","./Chat-DaxTP3x8.js","./markdown-Bv7nG63L.js","./Chat-DB46afPg.css","./Services-7jQywNbl.js","./Services-C8Qs6KXv.css","./Logs-BY6A0UNG.js","./Logs-Gf_Mv9Nx.css","./Skills-BCvgBkD3.js","./parsers-DftYMnlk.js","./Skills-BdjRyorN.css","./Providers-ivOAQtHM.js","./Providers-BEakqcO5.css","./McpTools-CrBVYlg6.js","./McpTools-CyhSLDwf.css","./Notes-1LcGD49x.js","./Notes-BG69sJKi.css","./Memory-CWx3SpUt.js","./Memory-DRghrGJr.css","./Cron-CNs03iHJ.js","./Tasks-CmJBC1cf.js","./Tasks-BJjN_YEm.css","./Security-DnEvJU5h.js","./Security-Dwxw7rfP.css","./Permissions-BQbC9FzG.js","./Permissions-C9WlkGl-.css","./P2P-B16fjqfJ.js","./P2P-OEzOeMZX.css","./Git-CCMVr3Y8.js","./Git-DGcuBXST.css","./Projects-CjhZbNYm.js","./Projects-DxKelI5h.css","./Wallet-3iYASEx_.js","./Wallet-DnIumafl.css","./Organization-Dx2DhbkM.js","./Organization-DdOOM4ic.css","./Analytics-sBrYoc3A.js","./Analytics-B4OM8S8X.css","./Templates-RXT8-DNk.js","./Templates-DOY_oZnm.css","./Backup-D68fenbD.js","./Backup-fZqtfC1m.css","./RssFeed-BrsErdrU.js","./RssFeed-BlFC20eg.css","./WebAuthn-s3Hzd9db.js","./WebAuthn-CNPl2VQR.css"])))=>i.map(i=>d[i]);
2
+ import{S as B,U as L,V as I,f as T,c as E,o as R,W as O,u as k,X as y,Y as x,Z as V,k as D,R as S,_ as w}from"./vendor-CN0Iv_qZ.js";import{a as g,A as M}from"./antd-gZyc63Qr.js";(function(){const a=document.createElement("link").relList;if(a&&a.supports&&a.supports("modulepreload"))return;for(const t of document.querySelectorAll('link[rel="modulepreload"]'))m(t);new MutationObserver(t=>{for(const r of t)if(r.type==="childList")for(const n of r.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&m(n)}).observe(document,{childList:!0,subtree:!0});function c(t){const r={};return t.integrity&&(r.integrity=t.integrity),t.referrerPolicy&&(r.referrerPolicy=t.referrerPolicy),t.crossOrigin==="use-credentials"?r.credentials="include":t.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function m(t){if(t.ep)return;t.ep=!0;const r=c(t);fetch(t.href,r)}})();const C="modulepreload",N=function(s,a){return new URL(s,a).href},P={},e=function(a,c,m){let t=Promise.resolve();if(c&&c.length>0){let b=function(i){return Promise.all(i.map(d=>Promise.resolve(d).then(p=>({status:"fulfilled",value:p}),p=>({status:"rejected",reason:p}))))};const n=document.getElementsByTagName("link"),o=document.querySelector("meta[property=csp-nonce]"),u=o?.nonce||o?.getAttribute("nonce");t=b(c.map(i=>{if(i=N(i,m),i in P)return;P[i]=!0;const d=i.endsWith(".css"),p=d?'[rel="stylesheet"]':"";if(m)for(let f=n.length-1;f>=0;f--){const _=n[f];if(_.href===i&&(!d||_.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${i}"]${p}`))return;const l=document.createElement("link");if(l.rel=d?"stylesheet":C,d||(l.as="script"),l.crossOrigin="",l.href=i,u&&l.setAttribute("nonce",u),document.head.appendChild(l),d)return new Promise((f,_)=>{l.addEventListener("load",f),l.addEventListener("error",()=>_(new Error(`Unable to preload CSS for ${i}`)))})}))}function r(n){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=n,window.dispatchEvent(o),!o.defaultPrevented)throw n}return t.then(n=>{for(const o of n||[])o.status==="rejected"&&r(o.reason);return a().catch(r)})},U=[{path:"/",component:()=>e(()=>import("./AppLayout-BhJ3YFWt.js"),__vite__mapDeps([0,1,2,3,4,5]),import.meta.url),children:[{path:"",redirect:"/dashboard"},{path:"dashboard",name:"Dashboard",component:()=>e(()=>import("./Dashboard-CjlX4CrX.js"),__vite__mapDeps([6,1,2,7,3,4,8]),import.meta.url)},{path:"chat",name:"Chat",component:()=>e(()=>import("./Chat-DaxTP3x8.js"),__vite__mapDeps([9,1,10,4,7,2,3,11]),import.meta.url)},{path:"services",name:"Services",component:()=>e(()=>import("./Services-7jQywNbl.js"),__vite__mapDeps([12,2,1,3,4,13]),import.meta.url)},{path:"logs",name:"Logs",component:()=>e(()=>import("./Logs-BY6A0UNG.js"),__vite__mapDeps([14,2,1,3,4,15]),import.meta.url)},{path:"skills",name:"Skills",component:()=>e(()=>import("./Skills-BCvgBkD3.js"),__vite__mapDeps([16,1,2,17,7,3,4,18]),import.meta.url)},{path:"providers",name:"Providers",component:()=>e(()=>import("./Providers-ivOAQtHM.js"),__vite__mapDeps([19,1,2,17,3,4,20]),import.meta.url)},{path:"mcp",name:"McpTools",component:()=>e(()=>import("./McpTools-CrBVYlg6.js"),__vite__mapDeps([21,2,1,3,4,22]),import.meta.url)},{path:"notes",name:"Notes",component:()=>e(()=>import("./Notes-1LcGD49x.js"),__vite__mapDeps([23,2,1,3,4,24]),import.meta.url)},{path:"memory",name:"Memory",component:()=>e(()=>import("./Memory-CWx3SpUt.js"),__vite__mapDeps([25,2,1,3,4,26]),import.meta.url)},{path:"cron",name:"Cron",component:()=>e(()=>import("./Cron-CNs03iHJ.js"),__vite__mapDeps([27,2,1,4]),import.meta.url)},{path:"tasks",name:"Tasks",component:()=>e(()=>import("./Tasks-CmJBC1cf.js"),__vite__mapDeps([28,1,2,3,4,29]),import.meta.url)},{path:"security",name:"Security",component:()=>e(()=>import("./Security-DnEvJU5h.js"),__vite__mapDeps([30,2,1,3,4,31]),import.meta.url)},{path:"permissions",name:"Permissions",component:()=>e(()=>import("./Permissions-BQbC9FzG.js"),__vite__mapDeps([32,2,1,3,4,33]),import.meta.url)},{path:"p2p",name:"P2P",component:()=>e(()=>import("./P2P-B16fjqfJ.js"),__vite__mapDeps([34,2,1,3,4,35]),import.meta.url)},{path:"git",name:"Git",component:()=>e(()=>import("./Git-CCMVr3Y8.js"),__vite__mapDeps([36,2,1,3,4,37]),import.meta.url)},{path:"projects",name:"Projects",component:()=>e(()=>import("./Projects-CjhZbNYm.js"),__vite__mapDeps([38,2,1,3,4,39]),import.meta.url)},{path:"wallet",name:"Wallet",component:()=>e(()=>import("./Wallet-3iYASEx_.js"),__vite__mapDeps([40,2,1,3,4,41]),import.meta.url)},{path:"organization",name:"Organization",component:()=>e(()=>import("./Organization-Dx2DhbkM.js"),__vite__mapDeps([42,1,2,3,4,43]),import.meta.url)},{path:"analytics",name:"Analytics",component:()=>e(()=>import("./Analytics-sBrYoc3A.js"),__vite__mapDeps([44,2,1,3,4,45]),import.meta.url)},{path:"templates",name:"Templates",component:()=>e(()=>import("./Templates-RXT8-DNk.js"),__vite__mapDeps([46,1,2,3,4,47]),import.meta.url)},{path:"backup",name:"Backup",component:()=>e(()=>import("./Backup-D68fenbD.js"),__vite__mapDeps([48,2,1,3,4,49]),import.meta.url)},{path:"rssfeed",name:"RssFeed",component:()=>e(()=>import("./RssFeed-BrsErdrU.js"),__vite__mapDeps([50,1,2,3,4,51]),import.meta.url)},{path:"webauthn",name:"WebAuthn",component:()=>e(()=>import("./WebAuthn-s3Hzd9db.js"),__vite__mapDeps([52,2,1,3,4,53]),import.meta.url)}]}],F=B({history:L(),routes:U}),A="cc_theme",v={dark:{label:"暗黑",icon:"🌑",antd:{algorithm:g.darkAlgorithm,token:{colorPrimary:"#1677ff",colorBgBase:"#141414",colorBgContainer:"#1f1f1f",colorBgElevated:"#2a2a2a",borderRadius:8,fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif'},components:{Layout:{siderBg:"#1c1c1c",headerBg:"#1c1c1c",bodyBg:"#141414"},Menu:{darkItemBg:"#1c1c1c",darkSubMenuItemBg:"#171717"}}},vars:{"--bg-base":"#141414","--bg-sidebar":"#1c1c1c","--bg-header":"#1c1c1c","--bg-card":"#1f1f1f","--bg-card-hover":"#262626","--border-color":"#252525","--border-subtle":"#1e1e1e","--text-primary":"#e0e0e0","--text-secondary":"#888","--text-muted":"#444","--logo-text":"#ffffff","--menu-mode":"dark","--shadow-card":"0 2px 8px rgba(0,0,0,.45)","--group-title":"#3a3a3a"}},light:{label:"亮白",icon:"☀️",antd:{algorithm:g.defaultAlgorithm,token:{colorPrimary:"#1677ff",colorBgBase:"#ffffff",colorBgContainer:"#ffffff",colorBgElevated:"#ffffff",borderRadius:8,fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif'},components:{Layout:{siderBg:"#ffffff",headerBg:"#ffffff",bodyBg:"#f4f6fb"},Menu:{itemBg:"#ffffff"}}},vars:{"--bg-base":"#f4f6fb","--bg-sidebar":"#ffffff","--bg-header":"#ffffff","--bg-card":"#ffffff","--bg-card-hover":"#f0f4ff","--border-color":"#e8edf5","--border-subtle":"#f0f0f0","--text-primary":"#1a1a2e","--text-secondary":"#5a6474","--text-muted":"#b0b8c8","--logo-text":"#1a1a2e","--menu-mode":"light","--shadow-card":"0 2px 12px rgba(0,0,0,.07)","--group-title":"#aab0bc"}},blue:{label:"深蓝",icon:"🌊",antd:{algorithm:g.darkAlgorithm,token:{colorPrimary:"#2f80ed",colorBgBase:"#0d1117",colorBgContainer:"#161b22",colorBgElevated:"#1c2230",borderRadius:8,fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif'},components:{Layout:{siderBg:"#0f1923",headerBg:"#0f1923",bodyBg:"#0d1117"},Menu:{darkItemBg:"#0f1923",darkSubMenuItemBg:"#0b1520"}}},vars:{"--bg-base":"#0d1117","--bg-sidebar":"#0f1923","--bg-header":"#0f1923","--bg-card":"#161b22","--bg-card-hover":"#1c2230","--border-color":"#21303f","--border-subtle":"#182030","--text-primary":"#c9d8ef","--text-secondary":"#6e8caa","--text-muted":"#2d4060","--logo-text":"#e0eeff","--menu-mode":"dark","--shadow-card":"0 2px 8px rgba(0,40,80,.5)","--group-title":"#2d4060"}},green:{label:"翠绿",icon:"🌿",antd:{algorithm:g.darkAlgorithm,token:{colorPrimary:"#29a270",colorBgBase:"#0a1a12",colorBgContainer:"#0f2318",colorBgElevated:"#152e20",borderRadius:8,fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif'},components:{Layout:{siderBg:"#0c1e14",headerBg:"#0c1e14",bodyBg:"#0a1a12"},Menu:{darkItemBg:"#0c1e14",darkSubMenuItemBg:"#091810"}}},vars:{"--bg-base":"#0a1a12","--bg-sidebar":"#0c1e14","--bg-header":"#0c1e14","--bg-card":"#0f2318","--bg-card-hover":"#152e20","--border-color":"#1a3828","--border-subtle":"#122a1c","--text-primary":"#c0e8c8","--text-secondary":"#5a9a6a","--text-muted":"#1e4028","--logo-text":"#d8f0e0","--menu-mode":"dark","--shadow-card":"0 2px 8px rgba(0,40,20,.5)","--group-title":"#1e4028"}}},j=I("theme",()=>{const s=T(localStorage.getItem(A)||"dark"),a=E(()=>v[s.value]||v.dark),c=E(()=>a.value.antd),m=E(()=>s.value!=="light");function t(){const o=a.value.vars,u=document.documentElement;for(const[b,i]of Object.entries(o))u.style.setProperty(b,i);u.setAttribute("data-theme",s.value)}function r(o){v[o]&&(s.value=o,localStorage.setItem(A,o),t())}function n(){t()}return{current:s,config:a,antdTheme:c,isDark:m,setTheme:r,init:n}}),W={__name:"App",setup(s){const a=j();return R(()=>a.init()),(c,m)=>{const t=y("router-view"),r=y("a-config-provider");return x(),O(r,{theme:k(a).antdTheme},{default:V(()=>[D(t)]),_:1},8,["theme"])}}},h=S(W);h.use(w());h.use(F);h.use(M);h.mount("#app");export{v as T,j as u};
@@ -1,4 +1,4 @@
1
- import{g as Yc}from"./antd-CJSBocer.js";function Ni(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}let He=Ni();function Mc(a){He=a}const Lc=/[&<>"']/,qc=new RegExp(Lc.source,"g"),xc=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,Hc=new RegExp(xc.source,"g"),Vc={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},$i=a=>Vc[a];function Ne(a,e){if(e){if(Lc.test(a))return a.replace(qc,$i)}else if(xc.test(a))return a.replace(Hc,$i);return a}const zc=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;function Wc(a){return a.replace(zc,(e,t)=>(t=t.toLowerCase(),t==="colon"?":":t.charAt(0)==="#"?t.charAt(1)==="x"?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const $c=/(^|[^\[])\^/g;function Z(a,e){let t=typeof a=="string"?a:a.source;e=e||"";const n={replace:(r,i)=>{let o=typeof i=="string"?i:i.source;return o=o.replace($c,"$1"),t=t.replace(r,o),n},getRegex:()=>new RegExp(t,e)};return n}function Ki(a){try{a=encodeURI(a).replace(/%25/g,"%")}catch{return null}return a}const pt={exec:()=>null};function Qi(a,e){const t=a.replace(/\|/g,(i,o,s)=>{let l=!1,_=o;for(;--_>=0&&s[_]==="\\";)l=!l;return l?"|":" |"}),n=t.split(/ \|/);let r=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;r<n.length;r++)n[r]=n[r].trim().replace(/\\\|/g,"|");return n}function yt(a,e,t){const n=a.length;if(n===0)return"";let r=0;for(;r<n&&a.charAt(n-r-1)===e;)r++;return a.slice(0,n-r)}function Kc(a,e){if(a.indexOf(e[1])===-1)return-1;let t=0;for(let n=0;n<a.length;n++)if(a[n]==="\\")n++;else if(a[n]===e[0])t++;else if(a[n]===e[1]&&(t--,t<0))return n;return-1}function Xi(a,e,t,n){const r=e.href,i=e.title?Ne(e.title):null,o=a[1].replace(/\\([\[\]])/g,"$1");if(a[0].charAt(0)!=="!"){n.state.inLink=!0;const s={type:"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,s}return{type:"image",raw:t,href:r,title:i,text:Ne(o)}}function Qc(a,e){const t=a.match(/^(\s+)(?:```)/);if(t===null)return e;const n=t[1];return e.split(`
1
+ import{g as Yc}from"./antd-gZyc63Qr.js";function Ni(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}let He=Ni();function Mc(a){He=a}const Lc=/[&<>"']/,qc=new RegExp(Lc.source,"g"),xc=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,Hc=new RegExp(xc.source,"g"),Vc={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},$i=a=>Vc[a];function Ne(a,e){if(e){if(Lc.test(a))return a.replace(qc,$i)}else if(xc.test(a))return a.replace(Hc,$i);return a}const zc=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;function Wc(a){return a.replace(zc,(e,t)=>(t=t.toLowerCase(),t==="colon"?":":t.charAt(0)==="#"?t.charAt(1)==="x"?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const $c=/(^|[^\[])\^/g;function Z(a,e){let t=typeof a=="string"?a:a.source;e=e||"";const n={replace:(r,i)=>{let o=typeof i=="string"?i:i.source;return o=o.replace($c,"$1"),t=t.replace(r,o),n},getRegex:()=>new RegExp(t,e)};return n}function Ki(a){try{a=encodeURI(a).replace(/%25/g,"%")}catch{return null}return a}const pt={exec:()=>null};function Qi(a,e){const t=a.replace(/\|/g,(i,o,s)=>{let l=!1,_=o;for(;--_>=0&&s[_]==="\\";)l=!l;return l?"|":" |"}),n=t.split(/ \|/);let r=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;r<n.length;r++)n[r]=n[r].trim().replace(/\\\|/g,"|");return n}function yt(a,e,t){const n=a.length;if(n===0)return"";let r=0;for(;r<n&&a.charAt(n-r-1)===e;)r++;return a.slice(0,n-r)}function Kc(a,e){if(a.indexOf(e[1])===-1)return-1;let t=0;for(let n=0;n<a.length;n++)if(a[n]==="\\")n++;else if(a[n]===e[0])t++;else if(a[n]===e[1]&&(t--,t<0))return n;return-1}function Xi(a,e,t,n){const r=e.href,i=e.title?Ne(e.title):null,o=a[1].replace(/\\([\[\]])/g,"$1");if(a[0].charAt(0)!=="!"){n.state.inLink=!0;const s={type:"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,s}return{type:"image",raw:t,href:r,title:i,text:Ne(o)}}function Qc(a,e){const t=a.match(/^(\s+)(?:```)/);if(t===null)return e;const n=t[1];return e.split(`
2
2
  `).map(r=>{const i=r.match(/^\s+/);if(i===null)return r;const[o]=i;return o.length>=n.length?r.slice(n.length):r}).join(`
3
3
  `)}class Lt{options;rules;lexer;constructor(e){this.options=e||He}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const n=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?n:yt(n,`
4
4
  `)}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const n=t[0],r=Qc(n,t[3]||"");return{type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:r}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(/#$/.test(n)){const r=yt(n,"#");(this.options.pedantic||!r||/ $/.test(r))&&(n=r.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let n=t[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,`
@@ -0,0 +1 @@
1
+ import{V as U,f as E,c as B}from"./vendor-CN0Iv_qZ.js";let F=0;const w=()=>`wp-${++F}`,b=new Set;function d(e,r={},n={}){return{type:e,kind:n.kind||"server",sessionId:n.sessionId||r.sessionId||null,timestamp:n.timestamp||Date.now(),payload:r}}function G(e){const r=e?.type,n=e?.payload||{};switch(r){case"task:notification":return d("task:notification",{task:e.task||n.task},{kind:"server"});case"session-created":case"session.started":return d("session:start",{sessionId:e.sessionId||n.sessionId,sessionType:e.sessionType||n.sessionType||null,record:e.record||n.record||{id:e.sessionId||n.sessionId,type:e.sessionType||n.sessionType||null,status:"created",history:[],messageCount:0}},{kind:"server",sessionId:e.sessionId||n.sessionId});case"session-resumed":case"session.resumed":{const i=e.sessionId||n.sessionId,a=e.history||n.history||[];return d("session:resume",{sessionId:i,history:a,historyCount:Array.isArray(a)?a.length:0,record:e.record||n.record||{id:i,type:null,status:"resumed",history:a,messageCount:Array.isArray(a)?a.length:0}},{kind:"server",sessionId:i})}case"worktree-diff":case"worktree.diff":return d("worktree:diff:ready",{requestId:e.requestId||e.id||null,record:e.record||n.record||{branch:e.branch||n.branch||null,summary:e.summary||n.summary||null,previewEntrypoints:[{type:"worktree-diff",branch:e.branch||n.branch||null}]}},{kind:"server"});case"worktree-merged":case"worktree.merged":return d("worktree:merge:completed",{requestId:e.requestId||e.id||null,record:e.record||n.record||{branch:e.branch||n.branch||null,summary:e.summary||n.summary||null,conflicts:e.conflicts||n.conflicts||[],previewEntrypoints:e.previewEntrypoints||n.previewEntrypoints||[]}},{kind:"server"});case"compression-stats":case"context.compaction.completed":return d("compression:summary",{requestId:e.requestId||e.id||null,summary:e.summary||n.summary||{}},{kind:"server"});default:return null}}function W(e,r=null){b.forEach(n=>n(e,r||e))}function Q(e){if(!e)return null;const r=e.record||{id:e.id||null,type:e.type||null,provider:e.provider||null,model:e.model||null,projectRoot:e.projectRoot||null,messageCount:e.messageCount??0,history:e.history||[],status:e.status||null};return{...e,id:e.id||r.id,type:e.type||r.type,provider:e.provider||r.provider,model:e.model||r.model,projectRoot:e.projectRoot||r.projectRoot,messageCount:e.messageCount??r.messageCount??0,status:e.status||r.status||null,record:r}}const K=U("ws",()=>{const e=E(null),r=E("disconnected"),n=E(null),i=new Map,a=new Map;let C=null,v=1e3;const y=window.__CC_CONFIG__||{},R=B(()=>`ws://${y.wsHost||"127.0.0.1"}:${y.wsPort||18800}`);function h(){if(e.value?.readyState!==WebSocket.OPEN){r.value="connecting",n.value=null;try{const t=new WebSocket(R.value);e.value=t,t.onopen=()=>{v=1e3,y.wsToken?l({type:"auth",id:w(),token:y.wsToken}).then(()=>{r.value="connected"}).catch(()=>{r.value="connected"}):r.value="connected"},t.onmessage=o=>{let s;try{s=JSON.parse(o.data)}catch{return}q(s)},t.onerror=()=>{n.value="WebSocket error",r.value="error"},t.onclose=()=>{r.value="disconnected",e.value=null,i.forEach(({reject:o})=>o(new Error("WebSocket closed"))),i.clear(),C=setTimeout(()=>{v=Math.min(v*2,3e4),h()},v)}}catch(t){r.value="error",n.value=t.message}}}function P(){clearTimeout(C),e.value?.close(),e.value=null,r.value="disconnected"}function T(t){if(!t.version&&!t.payload)return t;const o=t.payload||{};return{...t,...o,type:t.type,sessionId:t.sessionId||o.sessionId||null}}function q(t){const{type:o}=t,s=t.requestId||t.id;let u=!1;if(s&&i.has(s)){const{resolve:f,reject:O,timeout:S}=i.get(s);clearTimeout(S),i.delete(s),u=!0;const I=T(t);I.id=s,o==="error"?O(new Error(I.message||"Unknown error")):f(I)}const c=t.sessionId||t.payload&&t.payload.sessionId||null;if(c&&a.has(c)){const f=T(t);a.get(c).forEach(S=>S(f))}k.forEach(f=>f(t));const m=G(t);return m&&W(m,t),u}const k=new Set;function J(t){return k.add(t),()=>k.delete(t)}function j(t){return b.add(t),()=>b.delete(t)}function x(t,o){return a.has(t)||a.set(t,new Set),a.get(t).add(o),()=>{a.get(t)?.delete(o),a.get(t)?.size===0&&a.delete(t)}}function l(t,o=15e3){return new Promise((s,u)=>{if(e.value?.readyState!==WebSocket.OPEN){u(new Error("WebSocket not connected"));return}const c=t.id||w(),m=setTimeout(()=>{i.delete(c),u(new Error("Request timeout"))},o);i.set(c,{resolve:s,reject:u,timeout:m}),e.value.send(JSON.stringify({...t,id:c}))})}function p(t=8e3){return r.value==="connected"?Promise.resolve():new Promise((o,s)=>{const u=Date.now()+t,c=()=>{if(r.value==="connected")return o();if(r.value==="error"||Date.now()>=u)return s(new Error(`WS not ready: ${r.value}`));setTimeout(c,150)};r.value==="disconnected"&&h(),c()})}async function N(t,o=3e4){await p(8e3);const s=await l({type:"execute",command:t},o),u=s.output??s.stdout??"",c=s.stderr??"";return{output:u||c,exitCode:s.exitCode??0}}async function M(t,o=3e4){const{output:s,exitCode:u}=await N(t,o);if(u!==0)throw new Error(`Command failed: ${s}`);try{return JSON.parse(s.trim())}catch{const c=s.match(/\{[\s\S]*\}|\[[\s\S]*\]/);if(c)return JSON.parse(c[0]);throw new Error(`Invalid JSON output: ${s.slice(0,200)}`)}}async function _(t="chat",o=null){await p(8e3);const s=w();return(await l({type:"session-create",id:s,sessionType:t,projectRoot:o||y.projectRoot||null})).sessionId}function $(t,o){e.value?.readyState===WebSocket.OPEN&&e.value.send(JSON.stringify({type:"session-message",id:w(),sessionId:t,content:o}))}function A(t,o,s){e.value?.readyState===WebSocket.OPEN&&e.value.send(JSON.stringify({type:"session-answer",id:w(),sessionId:t,requestId:o,answer:s}))}async function D(){return await p(8e3),((await l({type:"session-list"},1e4)).sessions||[]).map(Q).filter(Boolean)}async function H(t){try{await l({type:"session-close",sessionId:t},5e3),W(d("session:end",{sessionId:t},{kind:"server",sessionId:t}),{type:"result",sessionId:t,success:!0})}catch{}}async function z(t){return await p(8e3),await l({type:"session-resume",sessionId:t},1e4)}return{status:r,error:n,wsUrl:R,connect:h,disconnect:P,waitConnected:p,onMessage:J,onRuntimeEvent:j,onSession:x,sendRaw:l,execute:N,executeJson:M,createSession:_,resumeSession:z,sendSessionMessage:$,answerQuestion:A,listSessions:D,closeSession:H}});export{K as u};
@@ -8,9 +8,9 @@
8
8
  // Injected by web-ui-server.js at serve time
9
9
  window.__CC_CONFIG__ = __CC_CONFIG_PLACEHOLDER__;
10
10
  </script>
11
- <script type="module" crossorigin src="./assets/index-IK-oro0g.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-DrmEk9S3.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-CN0Iv_qZ.js">
13
- <link rel="modulepreload" crossorigin href="./assets/antd-CJSBocer.js">
13
+ <link rel="modulepreload" crossorigin href="./assets/antd-gZyc63Qr.js">
14
14
  <link rel="stylesheet" crossorigin href="./assets/index-CyGyEIVX.css">
15
15
  </head>
16
16
  <body>
@@ -1,178 +1,60 @@
1
1
  import chalk from "chalk";
2
- import { execSync } from "node:child_process";
3
- import { existsSync, readdirSync } from "node:fs";
4
- import { createConnection } from "node:net";
5
- import semver from "semver";
6
- import { MIN_NODE_VERSION, DEFAULT_PORTS, VERSION } from "../constants.js";
7
- import { getHomeDir, getConfigPath, getBinDir } from "../lib/paths.js";
8
- import {
9
- isDockerAvailable,
10
- isDockerComposeAvailable,
11
- } from "../lib/service-manager.js";
12
- import { loadConfig } from "../lib/config-manager.js";
13
2
  import logger from "../lib/logger.js";
3
+ import { collectDoctorReport } from "../runtime/diagnostics.js";
14
4
 
15
5
  export function registerDoctorCommand(program) {
16
6
  program
17
7
  .command("doctor")
18
8
  .description("Diagnose your ChainlessChain environment")
19
- .action(async () => {
20
- logger.log(chalk.bold("\n ChainlessChain Doctor\n"));
21
-
22
- const checks = [];
23
-
24
- // Node.js
25
- const nodeVersion = process.versions.node;
26
- const nodeOk = semver.gte(nodeVersion, MIN_NODE_VERSION);
27
- checks.push({
28
- name: `Node.js ${nodeVersion}`,
29
- ok: nodeOk,
30
- detail: nodeOk ? "" : `Requires >=${MIN_NODE_VERSION}`,
31
- });
32
-
33
- // npm
34
- try {
35
- const npmVersion = execSync("npm --version", {
36
- encoding: "utf-8",
37
- }).trim();
38
- checks.push({ name: `npm ${npmVersion}`, ok: true });
39
- } catch {
40
- checks.push({ name: "npm", ok: false, detail: "Not found" });
41
- }
42
-
43
- // Docker
44
- checks.push({
45
- name: "Docker",
46
- ok: isDockerAvailable(),
47
- detail: isDockerAvailable() ? "" : "Not installed (optional)",
48
- });
49
- checks.push({
50
- name: "Docker Compose",
51
- ok: isDockerComposeAvailable(),
52
- detail: isDockerComposeAvailable() ? "" : "Not installed (optional)",
53
- });
54
-
55
- // Git
56
- try {
57
- const gitVersion = execSync("git --version", {
58
- encoding: "utf-8",
59
- }).trim();
60
- checks.push({ name: gitVersion, ok: true });
61
- } catch {
62
- checks.push({ name: "Git", ok: false, detail: "Not found" });
9
+ .option("--json", "Output as machine-readable JSON")
10
+ .action(async (options) => {
11
+ const report = await collectDoctorReport();
12
+
13
+ if (options.json) {
14
+ console.log(JSON.stringify(report, null, 2));
15
+ if (report.summary.criticalFailed > 0) {
16
+ process.exitCode = 1;
17
+ }
18
+ return;
63
19
  }
64
20
 
65
- // Config directory
66
- const homeDir = getHomeDir();
67
- checks.push({
68
- name: `Config dir: ${homeDir}`,
69
- ok: existsSync(homeDir),
70
- detail: existsSync(homeDir) ? "" : 'Run "chainlesschain setup"',
71
- });
72
-
73
- // Config file
74
- const configPath = getConfigPath();
75
- checks.push({
76
- name: "Config file",
77
- ok: existsSync(configPath),
78
- detail: existsSync(configPath) ? "" : 'Run "chainlesschain setup"',
79
- });
80
-
81
- // Binary
82
- const binDir = getBinDir();
83
- const hasBin = existsSync(binDir) && readdirSafe(binDir).length > 0;
84
- checks.push({
85
- name: "Desktop binary",
86
- ok: hasBin,
87
- detail: hasBin
88
- ? ""
89
- : 'Run "chainlesschain setup" or "chainlesschain update"',
90
- });
91
-
92
- // Setup completed
93
- const config = loadConfig();
94
- checks.push({
95
- name: "Setup completed",
96
- ok: config.setupCompleted,
97
- detail: config.setupCompleted ? "" : 'Run "chainlesschain setup"',
98
- });
21
+ logger.log(chalk.bold("\n ChainlessChain Doctor\n"));
99
22
 
100
- // Print results
101
- for (const check of checks) {
23
+ for (const check of report.checks) {
102
24
  const icon = check.ok ? chalk.green("✔") : chalk.red("✖");
103
25
  const detail = check.detail ? chalk.gray(` (${check.detail})`) : "";
104
26
  logger.log(` ${icon} ${check.name}${detail}`);
105
27
  }
106
28
 
107
- // Port scan
108
29
  logger.log(chalk.bold("\n Port Status\n"));
109
- for (const [name, port] of Object.entries(DEFAULT_PORTS)) {
110
- const open = await checkPort(port);
111
- const icon = open ? chalk.green("●") : chalk.gray("○");
112
- logger.log(` ${icon} ${name}: ${port}`);
30
+ for (const p of report.ports) {
31
+ const icon = p.open ? chalk.green("●") : chalk.gray("○");
32
+ logger.log(` ${icon} ${p.name}: ${p.port}`);
113
33
  }
114
34
 
115
- // Disk space (basic)
116
- try {
117
- const { statfsSync } = await import("node:fs");
118
- // statfsSync available in Node 22+
119
- if (statfsSync) {
120
- const stats = statfsSync(homeDir);
121
- const freeGB = (stats.bavail * stats.bsize) / (1024 * 1024 * 1024);
122
- const ok = freeGB > 2;
123
- logger.log(chalk.bold("\n Disk\n"));
124
- const icon = ok ? chalk.green("✔") : chalk.yellow("⚠");
125
- logger.log(` ${icon} Free space: ${freeGB.toFixed(1)} GB`);
126
- }
127
- } catch {
128
- // statfsSync not available on all platforms
35
+ if (report.disk) {
36
+ const ok = report.disk.freeGB > 2;
37
+ logger.log(chalk.bold("\n Disk\n"));
38
+ const icon = ok ? chalk.green("✔") : chalk.yellow("⚠");
39
+ logger.log(` ${icon} Free space: ${report.disk.freeGB.toFixed(1)} GB`);
129
40
  }
130
41
 
131
- // Summary
132
- const failures = checks.filter((c) => !c.ok);
133
42
  logger.newline();
134
- if (failures.length === 0) {
43
+ if (report.summary.failed === 0) {
135
44
  logger.log(chalk.bold.green(" All checks passed!\n"));
45
+ } else if (report.summary.criticalFailed > 0) {
46
+ logger.log(
47
+ chalk.bold.red(
48
+ ` ${report.summary.criticalFailed} issue(s) found. See details above.\n`,
49
+ ),
50
+ );
51
+ process.exitCode = 1;
136
52
  } else {
137
- const critical = failures.filter(
138
- (c) => !c.detail?.includes("optional"),
53
+ logger.log(
54
+ chalk.bold.yellow(
55
+ ` ${report.summary.failed} optional component(s) missing.\n`,
56
+ ),
139
57
  );
140
- if (critical.length > 0) {
141
- logger.log(
142
- chalk.bold.red(
143
- ` ${critical.length} issue(s) found. See details above.\n`,
144
- ),
145
- );
146
- } else {
147
- logger.log(
148
- chalk.bold.yellow(
149
- ` ${failures.length} optional component(s) missing.\n`,
150
- ),
151
- );
152
- }
153
58
  }
154
59
  });
155
60
  }
156
-
157
- function checkPort(port, host = "127.0.0.1") {
158
- return new Promise((resolve) => {
159
- const socket = createConnection({ port, host, timeout: 1000 });
160
- socket.on("connect", () => {
161
- socket.destroy();
162
- resolve(true);
163
- });
164
- socket.on("error", () => resolve(false));
165
- socket.on("timeout", () => {
166
- socket.destroy();
167
- resolve(false);
168
- });
169
- });
170
- }
171
-
172
- function readdirSafe(dir) {
173
- try {
174
- return readdirSync(dir);
175
- } catch {
176
- return [];
177
- }
178
- }
@@ -7,7 +7,7 @@ import chalk from "chalk";
7
7
  import ora from "ora";
8
8
  import { logger } from "../lib/logger.js";
9
9
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
- import { MCPClient, MCPServerConfig } from "../lib/mcp-client.js";
10
+ import { MCPClient, MCPServerConfig } from "../harness/mcp-client.js";
11
11
 
12
12
  // Singleton MCP client for session reuse
13
13
  let mcpClient = null;
@@ -23,7 +23,7 @@ import {
23
23
  installPluginSkills,
24
24
  removePluginSkills,
25
25
  getPluginSkills,
26
- } from "../lib/plugin-manager.js";
26
+ } from "../harness/plugin-manager.js";
27
27
 
28
28
  export function registerPluginCommand(program) {
29
29
  const plugin = program
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import fs from "fs";
7
+ import path from "path";
7
8
  import chalk from "chalk";
8
9
  import { logger } from "../lib/logger.js";
9
10
  import { bootstrap, shutdown } from "../runtime/bootstrap.js";
@@ -22,8 +23,12 @@ import {
22
23
  migrateLegacySessionsBatch,
23
24
  validateJsonlSession,
24
25
  validateAllJsonlSessions,
25
- } from "../lib/jsonl-session-store.js";
26
+ } from "../harness/jsonl-session-store.js";
26
27
  import { feature } from "../lib/feature-flags.js";
28
+ import {
29
+ listWorkflowSessions,
30
+ readWorkflowSession,
31
+ } from "../lib/workflow-state-reader.js";
27
32
 
28
33
  export function registerSessionCommand(program) {
29
34
  const session = program
@@ -313,7 +318,11 @@ export function registerSessionCommand(program) {
313
318
  .option("--dry-run", "Show what would migrate without writing files")
314
319
  .option("--force", "Overwrite existing JSONL sessions")
315
320
  .option("--no-archive", "Do not keep .migrated.json backups")
316
- .option("--sample-size <n>", "Validate N migrated sessions after migration", "3")
321
+ .option(
322
+ "--sample-size <n>",
323
+ "Validate N migrated sessions after migration",
324
+ "3",
325
+ )
317
326
  .option("--retry-failures", "Retry failed migrations once")
318
327
  .option("--json", "Output as JSON")
319
328
  .action(async (source, options) => {
@@ -325,7 +334,8 @@ export function registerSessionCommand(program) {
325
334
  sampleSize: parseInt(options.sampleSize, 10) || 3,
326
335
  retryFailures: options.retryFailures,
327
336
  });
328
- const results = report.results || migrateLegacySessions(source, options);
337
+ const results =
338
+ report.results || migrateLegacySessions(source, options);
329
339
 
330
340
  if (options.json) {
331
341
  console.log(JSON.stringify(report, null, 2));
@@ -357,9 +367,10 @@ export function registerSessionCommand(program) {
357
367
 
358
368
  if (report.sampledValidation?.length) {
359
369
  for (const item of report.sampledValidation) {
360
- const label = item.valid && item.matchesExpectedMessages
361
- ? chalk.green("sample-ok")
362
- : chalk.red("sample-fail");
370
+ const label =
371
+ item.valid && item.matchesExpectedMessages
372
+ ? chalk.green("sample-ok")
373
+ : chalk.red("sample-fail");
363
374
  logger.log(
364
375
  `${label} ${item.sessionId} (${item.messageCount}/${item.expectedMessageCount} messages)`,
365
376
  );
@@ -389,7 +400,9 @@ export function registerSessionCommand(program) {
389
400
 
390
401
  const results = Array.isArray(result) ? result : [result];
391
402
  for (const item of results) {
392
- const label = item.valid ? chalk.green("valid") : chalk.red("invalid");
403
+ const label = item.valid
404
+ ? chalk.green("valid")
405
+ : chalk.red("invalid");
393
406
  logger.log(
394
407
  `${label} ${item.sessionId} (${item.eventCount} events, ${item.messageCount || 0} messages, malformed: ${item.malformedLines})`,
395
408
  );
@@ -402,4 +415,90 @@ export function registerSessionCommand(program) {
402
415
  process.exit(1);
403
416
  }
404
417
  });
418
+
419
+ // session workflow — inspect canonical coding workflow state
420
+ // Reads .chainlesschain/sessions/<id>/{intent.md,plan.md,progress.log,mode.json}
421
+ // written by the 4 workflow skills ($deep-interview/$ralplan/$ralph/$team).
422
+ session
423
+ .command("workflow")
424
+ .description("Inspect coding workflow state (.chainlesschain/sessions/)")
425
+ .argument("[id]", "Workflow session ID (omit to list all)")
426
+ .option("--json", "Output as JSON")
427
+ .option("--cwd <path>", "Project root (defaults to process.cwd())")
428
+ .action((id, options) => {
429
+ try {
430
+ const projectRoot = path.resolve(options.cwd || process.cwd());
431
+
432
+ if (!id) {
433
+ const items = listWorkflowSessions(projectRoot);
434
+ if (options.json) {
435
+ console.log(JSON.stringify(items, null, 2));
436
+ return;
437
+ }
438
+ if (items.length === 0) {
439
+ logger.info("No workflow sessions under .chainlesschain/sessions/");
440
+ logger.info(
441
+ 'Start one with: $deep-interview "<your goal>" in the coding agent',
442
+ );
443
+ return;
444
+ }
445
+ logger.log(chalk.bold(`Workflow sessions (${items.length}):\n`));
446
+ for (const s of items) {
447
+ const approvedTag = s.approved
448
+ ? chalk.green("approved")
449
+ : s.hasPlan
450
+ ? chalk.yellow("unapproved")
451
+ : chalk.gray("no-plan");
452
+ logger.log(
453
+ ` ${chalk.cyan(s.sessionId)} ${chalk.white(s.stage || "?")} ${approvedTag} ${chalk.gray(s.updatedAt || "")}`,
454
+ );
455
+ }
456
+ return;
457
+ }
458
+
459
+ const data = readWorkflowSession(projectRoot, id);
460
+ if (!data) {
461
+ logger.error(`Workflow session "${id}" not found`);
462
+ process.exit(1);
463
+ }
464
+ if (options.json) {
465
+ console.log(JSON.stringify(data, null, 2));
466
+ return;
467
+ }
468
+ logger.log(chalk.bold(`\nSession: ${data.sessionId}`));
469
+ logger.log(
470
+ `Stage: ${data.mode?.stage || chalk.gray("(unset)")} Approved: ${
471
+ data.planApproved ? chalk.green("yes") : chalk.yellow("no")
472
+ }`,
473
+ );
474
+ logger.log(chalk.gray(`Dir: ${data.dir}\n`));
475
+
476
+ if (data.intent) {
477
+ logger.log(chalk.bold("── intent.md ──"));
478
+ logger.log(data.intent.trim());
479
+ logger.log("");
480
+ } else {
481
+ logger.log(chalk.gray("(no intent.md — run $deep-interview first)"));
482
+ }
483
+
484
+ if (data.plan) {
485
+ logger.log(chalk.bold("── plan.md ──"));
486
+ logger.log(data.plan.trim());
487
+ logger.log("");
488
+ } else {
489
+ logger.log(chalk.gray("(no plan.md — run $ralplan)"));
490
+ }
491
+
492
+ if (data.progress) {
493
+ logger.log(chalk.bold("── progress.log (tail) ──"));
494
+ const lines = data.progress.trim().split("\n");
495
+ for (const line of lines.slice(-20)) {
496
+ logger.log(` ${line}`);
497
+ }
498
+ }
499
+ } catch (err) {
500
+ logger.error(`Failed: ${err.message}`);
501
+ process.exit(1);
502
+ }
503
+ });
405
504
  }
@@ -1,84 +1,69 @@
1
1
  import chalk from "chalk";
2
- import { createConnection } from "node:net";
3
- import { isAppRunning, getAppPid } from "../lib/process-manager.js";
4
- import {
5
- isDockerAvailable,
6
- getServiceStatus,
7
- findComposeFile,
8
- } from "../lib/service-manager.js";
9
- import { loadConfig } from "../lib/config-manager.js";
10
- import { DEFAULT_PORTS } from "../constants.js";
11
2
  import logger from "../lib/logger.js";
3
+ import { collectStatusReport } from "../runtime/diagnostics.js";
12
4
 
13
5
  export function registerStatusCommand(program) {
14
6
  program
15
7
  .command("status")
16
8
  .description("Show status of ChainlessChain app and services")
17
- .action(async () => {
9
+ .option("--json", "Output as machine-readable JSON")
10
+ .action(async (options) => {
18
11
  try {
19
- const config = loadConfig();
12
+ const report = await collectStatusReport();
13
+
14
+ if (options.json) {
15
+ console.log(JSON.stringify(report, null, 2));
16
+ return;
17
+ }
20
18
 
21
19
  // App status
22
20
  logger.log(chalk.bold("\n App Status\n"));
23
- if (isAppRunning()) {
24
- const pid = getAppPid();
25
- logger.log(` ${chalk.green("●")} Desktop app running (PID: ${pid})`);
21
+ if (report.app.running) {
22
+ logger.log(
23
+ ` ${chalk.green("●")} Desktop app running (PID: ${report.app.pid})`,
24
+ );
26
25
  } else {
27
26
  logger.log(` ${chalk.gray("○")} Desktop app not running`);
28
27
  }
29
28
 
30
- // Setup status
31
- if (config.setupCompleted) {
29
+ if (report.setup.completed) {
32
30
  logger.log(
33
- ` ${chalk.green("●")} Setup completed (${config.completedAt || "unknown"})`,
31
+ ` ${chalk.green("●")} Setup completed (${report.setup.completedAt || "unknown"})`,
34
32
  );
35
- logger.log(` Edition: ${config.edition}`);
36
- logger.log(` LLM: ${config.llm.provider} (${config.llm.model})`);
33
+ if (report.setup.edition) {
34
+ logger.log(` Edition: ${report.setup.edition}`);
35
+ }
36
+ if (report.setup.llm) {
37
+ logger.log(
38
+ ` LLM: ${report.setup.llm.provider} (${report.setup.llm.model})`,
39
+ );
40
+ }
37
41
  } else {
38
42
  logger.log(` ${chalk.yellow("●")} Setup not completed`);
39
43
  }
40
44
 
41
45
  // Docker services
42
46
  logger.log(chalk.bold("\n Docker Services\n"));
43
- if (isDockerAvailable()) {
44
- const composePath = findComposeFile([
45
- process.cwd(),
46
- "backend/docker",
47
- ]);
48
- if (composePath) {
49
- const status = getServiceStatus(composePath);
50
- if (status && Array.isArray(status)) {
51
- for (const svc of status) {
52
- const running = svc.State === "running";
53
- const icon = running ? chalk.green("●") : chalk.red("●");
54
- logger.log(
55
- ` ${icon} ${svc.Service || svc.Name}: ${svc.State}`,
56
- );
57
- }
58
- } else if (status) {
59
- logger.log(` ${status}`);
60
- } else {
61
- logger.log(` ${chalk.gray("○")} No services running`);
62
- }
63
- } else {
64
- logger.log(` ${chalk.gray("○")} docker-compose.yml not found`);
65
- }
66
- } else {
47
+ if (!report.docker.available) {
67
48
  logger.log(` ${chalk.gray("○")} Docker not available`);
49
+ } else if (report.docker.services) {
50
+ for (const svc of report.docker.services) {
51
+ const running = svc.state === "running";
52
+ const icon = running ? chalk.green("●") : chalk.red("●");
53
+ logger.log(` ${icon} ${svc.name}: ${svc.state}`);
54
+ }
55
+ } else if (report.docker.note) {
56
+ const icon = report.docker.note.includes("not found")
57
+ ? chalk.gray("○")
58
+ : chalk.gray("○");
59
+ logger.log(` ${icon} ${report.docker.note}`);
68
60
  }
69
61
 
70
- // Port checks
62
+ // Ports
71
63
  logger.log(chalk.bold("\n Ports\n"));
72
- const portChecks = Object.entries(DEFAULT_PORTS).map(
73
- async ([name, port]) => {
74
- const open = await checkPort(port);
75
- const icon = open ? chalk.green("●") : chalk.gray("○");
76
- return ` ${icon} ${name}: ${port}`;
77
- },
78
- );
79
- const results = await Promise.all(portChecks);
80
- for (const line of results) {
81
- logger.log(line);
64
+ for (const p of report.ports) {
65
+ const icon = p.open ? chalk.green("●") : chalk.gray("○");
66
+ logger.log(` ${icon} ${p.name}: ${p.port}`);
82
67
  }
83
68
 
84
69
  logger.newline();
@@ -88,18 +73,3 @@ export function registerStatusCommand(program) {
88
73
  }
89
74
  });
90
75
  }
91
-
92
- function checkPort(port, host = "127.0.0.1") {
93
- return new Promise((resolve) => {
94
- const socket = createConnection({ port, host, timeout: 1000 });
95
- socket.on("connect", () => {
96
- socket.destroy();
97
- resolve(true);
98
- });
99
- socket.on("error", () => resolve(false));
100
- socket.on("timeout", () => {
101
- socket.destroy();
102
- resolve(false);
103
- });
104
- });
105
- }
@@ -46,7 +46,7 @@ async function ensureSessionHandler(server, ws, session) {
46
46
  interaction: session.interaction,
47
47
  });
48
48
  } else {
49
- const { WSAgentHandler } = await import("../../lib/ws-agent-handler.js");
49
+ const { WSAgentHandler } = await import("./ws-agent-handler.js");
50
50
  handler = new WSAgentHandler({
51
51
  session,
52
52
  interaction: session.interaction,