@devflow-tools/cli 0.16.11 → 0.16.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +278 -19
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/embeddings.d.ts +8 -0
- package/dist/commands/embeddings.d.ts.map +1 -0
- package/dist/commands/embeddings.js +26 -0
- package/dist/commands/embeddings.js.map +1 -0
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +41 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/index.js +53 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/with-server.d.ts.map +1 -1
- package/dist/lib/with-server.js +12 -6
- package/dist/lib/with-server.js.map +1 -1
- package/dist/plugin-files/.claude-plugin/plugin.json +1 -1
- package/dist/plugin-files/dist/command-registry.json +5 -5
- package/dist/plugin-files/dist/hooks/hook-daemon.js +32 -14
- package/dist/plugin-files/dist/hooks/memory-snapshot-cache.js +11 -0
- package/dist/plugin-files/dist/hooks/post-tool-use-failure.js +2 -2
- package/dist/plugin-files/dist/hooks/post-tool-use.js +6 -3
- package/dist/plugin-files/dist/hooks/pre-compact.js +3 -2
- package/dist/plugin-files/dist/hooks/pre-tool-use.js +3 -2
- package/dist/plugin-files/dist/hooks/server-bootstrap.js +22 -22
- package/dist/plugin-files/dist/hooks/session-end.js +4 -2
- package/dist/plugin-files/dist/hooks/stop.js +17 -2
- package/dist/plugin-files/dist/hooks/user-prompt-submit.js +15 -4
- package/dist/plugin-files/dist/skills/devflow:react/SKILL.md +8 -0
- package/dist/plugin-files/hooks/session-start +12 -15
- package/dist/plugin-files/package.json +7 -7
- package/dist/plugin-files/skills/react/SKILL.md +8 -0
- package/package.json +27 -27
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
import {createServer,createConnection}from'net';import {createHash,randomUUID as randomUUID$1}from'node:crypto';import {join,dirname}from'path';import {mkdirSync,lstatSync,openSync,writeFileSync,fstatSync,closeSync,readFileSync,unlinkSync,existsSync as existsSync$1,readdirSync,rmSync,renameSync as renameSync$1,appendFileSync}from'fs';import {getLocalApiKey,getDaemonSocketPath,getDaemonPidPath,formatSkillRuntimeOverlay,createSkillRuntimeOverlay,loadConfig,selectHostAdapter,getProjectStateDir,getDaemonRegistryPath,getProjectHash}from'@devflow-tools/sdk';import {request}from'http';import {homedir}from'os';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {fileURLToPath}from'url';import {spawn}from'child_process';import {mkdirSync as mkdirSync$1,existsSync,writeFileSync as writeFileSync$1,renameSync,unlinkSync as unlinkSync$1,readdirSync as readdirSync$1,readFileSync as readFileSync$1,rmSync as rmSync$1,openSync as openSync$1,closeSync as closeSync$1,statSync}from'node:fs';import {join as join$1,basename,resolve,relative,sep,dirname as dirname$1,isAbsolute}from'node:path';import {MemoryGate}from'@devflow-tools/memory-engine';import {randomUUID,createHash as createHash$1}from'crypto';import {homedir as homedir$1}from'node:os';var Ce=1e4,to=3e4,M=500;function oo(n,e,t){return new Promise(o=>{try{let r=new URL(n),i=request({hostname:r.hostname,port:r.port||80,path:r.pathname+r.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":t,"Content-Length":Buffer.byteLength(e)},timeout:5e3},s=>{let a=[];s.on("data",c=>a.push(c)),s.on("end",()=>{let c=Buffer.concat(a).toString();o(s.statusCode!=null&&s.statusCode>=200&&s.statusCode<300?c:null);});});i.on("error",()=>o(null)),i.on("timeout",()=>{i.destroy(),o(null);}),i.write(e),i.end();}catch{o(null);}})}var b=class{constructor(e){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=e?.apiUrl??process.env.DEVFLOW_API_URL??"http://127.0.0.1:13337",this.apiKey=e?.apiKey??getLocalApiKey(),this.cacheDir=e?.cacheDir??join(process.env.DEVFLOW_STATE_DIR??join(homedir(),".devflow","global"),"telemetry-cache"),this.legacyCacheDir=e?.legacyCacheDir??(e?.cacheDir?null:join(homedir(),".devflow","telemetry-cache")),this.database=e?.database??null,this.ownsDatabase=!e?.database;let t=e?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(t)&&t>=0?t:100;}async sendEvent(e){let t={...e,input:this.truncateInput(e.input)};return this.commitOrCache("tool_call",t)?(this.postHttp("/api/telemetry/tool-call",t),e.eventId):null}async sendExecutionStart(e,t,o,r,i=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:e,sessionId:t,skillName:o,startedAt:r,projectRoot:i,requiredMcpTools:s};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(e,t="completed",o=Date.now(),r){let i={executionId:e,status:t,finishedAt:o,metadata:r},s=this.commitOrCache("execution_complete",i);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",i),s}async sendSessionStart(e,t,o){let r={id:e,projectRoot:t,startedAt:o,label:t.split("/").pop()??"unknown"},i=this.commitOrCache("session_start",r);return i&&this.postHttp("/api/telemetry/sessions",r),i}async completeEvent(e){let t=this.commitOrCache("complete_event",e);return t&&(this.postHttp("/api/telemetry/tool-call/output",e),this.scheduleMetricAggregation()),t}async endSession(e,t=Date.now()){let o={sessionId:e,finishedAt:t},r=this.commitOrCache("session_end",o);return r&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(e)}/close`,{finishedAt:t})),r}async flushCache(){try{let o=this.getDatabase(),r=o.listTelemetryFailures({unresolvedOnly:!0,limit:M}).reverse();for(let i of r)try{this.applyOperation(i.operation,i.payload),o.resolveTelemetryFailure(i.id);}catch{}o.trimTelemetryFailures(M);}catch{}let t=[...new Set([this.cacheDir,this.legacyCacheDir].filter(o=>!!o))].filter(o=>existsSync$1(o)).flatMap(o=>readdirSync(o).filter(r=>r.endsWith(".json")).map(r=>{let i=join(o,r);try{return {cacheFile:i,envelope:no(JSON.parse(readFileSync(i,"utf8")),r)}}catch{return null}})).filter(o=>o!==null).sort((o,r)=>o.envelope.timestamp-r.envelope.timestamp||Pe(o.envelope.operation)-Pe(r.envelope.operation));for(let{cacheFile:o,envelope:r}of t)try{let i=this.getDatabase();i.insertTelemetryFailure({id:r.id,operation:r.operation,payload:r.payload,error:r.failure,createdAt:r.timestamp}),this.applyOperation(r.operation,r.payload),i.resolveTelemetryFailure(r.id),unlinkSync(o);}catch{}this.database?.aggregatePendingToolMetrics();}aggregateMetrics(){return this.getDatabase().aggregatePendingToolMetrics()}async flushAndAggregate(){await this.flushCache(),this.aggregateMetrics();}close(){this.ownsDatabase&&this.database?.close(),this.database=null;}getDatabase(){return this.database??=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:this.busyTimeoutMs}),this.database}commitOrCache(e,t){try{return this.applyOperation(e,t),!0}catch(o){return this.cacheOperation(e,t,o),false}}applyOperation(e,t){let o=this.getDatabase();switch(e){case "tool_call":this.ensureParentSession(o,t),o.insertToolCallEvent(t);return;case "execution_start":this.ensureParentSession(o,t),o.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running",requiredMcpTools:t.requiredMcpTools});return;case "execution_complete":o.reconcileSkillExecution(t.executionId,t.status,t.finishedAt,t.metadata);return;case "session_start":o.ensureSession(t),o.insertRun({id:Oe(t.id),source:"hook",tool:"session",input:{projectRoot:t.projectRoot},status:"active",startedAt:t.startedAt,tokenUsed:0,metadata:{sessionId:t.id,projectRoot:t.projectRoot}});return;case "complete_event":if(!o.updateToolCallEvent(t.eventId,{output:t.output===void 0?void 0:JSON.stringify(t.output),error:t.error,duration:t.duration}))throw new Error(`Tool call event ${t.eventId} is not available for completion`);return;case "session_end":o.closeSession(t.sessionId,t.finishedAt),o.updateRun(Oe(t.sessionId),{status:"completed",finishedAt:t.finishedAt});return}}ensureParentSession(e,t){let o=typeof t.sessionId=="string"?t.sessionId.trim():"";if(!o)throw new Error("Canonical session ID is required for telemetry");let r=typeof t.projectRoot=="string"&&t.projectRoot.trim()?t.projectRoot:typeof t.input?.projectRoot=="string"&&t.input.projectRoot.trim()?t.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";e.ensureSession({id:o,projectRoot:r,label:r==="unknown"?void 0:r.split("/").pop(),startedAt:Number(t.startedAt??t.timestamp??Date.now())});}cacheOperation(e,t,o){let r=Date.now(),i={id:`failure:${r}:${Math.random().toString(36).slice(2,11)}`,operation:e,payload:t,failure:o instanceof Error?o.message:String(o),timestamp:r};try{let s=this.getDatabase();s.insertTelemetryFailure({id:i.id,operation:e,payload:t,error:i.failure,createdAt:r}),s.trimTelemetryFailures(M),this.scheduleRetry();return}catch{}try{existsSync$1(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let s=join(this.cacheDir,`${r}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(s,JSON.stringify(i,null,2),{mode:384}),this.trimCompatibilityCache(),this.scheduleRetry();}catch{}}trimCompatibilityCache(){try{let e=readdirSync(this.cacheDir).filter(t=>t.endsWith(".json")).sort();for(let t of e.slice(0,Math.max(0,e.length-M)))unlinkSync(join(this.cacheDir,t));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},to).unref());}scheduleMetricAggregation(){if(this.metricAggregationScheduled||process.env.DEVFLOW_HOOK_DEGRADED==="1")return;this.metricAggregationScheduled=true,setTimeout(()=>{this.metricAggregationScheduled=false;try{this.getDatabase().aggregatePendingToolMetrics(50)===50&&this.scheduleMetricAggregation();}catch{}},25).unref();}postHttp(e,t){oo(`${this.apiUrl}${e}`,JSON.stringify(t),this.apiKey);}truncateInput(e){let t=JSON.stringify(e);return t===void 0||t.length<=Ce?e:{_truncated:true,_original_size:t.length,_preview:`${t.substring(0,Ce)}...`}}};function Pe(n){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(n)}function Oe(n){return `hook-run:${n}`}function no(n,e){if(!n||typeof n!="object")throw new Error("Invalid telemetry cache envelope");let t=n;if(typeof t.operation=="string"&&t.payload!==void 0)return t;let o=t.type==="tool_call"?"tool_call":t.type==="execution_start"?"execution_start":null;if(!o)throw new Error("Unknown legacy telemetry cache operation");let r=t.payload??{},i=Number(r.timestamp??r.startedAt??Date.now());return {id:`legacy-cache:${e}`,operation:o,payload:r,failure:"Replayed legacy HTTP-first telemetry cache entry",timestamp:i}}function C(n){return n??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function _(n){return process.env.DEVFLOW_STATE_DIR??getProjectStateDir(C(n))}var lo=2,uo=1;function po(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{return join(dirname(fileURLToPath(import.meta.url)),"..","..")}catch{return process.cwd()}}function Ae(n=po()){let e=[join(n,"dist","command-registry.json"),join(n,"command-registry.json")];for(let t of e)try{if(!existsSync$1(t))continue;let o=JSON.parse(readFileSync(t,"utf8"));if(o.version!==lo&&o.version!==uo||!mo(o.commands)){console.error(`[devflow] command registry contract mismatch: ${t}`);continue}return o.commands}catch(o){console.error(`[devflow] command registry load failed: ${o.message}`);}return null}function mo(n){return !n||typeof n!="object"||Array.isArray(n)?false:Object.values(n).every(e=>{if(!e||typeof e!="object"||Array.isArray(e))return false;let t=e;return V(t.mcpTools)&&V(t.blockedNative)&&(t.source===void 0||t.source==="core"||t.source==="plugin")&&(t.requiresContext===void 0||typeof t.requiresContext=="boolean")&&(t.runtimePackages===void 0||V(t.runtimePackages))&&(t.evidenceMode===void 0||["static","runtime","mixed"].includes(t.evidenceMode))})}function V(n){return Array.isArray(n)&&n.every(e=>typeof e=="string"&&e.length>0)}function je(n){let e=Ae();return e?e[n]?.mcpTools??[]:[]}var X=join(homedir(),".devflow"),Q=join(X,"server-refs.json"),vo="http://127.0.0.1:13337/api/health",wo=600*1e3,ko=500;function Ro(){existsSync$1(X)||mkdirSync(X,{recursive:true});}function P(){try{if(existsSync$1(Q))return JSON.parse(readFileSync(Q,"utf-8"))}catch{}return {sessions:[],lastActivity:0}}function Fe(n){Ro(),writeFileSync(Q,JSON.stringify(n));}var A=class{constructor(e){this.process=null;this.idleTimer=null;this.onShutdown=null;this.projectRoot=e;}setOnShutdown(e){this.onShutdown=e;}addRef(e){let t=P();t.sessions.includes(e)||t.sessions.push(e),t.lastActivity=Date.now(),Fe(t),this.resetIdleTimer();}removeRef(e){let t=P();t.sessions=t.sessions.filter(o=>o!==e),t.lastActivity=Date.now(),Fe(t),t.sessions.length===0&&this.resetIdleTimer();}get activeSessions(){return P().sessions.length}async ensureRunning(){return await this.healthCheck()?true:(await this.startServer(),this.waitForReady())}get isRunning(){return this.process!==null&&!this.process.killed}async stop(){this.idleTimer&&clearTimeout(this.idleTimer),this.process&&(this.process.kill("SIGTERM"),await new Promise(e=>{let t=setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL"),e();},5e3);this.process?this.process.on("exit",()=>{clearTimeout(t),e();}):(clearTimeout(t),e());}),this.process=null);}async startServer(){let e=join(this.projectRoot,"apps","server","dist","main.js"),t=join(this.projectRoot,"node_modules","@devflow-tools","server","dist","main.js"),o=existsSync$1(e)?e:t;this.process=spawn("node",[o],{cwd:this.projectRoot,env:{...process.env,NODE_ENV:process.env.NODE_ENV||"development"},stdio:["ignore","pipe","pipe"]}),this.process.stdout?.on("data",r=>{}),this.process.stderr?.on("data",r=>{}),this.process.on("exit",r=>{this.process=null,this.onShutdown&&this.onShutdown();}),this.process.on("error",()=>{this.process=null;});}async waitForReady(){let e=Date.now()+3e4;for(;Date.now()<e;){if(await this.healthCheck())return true;await new Promise(t=>setTimeout(t,ko));}return false}healthCheck(){return new Promise(e=>{let t=new URL(vo),o=request({hostname:t.hostname,port:t.port,path:t.pathname,method:"GET",timeout:2e3},r=>{e(r.statusCode===200);});o.on("error",()=>e(false)),o.on("timeout",()=>{o.destroy(),e(false);}),o.end();})}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),!(P().sessions.length>0)&&(this.idleTimer=setTimeout(()=>{this.stop();},wo).unref());}};function Ne(n,e,t){try{let o=openGlobalDevFlowDatabase();try{o.insertEvent({kind:n,timestamp:Date.now(),duration:t,success:e.success!==!1,metadata:e});}finally{o.close();}}catch{}}var oe=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",Co=getLocalApiKey(),Po=8,Oo=6e4,$e=new Map;function Ao(n){let e=new URL(n,oe).pathname,t=$e.get(e);return t||(t={failures:0,lastFailure:0,openUntil:0,status:"closed"},$e.set(e,t)),t}function ne(n,e,t){if(e.status===t)return;let o=e.status;e.status=t,Ne("http_circuit_transition",{path:new URL(n,oe).pathname,previous:o,status:t,failures:e.failures,openUntil:e.openUntil});}function ee(n,e){e.failures++,e.lastFailure=Date.now(),e.failures>=Po&&(e.openUntil=Date.now()+Oo,ne(n,e,"open"));}function jo(n,e){let t=e.status!=="closed";e.failures=0,e.openUntil=0,t&&ne(n,e,"closed");}var te=join(homedir(),".devflow","errors");function Le(n,e){try{existsSync$1(te)||mkdirSync(te,{recursive:!0});let t=`${new Date().toISOString()} | ${n} | ${e?.message??String(e)}
|
|
2
|
-
`;appendFileSync(join(te,"http-errors.log"),t);}catch{}}function He(n,e,t={}){let o=t.timeout??5e3,r=t.maxRetries??2,i=t.circuitBreaker??true,s=Ao(n);if(i&&s.openUntil>Date.now())return Promise.resolve();i&&s.status==="open"&&ne(n,s,"half_open");let a=c=>new Promise(l=>{let u=JSON.stringify(e),p=new URL(n,oe),m=request({hostname:p.hostname,port:p.port,path:p.pathname+p.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":Co,"Content-Length":Buffer.byteLength(u)},timeout:o},f=>{if(f.resume(),f.statusCode&&f.statusCode>=400){let d=new Error(`HTTP ${f.statusCode}`);if(Le(n,d),c>0){let y=Math.min(1e3*Math.pow(2,r-c),8e3);setTimeout(()=>{a(c-1).then(l);},y);}else ee(n,s),l();return}jo(n,s),l();});m.on("error",f=>{if(Le(n,f),c>0){let d=Math.min(1e3*Math.pow(2,r-c),8e3);setTimeout(()=>{a(c-1).then(l);},d);}else ee(n,s),l();}),m.on("timeout",()=>{m.destroy(),c>0?a(c-1).then(l):(ee(n,s),l());}),m.write(u),m.end();});return a(r)}function j(n){if(!n||typeof n!="object"||Array.isArray(n))return {};let e=n,t={};for(let o of ["lastMcpCall","bypassCount"])if(o in e){let r=e[o];if(r==null)continue;t[o]=typeof r=="number"&&Number.isFinite(r)&&r>=0?r:0;}return t}function $o(n,e){return n.lastMcpCall===e.lastMcpCall&&n.bypassCount===e.bypassCount}function Lo(n){try{return existsSync$1(n)?j(JSON.parse(readFileSync(n,"utf-8"))):{}}catch{return {}}}function Uo(n,e){let t=e instanceof Error?e.message:String(e);console.error(`[devflow] Receipt ${n} skipped: ${t}`);}function We(n){let e=_(n);for(let t of ["receipt.json","receipt-lock.sqlite","receipt-lock.sqlite-shm","receipt-lock.sqlite-wal"])try{existsSync$1(join(e,t))&&unlinkSync(join(e,t));}catch{}}function Ho(n,e){if(n.getHookReceipt(e)){We(e);return}let t=join(_(e),"receipt.json");if(!existsSync$1(t))return;let o=Lo(t);n.updateHookReceipt(e,()=>o),We(e);}function Je(n,e,t){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),Ho(o,n);let r={},i=o.updateHookReceipt(n,a=>(r=j(a),j(e(r)))),s=j(i);return {receipt:s,applied:!0,changed:!$o(r,s)}}catch(r){return Uo(t,r),{receipt:{},applied:false,changed:false}}finally{try{o?.close();}catch{}}}function F(n,e){return Je(n,()=>e,"write").applied}function se(n,e){return Je(n,e,"update")}var qe={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function Wo(n){switch(n){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}var E=class{constructor(e,t,o){this.projectRoot=e;this.sessionId=t;this.executionId=o;}getPhase(){if(!this.sessionId||!this.executionId)return "idle";let e;try{e=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let t=e.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(t&&t.expiresAt>Date.now())return "context_ready";t&&e.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{e?.close();}catch{}}return "context_gathering"}evaluate(e,t){let o=this.getPhase();if(t||e==="Skill")return {permissionDecision:"allow"};if(o==="context_gathering"&&qe[e])return {permissionDecision:"deny",reason:`DevFlow context required. Call mcp__devflow__get_project_context, then retry ${e}.`};if(o==="context_ready")return {permissionDecision:"allow"};let r=qe[e];if(!r)return {permissionDecision:"allow"};let i=se(this.projectRoot,c=>({...c,bypassCount:(c.bypassCount??0)+1}));if(!i.applied)return {permissionDecision:"allow"};let s=i.receipt.bypassCount??0,a=Wo(e);return s>=a?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${e}\uFF0C\u5EFA\u8BAE\u7528 mcp__devflow__${r} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){F(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}};var Ko=10,Vo=5e3,Yo=3e4,Xo=new Int32Array(new SharedArrayBuffer(4)),Xe=0;function Qo(n){if(typeof n!="object"||n===null)return false;let e=n;return typeof e.rootPath=="string"&&e.rootPath.length>0&&typeof e.projectHash=="string"&&e.projectHash.length>0&&typeof e.pid=="number"&&Number.isInteger(e.pid)&&e.pid>0&&typeof e.startedAt=="number"&&Number.isFinite(e.startedAt)&&e.startedAt>=0}function Qe(n){if(!existsSync(n))return {entries:[],needsRepair:false};try{let e=JSON.parse(readFileSync$1(n,"utf8"));if(!Array.isArray(e))return {entries:[],needsRepair:!0};let t=e.filter(Qo);return {entries:t,needsRepair:t.length!==e.length}}catch{return {entries:[],needsRepair:true}}}function Ze(n,e){mkdirSync$1(dirname$1(n),{recursive:true});let t=`${n}.${process.pid}.${Date.now()}.${Xe++}.tmp`,o;try{o=openSync$1(t,"wx"),writeFileSync$1(o,JSON.stringify(e,null,2)),closeSync$1(o),o=void 0,renameSync(t,n);}finally{try{o!==void 0&&closeSync$1(o);}finally{rmSync$1(t,{force:true});}}}function et(n){try{return process.kill(n,0),!0}catch(e){return e.code!=="ESRCH"}}function tt(n){if(typeof n!="object"||n===null)return false;let e=n;return typeof e.pid=="number"&&Number.isInteger(e.pid)&&e.pid>0&&typeof e.createdAt=="number"&&Number.isFinite(e.createdAt)&&typeof e.token=="string"&&e.token.length>0}function Ge(n,e){try{return readFileSync$1(n,"utf8")!==e?!1:(rmSync$1(n),!0)}catch(t){return t.code==="ENOENT"}}function Zo(n){try{let e=readFileSync$1(n,"utf8"),t;try{let r=JSON.parse(e);tt(r)&&(t=r);}catch{}return t?et(t.pid)?!1:Ge(n,e):Date.now()-statSync(n).mtimeMs>Yo&&Ge(n,e)}catch(e){return e.code==="ENOENT"}}function en(n){mkdirSync$1(dirname$1(n),{recursive:true});let e=`${n}.lock`,t=Date.now()+Vo;for(;;){let o=`${process.pid}:${Date.now()}:${Xe++}`,r;try{return r=openSync$1(e,"wx"),writeFileSync$1(r,JSON.stringify({pid:process.pid,createdAt:Date.now(),token:o})),closeSync$1(r),r=void 0,{path:e,token:o}}catch(i){if(r!==void 0)try{closeSync$1(r);}finally{rmSync$1(e,{force:true});}if(i.code!=="EEXIST")throw i}if(!Zo(e)){if(Date.now()>=t)throw new Error(`Timed out acquiring daemon registry lock: ${e}`);Atomics.wait(Xo,0,0,Ko);}}}function tn(n){try{let e=readFileSync$1(n.path,"utf8"),t=JSON.parse(e);tt(t)&&t.token===n.token&&rmSync$1(n.path);}catch(e){if(e.code!=="ENOENT")throw e}}function ot(n){let e=getDaemonRegistryPath(),t=en(e);try{return n(e)}finally{tn(t);}}function nt(n,e){ot(t=>{let o=Qe(t).entries.filter(r=>r.rootPath!==n&&et(r.pid));o.push({rootPath:n,projectHash:getProjectHash(n),pid:e,startedAt:Date.now()}),Ze(t,o);});}function rt(n,e){ot(t=>{let o=Qe(t).entries.filter(r=>r.rootPath!==n||e!==void 0&&r.pid!==e);Ze(t,o);});}async function x(n){let e=!n.memory,t=n.memory??new MemoryGate(n.projectRoot),o=0,r=0;try{await t.forceWarmUp(),n.trigger==="session_end"&&(o=await t.releasePendingDistillLeases(n.sessionId)),r=t.getPendingEventCount();}finally{e&&t.close();}let i={pendingEvents:r,releasedLeases:o,trigger:n.trigger,sessionId:n.sessionId};try{let s=openGlobalDevFlowDatabase();try{let a=Date.now(),c=`distill:${a}:${Math.random().toString(36).slice(2,10)}`;s.recordMemoryDistillCheckpoint({id:c,projectRoot:n.projectRoot,sessionId:n.sessionId,trigger:n.trigger,pendingEvents:r,releasedLeases:o,createdAt:a}),s.insertEvent({kind:"memory_distill_requested",timestamp:a,success:!0,metadata:{...i,projectRoot:n.projectRoot}});}finally{s.close();}}catch{}return i}function it(n){if(n.pendingEvents===0)return "";let e=n.sessionId?`\uFF0CsessionId=${n.sessionId}`:"";return `Memory distill checkpoint: ${n.pendingEvents} \u4E2A\u4E8B\u4EF6\u5F85\u63D0\u70BC${e}\u3002\u4E0A\u4E0B\u6587\u538B\u7F29\u5B8C\u6210\u540E\uFF0C\u8C03\u7528 mcp__devflow__memory_request_distill\uFF1B\u6309\u8FD4\u56DE\u7684 nextPage \u5206\u9875\u8BFB\u53D6\u5168\u90E8\u4E8B\u4EF6\uFF0C\u63D0\u70BC observations\uFF0C\u518D\u8C03\u7528 mcp__devflow__memory_save_distilled \u5E76\u786E\u8BA4\u4FDD\u5B58\u7ED3\u679C\u3002`}function pn(n){return Buffer.from(n,"utf8").toString("base64url")}var I=class{constructor(e){this.projectRoot=e;this.sessions=new Map;this.sessionsDir=join(_(e),"hook-sessions");}registerSession(e){let t=e.trim();if(!t)throw new Error("session_id_required");let o=this.get(t);if(o)return o.lastActivityAt=Date.now(),this.persist(o),o;let r=Date.now(),i={sessionId:t,projectRoot:this.projectRoot,requiredMcpTools:[],startedAt:r,lastActivityAt:r};return this.sessions.set(t,i),this.persist(i),i}startExecution(e,t,o){let r=this.registerSession(e);return (!r.executionId||r.skillName!==t)&&(r.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),r.skillName=t,r.requiredMcpTools=[...new Set(o)],r.lastActivityAt=Date.now(),this.persist(r),r}get(e){let t=e.trim();if(!t)return null;let o=this.sessions.get(t);if(o)return o;let r=this.snapshotPath(t);if(!existsSync$1(r))return null;try{let i=JSON.parse(readFileSync(r,"utf8"));return i.sessionId!==t||i.projectRoot!==this.projectRoot?null:(i.requiredMcpTools=Array.isArray(i.requiredMcpTools)?i.requiredMcpTools:[],this.sessions.set(t,i),i)}catch{return null}}completeExecution(e){let t=this.get(e);if(!t)return null;let o={...t,requiredMcpTools:[...t.requiredMcpTools]};return delete t.executionId,delete t.skillName,t.requiredMcpTools=[],t.lastActivityAt=Date.now(),this.persist(t),o}removeSession(e){let t=e.trim();t&&(this.sessions.delete(t),rmSync(this.snapshotPath(t),{force:true}));}list(){return [...this.sessions.values()]}snapshotPath(e){return join(this.sessionsDir,`${pn(e)}.json`)}persist(e){mkdirSync(this.sessionsDir,{recursive:true,mode:448});let t=this.snapshotPath(e.sessionId),o=`${t}.${process.pid}.tmp`;writeFileSync(o,JSON.stringify(e),{mode:384}),renameSync$1(o,t);}};function lt(n,e){let t=mt(n);mkdirSync$1(t,{recursive:true,mode:448});let o=join$1(t,`${e.receiptId}.json`);if(existsSync(o))return e.receiptId;let r=`${o}.${process.pid}.tmp`;writeFileSync$1(r,JSON.stringify(e),{mode:384});try{renameSync(r,o);}catch(i){try{unlinkSync$1(r);}catch{}if(!existsSync(o))throw i}return e.receiptId}function ut(n){let e=mt(n);mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join$1(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=JSON.parse(readFileSync$1(i,"utf8"));if(typeof s.receiptId!="string"||typeof s.inputJson!="string"||typeof s.sessionId!="string"||typeof s.cleanupSharedState!="boolean")throw unlinkSync$1(i),new Error("session_finalize_spool_payload_invalid");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),payload:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function dt(n){unlinkSync$1(n.path);}function pt(n){try{renameSync(n.path,n.path.replace(/\.claim-\d+$/u,""));}catch{}}function mt(n){return join$1(_(n),"session-finalize-pending")}var wn=process.env.DEVFLOW_SERVER_URL||"http://127.0.0.1:13337",kn=getLocalApiKey();function H(n,e=C(),t=true,o,r=true){let i;try{i=JSON.parse(n);}catch{return null}let s=i.session_id?.trim();if(!s)return null;let a=`session-close:${createHash("sha256").update(`${e}\0${s}`).digest("hex").slice(0,24)}`,c={inputJson:n,sessionId:s,cleanupSharedState:t,executionId:o},l;try{l=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});let u=l.requestSessionClosure({receiptId:a,projectRoot:e,sessionId:s,payload:c}),p=l.getWorkByIdempotencyKey(a);return {status:u.state==="closed"||u.state==="closed_with_pending_work"?"completed":"accepted",receiptId:a,workState:p?.state??"pending",closureState:u.state,pendingWorkCount:u.pendingWorkCount}}catch(u){if(!r)throw u;return lt(e,{receiptId:a,...c}),{status:"accepted",receiptId:a,workState:"spooled",closureState:"closing",pendingWorkCount:1}}finally{l?.close();}}function ht(n,e){return new Promise(t=>{let o=JSON.stringify(e),r=new URL(n,wn),i=request({hostname:r.hostname,port:r.port,path:r.pathname,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":kn,"Content-Length":Buffer.byteLength(o)},timeout:5e3},()=>t());i.on("error",()=>t()),i.write(o),i.end();})}async function gt(n,e=C(),t=true,o){let r;try{r=JSON.parse(n);}catch{return}let i=r.session_id?.trim();if(!i)return;let s=new I(e),a=s.get(i),c=o?.telemetry??new b,l=!o?.telemetry;try{try{await c.flushAndAggregate();}catch{}let u;try{u=openGlobalDevFlowDatabase();let p=a?.executionId;if(p){let d=Date.now(),y=u.listMemoryTurns(e,i,100);try{u.reconcileSkillExecution(p,"completed",d,{memoryReceiptIds:y.flatMap(g=>g.receiptId?[g.receiptId]:[]),missingMemoryDecisionCount:y.filter(g=>g.status==="pending").length});let h=u.getSkillExecution(p);await ht("/api/telemetry/skill-execution/complete",{executionId:p,finishedAt:d,status:"completed",summary:{totalToolCalls:h?.totalToolCalls??0,mcpToolCalls:h?.mcpToolCalls??0,directToolCalls:h?.directToolCalls??0,subagentCount:h?.subagentCount??0,totalDuration:h?.totalDuration??0,mcpComplianceRate:h?.mcpComplianceRate??0,missedTools:h?.missedMcpTools??[],actualFailureCount:h?.failedToolCalls??0,fallbackCount:h?.fallbackCount??0,fallbackReasons:h?.fallbackReasons??[]}});}catch{}}let m=u.listMemoryTurns(e,i,100),f=u.reconcileRunningSkillExecutionsForSession(i,Date.now(),{memoryReceiptIds:m.flatMap(d=>d.receiptId?[d.receiptId]:[]),missingMemoryDecisionCount:m.filter(d=>d.status==="pending").length,closureReason:"session_finalize"});for(let d of f)await ht("/api/telemetry/skill-execution/complete",{executionId:d.executionId,finishedAt:d.finishedAt,status:d.status,summary:{totalToolCalls:d.totalToolCalls??0,mcpToolCalls:d.mcpToolCalls??0,directToolCalls:d.directToolCalls??0,subagentCount:d.subagentCount??0,totalDuration:d.totalDuration??0,mcpComplianceRate:d.mcpComplianceRate??0,missedTools:d.missedMcpTools??[],actualFailureCount:d.failedToolCalls??0,fallbackCount:d.fallbackCount??0,fallbackReasons:d.fallbackReasons??[]}});if(t){u.deleteHookReceipt(e);let d=_(e),y=createHash("sha256").update(e).digest("hex").slice(0,12);for(let h of [`session-id-${y}`,"current-execution-id","current-skill.json","event-map.json"])rmSync$1(join$1(d,h),{force:!0});}u.deleteContextReceipt(e,i);}catch{}finally{u?.close();}try{if(await x({projectRoot:e,sessionId:i,trigger:"session_end",memory:o?.memory}),o?.memory)await o.memory.closeSession(i);else {let p=new(await import('@devflow-tools/memory-engine')).MemoryGate(e);try{await p.closeSession(i);}finally{p.close();}}}catch{}try{await c.endSession(i),await c.flushAndAggregate();}catch{}}finally{l&&c.close(),s.removeSession(i);}}if(process.argv[1]?.endsWith("session-end")||process.argv[1]?.endsWith("session-end.js")){let n=console.log.bind(console);console.log=console.error.bind(console),console.info=console.error.bind(console);let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{e+=t;}),process.stdin.on("end",async()=>{let t=H(e.trim()||process.argv[2]||"");t&&n(JSON.stringify(t)),process.exit(0);}),process.stdin.on("error",()=>process.exit(0)),setTimeout(()=>process.exit(0),1e4).unref();}var Dn=/^\/(?:devflow:)?[\w-]+\b\s*/iu,Mn=/\b(?:(?:do\s+not|don't|dont|never|not)(?:\s+need\s+to)?|no\s+need\s+to)\s+(?:please\s+)?(?:remember|memorize)\b|(?:不要|别|不用|无需|不必|不需要)(?:再)?(?:记住|记|记忆)/iu,Cn=/(?:^|[.!?]\s*)(?:(?:please|kindly)\s+)?(?:remember|memorize|save\s+this|store\s+this|note\s+that)(?:\s+(?:that|to))?[\s:,-]*(.+)$/iu,Pn=/(?:^|[。!?;,,]\s*)(?:(?:请|麻烦|务必|一定要|帮我|帮忙|需要)\s*)?(?:记住|记一下|记下来|记|记录一下|记录下来|保存一下|保存下来)(?:这(?:件事|一点|个信息|些内容))?[\s::,,]*(.+)$/iu;function W(n){let e=n.trim().replace(Dn,"").trim();return !e||Mn.test(e)?null:(Pn.exec(e)??Cn.exec(e))?.[1]?.trim().replace(/^[::,,\s]+/u,"")||null}function On(n){let e=createHash("sha256").update(n).digest("hex").slice(0,16),t=process.env.DEVFLOW_STATE_DIR||join$1(homedir$1(),".devflow","state",e);return join$1(t,"memory-intents.jsonl")}function An(n){try{return readFileSync$1(n,"utf8").split(`
|
|
3
|
-
|
|
1
|
+
import {createServer,createConnection}from'net';import {createHash,randomUUID as randomUUID$1}from'node:crypto';import {join as join$1,dirname}from'path';import {mkdirSync,lstatSync,openSync,writeFileSync,fstatSync,closeSync,readFileSync,unlinkSync,existsSync as existsSync$1,readdirSync,rmSync,linkSync,renameSync as renameSync$1}from'fs';import {getLocalApiKey,getDaemonSocketPath,getDaemonPidPath,formatSkillRuntimeOverlay,createSkillRuntimeOverlay,loadConfig,readRuntimeEndpointState,updateRuntimeEndpointStatus,resolveRuntimeEndpoint,writeRuntimeEndpointState,selectHostAdapter,getProjectStateDir,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getDaemonRegistryPath,getProjectHash}from'@devflow-tools/sdk';import {homedir as homedir$1}from'os';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {request as request$1}from'node:http';import {mkdirSync as mkdirSync$1,existsSync,writeFileSync as writeFileSync$1,renameSync,unlinkSync as unlinkSync$1,readFileSync as readFileSync$1,openSync as openSync$1,constants,fstatSync as fstatSync$1,closeSync as closeSync$1,readdirSync as readdirSync$1,rmSync as rmSync$1,appendFileSync,lstatSync as lstatSync$1,readSync,statSync,chmodSync,fsyncSync}from'node:fs';import {join,basename,resolve,relative,sep,dirname as dirname$1,isAbsolute}from'node:path';import {homedir}from'node:os';import {fileURLToPath}from'url';import {spawn}from'child_process';import {request}from'http';import {createRequire}from'node:module';import {prepareEmbeddingModel,MemoryGate}from'@devflow-tools/memory-engine';import {randomUUID,createHash as createHash$1}from'crypto';function Ie(n,e,t){try{let o=openGlobalDevFlowDatabase();try{o.insertEvent({kind:n,timestamp:Date.now(),duration:t,success:e.success!==!1,metadata:e});}finally{o.close();}}catch{}}var To=getLocalApiKey(),Ee=join(homedir(),".devflow","errors");async function M(n,e,t={}){let o=t.endpoint??resolveRuntimeEndpoint().url,r=t.timeout??1500,i=t.durableMirror??true,s=t.maxRetries??(i?0:2),a=t.circuitBreaker??true,c=acquireRuntimeHttpCircuit(o,n);if(a&&!c.allowed)return {delivered:false,suppressed:true,fallbackReason:c.state.fallbackReason};let l;for(let d=0;d<=s;d+=1)try{return await Mo(o,n,e,r),a&®isterRuntimeHttpSuccess(o,n).transitioned&&Ie("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:c.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(p){l=p instanceof Error?p:new Error(String(p)),d<s&&await Do(Math.min(100*2**d,1e3));}if(!l)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return wt(n,l),{delivered:false,suppressed:false,fallbackReason:l.message};let u=registerRuntimeHttpFailure(o,n,t.fallbackReason??(i?"local_durable_mirror":"http_delivery_failed"));return u.transitioned&&(wt(n,l),Ie("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:c.state.status,status:"open",failures:u.state.failures,openUntil:u.state.openUntil,fallbackReason:u.state.fallbackReason})),{delivered:false,suppressed:false,fallbackReason:u.state.fallbackReason}}function Mo(n,e,t,o){return new Promise((r,i)=>{let s=JSON.stringify(t),a=new URL(e,n),c=false,l=d=>{c||(c=true,d?i(d):r());},u=request$1({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":To,"Content-Length":Buffer.byteLength(s)},timeout:o},d=>{d.on("error",l),d.on("end",()=>{let p=d.statusCode??0;l(p>=200&&p<300?void 0:new Error(`HTTP ${p}`));}),d.resume();});u.on("error",l),u.on("timeout",()=>u.destroy(new Error(`HTTP mirror timed out after ${o}ms`))),u.write(s),u.end();})}function wt(n,e){try{existsSync(Ee)||mkdirSync$1(Ee,{recursive:!0}),appendFileSync(join(Ee,"http-errors.log"),`${new Date().toISOString()} | ${n} | ${e.message}
|
|
2
|
+
`);}catch{}}function Do(n){return new Promise(e=>setTimeout(e,n))}var Tt=1e4,jo=3e4,Z=500,O=class{constructor(e){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=e?.apiUrl,this.cacheDir=e?.cacheDir??join$1(process.env.DEVFLOW_STATE_DIR??join$1(homedir$1(),".devflow","global"),"telemetry-cache"),this.legacyCacheDir=e?.legacyCacheDir??(e?.cacheDir?null:join$1(homedir$1(),".devflow","telemetry-cache")),this.database=e?.database??null,this.ownsDatabase=!e?.database;let t=e?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(t)&&t>=0?t:100;}async sendEvent(e){let t={...e,input:this.truncateInput(e.input)};return this.commitOrCache("tool_call",t)?(this.postHttp("/api/telemetry/tool-call",t),e.eventId):null}async sendExecutionStart(e,t,o,r,i=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:e,sessionId:t,skillName:o,startedAt:r,projectRoot:i,requiredMcpTools:s};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(e,t="completed",o=Date.now(),r){let i={executionId:e,status:t,finishedAt:o,metadata:r},s=this.commitOrCache("execution_complete",i);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",i),s}async sendSessionStart(e,t,o){let r={id:e,projectRoot:t,startedAt:o,label:t.split("/").pop()??"unknown"},i=this.commitOrCache("session_start",r);return i&&this.postHttp("/api/telemetry/sessions",r),i}async completeEvent(e){let t=this.commitOrCache("complete_event",e);return t&&(this.postHttp("/api/telemetry/tool-call/output",e),this.scheduleMetricAggregation()),t}async endSession(e,t=Date.now()){let o={sessionId:e,finishedAt:t},r=this.commitOrCache("session_end",o);return r&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(e)}/close`,{finishedAt:t})),r}async flushCache(){try{let o=this.getDatabase(),r=o.listTelemetryFailures({unresolvedOnly:!0,limit:Z}).reverse();for(let i of r)try{this.applyOperation(i.operation,i.payload),o.resolveTelemetryFailure(i.id);}catch{}o.trimTelemetryFailures(Z);}catch{}let t=[...new Set([this.cacheDir,this.legacyCacheDir].filter(o=>!!o))].filter(o=>existsSync$1(o)).flatMap(o=>readdirSync(o).filter(r=>r.endsWith(".json")).map(r=>{let i=join$1(o,r);try{return {cacheFile:i,envelope:Fo(JSON.parse(readFileSync(i,"utf8")),r)}}catch{return null}})).filter(o=>o!==null).sort((o,r)=>o.envelope.timestamp-r.envelope.timestamp||Mt(o.envelope.operation)-Mt(r.envelope.operation));for(let{cacheFile:o,envelope:r}of t)try{let i=this.getDatabase();i.insertTelemetryFailure({id:r.id,operation:r.operation,payload:r.payload,error:r.failure,createdAt:r.timestamp}),this.applyOperation(r.operation,r.payload),i.resolveTelemetryFailure(r.id),unlinkSync(o);}catch{}this.database?.aggregatePendingToolMetrics();}aggregateMetrics(){return this.getDatabase().aggregatePendingToolMetrics()}async flushAndAggregate(){await this.flushCache(),this.aggregateMetrics();}close(){this.ownsDatabase&&this.database?.close(),this.database=null;}getDatabase(){return this.database??=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:this.busyTimeoutMs}),this.database}commitOrCache(e,t){try{return this.applyOperation(e,t),!0}catch(o){return this.cacheOperation(e,t,o),false}}applyOperation(e,t){let o=this.getDatabase();switch(e){case "tool_call":this.ensureParentSession(o,t),o.insertToolCallEvent(t);return;case "execution_start":this.ensureParentSession(o,t),o.insertSkillExecution({executionId:t.executionId,sessionId:t.sessionId,skillName:t.skillName,startedAt:t.startedAt,status:"running",requiredMcpTools:t.requiredMcpTools});return;case "execution_complete":o.reconcileSkillExecution(t.executionId,t.status,t.finishedAt,t.metadata);return;case "session_start":o.ensureSession(t),o.insertRun({id:Dt(t.id),source:"hook",tool:"session",input:{projectRoot:t.projectRoot},status:"active",startedAt:t.startedAt,tokenUsed:0,metadata:{sessionId:t.id,projectRoot:t.projectRoot}});return;case "complete_event":if(!o.updateToolCallEvent(t.eventId,{output:t.output===void 0?void 0:JSON.stringify(t.output),error:t.error,failureCategory:t.failureCategory,duration:t.duration}))throw new Error(`Tool call event ${t.eventId} is not available for completion`);return;case "session_end":o.closeSession(t.sessionId,t.finishedAt),o.updateRun(Dt(t.sessionId),{status:"completed",finishedAt:t.finishedAt});return}}ensureParentSession(e,t){let o=typeof t.sessionId=="string"?t.sessionId.trim():"";if(!o)throw new Error("Canonical session ID is required for telemetry");let r=typeof t.projectRoot=="string"&&t.projectRoot.trim()?t.projectRoot:typeof t.input?.projectRoot=="string"&&t.input.projectRoot.trim()?t.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";e.ensureSession({id:o,projectRoot:r,label:r==="unknown"?void 0:r.split("/").pop(),startedAt:Number(t.startedAt??t.timestamp??Date.now())});}cacheOperation(e,t,o){let r=Date.now(),i={id:`failure:${r}:${Math.random().toString(36).slice(2,11)}`,operation:e,payload:t,failure:o instanceof Error?o.message:String(o),timestamp:r};try{let s=this.getDatabase();s.insertTelemetryFailure({id:i.id,operation:e,payload:t,error:i.failure,createdAt:r}),s.trimTelemetryFailures(Z),this.scheduleRetry();return}catch{}try{existsSync$1(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let s=join$1(this.cacheDir,`${r}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(s,JSON.stringify(i,null,2),{mode:384}),this.trimCompatibilityCache(),this.scheduleRetry();}catch{}}trimCompatibilityCache(){try{let e=readdirSync(this.cacheDir).filter(t=>t.endsWith(".json")).sort();for(let t of e.slice(0,Math.max(0,e.length-Z)))unlinkSync(join$1(this.cacheDir,t));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},jo).unref());}scheduleMetricAggregation(){if(this.metricAggregationScheduled||process.env.DEVFLOW_HOOK_DEGRADED==="1")return;this.metricAggregationScheduled=true,setTimeout(()=>{this.metricAggregationScheduled=false;try{this.getDatabase().aggregatePendingToolMetrics(50)===50&&this.scheduleMetricAggregation();}catch{}},25).unref();}postHttp(e,t){M(e,t,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(e){let t=JSON.stringify(e);return t===void 0||t.length<=Tt?e:{_truncated:true,_original_size:t.length,_preview:`${t.substring(0,Tt)}...`}}};function Mt(n){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(n)}function Dt(n){return `hook-run:${n}`}function Fo(n,e){if(!n||typeof n!="object")throw new Error("Invalid telemetry cache envelope");let t=n;if(typeof t.operation=="string"&&t.payload!==void 0)return t;let o=t.type==="tool_call"?"tool_call":t.type==="execution_start"?"execution_start":null;if(!o)throw new Error("Unknown legacy telemetry cache operation");let r=t.payload??{},i=Number(r.timestamp??r.startedAt??Date.now());return {id:`legacy-cache:${e}`,operation:o,payload:r,failure:"Replayed legacy HTTP-first telemetry cache entry",timestamp:i}}function ee(n){return n??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function E(n){return process.env.DEVFLOW_STATE_DIR??getProjectStateDir(ee(n))}var Wo=2,zo=1;function qo(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{return join$1(dirname(fileURLToPath(import.meta.url)),"..","..")}catch{return process.cwd()}}function Ct(n=qo()){let e=[join$1(n,"dist","command-registry.json"),join$1(n,"command-registry.json")];for(let t of e)try{if(!existsSync$1(t))continue;let o=JSON.parse(readFileSync(t,"utf8"));if(o.version!==Wo&&o.version!==zo||!Jo(o.commands)){console.error(`[devflow] command registry contract mismatch: ${t}`);continue}return o.commands}catch(o){console.error(`[devflow] command registry load failed: ${o.message}`);}return null}function Jo(n){return !n||typeof n!="object"||Array.isArray(n)?false:Object.values(n).every(e=>{if(!e||typeof e!="object"||Array.isArray(e))return false;let t=e;return xe(t.mcpTools)&&xe(t.blockedNative)&&(t.source===void 0||t.source==="core"||t.source==="plugin")&&(t.requiresContext===void 0||typeof t.requiresContext=="boolean")&&(t.runtimePackages===void 0||xe(t.runtimePackages))&&(t.evidenceMode===void 0||["static","runtime","mixed"].includes(t.evidenceMode))})}function xe(n){return Array.isArray(n)&&n.every(e=>typeof e=="string"&&e.length>0)}function Ot(n){let e=Ct();return e?e[n]?.mcpTools??[]:[]}var Me=join$1(homedir$1(),".devflow"),De=join$1(Me,"server-refs.json"),er=600*1e3,tr=500;function nr(){existsSync$1(Me)||mkdirSync(Me,{recursive:true});}function te(){try{if(existsSync$1(De))return JSON.parse(readFileSync(De,"utf-8"))}catch{}return {sessions:[],lastActivity:0}}function At(n){nr(),writeFileSync(De,JSON.stringify(n));}var oe=class{constructor(e){this.process=null;this.idleTimer=null;this.onShutdown=null;this.ownerToken=null;this.projectRoot=e;}setOnShutdown(e){this.onShutdown=e;}addRef(e){let t=te();t.sessions.includes(e)||t.sessions.push(e),t.lastActivity=Date.now(),At(t),this.resetIdleTimer();}removeRef(e){let t=te();t.sessions=t.sessions.filter(o=>o!==e),t.lastActivity=Date.now(),At(t),t.sessions.length===0&&this.resetIdleTimer();}get activeSessions(){return te().sessions.length}async ensureRunning(){return await this.healthCheck()?true:(await this.startServer(),this.waitForReady())}get isRunning(){return this.process!==null&&!this.process.killed}async stop(){if(this.idleTimer&&clearTimeout(this.idleTimer),this.process){this.process.kill("SIGTERM"),await new Promise(t=>{let o=setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL"),t();},5e3);this.process?this.process.on("exit",()=>{clearTimeout(o),t();}):(clearTimeout(o),t());}),this.process=null;let e=readRuntimeEndpointState();e&&e.ownerToken===this.ownerToken&&updateRuntimeEndpointStatus("stopped");}}async startServer(){let e=or(this.projectRoot);this.ownerToken=randomUUID$1();let t=resolveRuntimeEndpoint();this.process=spawn(process.execPath,[e,"--devflow-instance-token",this.ownerToken],{cwd:this.projectRoot,env:{...process.env,NODE_ENV:process.env.NODE_ENV||"development"},stdio:["ignore","pipe","pipe"]}),writeRuntimeEndpointState({url:t.url,port:t.port,pid:this.process.pid??0,ownerToken:this.ownerToken,status:"launching"}),this.process.stdout?.on("data",o=>{}),this.process.stderr?.on("data",o=>{}),this.process.on("exit",o=>{let r=readRuntimeEndpointState();r&&r.ownerToken===this.ownerToken&&updateRuntimeEndpointStatus("stopped"),this.process=null,this.onShutdown&&this.onShutdown();}),this.process.on("error",()=>{let o=readRuntimeEndpointState();o&&o.ownerToken===this.ownerToken&&updateRuntimeEndpointStatus("degraded"),this.process=null;});}async waitForReady(){let e=Date.now()+3e4;for(;Date.now()<e;){if(await this.healthCheck())return true;await new Promise(t=>setTimeout(t,tr));}return false}healthCheck(){return new Promise(e=>{let t=resolveRuntimeEndpoint(),o=new URL("/api/health",t.url),r=request({hostname:o.hostname,port:o.port,path:o.pathname,method:"GET",timeout:2e3},i=>{let s=i.statusCode===200;s&&readRuntimeEndpointState()&&updateRuntimeEndpointStatus("healthy"),i.resume(),e(s);});r.on("error",()=>e(false)),r.on("timeout",()=>{r.destroy(),e(false);}),r.end();})}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),!(te().sessions.length>0)&&(this.idleTimer=setTimeout(()=>{this.stop();},er).unref());}};function or(n){let e=createRequire(import.meta.url),t=[()=>e.resolve("@devflow-tools/server/dist/main.js"),()=>join$1(n,"node_modules","@devflow-tools","server","dist","main.js"),()=>join$1(n,"apps","server","dist","main.js")];for(let o of t)try{let r=o();if(existsSync$1(r))return r}catch{}throw new Error("DevFlow server entry point is not installed or built")}function re(n){if(!n||typeof n!="object"||Array.isArray(n))return {};let e=n,t={};for(let o of ["lastMcpCall","bypassCount"])if(o in e){let r=e[o];if(r==null)continue;t[o]=typeof r=="number"&&Number.isFinite(r)&&r>=0?r:0;}return t}function sr(n,e){return n.lastMcpCall===e.lastMcpCall&&n.bypassCount===e.bypassCount}function ar(n){try{return existsSync$1(n)?re(JSON.parse(readFileSync(n,"utf-8"))):{}}catch{return {}}}function cr(n,e){let t=e instanceof Error?e.message:String(e);console.error(`[devflow] Receipt ${n} skipped: ${t}`);}function Pt(n){let e=E(n);for(let t of ["receipt.json","receipt-lock.sqlite","receipt-lock.sqlite-shm","receipt-lock.sqlite-wal"])try{existsSync$1(join$1(e,t))&&unlinkSync(join$1(e,t));}catch{}}function lr(n,e){if(n.getHookReceipt(e)){Pt(e);return}let t=join$1(E(e),"receipt.json");if(!existsSync$1(t))return;let o=ar(t);n.updateHookReceipt(e,()=>o),Pt(e);}function $t(n,e,t){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),lr(o,n);let r={},i=o.updateHookReceipt(n,a=>(r=re(a),re(e(r)))),s=re(i);return {receipt:s,applied:!0,changed:!sr(r,s)}}catch(r){return cr(t,r),{receipt:{},applied:false,changed:false}}finally{try{o?.close();}catch{}}}function ie(n,e){return $t(n,()=>e,"write").applied}function Pe(n,e){return $t(n,e,"update")}var jt={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function dr(n){switch(n){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}var q=class{constructor(e,t,o){this.projectRoot=e;this.sessionId=t;this.executionId=o;}getPhase(){if(!this.sessionId||!this.executionId)return "idle";let e;try{e=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let t=e.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(t&&t.expiresAt>Date.now())return "context_ready";t&&e.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{e?.close();}catch{}}return "context_gathering"}evaluate(e,t){let o=this.getPhase();if(t||e==="Skill")return {permissionDecision:"allow"};if(o==="context_gathering"&&jt[e])return {permissionDecision:"deny",reason:`DevFlow context required. Call mcp__devflow__get_project_context, then retry ${e}.`};if(o==="context_ready")return {permissionDecision:"allow"};let r=jt[e];if(!r)return {permissionDecision:"allow"};let i=Pe(this.projectRoot,c=>({...c,bypassCount:(c.bypassCount??0)+1}));if(!i.applied)return {permissionDecision:"allow"};let s=i.receipt.bypassCount??0,a=dr(e);return s>=a?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${e}\uFF0C\u5EFA\u8BAE\u7528 mcp__devflow__${r} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){ie(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}};var gr=10,yr=5e3,vr=3e4,br=new Int32Array(new SharedArrayBuffer(4)),zt=0;function Sr(n){if(typeof n!="object"||n===null)return false;let e=n;return typeof e.rootPath=="string"&&e.rootPath.length>0&&typeof e.projectHash=="string"&&e.projectHash.length>0&&typeof e.pid=="number"&&Number.isInteger(e.pid)&&e.pid>0&&typeof e.startedAt=="number"&&Number.isFinite(e.startedAt)&&e.startedAt>=0}function qt(n){if(!existsSync(n))return {entries:[],needsRepair:false};try{let e=JSON.parse(readFileSync$1(n,"utf8"));if(!Array.isArray(e))return {entries:[],needsRepair:!0};let t=e.filter(Sr);return {entries:t,needsRepair:t.length!==e.length}}catch{return {entries:[],needsRepair:true}}}function Jt(n,e){mkdirSync$1(dirname$1(n),{recursive:true});let t=`${n}.${process.pid}.${Date.now()}.${zt++}.tmp`,o;try{o=openSync$1(t,"wx"),writeFileSync$1(o,JSON.stringify(e,null,2)),closeSync$1(o),o=void 0,renameSync(t,n);}finally{try{o!==void 0&&closeSync$1(o);}finally{rmSync$1(t,{force:true});}}}function Bt(n){try{return process.kill(n,0),!0}catch(e){return e.code!=="ESRCH"}}function Gt(n){if(typeof n!="object"||n===null)return false;let e=n;return typeof e.pid=="number"&&Number.isInteger(e.pid)&&e.pid>0&&typeof e.createdAt=="number"&&Number.isFinite(e.createdAt)&&typeof e.token=="string"&&e.token.length>0}function Nt(n,e){try{return readFileSync$1(n,"utf8")!==e?!1:(rmSync$1(n),!0)}catch(t){return t.code==="ENOENT"}}function _r(n){try{let e=readFileSync$1(n,"utf8"),t;try{let r=JSON.parse(e);Gt(r)&&(t=r);}catch{}return t?Bt(t.pid)?!1:Nt(n,e):Date.now()-statSync(n).mtimeMs>vr&&Nt(n,e)}catch(e){return e.code==="ENOENT"}}function wr(n){mkdirSync$1(dirname$1(n),{recursive:true});let e=`${n}.lock`,t=Date.now()+yr;for(;;){let o=`${process.pid}:${Date.now()}:${zt++}`,r;try{return r=openSync$1(e,"wx"),writeFileSync$1(r,JSON.stringify({pid:process.pid,createdAt:Date.now(),token:o})),closeSync$1(r),r=void 0,{path:e,token:o}}catch(i){if(r!==void 0)try{closeSync$1(r);}finally{rmSync$1(e,{force:true});}if(i.code!=="EEXIST")throw i}if(!_r(e)){if(Date.now()>=t)throw new Error(`Timed out acquiring daemon registry lock: ${e}`);Atomics.wait(br,0,0,gr);}}}function kr(n){try{let e=readFileSync$1(n.path,"utf8"),t=JSON.parse(e);Gt(t)&&t.token===n.token&&rmSync$1(n.path);}catch(e){if(e.code!=="ENOENT")throw e}}function Vt(n){let e=getDaemonRegistryPath(),t=wr(e);try{return n(e)}finally{kr(t);}}function Kt(n,e){Vt(t=>{let o=qt(t).entries.filter(r=>r.rootPath!==n&&Bt(r.pid));o.push({rootPath:n,projectHash:getProjectHash(n),pid:e,startedAt:Date.now()}),Jt(t,o);});}function Yt(n,e){Vt(t=>{let o=qt(t).entries.filter(r=>r.rootPath!==n||e!==void 0&&r.pid!==e);Jt(t,o);});}async function J(n){let e=!n.memory,t=n.memory??new MemoryGate(n.projectRoot),o=0,r=0;try{await t.forceWarmUp(),n.trigger==="session_end"&&(o=await t.releasePendingDistillLeases(n.sessionId)),r=t.getPendingEventCount(n.sessionId,n.trigger!=="session_end");}finally{e&&t.close();}let i={pendingEvents:r,releasedLeases:o,trigger:n.trigger,sessionId:n.sessionId,details:n.details};try{let s=openGlobalDevFlowDatabase();try{let a=Date.now(),c=n.trigger==="session_end"&&n.sessionId?`distill:session_end:${createHash("sha256").update(`${n.projectRoot}\0${n.sessionId}`).digest("hex").slice(0,24)}`:`distill:${a}:${Math.random().toString(36).slice(2,10)}`;s.recordMemoryDistillCheckpoint({id:c,projectRoot:n.projectRoot,sessionId:n.sessionId,trigger:n.trigger,pendingEvents:r,releasedLeases:o,details:n.details,createdAt:a}),s.insertEvent({kind:"memory_distill_requested",timestamp:a,success:!0,metadata:{...i,projectRoot:n.projectRoot}});}finally{s.close();}}catch(s){if(n.strictPersistence)throw s}return i}function Xt(n){if(n.pendingEvents===0)return "";let e=n.sessionId?`\uFF0CsessionId=${n.sessionId}`:"";return `Memory distill checkpoint: ${n.pendingEvents} \u4E2A\u4E8B\u4EF6\u5F85\u63D0\u70BC${e}\u3002\u4E0A\u4E0B\u6587\u538B\u7F29\u5B8C\u6210\u540E\uFF0C\u8C03\u7528 mcp__devflow__memory_request_distill\uFF1B\u6309\u8FD4\u56DE\u7684 nextPage \u5206\u9875\u8BFB\u53D6\u5168\u90E8\u4E8B\u4EF6\uFF0C\u63D0\u70BC observations\uFF0C\u518D\u8C03\u7528 mcp__devflow__memory_save_distilled \u5E76\u786E\u8BA4\u4FDD\u5B58\u7ED3\u679C\u3002`}function tn(n){return Buffer.from(n,"utf8").toString("base64url")}function Dr(n,e,t){let o=e?.trim();if(o){let r=/^[a-zA-Z0-9:._-]{1,192}$/.test(o)?o:`tool-${createHash$1("sha256").update(o.slice(0,1024)).digest("hex").slice(0,32)}`;return `${n}:${r}`}return `${n}:legacy-${t}-${randomUUID().slice(0,8)}`}function cn(n){return `${n}:legacy-journal`}var T=class{constructor(e){this.projectRoot=e;this.sessions=new Map;this.sessionsDir=join$1(E(e),"hook-sessions");}registerSession(e){let t=e.trim();if(!t)throw new Error("session_id_required");let o=this.get(t);if(o)return o.lastActivityAt=Date.now(),this.persist(o),o;let r=Date.now(),i={sessionId:t,projectRoot:this.projectRoot,requiredMcpTools:[],evidenceObligations:[],evidenceDegradations:[],evidenceOutcomes:[],startedAt:r,lastActivityAt:r};return this.sessions.set(t,i),this.persist(i),i}startExecution(e,t,o){let r=this.registerSession(e);return (!r.executionId||r.skillName!==t)&&(r.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),r.skillName=t,r.requiredMcpTools=[...new Set(o)],r.lastActivityAt=Date.now(),this.persist(r),r}get(e){let t=e.trim();if(!t)return null;let o=this.sessions.get(t);if(o)return this.replayEvidenceJournal(o),o;let r=this.snapshotPath(t);if(!existsSync$1(r))return null;try{let i=JSON.parse(readFileSync(r,"utf8"));return i.sessionId!==t||i.projectRoot!==this.projectRoot?null:(i.requiredMcpTools=Array.isArray(i.requiredMcpTools)?i.requiredMcpTools:[],i.evidenceObligations=nn(i.evidenceObligations),i.evidenceDegradations=on(i.evidenceDegradations),i.evidenceOutcomes=rn(i.evidenceOutcomes),this.replayEvidenceJournal(i),this.sessions.set(t,i),i)}catch{return null}}completeExecution(e){let t=this.get(e);if(!t)return null;let o=structuredClone(t);return delete t.executionId,delete t.skillName,t.requiredMcpTools=[],t.lastActivityAt=Date.now(),this.persist(t),o}addEvidenceObligation(e,t,o=Date.now(),r){let i=this.registerSession(e),a=(r?void 0:i.evidenceObligations.find(l=>l.contractId===t.id))?.obligationId??Dr(t.id,r,o);this.appendEvidenceEvent(e,{kind:"add",obligationId:a,contractId:t.id,at:o,contract:t},`add\0${a}`),this.replayEvidenceJournal(i);let c=i.evidenceObligations.find(l=>l.obligationId===a);return c?(i.lastActivityAt=Date.now(),this.persist(i),structuredClone(c)):null}listEvidenceObligations(e){return (this.get(e)?.evidenceObligations??[]).map(t=>structuredClone(t))}markEvidenceCorrection(e,t,o,r,i=Date.now()){let s=this.get(e),a=s?.evidenceObligations.find(u=>u.obligationId===t);if(!s||!a)return null;let c=/^[a-f0-9]{64}$/.test(r)?r:"";if(!c)return null;this.appendEvidenceEvent(e,{kind:"correction",obligationId:t,contractId:a.contractId,at:i,fingerprint:c,violations:o.slice(0,16).map(u=>u.slice(0,240))},`correction\0${t}\0${c}`),this.replayEvidenceJournal(s),s.lastActivityAt=i,this.persist(s);let l=s.evidenceObligations.find(u=>u.obligationId===t);return l?structuredClone(l):null}resolveEvidenceObligation(e,t){let o=this.get(e);if(!o)return false;let r=o.evidenceObligations.find(s=>s.obligationId===t);if(!r)return false;let i=Date.now();return this.appendEvidenceEvent(e,{kind:"resolve",obligationId:t,contractId:r.contractId,at:i},`resolve\0${t}`),this.replayEvidenceJournal(o),o.lastActivityAt=i,this.persist(o),true}degradeEvidenceObligation(e,t,o,r=Date.now()){let i=this.get(e),s=i?.evidenceObligations.find(c=>c.obligationId===t);if(!i||!s)return false;let a=o.slice(0,240);return this.appendEvidenceEvent(e,{kind:"degrade",obligationId:t,contractId:s.contractId,at:r,reason:a},`degrade\0${t}\0${a}`),this.replayEvidenceJournal(i),i.lastActivityAt=r,this.persist(i),true}removeSession(e){let t=e.trim();t&&(this.sessions.delete(t),rmSync(this.snapshotPath(t),{force:true}),rmSync(this.evidenceJournalDir(t),{recursive:true,force:true}));}list(){return [...this.sessions.values()]}snapshotPath(e){return join$1(this.sessionsDir,`${tn(e)}.json`)}evidenceJournalDir(e){return join$1(this.sessionsDir,"evidence-journal",tn(e))}appendEvidenceEvent(e,t,o){let r=this.evidenceJournalDir(e);mkdirSync(r,{recursive:true,mode:448});let i=createHash$1("sha256").update(o).digest("hex"),s=join$1(r,`${t.kind}-${i}.json`);if(existsSync$1(s))return;let a=join$1(r,`.${process.pid}.${randomUUID()}.tmp`);writeFileSync(a,JSON.stringify(t),{mode:384});try{linkSync(a,s);}catch(c){if(c.code!=="EEXIST")throw c}finally{rmSync(a,{force:true});}}replayEvidenceJournal(e){e.evidenceObligations=nn(e.evidenceObligations),e.evidenceDegradations=on(e.evidenceDegradations),e.evidenceOutcomes=rn(e.evidenceOutcomes);let t=this.evidenceJournalDir(e.sessionId);if(!existsSync$1(t))return;let o;try{o=readdirSync(t).filter(i=>/^(?:add|correction|resolve|degrade)-[a-f0-9]{64}\.json$/.test(i)).slice(0,4096);}catch{return}let r=o.flatMap(i=>{try{let s=readFileSync(join$1(t,i),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let a=Cr(JSON.parse(s));return a?[a]:[]}catch{return []}}).sort((i,s)=>i.at-s.at||sn(i.kind)-sn(s.kind));for(let i of r)this.applyEvidenceEvent(e,i);e.evidenceObligations=e.evidenceObligations.slice(-8),e.evidenceDegradations=e.evidenceDegradations.slice(-20),e.evidenceOutcomes=e.evidenceOutcomes.slice(-20);}applyEvidenceEvent(e,t){let o=e.evidenceOutcomes.find(s=>s.obligationId===t.obligationId);if(t.kind==="add"){if(o)return;let s=e.evidenceObligations.find(a=>a.obligationId===t.obligationId);s?(s.contract=t.contract,s.promptedAt=Math.min(s.promptedAt,t.at)):e.evidenceObligations.push({obligationId:t.obligationId,contractId:t.contractId,contract:t.contract,promptedAt:t.at,attempt:0,correctionRequested:false,violations:[]});return}let r=e.evidenceObligations.find(s=>s.obligationId===t.obligationId);if(t.kind==="correction"){if(!r||o||r.correctionFingerprint===t.fingerprint)return;r.attempt+=1,r.correctionRequested=true,r.correctionRequestedAt=t.at,r.correctionFingerprint=t.fingerprint,r.violations=t.violations;return}let i=r?.attempt??0;e.evidenceObligations=e.evidenceObligations.filter(s=>s.obligationId!==t.obligationId),!o&&(t.kind==="degrade"&&e.evidenceDegradations.push({obligationId:t.obligationId,contractId:t.contractId,reason:t.reason,degradedAt:t.at,attempt:i}),e.evidenceOutcomes.push({obligationId:t.obligationId,contractId:t.contractId,status:t.kind==="resolve"?"resolved":"degraded",completedAt:t.at,attempt:i,...t.kind==="degrade"?{reason:t.reason}:{}}));}persist(e){mkdirSync(this.sessionsDir,{recursive:true,mode:448});let t=this.snapshotPath(e.sessionId),o=`${t}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(o,JSON.stringify(e),{mode:384}),renameSync$1(o,t);}};function nn(n){return Array.isArray(n)?n.flatMap(e=>{if(!e||typeof e!="object")return [];let t=e;if(typeof t.contractId!="string"||t.contractId.length===0||t.contractId.length>128||typeof t.promptedAt!="number"||typeof t.attempt!="number"||typeof t.correctionRequested!="boolean"||!Array.isArray(t.violations)||!ln(t.contract))return [];let o=typeof t.obligationId=="string"&&t.obligationId.length>0&&t.obligationId.length<=384?t.obligationId:cn(t.contractId),r=typeof t.correctionTranscriptHash=="string"?t.correctionTranscriptHash:void 0,i=t.correctionFingerprint??r;return i!==void 0&&!/^[a-f0-9]{64}$/.test(i)?[]:[{...t,obligationId:o,correctionFingerprint:i}]}).slice(-8):[]}function on(n){return Array.isArray(n)?n.filter(e=>{if(!e||typeof e!="object")return false;let t=e;return typeof t.obligationId=="string"&&typeof t.contractId=="string"&&typeof t.reason=="string"&&typeof t.degradedAt=="number"&&typeof t.attempt=="number"}).slice(-20):[]}function rn(n){return Array.isArray(n)?n.filter(e=>{if(!e||typeof e!="object")return false;let t=e;return typeof t.obligationId=="string"&&typeof t.contractId=="string"&&(t.status==="resolved"||t.status==="degraded")&&typeof t.completedAt=="number"&&typeof t.attempt=="number"&&(t.reason===void 0||typeof t.reason=="string")}).slice(-20):[]}function Cr(n){if(!n||typeof n!="object")return null;let e=n;if(!["add","correction","resolve","degrade"].includes(e.kind??"")||typeof e.contractId!="string"||e.contractId.length>128||typeof e.at!="number")return null;let t=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:cn(e.contractId);if(e.kind==="add")return ln(e.contract)?{...e,obligationId:t}:null;if(e.kind==="correction"){let o=typeof e.fingerprint=="string"?e.fingerprint:e.transcriptHash;return typeof o=="string"&&/^[a-f0-9]{64}$/.test(o)&&Array.isArray(e.violations)&&e.violations.every(r=>typeof r=="string"&&r.length<=240)?{...e,obligationId:t,fingerprint:o}:null}return e.kind==="resolve"?{...e,obligationId:t}:typeof e.reason=="string"&&e.reason.length<=240?{...e,obligationId:t}:null}function sn(n){return n==="add"?0:n==="correction"?1:2}function ln(n){if(!n||typeof n!="object")return false;let e=n,t=e.requiredSections,o=e.prohibitedClaims;return e.version==="1.0"&&typeof e.id=="string"&&/^[a-zA-Z0-9][a-zA-Z0-9:._-]{0,127}$/.test(e.id)&&typeof e.runtimeProfilingOccurred=="boolean"&&typeof e.samplingEvidenceOccurred=="boolean"&&Array.isArray(t)&&t.length===3&&t[0]==="\u5DE5\u5177\u53D1\u73B0"&&t[1]==="\u6A21\u578B\u5047\u8BBE"&&t[2]==="\u9700\u8981\u8FD0\u884C\u65F6\u9A8C\u8BC1"&&Array.isArray(o)&&o.length<=16&&o.every(r=>typeof r=="string"&&r.length<=128)&&typeof e.canonicalReport=="string"&&Buffer.byteLength(e.canonicalReport,"utf8")<=48*1024&&!!e.correctionPolicy&&e.correctionPolicy.maxAttempts===1&&e.correctionPolicy.repeatedViolation==="fail_open"}function pn(n,e){let t=gn(n);mkdirSync$1(t,{recursive:true,mode:448});let o=join(t,`${e.receiptId}.json`);if(existsSync(o))return e.receiptId;let r=`${o}.${process.pid}.tmp`;writeFileSync$1(r,JSON.stringify(e),{mode:384});try{renameSync(r,o);}catch(i){try{unlinkSync$1(r);}catch{}if(!existsSync(o))throw i}return e.receiptId}function mn(n){let e=gn(n);mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=JSON.parse(readFileSync$1(i,"utf8"));if(typeof s.receiptId!="string"||typeof s.inputJson!="string"||typeof s.sessionId!="string"||typeof s.cleanupSharedState!="boolean")throw unlinkSync$1(i),new Error("session_finalize_spool_payload_invalid");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),payload:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function fn(n){unlinkSync$1(n.path);}function hn(n){try{renameSync(n.path,n.path.replace(/\.claim-\d+$/u,""));}catch{}}function gn(n){return join(E(n),"session-finalize-pending")}var Wr=256*1024,zr=48*1024,qr=512*1024,Jr=500,Br=5,B=["\u5DE5\u5177\u53D1\u73B0","\u6A21\u578B\u5047\u8BBE","\u9700\u8981\u8FD0\u884C\u65F6\u9A8C\u8BC1"];function Gr(n){return n==="react_audit_performance"||n.endsWith("__react_audit_performance")}function Vr(n){let e=G(n,0,new Set);return e?si(e.contract,e.canonicalReport):null}function bn(n){if(!n.sessionId||!Gr(n.toolName))return null;let e=Vr(n.toolResponse);if(!e)return null;let t=Date.now(),o=n.runtimeStore.addEvidenceObligation(n.sessionId,e,t,n.toolUseId),r=n.runtimeStore.get(n.sessionId);if(o&&r){let i=openGlobalDevFlowDatabase();try{i.upsertSessionObligation({obligationId:`evidence:${o.obligationId}`,projectRoot:r.projectRoot,sessionId:n.sessionId,executionId:r.executionId,kind:"evidence_contract",state:"open",payload:{contract:e,runtimeObligationId:o.obligationId},createdAt:t,updatedAt:t});}finally{i.close();}}return Kr(e)}function Kr(n){return [`DevFlow performance evidence contract ${n.id} is active.`,`The final performance answer MUST contain these three sections exactly: ${n.requiredSections.join(" / ")}.`,n.runtimeProfilingOccurred?"Only claims directly supported by the returned runtime measurements may be stated as measured facts.":"No runtime profiling occurred. Treat every finding as a static candidate: do not assign P0/high-risk severity, claim a confirmed bottleneck/jank/frame drop/CPU hotspot, quantify performance or benefit, or recommend requestAnimationFrame as generic throttling without sampling evidence.",`samplingEvidenceOccurred=${n.samplingEvidenceOccurred}. RAF recommendations are permitted only when this structured contract field is true; answer text cannot self-declare sampling evidence.`,"Use the canonical report below directly or preserve its evidence boundaries. Stop will request one correction for unsupported claims, then fail open with degradation telemetry.",n.canonicalReport].join(`
|
|
3
|
+
|
|
4
|
+
`)}function Sn(n){let e=n.runtimeStore??new T(n.projectRoot),t=e.listEvidenceObligations(n.sessionId);if(t.length===0)return null;let o=_n(n.transcriptPath,t);if(!o.answer){let s=o.degradationReason??"transcript_answer_unavailable";for(let a of t)e.degradeEvidenceObligation(n.sessionId,a.obligationId,s);return null}let r=o.fingerprint;if(!r){for(let s of t)e.degradeEvidenceObligation(n.sessionId,s.obligationId,"transcript_identity_unavailable");return null}let i=[];for(let s of t){let a=Xr(o.answer,[s]);if(a.length===0){e.resolveEvidenceObligation(n.sessionId,s.obligationId);continue}if(!s.correctionFingerprint){e.markEvidenceCorrection(n.sessionId,s.obligationId,a,r),i.push({obligation:s,violations:a});continue}if(s.correctionFingerprint===r){i.push({obligation:s,violations:a});continue}e.degradeEvidenceObligation(n.sessionId,s.obligationId,"evidence_contract_unresolved");}return i.length===0?null:Yr(i)}function Yr(n){let e=[...new Set(n.flatMap(o=>o.violations))],t=[...new Map(n.map(o=>[o.obligation.contractId,o.obligation.contract.canonicalReport])).values()];return {decision:"block",reason:["DevFlow evidence contract violation. Correct the final performance answer once before stopping.",`Violations: ${e.join("; ")}`,"Use this canonical report (you may add clearly labeled hypotheses or runtime verification steps, but no unsupported measured claims):",t.join(`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`)].join(`
|
|
9
|
+
|
|
10
|
+
`)}}function Xr(n,e){let t=new Set,o=new Set(e.flatMap(c=>c.contract.requiredSections)),r=Qr(n.split(/\r?\n/)),i=li(r.headingLines);for(let c of o)i.found.has(c)||t.add(`missing_section:${c}`);if(e.every(c=>c.contract.runtimeProfilingOccurred))return [...t];let a=e.every(c=>c.contract.samplingEvidenceOccurred);for(let c=0;c<r.claimLines.length;c++){let l=r.claimLines[c].trim();if(!l||ei(l))continue;let u=i.byLine.get(c);for(let d of ii(l))ni(d,u,a,t);}return [...t]}function Qr(n){let e=false,t=[],o=[];for(let r of n){if(/^\s*```/.test(r)){e=!e,t.push(""),o.push(r.replace(/^\s*```+[^\s`]*/,"").replace(/```+\s*$/,"").trim());continue}t.push(e?"":r.replace(/`[^`]*`/g,"").trim()),o.push(r.replace(/`([^`]*)`/g,(i,s)=>Zr(s)?"":s).trim());}return {headingLines:t,claimLines:o}}function Zr(n){let e=n.trim().slice(0,256);return !e||/\s/.test(e)||n.trim().length>256?false:/^[A-Za-z_$][\w$.-]*$/.test(e)||/^(['"])[^'"`]*\1$/.test(e)}function ei(n){if(n.length>2048)return false;let e=n.replace(/^\s*(?:[-*+]|\d+[.)])\s+/,"").trim();return e?ti(e)||/^(?:\/\/|\/\*|\*\/|\*\s|#!)/.test(e)||/^(?:import|export|const|let|var|function|class|type|interface|enum|namespace|declare)\b/.test(e)||/^(?:async\s+)?(?:function\s+)?[A-Za-z_$][\w$]*\s*=\s*/.test(e)||/^[A-Za-z_$][\w$.[\]'"-]*\s*(?:=|\+=|-=|\*=|\/=|\?\?=|&&=|\|\|=)\s*/.test(e)||/^[A-Za-z_$'"-][\w$.'"-]*\s*:\s*[^:]+[,}]?$/.test(e)||/=>/.test(e)||/^(?:await\s+|return\s+|throw\s+|new\s+)?[A-Za-z_$][\w$.]*\s*\([^)]*\)\s*;?$/.test(e)||/^(['"])[\s\S]*\1[;,]?$/.test(e)?true:/[{}()[\]=<>]\s*;?$/.test(e)&&/(?:;|=>|\b(?:return|new|await)\b)/.test(e):false}function ti(n){if(n.length>1024)return false;let e="(?:--[A-Za-z0-9_-]+|(?:-webkit-|-moz-|-ms-)?(?:animation(?:-[a-z-]+)?|transition(?:-[a-z-]+)?|opacity|transform|will-change|contain|content-visibility|display|position|top|right|bottom|left|width|height|min-(?:width|height)|max-(?:width|height)|margin(?:-[a-z]+)?|padding(?:-[a-z]+)?|color|background(?:-[a-z-]+)?|border(?:-[a-z-]+)?|font(?:-[a-z-]+)?|line-height|z-index|overflow(?:-[xy])?))";return new RegExp(`^${e}\\s*:\\s*\\S[^;]{0,960};$`,"i").test(n)}function ni(n,e,t,o){let r=/\bP0\b/gi;for(let v of n.matchAll(r))vn(n,v.index??0,v[0],"p0")||o.add("unsupported_p0_severity");let i=/(?:中高|高)(?:风险|优先级)|严重(?:问题|风险)|\bhigh[- ](?:risk|severity|priority)\b/gi;for(let v of n.matchAll(i))vn(n,v.index??0,v[0],"high")||o.add("unsupported_high_severity");let s=/(?:性能)?瓶颈|卡顿|掉帧|CPU\s*(?:热点|尖峰)|\bbottleneck\b|\bjank\b|\bdropped frames?\b|\bCPU hotspot\b/gi;for(let v of n.matchAll(s))ri(n,v.index??0,v[0])||(/(?:瓶颈|bottleneck)/i.test(v[0])?o.add("unsupported_confirmed_bottleneck"):o.add("unsupported_runtime_effect"));let a=/\b\d{1,3}(?:\.\d+)?\s*%/.test(n),c=/(?:预计|预期|估计|提升|降低|减少|节省|改善|收益|加速|improve|reduce|faster|gain|benefit|speedup|expected|estimated)/i.test(n),l=/\b\d+(?:\.\d+)?\s*[x×]\b/i.test(n);(a||l)&&c&&o.add(a?"unsupported_benefit_percentage":"unsupported_performance_number");let u=/\b\d+(?:\.\d+)?(?:\s*[-–~]\s*\d+(?:\.\d+)?)?\s*(?:ms|fps|hz)\b/i.test(n)||/\d+(?:\.\d+)?(?:\s*[-–~]\s*\d+(?:\.\d+)?)?\s*(?:毫秒|次\s*\/\s*秒|帧)/.test(n),d=e==="\u9700\u8981\u8FD0\u884C\u65F6\u9A8C\u8BC1"&&/(?:采集|记录|测量|收集|collect|measure|record)/i.test(n)&&!/(?:预计|预期|估计|约|大约|通常|平均|每(?:隔)?|达到|提升|降低|减少|节省|改善|improve|reduce|faster|expected|estimated|average|typically|every)/i.test(n);a&&!c&&!d&&o.add("unsupported_benefit_percentage"),u&&!d&&o.add("unsupported_performance_number");let p=/(?:requestAnimationFrame|\bRAF\b)/i.test(n),f=/(?:建议|应该|应当|使用|添加|采用|切换|包裹|优化|节流|\buse\b|\badopt\b|\brecommend\b|\bswitch\b|\bwrap\b|\bthrottl(?:e|ing)\b)/i.test(n),h=/(?:不要|不得|不能|不应|避免|不建议|不推荐).{0,16}(?:使用|采用|添加|切换|包裹|节流)?.{0,8}(?:requestAnimationFrame|\bRAF\b)|\b(?:do\s+not|don't|never|avoid)\s+(?:use|adopt|recommend|switch|wrap|throttle)?.{0,8}(?:requestAnimationFrame|RAF)\b/i.test(n);p&&f&&!h&&!t&&o.add("raf_without_sampling_evidence");}function vn(n,e,t,o){let r=n.slice(Math.max(0,e-64),e),i=n.slice(e+t.length,e+t.length+28),s=oi(r),a=/^(?:\s+)?(?:未发现|不存在|并不存在|未被发现)/.test(i)||/^(?:\s+)?(?:was\s+|is\s+)?not found\b/i.test(i);return s||a?true:o==="high"?/(?:未发现|没有发现|不存在|无证据(?:表明|证明)?)\s*(?:任何|明确的)?\s*P0\s*(?:或|和|及|、)\s*$/i.test(r)||/\b(?:no evidence (?:of|for)|no)\s+P0\s+(?:or|and)\s+$/i.test(r):false}function oi(n){if(/(?:未发现|没有发现|不存在|无证据(?:表明|证明)?|不是|并非|未被)\s*(?:任何|明确的)?\s*(?:(?:问题|发现|证据|项|内容)\s*)?(?:(?:属于|(?:被)?(?:评|判定|认定|标记|列|视|定|归(?:类)?)为)\s*)?$/i.test(n)||/\b(?:no evidence (?:of|for)|no|not|isn't|is\s+not)\s+(?:an?\s+)?(?:(?:issues?|findings?|evidence|items?)\s+)?(?:(?:classified|rated|marked|labelled|labeled)(?:\s+as)?\s+)?$/i.test(n))return true;let t=/(?:不得|不能|不应|不宜|不要)\s*(?:被\s*)?(?:(?:直接|轻易|简单|明确|正式|合理|据此|当前|目前)\s*){0,2}(?:(?:评|判定|认定|标记|列|视|定|归(?:类)?)为|属于)\s*$/i,o=/\b(?:cannot|can't|must not|should not|shouldn't|do not|don't)\s+(?:(?:reasonably|directly|formally|currently)\s+){0,2}(?:be\s+)?(?:classified|labeled|labelled|rated|marked)(?:\s+as)?\s+$/i;return t.test(n)||o.test(n)}function ri(n,e,t){let o=n.slice(Math.max(0,e-40),e),r=n.slice(e+t.length,e+t.length+32),i=/(?:是否|待验证|候选|可能|潜在|未观察到|没有观察到|未发现|不存在|无证据(?:表明)?|不能(?:据此)?确认|尚未(?:确认|证明)|验证(?:是否)?|测量(?:是否)?|采集|记录|收集).{0,16}$/i.test(o)||/\b(?:whether|measure|validate|candidate|potential|possible|may|might|no|no evidence(?: of| for)?|not observed|unobserved|collect|record).{0,18}$/i.test(o),s=/^(?:是否|有待验证|待验证|候选|可能|潜在|指标|需要(?:验证|测量)|需(?:验证|测量))/.test(r)||/^(?:\s+)?(?:candidate|potential|possible|metric|metrics|to (?:measure|validate)|needs? (?:measurement|validation)|is (?:a )?(?:candidate|potential))/i.test(r);return i||s}function ii(n){return n.split(/(?:[。!?;;,,]|\b(?:but|however|yet|nevertheless|nonetheless)\b|但是|但|然而|却|不过|可是)/i).map(e=>e.trim()).filter(Boolean)}function G(n,e,t){if(e>Br||n===null||n===void 0)return null;if(typeof n=="string"){if(Buffer.byteLength(n,"utf8")>Wr)return null;try{return G(JSON.parse(n),e+1,t)}catch{return null}}if(typeof n!="object"||t.has(n))return null;if(t.add(n),Array.isArray(n)){for(let r of n.slice(0,16)){let i=G(r,e+1,t);if(i)return i}return null}let o=n;if("evidenceContract"in o)return {contract:o.evidenceContract,canonicalReport:o.canonicalReport};for(let r of ["structuredContent","data","result"])if(r in o){let i=G(o[r],e+1,t);if(i)return i}if(Array.isArray(o.content))for(let r of o.content.slice(0,16)){let i=r&&typeof r=="object"&&"text"in r?r.text:r,s=G(i,e+1,t);if(s)return s}return null}function si(n,e){if(!n||typeof n!="object"||Array.isArray(n))return null;let t=n;if(t.version!=="1.0"||typeof t.id!="string"||!/^[a-zA-Z0-9][a-zA-Z0-9:._-]{0,127}$/.test(t.id)||typeof t.runtimeProfilingOccurred!="boolean"||typeof t.samplingEvidenceOccurred!="boolean"||!Array.isArray(t.requiredSections)||t.requiredSections.length!==B.length)return null;let o=t.requiredSections.filter(c=>typeof c=="string");if(o.length!==B.length||B.some((c,l)=>o[l]!==c)||!Array.isArray(t.prohibitedClaims)||t.prohibitedClaims.length>16)return null;let r=t.prohibitedClaims.filter(c=>typeof c=="string"&&c.length<=128);if(r.length!==t.prohibitedClaims.length)return null;let i=t.correctionPolicy;if(!i||typeof i!="object"||Array.isArray(i))return null;let s=i;if(s.maxAttempts!==1||s.repeatedViolation!=="fail_open")return null;let a=typeof t.canonicalReport=="string"?t.canonicalReport:e;return typeof a!="string"||Buffer.byteLength(a,"utf8")>zr||B.some(c=>!a.includes(c))?null:{version:"1.0",id:t.id,runtimeProfilingOccurred:t.runtimeProfilingOccurred,samplingEvidenceOccurred:t.samplingEvidenceOccurred,requiredSections:o,prohibitedClaims:r,correctionPolicy:{maxAttempts:1,repeatedViolation:"fail_open"},canonicalReport:a}}function _n(n,e){if(!n||n.length>4096)return {degradationReason:"transcript_path_missing"};let t;try{let o=lstatSync$1(n);if(!o.isFile()||o.isSymbolicLink())return {degradationReason:"transcript_path_unsafe"};t=openSync$1(n,constants.O_RDONLY|(constants.O_NOFOLLOW??0));let r=fstatSync$1(t);if(!r.isFile()||r.dev!==o.dev||r.ino!==o.ino)return {degradationReason:"transcript_path_changed"};let i=Math.min(r.size,qr),s=Buffer.alloc(i),a=0;for(;a<i;){let h=readSync(t,s,a,i-a,r.size-i+a);if(h===0)break;a+=h;}let c=s.subarray(0,a).toString("utf8");r.size>i&&(c=c.slice(Math.max(0,c.indexOf(`
|
|
11
|
+
`)+1)));let l=c.split(/\r?\n/).slice(-Jr),u=e.length>0?Math.min(...e.map(h=>h.promptedAt)):0,d=ai(l,u),f=[...d].reverse().find(h=>e.every(v=>v.contract.requiredSections.every(b=>h.text.includes(b))))??d.at(-1);return f?.text?{answer:f.text,fingerprint:f.fingerprint}:{degradationReason:"transcript_answer_unavailable"}}catch{return {degradationReason:"transcript_unreadable"}}finally{t!==void 0&&closeSync$1(t);}}function wn(n){return _n(n,[]).answer}function ai(n,e){let t=[];for(let o=0;o<n.length;o++){let r=n[o];if(r.trim())try{let i=JSON.parse(r),s=i.message;if(!s||typeof s!="object"||s.role!=="assistant")continue;let a=s,c=ci(i.timestamp);if(c>0&&c+5e3<e)continue;let l=s.content,u=typeof l=="string"?l:Array.isArray(l)?l.filter(d=>d&&typeof d=="object"&&d.type==="text").map(d=>d.text).filter(d=>typeof d=="string").join(`
|
|
12
|
+
`):"";if(u.trim()){let d=u.trim(),p=typeof a.id=="string"&&a.id?`message:${a.id}`:typeof i.uuid=="string"&&i.uuid?`uuid:${i.uuid}`:`record:${String(i.timestamp??"")}:${o}:${createHash("sha256").update(r).digest("hex")}`,f=createHash("sha256").update(d).digest("hex"),h=createHash("sha256").update(`${p}\0${f}`).digest("hex");t.push({text:d,timestamp:c,fingerprint:h});}}catch{continue}}return t}function ci(n){if(typeof n=="number"&&Number.isFinite(n))return n;if(typeof n!="string")return 0;let e=Date.parse(n);return Number.isFinite(e)?e:0}function li(n){let e=new Set,t=new Map,o;for(let r=0;r<n.length;r++){let i=n[r].trim().replace(/^#{1,6}\s*/,"").replace(/^\*\*(.*)\*\*$/,"$1").replace(/^(?:[一二三123][、..]\s*)/,"").replace(/[::]\s*$/,"").trim(),s=B.find(a=>i===a);s&&(o=s,e.add(s)),t.set(r,o);}return {found:e,byLine:t}}function He(n){let e={committed:0,skipped:0,pending:0},t=[];for(let o of n)e[o.status]+=1,o.receiptId&&t.push(o.receiptId);return {memoryReceiptIds:[...new Set(t)],missingMemoryDecisionCount:e.pending,memoryTurnOutcomes:e}}function V(n){return (n instanceof Error?n.message:String(n)).trim().slice(0,240)||"memory_lifecycle_unavailable"}var P=class extends Error{constructor(e,t){super(`session_finalize_${e}:${t}`),this.name="SessionFinalizationRetryableError",this.category=`session_finalize_${e}`;}};function ue(n){let e;try{e=openGlobalDevFlowDatabase();let t=(n.executionId?e.getSkillExecution(n.executionId):null)??e.getLatestSkillExecutionForSession(n.sessionId),o={stage:n.stage,reason:n.reason,degradedAt:Date.now()};t&&e.mergeSkillExecutionMetadata(t.executionId,{...n.metadata,sessionFinalizationDegradations:[o]}),e.insertEvent({kind:"session_finalize_degraded",timestamp:o.degradedAt,success:!1,metadata:{projectRoot:n.projectRoot,sessionId:n.sessionId,executionId:t?.executionId,...o}});}catch{}finally{e?.close();}}function pe(n,e=ee(),t=true,o,r=true){let i;try{i=JSON.parse(n);}catch{return null}let s=i.session_id?.trim();if(!s)return null;let a=`session-close:${createHash("sha256").update(`${e}\0${s}`).digest("hex").slice(0,24)}`,c={inputJson:n,sessionId:s,cleanupSharedState:t,executionId:o},l;try{l=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});let u=l.requestSessionClosure({receiptId:a,projectRoot:e,sessionId:s,payload:c}),d=l.getWorkByIdempotencyKey(a);return {status:u.state==="closed"||u.state==="closed_with_pending_work"?"completed":"accepted",receiptId:a,workState:d?.state??"pending",closureState:u.state,pendingWorkCount:u.pendingWorkCount}}catch(u){if(!r)throw u;return pn(e,{receiptId:a,...c}),{status:"accepted",receiptId:a,workState:"spooled",closureState:"closing",pendingWorkCount:1}}finally{l?.close();}}async function Rn(n,e=ee(),t=true,o){let r;try{r=JSON.parse(n);}catch{return}let i=r.session_id?.trim();if(!i)return;let s=new T(e),a=s.get(i),c={evidenceDegradations:a?.evidenceDegradations??[],evidenceContractOutcomes:a?.evidenceOutcomes??[],pendingEvidenceContractIds:a?.evidenceObligations.map(f=>f.contractId)??[]},l=o?.telemetry??new O,u=!o?.telemetry,d=false,p;try{try{await l.flushAndAggregate();}catch{}let f=Date.now(),h=o?.executionId??a?.executionId,v;try{let y=openGlobalDevFlowDatabase();try{v=y.listSessionMemoryTurnsForReconciliation(e,i);for(let m of v){let _=`memory:${m.turnId}`,g=y.getSessionObligation(e,i,_);g?g.state==="open"&&m.status!=="pending"&&y.resolveSessionObligation({projectRoot:e,sessionId:i,obligationId:_,state:"satisfied",receiptId:m.receiptId,reason:m.reason,resolvedAt:m.decidedAt}):y.upsertSessionObligation({obligationId:_,projectRoot:e,sessionId:i,turnId:m.turnId,kind:"memory_decision",state:m.status==="pending"?"open":"satisfied",payload:{eventId:m.eventId,promptHash:m.promptHash},receiptId:m.receiptId,reason:m.reason,createdAt:m.createdAt,updatedAt:m.decidedAt??m.createdAt,resolvedAt:m.decidedAt});}}finally{y.close();}}catch(y){let m=V(y),_={...c,memoryEventReconciliation:{status:"degraded",stage:"turn_load",reason:m,committedProcessed:0,skippedDiscarded:0,remainingUndecided:null,checkpointPending:null}};throw ue({projectRoot:e,sessionId:i,executionId:h,stage:"turn_load",reason:m,metadata:_}),new P("turn_load",m)}let b=He(v),w=o?.memory??(p=new MemoryGate(e)),R={status:"unknown",selected:0,adopted:0,unknown:0};try{let y=wn(r.transcript_path),m=await w.attributeRetrievalBenefits({sessionId:i,executionId:h,finalAnswer:y});R={status:y?"evaluated":"unknown",...m};}catch(y){R={...R,status:"degraded",reason:V(y)};}let I;try{I=await w.reconcileDecidedTurnEventWindows(i,v,f);}catch(y){let m=V(y),_={...b,...c,memoryEventReconciliation:{status:"degraded",stage:"event_reconciliation",reason:m,committedProcessed:0,skippedDiscarded:0,remainingUndecided:null,checkpointPending:null}};throw ue({projectRoot:e,sessionId:i,executionId:h,stage:"event_reconciliation",reason:m,metadata:_}),new P("event_reconciliation",m)}let x;try{x=await J({projectRoot:e,sessionId:i,trigger:"session_end",memory:w,details:{eventReconciliation:I},strictPersistence:!0});}catch(y){let m=V(y),_={...b,...c,memoryEventReconciliation:{status:"completed",...I,checkpointPending:null},memoryCheckpointDegradation:m};throw ue({projectRoot:e,sessionId:i,executionId:h,stage:"checkpoint",reason:m,metadata:_}),new P("checkpoint",m)}let H={memoryBenefitAttribution:R,memoryEventReconciliation:{status:"completed",...I,checkpointPending:x.pendingEvents},memoryDistillCheckpoint:x};try{let y=openGlobalDevFlowDatabase();try{let m=`session-finalize:${i}:events`,_=Math.max(Number(x.pendingEvents??0),Number(I.remainingUndecided??0)),g=y.getSessionObligation(e,i,m);_>0?y.upsertSessionObligation({obligationId:m,projectRoot:e,sessionId:i,executionId:h,kind:"session_finalize",state:"open",payload:{pendingEvents:_,reconciliation:I,checkpointId:x.id},reason:"active_unprocessed_session_events",createdAt:g?.createdAt??f,updatedAt:f}):g?.state==="open"&&y.resolveSessionObligation({projectRoot:e,sessionId:i,obligationId:m,state:"satisfied",reason:"session_events_reconciled",resolvedAt:f});}finally{y.close();}}catch(y){console.error("[devflow] Session finalization obligation persistence failed:",y.message);}try{await w.closeSession(i),p&&(p.close(),p=void 0);}catch(y){let m=V(y),_={...b,...c,...H,memorySessionCloseDegradation:m};throw ue({projectRoot:e,sessionId:i,executionId:h,stage:"memory_close",reason:m,metadata:_}),new P("memory_close",m)}let S={...b,...c,...H};d=!0;let k;try{k=openGlobalDevFlowDatabase();let y=h;if(y)try{k.reconcileSkillExecution(y,"completed",f,S);let g=k.getSkillExecution(y);await M("/api/telemetry/skill-execution/complete",{executionId:y,finishedAt:f,status:"completed",summary:{totalToolCalls:g?.totalToolCalls??0,mcpToolCalls:g?.mcpToolCalls??0,directToolCalls:g?.directToolCalls??0,subagentCount:g?.subagentCount??0,totalDuration:g?.totalDuration??0,mcpComplianceRate:g?.mcpComplianceRate??0,missedTools:g?.missedMcpTools??[],actualFailureCount:g?.failedToolCalls??0,fallbackCount:g?.fallbackCount??0,fallbackReasons:g?.fallbackReasons??[]},metadata:S},{fallbackReason:"skill_execution_already_reconciled_locally"});}catch{}let m=k.reconcileRunningSkillExecutionsForSession(i,f,{closureReason:"session_finalize",...S});for(let g of m)await M("/api/telemetry/skill-execution/complete",{executionId:g.executionId,finishedAt:g.finishedAt,status:g.status,summary:{totalToolCalls:g.totalToolCalls??0,mcpToolCalls:g.mcpToolCalls??0,directToolCalls:g.directToolCalls??0,subagentCount:g.subagentCount??0,totalDuration:g.totalDuration??0,mcpComplianceRate:g.mcpComplianceRate??0,missedTools:g.missedMcpTools??[],actualFailureCount:g.failedToolCalls??0,fallbackCount:g.fallbackCount??0,fallbackReasons:g.fallbackReasons??[]},metadata:S},{fallbackReason:"skill_execution_already_reconciled_locally"});let _=k.getLatestSkillExecutionForSession(i);if(_&&!m.some(g=>g.executionId===_.executionId)&&k.mergeSkillExecutionMetadata(_.executionId,S),t){k.deleteHookReceipt(e);let g=E(e),bo=createHash("sha256").update(e).digest("hex").slice(0,12);for(let So of [`session-id-${bo}`,"current-execution-id","current-skill.json","event-map.json"])rmSync$1(join(g,So),{force:!0});}k.deleteContextReceipt(e,i);}catch{}finally{k?.close();}try{await l.endSession(i),await l.flushAndAggregate();}catch{}}finally{if(p)try{p.close();}catch{}u&&l.close(),d&&s.removeSession(i);}}if(process.argv[1]?.endsWith("session-end")||process.argv[1]?.endsWith("session-end.js")){let n=console.log.bind(console);console.log=console.error.bind(console),console.info=console.error.bind(console);let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{e+=t;}),process.stdin.on("end",async()=>{let t=pe(e.trim()||process.argv[2]||"");t&&n(JSON.stringify(t)),process.exit(0);}),process.stdin.on("error",()=>process.exit(0)),setTimeout(()=>process.exit(0),1e4).unref();}var bi=/^\/(?:devflow:)?[\w-]+\b\s*/iu,Si=/\b(?:(?:do\s+not|don't|dont|never|not)(?:\s+need\s+to)?|no\s+need\s+to)\s+(?:please\s+)?(?:remember|memorize)\b|(?:不要|别|不用|无需|不必|不需要)(?:再)?(?:记住|记|记忆)/iu,_i=/(?:^|[.!?]\s*)(?:(?:please|kindly)\s+)?(?:remember|memorize|save\s+this|store\s+this|note\s+that)(?:\s+(?:that|to))?[\s:,-]*(.+)$/iu,wi=/(?:^|[。!?;,,]\s*)(?:(?:请|麻烦|务必|一定要|帮我|帮忙|需要)\s*)?(?:记住|记一下|记下来|记|记录一下|记录下来|保存一下|保存下来)(?:这(?:件事|一点|个信息|些内容))?[\s::,,]*(.+)$/iu;function me(n){let e=n.trim().replace(bi,"").trim();return !e||Si.test(e)?null:(wi.exec(e)??_i.exec(e))?.[1]?.trim().replace(/^[::,,\s]+/u,"")||null}function ki(n){let e=createHash("sha256").update(n).digest("hex").slice(0,16),t=process.env.DEVFLOW_STATE_DIR||join(homedir(),".devflow","state",e);return join(t,"memory-intents.jsonl")}function Ri(n){try{return readFileSync$1(n,"utf8").split(`
|
|
13
|
+
`).filter(Boolean).flatMap(e=>{try{let t=JSON.parse(e);return typeof t.content=="string"&&typeof t.createdAt=="number"?[t]:[]}catch{return []}})}catch{return []}}function Tn(n){let e=ki(n),t=`${e}.claim-`,o=`${basename(e)}.claim-`,r=(()=>{try{return readdirSync$1(dirname$1(e)).filter(a=>a.startsWith(o)&&!a.includes(".tmp-")).sort()[0]}catch{return}})(),i=r?join(dirname$1(e),r):`${t}${Date.now()}-${process.pid}`;if(!r)try{renameSync(e,i);}catch{return null}let s=Ri(i);if(s.length===0){try{unlinkSync$1(i);}catch{}return null}return {path:i,intents:s}}function We(n){if(n.intents.shift(),n.intents.length===0){try{unlinkSync$1(n.path);}catch{}return}let e=`${n.path}.tmp-${process.pid}`;writeFileSync$1(e,n.intents.map(t=>JSON.stringify(t)).join(`
|
|
4
14
|
`)+`
|
|
5
|
-
`,{mode:384}),renameSync(e,n.path);}function q(n){let e=n.trim().replace(/^\//,"");if(!e.startsWith("devflow:"))return null;let t=e.slice(8).replace(/^devflow-/,"");return /^[a-z0-9][a-z0-9-]*$/i.test(t)?`devflow:${t.toLowerCase()}`:null}function kt(n){let e=n.trimStart().match(/^\/(devflow:[a-z0-9][a-z0-9-]*)\b/i);if(!e)return null;let t=q(e[1]);return t?{rawName:e[1],skillName:t}:null}function D(n,e){return e?`evt_tool_${createHash$1("sha256").update(`${n}\0${e}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var Fn=/^(?:ok(?:ay)?|yes|no|thanks?|thank you|continue|好的?|可以|行|是|否|谢谢|继续|收到|明白了?)[.!。!\s]*$/iu;function Nn(n){let e=n.trim();return e.length>0&&!Fn.test(e)}function $n(n,e,t=Date.now()){let o=createHash("sha256").update(e.trim()).digest("hex"),r=createHash("sha256").update(`${n}\0${t}\0${o}`).digest("hex").slice(0,24);return {turnId:`turn:${r}`,eventId:`memory-turn:${r}`,promptHash:o,createdAt:t}}function me(n,e,t=[]){return `memory-receipt:${createHash("sha256").update(`${n}\0${e}\0${[...t].sort().join("\0")}`).digest("hex").slice(0,24)}`}function he(n){return `DevFlow memory decision required for ${n.turnId}. Before the final response, semantically decide whether this turn contains durable project knowledge. Call mcp__devflow__memory_commit_turn with evidence-bound candidates, or mcp__devflow__memory_skip_turn with a concrete reason. Do not claim memory success without a canonical receipt.`}function de(n){let e=n.memoryIds.length>0?n.memoryIds.join(","):"none",t=n.status==="committed"?"accepted":n.status,o=n.status==="committed"?"; indexStatus=pending":"";return `DevFlow canonical memory receipt: status=${t}; receiptId=${n.receiptId??"missing"}; turnId=${n.turnId}; memoryIds=${e}; source=${n.source??"unknown"}${o}.`}function Rt(n,e,t){if(t)return null;let o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});try{let r=o.getPendingMemoryTurn(n,e);return !r||!o.markMemoryTurnStopPrompted(r.turnId)?null:{decision:"block",reason:he(r)}}finally{o.close();}}function fe(n){if(!Nn(n.prompt))return null;let e=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});try{let t=n.prompt.trim().slice(0,4e3),o=createHash("sha256").update(t).digest("hex"),r=e.listMemoryTurns(n.projectRoot,n.sessionId,5).find(l=>l.promptHash===o&&Date.now()-l.createdAt<1e4),i=r?{turnId:r.turnId,eventId:r.eventId,promptHash:r.promptHash,createdAt:r.createdAt}:$n(n.sessionId,t),s=r??e.beginMemoryTurn({...i,projectRoot:n.projectRoot,sessionId:n.sessionId});if(s.status!=="pending")return {turn:s,additionalContext:de(s),skipSkillRouting:s.source==="explicit_intent"};let a=W(t)??void 0,c=a?"commit_explicit":"capture_prompt";return e.enqueueWork({idempotencyKey:`memory-turn:${c}:${s.turnId}`,kind:a?"memory.explicit_commit":"memory.turn_capture",projectRoot:n.projectRoot,sessionId:n.sessionId,turnId:s.turnId,payload:{operation:c,turnId:s.turnId,eventId:s.eventId,sessionId:n.sessionId,prompt:t,explicitContent:a,createdAt:s.createdAt}}),{turn:s,explicitContent:a,additionalContext:a?`DevFlow explicit memory is durably queued for ${s.turnId}, but no canonical receipt exists yet. Do not claim that it was remembered.`:he(s),skipSkillRouting:!!a}}finally{e.close();}}async function ye(n){let{payload:e,memory:t,projectRoot:o}=n,r=openGlobalDevFlowDatabase();try{let i=r.getMemoryTurn(e.turnId);if(!i)throw new Error(`Memory turn ${e.turnId} does not exist`);if(i.status!=="pending")return {turn:i,additionalContext:de(i),skipSkillRouting:i.source==="explicit_intent"};if(await t.recordUserMessage(e.prompt,e.sessionId,e.prompt.slice(0,200)),await t.recordEvent({id:e.eventId,sessionId:e.sessionId,tool:"UserPromptSubmit",kind:"user_message",payload:{prompt:e.prompt,turnId:e.turnId},createdAt:e.createdAt}),e.operation==="capture_prompt"||!e.explicitContent)return {turn:i,additionalContext:he(i),skipSkillRouting:!1};let s=await t.saveExplicitMemoryIntent(e.explicitContent,e.sessionId,e.eventId),a=me(i.turnId,"committed",[s.id]),c=r.commitMemoryTurn({turnId:i.turnId,receiptId:a,memoryIds:[s.id],source:"explicit_intent",reason:"explicit_user_request"});return r.enqueueWork({idempotencyKey:`vector:${o}:${s.id}`,kind:"memory.vector_backfill",projectRoot:o,sessionId:e.sessionId,turnId:c.turnId,payload:{observationId:s.id},maxAttempts:20}),{turn:c,explicitContent:e.explicitContent,additionalContext:de(c),skipSkillRouting:!0}}finally{r.close();}}var Hn=new Set(["Write","Edit","NotebookEdit"]),bt="Claude native memory writes are disabled for this project. Use DevFlow explicit memory or mcp__devflow__memory_commit_turn so a canonical receipt is created.";function Dt(n){if(!Hn.has(n.toolName))return null;let e=Wn(n.toolInput);if(!e)return null;let t=qn(e,n.projectRoot),o=resolve(n.projectRoot,".claude");if(It(t,o)&&basename(t).toLocaleUpperCase("en-US")==="MEMORY.MD")return bt;let r=resolve(n.home??homedir$1(),".claude","projects");return It(t,r)&&relative(r,t).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?bt:null}function Wn(n){for(let e of ["file_path","notebook_path","path"]){let t=n[e];if(typeof t=="string"&&t.trim())return t.trim()}return null}function qn(n,e){return resolve(isAbsolute(n)?n:resolve(e,n))}function It(n,e){let t=relative(e,n);return t===""||!t.startsWith(`..${sep}`)&&t!==".."&&!isAbsolute(t)}var Vn=1024*1024;function Pt(n){let e=join$1(getProjectStateDir(n),"session-start-pending");mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join$1(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=readFileSync$1(i,"utf8");if(Buffer.byteLength(s,"utf8")>Vn)throw unlinkSync$1(i),new Error("session_start_spool_input_too_large");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),input:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function Ot(n){unlinkSync$1(n.path);}function At(n){let e=n.path.replace(/\.claim-\d+$/u,"");try{renameSync(n.path,e);}catch{}}function Ft(n,e){let t=Ut(n);mkdirSync$1(t,{recursive:true,mode:448});let o=`memory-turn-spool-${Date.now()}-${process.pid}-${randomUUID$1()}`,r=join$1(t,`${o}.json`),i=`${r}.tmp`;return writeFileSync$1(i,JSON.stringify({...e,prompt:e.prompt.trim().slice(0,4e3)}),{mode:384}),renameSync(i,r),o}function Nt(n){let e=Ut(n);mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join$1(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=JSON.parse(readFileSync$1(i,"utf8"));if(typeof s.sessionId!="string"||typeof s.prompt!="string"||typeof s.createdAt!="number")throw unlinkSync$1(i),new Error("memory_turn_spool_payload_invalid");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),payload:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function $t(n){unlinkSync$1(n.path);}function Lt(n){try{renameSync(n.path,n.path.replace(/\.claim-\d+$/u,""));}catch{}}function Ut(n){return join$1(_(n),"memory-turn-pending")}var G=class extends Error{constructor(e,t){super(t),this.name="PermanentWorkError",this.category=e;}},nr=1e3,rr=3e4,ir=1,sr=5*6e4,B=class{constructor(e){this.timer=null;this.draining=null;this.stopped=true;this.projectRoot=e.projectRoot,this.handlers=e.handlers,this.pollIntervalMs=we(e.pollIntervalMs,nr),this.leaseMs=we(e.leaseMs,rr),this.batchSize=we(e.batchSize,ir),this.owner=e.owner??`hook-daemon:${process.pid}:${randomUUID$1()}`,this.now=e.now??Date.now,this.random=e.random??Math.random,this.openDatabase=e.openDatabase??(()=>openGlobalDevFlowDatabase());}start(){this.stopped&&(this.stopped=false,this.schedule(0));}stop(){this.stopped=true,this.timer&&clearTimeout(this.timer),this.timer=null;}drainOnce(){return this.draining?this.draining:(this.draining=this.performDrain().finally(()=>{this.draining=null;}),this.draining)}schedule(e){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>{this.timer=null,this.drainOnce().catch(t=>console.error("[devflow-work] Drain failed:",Ht(t))).finally(()=>this.schedule(this.pollIntervalMs));},e),this.timer.unref());}async performDrain(){let e=Object.keys(this.handlers);if(e.length===0)return 0;let t=this.openDatabase();try{let o=this.now();t.recoverExpiredWork(this.projectRoot,o);let r=t.leaseWork({projectRoot:this.projectRoot,owner:this.owner,kinds:e,limit:this.batchSize,leaseMs:this.leaseMs,now:o});for(let i of r)await this.processItem(t,i);return r.length}finally{t.close();}}async processItem(e,t){let o=this.handlers[t.kind];if(!o){e.deadLetterWork(t.id,this.owner,{category:"unsupported_work_kind",message:`No work handler is registered for ${t.kind}`});return}try{if(await o({item:t}),!e.completeWork(t.id,this.owner,this.now()))throw new Error(`Work lease was lost before completion: ${t.id}`)}catch(r){let i=ar(r);if(r instanceof G){e.deadLetterWork(t.id,this.owner,i);return}e.retryWork(t.id,this.owner,i,this.now()+cr(t.attempts,this.random()));}}};function we(n,e){return Number.isSafeInteger(n)&&n>0?n:e}function ar(n){if(n instanceof G)return {category:n.category,message:n.message};let e=n&&typeof n=="object"?n:null;return {category:typeof e?.category=="string"?e.category:"runtime_error",message:Ht(n)}}function cr(n,e){let t=Math.min(sr,500*2**Math.max(0,n-1)),o=Math.floor(t*.2*Math.max(0,Math.min(1,e)));return t+o}function Ht(n){return n instanceof Error?n.message:String(n)}var mr=250;function zt(n,e=process.env){let t=qt(join$1(homedir$1(),".devflow","config.json")),o=qt(join$1(n,".devflow","config.json")),r=ke(e.DEVFLOW_HOOK_PROFILE)??ke(o.profile)??ke(t.profile)??"standard",i=Number(e.DEVFLOW_HOOK_ACK_BUDGET_MS??o.acknowledgementBudgetMs??t.acknowledgementBudgetMs),s=Number.isSafeInteger(i)&&i>0?Math.min(i,5e3):mr,a=new Set([...Re(t.disabledHandlers),...Re(o.disabledHandlers),...Re(e.DEVFLOW_DISABLED_HOOK_HANDLERS?.split(","))].map(gr).filter(c=>!!c));return {profile:r,acknowledgementBudgetMs:s,disabledHandlers:a}}async function K(n,e,t,o){let r,i=new Promise(s=>{r=setTimeout(()=>{console.error(`[devflow-hook] ${n} exceeded ${e}ms acknowledgement budget`),s(o());},e),r.unref();});try{return await Promise.race([Promise.resolve().then(t),i])}finally{r&&clearTimeout(r);}}async function Jt(n,e=process.env){let t=e.DEVFLOW_HOST_ADAPTER??(e.CLAUDE_PROJECT_DIR||e.CLAUDE_PLUGIN_ROOT||e.CLAUDE_CODE_ENTRYPOINT?"claude-code":void 0),o=await selectHostAdapter({projectRoot:n,env:e,explicitHost:t});if(o.status==="failed")throw new Error(`host_adapter_selection_failed:${o.code}:${o.reason}`);let r=await o.adapter.capabilities({projectRoot:n,env:e,explicitHost:t});return {hostId:o.adapter.id,capabilities:new Map(r.map(i=>[i.capability,i])),profiles:new Set(o.adapter.hooks?.profileSupport??[])}}function Gt(n,e,t){let o=yr(n,e.profile);if(!t.profiles.has(e.profile))return {enabled:false,policy:"fail_open",reason:`hook_profile_${e.profile}_unsupported_by_${t.hostId}`,fallback:"host_event_continues_without_devflow_handler"};if(e.disabledHandlers.has(n))return {enabled:false,policy:"fail_open",reason:"hook_handler_disabled",fallback:"host_event_continues_without_devflow_handler"};if(e.profile==="minimal"&&!hr.has(n))return {enabled:false,policy:"fail_open",reason:"hook_handler_not_in_minimal_profile",fallback:"critical_receipts_only"};let r=fr[n];if(!r)return {enabled:true,policy:o};let i=t.capabilities.get(r);return !i||i.status!=="supported"?{enabled:false,policy:"fail_open",reason:i?.reason??`${r}_unsupported_by_${t.hostId}`,fallback:i?.fallback??"host_event_continues_without_native_hook_processing"}:{enabled:true,policy:o}}var hr=new Set(["session-start","user-prompt-submit","stop","session-end","memory-snapshot"]),fr={"session-start":"hooks.session_start","user-prompt-submit":"hooks.prompt_submit","pre-tool-use":"hooks.pre_tool_use","post-tool-use":"hooks.post_tool_use","post-tool-use-failure":"hooks.post_tool_use",stop:"hooks.stop","session-end":"hooks.session_end"};function yr(n,e){return n==="user-prompt-submit"||n==="stop"||n==="session-end"?"enqueue_and_open":n==="pre-tool-use"&&e==="strict"?"fail_closed":"fail_open"}function qt(n){if(!existsSync(n))return {};try{let t=JSON.parse(readFileSync$1(n,"utf8")).hooks;return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return {}}}function ke(n){return n==="minimal"||n==="standard"||n==="strict"?n:void 0}function Re(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):[]}function gr(n){let e=n.trim().replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase();return ({sessionstart:"session-start",userpromptsubmit:"user-prompt-submit",pretooluse:"pre-tool-use",posttooluse:"post-tool-use",posttoolusefailure:"post-tool-use-failure",sessionend:"session-end",precompact:"pre-compact",memorysnapshot:"memory-snapshot"}[e.replace(/-/g,"")]??e)||void 0}var jr=600*1e3,Fr=2e3,Nr=250,$r=2e3,Lr=1e3,Bt=1024*1024,Ur=2*1024*1024,Hr=6e4,Wr=100,qr={Agent:"get_project_context",Bash:"get_project_context",Glob:"get_project_context",Grep:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function zr(n){switch(n){case "Read":case "Glob":return "file_read";case "Write":case "Edit":case "NotebookEdit":return "file_write";case "Bash":return "bash_command";case "Agent":return "subagent";case "Skill":return "skill_invoke";default:return "tool_use"}}function Ie(n){return typeof n=="string"&&n.trim().length>0}function Jr(n,e,t=process.env,o){if(!n.startsWith("mcp__devflow__"))return e;let r=e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{};if(Ie(r.projectRoot))return r;let i=Ie(t.CLAUDE_PROJECT_DIR)?t.CLAUDE_PROJECT_DIR:o;return Ie(i)&&(r.projectRoot=i),r}var Te=class{constructor(e,t){this.socketIdentity=null;this.pidIdentity=null;this.server=null;this.activeSessionIds=new Set;this.eventMap=[];this.idleTimer=null;this.telemetryFlushTimer=null;this.successfulTelemetryOperations=0;this.shutdownPromise=null;this.explicitMemoryGate=null;this.memoryWarmup=null;this.explicitIntentFlush=null;this.hostRuntime=null;this.memoryTurnSpoolTimer=null;this.sessionFinalizeSpoolTimer=null;this.projectRoot=e,this.socketPath=getDaemonSocketPath(e),this.pidPath=getDaemonPidPath(e),this.telemetry=new b,this.runtimeStore=new I(this.projectRoot),this.serverManager=new A(e),this.hookRuntime=zt(e),this.initialSessionInput=t,this.workRuntime=new B({projectRoot:e,handlers:{"memory.explicit_commit":async({item:o})=>{await this.persistMemoryTurnItem(o.payload);},"memory.turn_capture":async({item:o})=>{await this.persistMemoryTurnItem(o.payload);},"session.bootstrap":async({item:o})=>{await this.bootstrapSessionWork(o.payload);},"memory.vector_backfill":async()=>{await(await this.getMemoryGate()).backfillObservationVectors({batchSize:32});},"memory.turn_distill":async({item:o})=>{await x({projectRoot:this.projectRoot,sessionId:o.sessionId,trigger:"session_end",memory:await this.getMemoryGate()});},"session.finalize":async({item:o})=>{await this.finalizeSessionWork(o.payload,o.id);},"telemetry.reconcile":async()=>{await this.flushTelemetry();}}});}async start(){this.hostRuntime=await Jt(this.projectRoot),mkdirSync(dirname(this.socketPath),{recursive:true,mode:448}),await this.cleanStaleStartupResources(),this.server=createServer(e=>this.handleConnection(e));try{await this.listen(),this.writePidFile(),nt(this.projectRoot,process.pid);}catch(e){throw await this.closeServer(),this.cleanupOwnedResources(),e}if(this.server.on("error",e=>{console.error("[devflow-daemon] Server error:",e.message);}),console.error("[devflow-daemon] Listening on",this.socketPath),await this.telemetry.flushAndAggregate(),this.telemetryFlushTimer=setInterval(()=>{this.flushTelemetry();},Hr),this.telemetryFlushTimer.unref(),this.workRuntime.start(),this.initialSessionInput){let e=this.initialSessionInput;this.initialSessionInput=void 0,this.handleRequest({type:"session-start",input:e});}this.drainSessionStartSpool(),this.scheduleMemoryTurnSpoolDrain(0),this.scheduleSessionFinalizeSpoolDrain(0),this.resetIdleTimer();}handleConnection(e){let t="",o=false,r=false,i=0,s=Promise.resolve();e.setEncoding("utf8");let a=()=>{r||(r=true,clearTimeout(c),e.destroy());},c=setTimeout(()=>{a();},Fr).unref(),l=async u=>{if(!r){r=true,clearTimeout(c);try{await this.writeFrame(e,u);}catch{}finally{e.destroy();}}};e.on("data",u=>{if(r)return;t+=u;let p=t.split(`
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
${r}`:r;}t.tool_name.startsWith("mcp__devflow__")&&(m.hookSpecificOutput.updatedInput=t.tool_input);let f={...t.tool_input};delete f._devflow_session_id,delete f._devflow_execution_id,delete f._devflow_tool_use_id;let d=i?.executionId??o,h={eventId:D(o,t.tool_use_id),executionId:d,sessionId:o,projectRoot:this.projectRoot,toolUseId:t.tool_use_id,timestamp:Date.now(),toolName:t.tool_name,toolType:s?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:s,mcpToolName:a,mcpEnforced:s&&l==="context_gathering",mcpFallback:!s&&l==="context_gathering",kind:zr(t.tool_name),input:f,duration:0,blocked:m&&m.hookSpecificOutput?.permissionDecision==="deny"},g=await this.telemetry.sendEvent({...h,blockReason:h.blocked?u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED":void 0,error:h.blocked?u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED":void 0});return g&&!h.blocked&&(this.eventMap.push({toolName:t.tool_name,toolUseId:t.tool_use_id,eventId:g,sessionId:o,timestamp:h.timestamp}),this.noteTelemetryOperation()),g&&h.blocked&&await this.telemetry.completeEvent({eventId:g,sessionId:o,error:u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-h.timestamp,completedAt:Date.now()}),m}catch{return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}}trackSession(e){let t=e?.trim()||(this.activeSessionIds.size===1?[...this.activeSessionIds][0]:"");if(!t)throw new Error("session_id_required");return this.registerSession(t),t}registerSession(e){this.activeSessionIds.has(e)||(this.activeSessionIds.size===0&&F(this.projectRoot,{bypassCount:0}),this.activeSessionIds.add(e),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null),this.serverManager.addRef(e),this.telemetry.sendSessionStart(e,this.projectRoot,Date.now()).catch(()=>{})),this.runtimeStore.registerSession(e);}startSkillExecution(e,t){let o=this.runtimeStore.get(e)?.executionId,r=this.runtimeStore.startExecution(e,t,je(t));return r.executionId&&r.executionId!==o&&this.telemetry.sendExecutionStart(r.executionId,e,t,r.lastActivityAt,this.projectRoot,r.requiredMcpTools).catch(()=>{}),formatSkillRuntimeOverlay(createSkillRuntimeOverlay(t,this.projectRoot))}async handleSessionStart(e){try{let t=JSON.parse(e);if(typeof t.session_id!="string"||!t.session_id.trim())return {error:"session_id_required"};let o=t.session_id.trim();this.registerSession(o);let r=`session-start:${createHash("sha256").update(`${this.projectRoot}\0${o}`).digest("hex").slice(0,24)}`,i=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50}),s="pending";try{s=i.enqueueWork({idempotencyKey:r,kind:"session.bootstrap",projectRoot:this.projectRoot,sessionId:o,payload:{sessionId:o}}).state;}finally{i.close();}return {status:s==="completed"?"completed":"accepted",receiptId:r,workState:s}}catch{return {error:"session_start_invalid"}}}popEventFromMap(e,t,o){let r=this.eventMap.filter(s=>s.toolName===e&&s.sessionId===t);if(r.length===0)return null;let i=o?r.find(s=>s.toolUseId===o):r.sort((s,a)=>s.timestamp-a.timestamp)[0];return i?(this.eventMap=this.eventMap.filter(s=>s.eventId!==i.eventId),i):null}enforcePostToolUse(e){if(!qr[e])return null;let t=Math.floor(Date.now()/1e3),o=se(this.projectRoot,s=>t-(s.lastMcpCall??0)<30?s:{...s,bypassCount:(s.bypassCount??0)+1});if(!o.applied||!o.changed)return null;let r=o.receipt.bypassCount??0;if(r===1)return null;let i;switch(e){case "Agent":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u4F7F\u7528\u4E86 Agent \u5B50\u4EE3\u7406\u6267\u884C\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Bash":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Bash \u547D\u4EE4\u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Glob":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Glob \u5339\u914D\u6587\u4EF6\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Grep":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Grep \u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "WebSearch":case "WebFetch":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86\u7F51\u7EDC\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_knowledge MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;default:i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u8BF7\u4F7F\u7528 DevFlow MCP \u5DE5\u5177\u66FF\u4EE3\u76F4\u63A5\u8C03\u7528\u3002`;}return r>=3?i=`${i} \u5DF2\u8FBE\u5230\u6700\u5927\u8FDD\u89C4\u6B21\u6570\uFF0C\u540E\u7EED\u7ED5\u8FC7\u5C06\u88AB\u786C\u963B\u6B62\u3002`:r>=2?i=`${i} \u4E0B\u6B21\u8FDD\u89C4\u5C06\u88AB\u963B\u6B62\u3002`:i=`${i} \u8BF7\u7ACB\u5373\u7EA0\u6B63\u3002`,i}async handlePostToolUse(e){if(!e)return null;let t;try{t=JSON.parse(e);}catch{return null}let o=t.tool_name||"",r=t.tool_input||{},i=t.tool_response,s=this.trackSession(t.session_id);if(o==="Skill"){let v=r?.skill,k=v?q(v):null;k&&(this.startSkillExecution(s,k),F(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0}));}o.startsWith("mcp__")&&new E(this.projectRoot).recordMcpCall();let a=this.popEventFromMap(o,s,t.tool_use_id);if(a){let v=typeof i=="string"?i:JSON.stringify(i),k=v.length>5e3?{_truncated:true,_originalSize:v.length,text:v.slice(0,5e3)}:i,Kt=Date.now()-a.timestamp;await this.telemetry.completeEvent({eventId:a.eventId,sessionId:s,output:k,duration:Kt,completedAt:Date.now()})&&this.noteTelemetryOperation();}let c=typeof i=="object"&&i!==null?i:null,l=c?.exitCode,u=c?.stderr,p=/^\s*(ls|cat|pwd|cd|echo|head|tail|wc|which|whoami|date|env|printenv|id|hostname|uname)\b/,m=r.command||"",f=JSON.stringify(i),d=Buffer.byteLength(f,"utf8"),y=this.countResults(i),h,g,S=true;if(o.startsWith("mcp__"))h="mcp_call",g={mcpTool:o.replace(/^mcp__[^_]+__/,""),query:r.query??null,resultCount:y,resultSizeBytes:d};else if(o==="Read"||o==="Write"||o==="Edit")h=o==="Read"?"file_read":"file_write",g={filePath:r.file_path??null,fileContentSize:d};else if(o==="Bash"){let v=p.test(m),k=l!==void 0&&l!==0;S=!v||k,h=k?"bash_error":"bash_command",g={command:m||o,exitCode:l??null,stderr:u??null};}else o==="Agent"?(h="subagent",g={subagentType:r.subagent_type??null,description:typeof r.description=="string"?r.description.slice(0,200):null}):o==="WebSearch"||o==="WebFetch"?(h=o==="WebSearch"?"web_search":"web_fetch",g={query:typeof r.query=="string"?r.query.slice(0,200):null}):(S=false,h="tool_use",g={});if(S){let v={id:t.tool_use_id?`memory:${D(s,t.tool_use_id)}`:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:s,tool:o,kind:h,payload:g,command:m||void 0,exitCode:l,stderr:u??void 0,durationMs:0,createdAt:Date.now()};this.postMemoryEvent(v);}let w=this.enforcePostToolUse(o);return w?(console.error("[devflow-daemon] Enforcement:",w),{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:JSON.stringify(w)}}):null}async handlePostToolUseFailure(e){let t;try{t=JSON.parse(e);}catch{return null}let o=this.trackSession(t.session_id),r=t.tool_name??"unknown",i=t.error??`${r} failed`,s=this.popEventFromMap(r,o,t.tool_use_id);if(s)await this.telemetry.completeEvent({eventId:s.eventId,sessionId:o,error:i,duration:Date.now()-s.timestamp,completedAt:Date.now()})&&this.noteTelemetryOperation();else {let a=D(o,t.tool_use_id);await this.telemetry.sendEvent({eventId:a,executionId:this.runtimeStore.get(o)?.executionId??o,sessionId:o,projectRoot:this.projectRoot,toolUseId:t.tool_use_id,timestamp:Date.now(),toolName:r,toolType:r.startsWith("mcp__")?"mcp":"direct",isMcpTool:r.startsWith("mcp__"),mcpToolName:r.startsWith("mcp__")?r.replace(/^mcp__[^_]+__/,""):void 0,mcpEnforced:false,mcpFallback:false,kind:"error",input:t.tool_input??{},duration:0,error:i,blocked:false});}return this.postMemoryEvent({id:t.tool_use_id?`memory:${D(o,t.tool_use_id)}`:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:o,tool:r,command:typeof t.tool_input?.command=="string"?t.tool_input.command:r,exitCode:-1,stderr:i,durationMs:s?Date.now()-s.timestamp:0,createdAt:Date.now(),kind:r==="Bash"?"bash_error":"tool_use",payload:{command:t.tool_input?.command??r,exitCode:-1,stderr:i}}),null}countResults(e){if(!e)return 0;let t=e;if(typeof e=="string")try{t=JSON.parse(e);}catch{return 1}let o=t,r=["files","results","data","result","memories","nodes","chunks","findings","symbols"],i=Array.isArray(o.data)?o.data:o.structuredContent??o;if(Array.isArray(i))return i.length;if(typeof i=="object"&&i!==null){let s=i,a=0,c=false;for(let l of r)Array.isArray(s[l])&&(c=true,a+=s[l].length);for(let[,l]of Object.entries(s))l&&typeof l=="object"&&!Array.isArray(l)&&(a+=this.countResults(l));return a>0?a:c?0:Object.keys(s).length>0?1:0}return 0}async postMemoryEvent(e){He(`/api/memory/session-events?rootPath=${encodeURIComponent(this.projectRoot)}`,e);try{await(await this.getMemoryGate()).recordEvent(e);}catch(t){console.error("[devflow-daemon] Local memory event write failed:",t.message);}}async getMemoryGate(){let e=this.explicitMemoryGate??=new MemoryGate(this.projectRoot);return this.memoryWarmup??=e.forceWarmUp().catch(t=>{throw this.memoryWarmup=null,t}),await this.memoryWarmup,e}async handleUserPromptSubmit(e){let t=[];try{let o=JSON.parse(e),r=typeof o.prompt=="string"?o.prompt:"",i=typeof o.session_id=="string"&&o.session_id.trim()?this.trackSession(o.session_id):null,s=kt(r),a=!1;if(r.trim()&&i)try{let c=fe({projectRoot:this.projectRoot,sessionId:i,prompt:r});if(c){let l=c;if(c.explicitContent&&c.turn.status==="pending")try{l=await ye({projectRoot:this.projectRoot,payload:{operation:"commit_explicit",turnId:c.turn.turnId,eventId:c.turn.eventId,sessionId:i,prompt:r.trim().slice(0,4e3),explicitContent:c.explicitContent,createdAt:c.turn.createdAt},memory:await this.getMemoryGate()});}catch(u){console.error("[devflow-daemon] Explicit memory commit deferred:",u.message);}t.push(l.additionalContext),a=l.skipSkillRouting;}}catch(c){a=!!W(r);try{let u=Ft(this.projectRoot,{sessionId:i,prompt:r,createdAt:Date.now()});t.push(`DevFlow memory turn status=accepted; durable=true; receiptId=${u}; canonicalMemory=false; SQLite queue replay pending. Do not claim memory success without a canonical receipt.`),this.scheduleMemoryTurnSpoolDrain(250),console.error("[devflow-daemon] Memory turn spooled after database contention:",c.message);}catch(u){t.push("DevFlow memory turn status=degraded; durable=false; no canonical receipt exists. Do not claim memory success."),console.error("[devflow-daemon] Memory turn persistence unavailable:",u.message);}}if(i&&s&&!a){let c=this.startSkillExecution(i,s.skillName);c&&t.push(c);}}catch{}return {hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow",...t.length?{additionalContext:t.join(`
|
|
10
|
-
`)}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`);}};if(process.env.DEVFLOW_HOOK_DAEMON_DISABLE_AUTOSTART!=="1"){let n=process.argv[2]||process.env.CLAUDE_PROJECT_DIR||process.cwd(),e=new Te(n,process.argv[3]);process.once("SIGTERM",()=>{e.shutdown();}),process.once("SIGINT",()=>{e.shutdown();}),e.start().catch(t=>{console.error("[devflow-daemon] Failed to start:",t),process.exit(1);});}export{Te as HookDaemon,Jr as injectProjectRootIfMissing};
|
|
15
|
+
`,{mode:384}),renameSync(e,n.path);}function fe(n){let e=n.trim().replace(/^\//,"");if(!e.startsWith("devflow:"))return null;let t=e.slice(8).replace(/^devflow-/,"");return /^[a-z0-9][a-z0-9-]*$/i.test(t)?`devflow:${t.toLowerCase()}`:null}function Mn(n){let e=n.trimStart().match(/^\/(devflow:[a-z0-9][a-z0-9-]*)\b/i);if(!e)return null;let t=fe(e[1]);return t?{rawName:e[1],skillName:t}:null}function Y(n,e){return e?`evt_tool_${createHash$1("sha256").update(`${n}\0${e}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var Q=1,Ke="memory-snapshot-v1.json",Un=512*1024,Wn=256*1024,zn=2e3,Oi=500,Ai=10,Pi=240,ji=300*1e3,Fi=720*60*60*1e3,qn=2147483647,$i=100,An=250,Ni=3e4,Li=10,he=new Map;function Jn(n){return n.currentUid===void 0?{ownerSafe:true,modeSafe:true}:{ownerSafe:n.ownerUid===n.currentUid,modeSafe:(n.mode&18)===0}}function D(n){return resolve(n)}function $(n){return createHash("sha256").update(D(n)).digest("hex").slice(0,16)}function Ye(n,e={}){let t=$(n),o=e.stateRoot?join(e.stateRoot,t):getProjectStateDir(D(n));return join(o,Ke)}function ye(n,e){let o=(n instanceof Error?n.message:"").replace(/[\r\n\t]+/gu," ").trim().slice(0,160);return o?`${e}:${o}`:e}function Xe(n,e){return Array.isArray(n)&&n.length<=e&&n.every(t=>typeof t=="string"&&t.length>0&&t.length<=512)}function Hi(n){if(!n||typeof n!="object"||Array.isArray(n))return false;let e=n;return typeof e.id=="string"&&e.id.length>0&&e.id.length<=512&&typeof e.kind=="string"&&e.kind.length>0&&e.kind.length<=128&&(e.family===void 0||typeof e.family=="string"&&e.family.length>0&&e.family.length<=256)&&(e.entity===void 0||typeof e.entity=="string"&&e.entity.length>0&&e.entity.length<=256)&&Xe(e.memoryIds,100)&&(e.status==="withheld"||e.status==="resolved")&&(e.summary===void 0||typeof e.summary=="string"&&e.summary.length<=2e3)}function Ui(n){if(!n||typeof n!="object"||Array.isArray(n))return false;let e=n;return typeof e.reason=="string"&&e.reason.length>0&&e.reason.length<=512&&(e.stale===void 0||typeof e.stale=="boolean")}function Qe(n,e,t){if(!n||typeof n!="object"||Array.isArray(n))return null;let o=n,r=D(e),i=$(r),s=o.generation===void 0?0:o.generation;return o.version!==Q||o.projectRoot!==r||o.projectHash!==i||typeof o.markdown!="string"||Buffer.byteLength(o.markdown,"utf8")>Wn||!Xe(o.memoryIds,zn)||!Array.isArray(o.conflicts)||o.conflicts.length>Oi||!o.conflicts.every(Hi)||typeof o.generatedAt!="number"||!Number.isFinite(o.generatedAt)||o.generatedAt<0||o.generatedAt>t+ji||!Number.isInteger(s)||s<0||s>qn||!["ready","pending","degraded","disabled"].includes(String(o.status))||o.degradation!==void 0&&!Ui(o.degradation)?null:{...o,generation:s}}function Ze(n,e,t,o,r=0){let i=D(n);return {version:Q,projectRoot:i,projectHash:$(i),markdown:"",memoryIds:[],conflicts:[],generatedAt:o,generation:r,status:e,degradation:{reason:t}}}function j(n,e={}){let t=e.now??Date.now(),o=Ye(n,e),r;try{r=openSync$1(o,constants.O_RDONLY|constants.O_NOFOLLOW);let i=fstatSync$1(r);if(!i.isFile()||i.size<=0||i.size>Un)throw new Error("cache_size_invalid");let s=Jn({...typeof process.getuid=="function"?{currentUid:process.getuid()}:{},ownerUid:i.uid,mode:i.mode});if(!s.ownerSafe)throw new Error("cache_owner_invalid");if(!s.modeSafe)throw new Error("cache_permissions_unsafe");let a=JSON.parse(readFileSync$1(r,"utf8")),c=Qe(a,n,t);if(!c)throw new Error("cache_schema_invalid");return c.status==="ready"&&t-c.generatedAt>Fi?{snapshot:{...c,status:"degraded",degradation:{reason:"cache_stale",stale:!0}},source:"cache",valid:!0,stale:!0}:{snapshot:c,source:"cache",valid:!0,stale:!1}}catch(i){let a=i.code==="ENOENT";return {snapshot:Ze(n,a?"pending":"degraded",a?"cache_missing":ye(i,"cache_invalid"),t),source:"none",valid:false,stale:false}}finally{if(r!==void 0)try{closeSync$1(r);}catch{}}}function Pn(n){if(!Number.isInteger(n)||n<0||n>=qn)throw new Error("memory_snapshot_generation_exhausted");return n+1}function Wi(n){let e=dirname$1(n);mkdirSync$1(e,{recursive:true,mode:448}),chmodSync(e,448);}function zi(n){Wi(n);let e=`${n}.lock`,t={pid:process.pid,createdAt:Date.now(),token:randomUUID$1()},o=JSON.stringify(t),r;try{return r=openSync$1(e,"wx",384),writeFileSync$1(r,o),fsyncSync(r),{fd:r,path:e,contents:o}}catch(i){if(r!==void 0){try{closeSync$1(r);}catch{}try{unlinkSync$1(e);}catch{}}if(i.code==="EEXIST")return null;throw i}}function qi(n){if(!n||typeof n!="object"||Array.isArray(n))return false;let e=n;return Number.isInteger(e.pid)&&Number(e.pid)>0&&typeof e.createdAt=="number"&&Number.isFinite(e.createdAt)&&typeof e.token=="string"&&e.token.length>0}function Ji(n){try{return process.kill(n,0),!1}catch(e){return e.code==="ESRCH"}}function Bi(n){return !n.canonicalCachePath||!n.directoryIsSafe||!n.lockIsRegularFile||!n.metadataValid||!n.contentsUnchanged||!n.ownerDead&&!n.stale?false:n.currentUid!==void 0?n.directoryUid===n.currentUid&&n.lockUid===n.currentUid:true}function Gi(n){return isAbsolute(n)&&resolve(n)===n&&basename(n)===Ke&&/^[a-f0-9]{16}$/u.test(basename(dirname$1(n)))}function Vi(n,e){let t=`${n}.lock`;try{let o=lstatSync$1(dirname$1(n)),r=lstatSync$1(t),i=readFileSync$1(t,"utf8"),s=null;try{let f=JSON.parse(i);qi(f)&&(s=f);}catch{}let a=s?.createdAt??r.mtimeMs,c=Date.now()-a>e,l=s?Ji(s.pid):!1,u=readFileSync$1(t,"utf8")===i,d=typeof process.getuid=="function"?process.getuid():void 0,p=Jn({...d!==void 0?{currentUid:d}:{},ownerUid:o.uid,mode:o.mode});return Bi({canonicalCachePath:Gi(n),directoryIsSafe:o.isDirectory()&&!o.isSymbolicLink()&&p.modeSafe,lockIsRegularFile:r.isFile()&&!r.isSymbolicLink(),metadataValid:s!==null,ownerDead:l,stale:c,contentsUnchanged:u,...d!==void 0?{currentUid:d}:{},directoryUid:o.uid,lockUid:r.uid})?(unlinkSync$1(t),!0):!1}catch{return false}}function Ki(n){try{closeSync$1(n.fd);}catch{}try{readFileSync$1(n.path,"utf8")===n.contents&&unlinkSync$1(n.path);}catch{}}function Yi(n){return new Promise(e=>setTimeout(e,n))}function ze(n,e,t,o){let r=Number.isFinite(n)?Math.floor(n):e;return Math.min(o,Math.max(t,r))}async function Xi(n,e){let t=ze(e.lockTimeoutMs,$i,0,An),o=ze(e.lockRetryMs,Li,1,An),r=ze(e.lockStaleMs,Ni,0,Number.MAX_SAFE_INTEGER),i=Date.now()+t;for(;;){let s=zi(n);if(s)return s;if(Vi(n,r))continue;let a=i-Date.now();if(a<=0)throw new Error("memory_snapshot_cache_lock_timeout");await Yi(Math.min(o,a));}}async function jn(n,e,t){let o=await Xi(n,e);try{return await t()}finally{Ki(o);}}function Fn(n,e,t,o){let r=o.now??Date.now(),i=D(n),s={version:Q,projectRoot:i,projectHash:$(i),markdown:e.markdown,memoryIds:e.memoryIds??[],conflicts:e.conflicts??[],generatedAt:r,generation:t,status:e.status??"ready",...e.degradation?{degradation:e.degradation}:{}};if(!Qe(s,n,r))throw new Error("memory_snapshot_payload_invalid");let a=JSON.stringify(s);if(Buffer.byteLength(a,"utf8")>Un)throw new Error("memory_snapshot_cache_too_large");let c=Ye(n,o),l=dirname$1(c);mkdirSync$1(l,{recursive:true,mode:448}),chmodSync(l,448);let u=join(l,`.${Ke}.${process.pid}.${randomUUID$1()}.tmp`),d;try{d=openSync$1(u,"wx",384),writeFileSync$1(d,a),fsyncSync(d),closeSync$1(d),d=void 0,chmodSync(u,384),renameSync(u,c),chmodSync(c,384);let p;try{p=openSync$1(l,"r");try{fsyncSync(p);}catch{}}finally{p!==void 0&&closeSync$1(p);}return s}finally{if(d!==void 0)try{closeSync$1(d);}catch{}rmSync$1(u,{force:true});}}function Qi(n,e){let o=(he.get(n)??Promise.resolve()).catch(()=>{}).then(e),r=o.then(()=>{},()=>{});return he.set(n,r),o.finally(()=>{he.get(n)===r&&he.delete(n);})}function qe(n,e,t,o,r){return n.valid?n.snapshot.generation>r?{...n,persisted:false}:{...n,snapshot:{...n.snapshot,status:"degraded",degradation:{reason:t,stale:n.stale||void 0}},persisted:false}:{snapshot:Ze(e,"degraded",t,o,r),source:"none",valid:false,stale:false,persisted:false}}async function et(n){let e=Ye(n.projectRoot,n.cacheOptions);return Qi(e,async()=>{let t=j(n.projectRoot,n.cacheOptions),o=t.valid?t.snapshot.generation:0,r;try{r=await n.load();}catch(i){let s=ye(i,`refresh_failed:${n.reason}`);try{return await jn(e,n.cacheOptions??{},()=>{let a=j(n.projectRoot,n.cacheOptions);if(a.valid)return qe(a,n.projectRoot,s,n.cacheOptions?.now??Date.now(),o);let c=Pn(o),l=Ze(n.projectRoot,"degraded",s,n.cacheOptions?.now??Date.now(),c);return {snapshot:Fn(n.projectRoot,l,c,n.cacheOptions??{}),source:"cache",valid:!0,stale:!1,persisted:!0}})}catch(a){let c=j(n.projectRoot,n.cacheOptions);return qe(c,n.projectRoot,ye(a,s),n.cacheOptions?.now??Date.now(),o)}}try{return await jn(e,n.cacheOptions??{},()=>{let i=j(n.projectRoot,n.cacheOptions);if(i.valid&&i.snapshot.generation>o)return {...i,persisted:!1};let s=Pn(Math.max(o,i.valid?i.snapshot.generation:0));return {snapshot:Fn(n.projectRoot,r,s,n.cacheOptions??{}),source:"cache",valid:!0,stale:!1,persisted:!0}})}catch(i){let s=j(n.projectRoot,n.cacheOptions);return qe(s,n.projectRoot,ye(i,`refresh_commit_failed:${n.reason}`),n.cacheOptions?.now??Date.now(),o)}})}async function Se(n){return et({projectRoot:n.projectRoot,reason:n.reason,cacheOptions:n.cacheOptions,load:async()=>{if(n.injectConfig===false)return {status:"disabled",markdown:"",memoryIds:[],conflicts:[]};let e=typeof n.injectConfig=="object"?n.injectConfig:{},t=Number.isFinite(e.topN)?Math.max(0,Math.floor(e.topN)):10,o=Number.isFinite(e.budgetTokens)?Math.max(1,Math.floor(e.budgetTokens)):800,r=await n.memory.getAll({purpose:"session_bootstrap",budgetTokens:o,limit:t}),s=Number.isInteger(r.truncatedCount)&&r.truncatedCount>=0?r.truncatedCount:null,a=r.memories.length===0&&s!==0,c=s!==null&&s>0?"snapshot_results_truncated":"snapshot_truncation_unknown",l=(r.conflicts??[]).map(d=>({id:d.id,kind:d.kind,family:d.family,entity:d.entity,memoryIds:d.memoryIds,status:d.status,...d.summary?{summary:d.summary}:{}})),u=a?`## Project memory
|
|
16
|
+
DevFlow memory snapshot=degraded; reason=${c}. Memory result completeness is not authoritative; do not conclude that the project has no memories.`:r.memories.length===0&&l.length>0?`## Project memory
|
|
17
|
+
${l.length} explicit preference conflict(s) are withheld from automatic guidance; an explicit choice is required.`:r.memories.length===0?`## Project memory
|
|
18
|
+
\u672C\u9879\u76EE\u6682\u65E0\u8BB0\u5FC6`:`## Project memory (auto-injected, ${r.memories.length} items, ${r.tokenCount} tokens)
|
|
19
|
+
${r.memories.map(d=>`- **${d.title||d.type}**: ${d.content} (confidence ${d.confidence.toFixed(2)}, ${d.source})`).join(`
|
|
20
|
+
`)}`;return {status:a?"degraded":"ready",markdown:u,memoryIds:r.memories.map(d=>d.id),conflicts:l,...a?{degradation:{reason:c}}:{}}}})}function Zi(n){if(!n)return true;try{return JSON.parse(readFileSync$1(n,"utf8")).sessionStart?.injectMemories??!0}catch{return true}}function es(n,e,t){if(!e.trim())return null;try{let o=JSON.parse(e);if(o.status!=="ok"&&o.status!=="degraded")return null;if(o.enabled===!1){let i=D(n);return {version:Q,projectRoot:i,projectHash:$(i),markdown:"",memoryIds:[],conflicts:[],generatedAt:t,generation:0,status:"disabled"}}let r=Qe(o.snapshot,n,t);if(r)return r;if(o.status==="ok"&&typeof o.markdown=="string"&&o.markdown.length>0&&Buffer.byteLength(o.markdown,"utf8")<=Wn){let i=D(n);return {version:Q,projectRoot:i,projectHash:$(i),markdown:o.markdown,memoryIds:Xe(o.memoryIds,zn)?o.memoryIds:[],conflicts:[],generatedAt:t,generation:0,status:"ready"}}}catch{}return null}function Je(n,e){return [...(n??e).replace(/[\r\n\t|]+/gu," ").trim()||e].slice(0,Pi).join("")}function ts(n){if(n.length===0)return "";let e=n.slice(0,Ai),t=e.map(o=>{let r=Je(o.family,"unknown"),i=Je(o.entity,"unknown"),s=Je(o.summary,"Explicit choice required.");return `- family=${r}; entity=${i}; status=${o.status}; summary=${s}`});return n.length>e.length&&t.push(`- ${n.length-e.length} additional conflict(s) omitted from SessionStart output.`),`## Withheld preference conflicts (${n.length})
|
|
21
|
+
${t.join(`
|
|
22
|
+
`)}`}function ns(n){let e=n.now??Date.now();if(Zi(n.configPath)===false)return "";let t=es(n.projectRoot,n.daemonResponse??"",e),o=t?{snapshot:t,source:"daemon"}:j(n.projectRoot,{...n.cacheOptions,now:e}),{snapshot:r}=o;if(r.status==="disabled")return `## Project memory
|
|
23
|
+
DevFlow memory snapshot=pending; source=${o.source}; reason=previous_snapshot_disabled. Memory availability is not yet known; do not conclude that the project has no memories.`;let i=new Date(r.generatedAt).toISOString(),s=r.degradation?.reason?`; reason=${r.degradation.reason}`:"",a=`DevFlow memory snapshot=${r.status}; source=${o.source}; generatedAt=${i}${s}.`,c=ts(r.conflicts);return r.markdown?[r.markdown,c,a].filter(Boolean).join(`
|
|
24
|
+
`):["## Project memory",c,`${a} Memory availability is not yet known; do not conclude that the project has no memories.`].filter(Boolean).join(`
|
|
25
|
+
`)}if(process.env.DEVFLOW_MEMORY_SNAPSHOT_CLI==="1"){let[,,n,e,t]=process.argv;n!=="session-start"||!e?process.exitCode=2:process.stdout.write(ns({projectRoot:e,configPath:t,daemonResponse:process.env.DEVFLOW_MEMORY_RESPONSE}));}var rs=/^(?:ok(?:ay)?|yes|no|thanks?|thank you|continue|好的?|可以|行|是|否|谢谢|继续|收到|明白了?)[.!。!\s]*$/iu;function is(n){let e=n.trim();return e.length>0&&!rs.test(e)}function ss(n,e,t=Date.now()){let o=createHash("sha256").update(e.trim()).digest("hex"),r=createHash("sha256").update(`${n}\0${t}\0${o}`).digest("hex").slice(0,24);return {turnId:`turn:${r}`,eventId:`memory-turn:${r}`,promptHash:o,createdAt:t}}function ot(n,e,t=[]){return `memory-receipt:${createHash("sha256").update(`${n}\0${e}\0${[...t].sort().join("\0")}`).digest("hex").slice(0,24)}`}function rt(n){return `DevFlow memory decision required for ${n.turnId}. Before the final response, semantically decide whether this turn contains durable project knowledge. Call mcp__devflow__memory_commit_turn with evidence-bound candidates, or mcp__devflow__memory_skip_turn with a concrete reason. Do not claim memory success without a canonical receipt.`}function tt(n){let e=n.memoryIds.length>0?n.memoryIds.join(","):"none",t=n.status==="committed"?"accepted":n.status,o=n.status==="committed"?"; indexStatus=pending":"",r=n.status==="committed"&&n.source==="explicit_intent"?"; memoryOnlyCompleted=true; skipProjectContext=true; skipMemoryTool=true":"",i=n.status==="committed"&&n.source==="explicit_intent"?" This explicit-memory request is complete. Return the canonical receipt to the user. Do not call a memory tool, project-context tool, domain tool, or native memory write for this request.":"";return `DevFlow canonical memory receipt: status=${t}; receiptId=${n.receiptId??"missing"}; turnId=${n.turnId}; memoryIds=${e}; source=${n.source??"unknown"}${o}${r}.`+i}function Bn(n,e,t){let o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});try{let r=o.getPendingMemoryTurn(n,e);return !r||!o.markMemoryTurnStopPrompted(r.turnId)?null:{decision:"block",reason:rt(r)}}finally{o.close();}}function it(n){if(!is(n.prompt))return null;let e=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});try{let t=n.prompt.trim().slice(0,4e3),o=createHash("sha256").update(t).digest("hex"),r=e.listMemoryTurns(n.projectRoot,n.sessionId,5).find(l=>l.promptHash===o&&Date.now()-l.createdAt<1e4),i=r?{turnId:r.turnId,eventId:r.eventId,promptHash:r.promptHash,createdAt:r.createdAt}:ss(n.sessionId,t),s=r??e.beginMemoryTurn({...i,projectRoot:n.projectRoot,sessionId:n.sessionId});if(s.status!=="pending")return {turn:s,additionalContext:tt(s),skipSkillRouting:s.source==="explicit_intent"};let a=me(t)??void 0,c=a?"commit_explicit":"capture_prompt";return e.enqueueWork({idempotencyKey:`memory-turn:${c}:${s.turnId}`,kind:a?"memory.explicit_commit":"memory.turn_capture",projectRoot:n.projectRoot,sessionId:n.sessionId,turnId:s.turnId,payload:{operation:c,turnId:s.turnId,eventId:s.eventId,sessionId:n.sessionId,prompt:t,explicitContent:a,createdAt:s.createdAt}}),{turn:s,explicitContent:a,additionalContext:a?`DevFlow explicit memory is durably queued for ${s.turnId}, but no canonical receipt exists yet. Do not claim that it was remembered.`:rt(s),skipSkillRouting:!!a}}finally{e.close();}}async function st(n){let{payload:e,memory:t,projectRoot:o}=n,r=openGlobalDevFlowDatabase();try{let i=r.getMemoryTurn(e.turnId);if(!i)throw new Error(`Memory turn ${e.turnId} does not exist`);if(i.status!=="pending")return {turn:i,additionalContext:tt(i),skipSkillRouting:i.source==="explicit_intent"};if(await t.recordUserMessage(e.prompt,e.sessionId,e.prompt.slice(0,200)),await t.recordEvent({id:e.eventId,sessionId:e.sessionId,tool:"UserPromptSubmit",kind:"user_message",payload:{prompt:e.prompt,turnId:e.turnId},createdAt:e.createdAt}),e.operation==="capture_prompt"||!e.explicitContent)return {turn:i,additionalContext:rt(i),skipSkillRouting:!1};let s=await t.saveExplicitMemoryIntent(e.explicitContent,e.sessionId,e.eventId),a=ot(i.turnId,"committed",[s.id]),c=r.commitMemoryTurn({turnId:i.turnId,receiptId:a,memoryIds:[s.id],source:"explicit_intent",reason:"explicit_user_request"});try{await t.enrichExplicitMemoryObservation(s.id);}catch(l){console.error("[devflow] Explicit memory enrichment deferred:",l.message),r.enqueueWork({idempotencyKey:`explicit-enrichment:${o}:${s.id}`,kind:"memory.explicit_enrichment",projectRoot:o,sessionId:e.sessionId,turnId:c.turnId,payload:{observationId:s.id},maxAttempts:20});}r.enqueueWork({idempotencyKey:`vector:${o}:${s.id}`,kind:"memory.vector_backfill",projectRoot:o,sessionId:e.sessionId,turnId:c.turnId,payload:{observationId:s.id},maxAttempts:20});try{await Se({projectRoot:o,memory:t,injectConfig:loadConfig(o).sessionStart?.injectMemories,reason:"explicit_memory_commit"});}catch(l){console.error("[devflow] Memory snapshot refresh failed after canonical commit:",l.message);}return {turn:c,explicitContent:e.explicitContent,additionalContext:tt(c),skipSkillRouting:!0}}finally{r.close();}}var ls=new Set(["Write","Edit","NotebookEdit"]),Gn="Claude native memory writes are disabled for this project. Use DevFlow explicit memory or mcp__devflow__memory_commit_turn so a canonical receipt is created.";function Qn(n){if(!ls.has(n.toolName))return null;let e=ds(n.toolInput);if(!e)return null;let t=us(e,n.projectRoot),o=resolve(n.projectRoot,".claude");if(Vn(t,o)&&basename(t).toLocaleUpperCase("en-US")==="MEMORY.MD")return Gn;let r=resolve(n.home??homedir(),".claude","projects");return Vn(t,r)&&relative(r,t).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?Gn:null}function ds(n){for(let e of ["file_path","notebook_path","path"]){let t=n[e];if(typeof t=="string"&&t.trim())return t.trim()}return null}function us(n,e){return resolve(isAbsolute(n)?n:resolve(e,n))}function Vn(n,e){let t=relative(e,n);return t===""||!t.startsWith(`..${sep}`)&&t!==".."&&!isAbsolute(t)}var ys=1024*1024;function to(n){let e=join(getProjectStateDir(n),"session-start-pending");mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=readFileSync$1(i,"utf8");if(Buffer.byteLength(s,"utf8")>ys)throw unlinkSync$1(i),new Error("session_start_spool_input_too_large");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),input:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function no(n){unlinkSync$1(n.path);}function oo(n){let e=n.path.replace(/\.claim-\d+$/u,"");try{renameSync(n.path,e);}catch{}}function io(n,e){let t=lo(n);mkdirSync$1(t,{recursive:true,mode:448});let o=`memory-turn-spool-${Date.now()}-${process.pid}-${randomUUID$1()}`,r=join(t,`${o}.json`),i=`${r}.tmp`;return writeFileSync$1(i,JSON.stringify({...e,prompt:e.prompt.trim().slice(0,4e3)}),{mode:384}),renameSync(i,r),o}function so(n){let e=lo(n);mkdirSync$1(e,{recursive:true,mode:448});let t=readdirSync$1(e).filter(s=>s.endsWith(".json")||/\.json\.claim-\d+$/u.test(s)).sort()[0];if(!t)return null;let o=join(e,t),r=/\.json\.claim-\d+$/u.test(t),i=r?o:`${o}.claim-${process.pid}`;if(!r)try{renameSync(o,i);}catch{return null}try{let s=JSON.parse(readFileSync$1(i,"utf8"));if(typeof s.sessionId!="string"||typeof s.prompt!="string"||typeof s.createdAt!="number")throw unlinkSync$1(i),new Error("memory_turn_spool_payload_invalid");return {receiptId:basename(t).replace(/\.json(?:\.claim-\d+)?$/u,""),payload:s,path:i}}catch(s){try{unlinkSync$1(i);}catch{}throw s}}function ao(n){unlinkSync$1(n.path);}function co(n){try{renameSync(n.path,n.path.replace(/\.claim-\d+$/u,""));}catch{}}function lo(n){return join(E(n),"memory-turn-pending")}var N=class extends Error{constructor(e,t){super(t),this.name="PermanentWorkError",this.category=e;}},Is=1e3,Es=3e4,xs=1,Ts=5*6e4,ke=class{constructor(e){this.timer=null;this.draining=null;this.stopped=true;this.projectRoot=e.projectRoot,this.handlers=e.handlers,this.pollIntervalMs=ut(e.pollIntervalMs,Is),this.leaseMs=ut(e.leaseMs,Es),this.batchSize=ut(e.batchSize,xs),this.owner=e.owner??`hook-daemon:${process.pid}:${randomUUID$1()}`,this.now=e.now??Date.now,this.random=e.random??Math.random,this.openDatabase=e.openDatabase??(()=>openGlobalDevFlowDatabase());}start(){this.stopped&&(this.stopped=false,this.schedule(0));}stop(){this.stopped=true,this.timer&&clearTimeout(this.timer),this.timer=null;}drainOnce(){return this.draining?this.draining:(this.draining=this.performDrain().finally(()=>{this.draining=null;}),this.draining)}schedule(e){this.stopped||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>{this.timer=null,this.drainOnce().catch(t=>console.error("[devflow-work] Drain failed:",uo(t))).finally(()=>this.schedule(this.pollIntervalMs));},e),this.timer.unref());}async performDrain(){let e=Object.keys(this.handlers);if(e.length===0)return 0;let t=this.openDatabase();try{let o=this.now();t.recoverExpiredWork(this.projectRoot,o);let r=t.leaseWork({projectRoot:this.projectRoot,owner:this.owner,kinds:e,limit:this.batchSize,leaseMs:this.leaseMs,now:o});for(let i of r)await this.processItem(t,i);return r.length}finally{t.close();}}async processItem(e,t){let o=this.handlers[t.kind];if(!o){e.deadLetterWork(t.id,this.owner,{category:"unsupported_work_kind",message:`No work handler is registered for ${t.kind}`});return}try{if(await o({item:t}),!e.completeWork(t.id,this.owner,this.now()))throw new Error(`Work lease was lost before completion: ${t.id}`)}catch(r){let i=Ms(r);if(r instanceof N){e.deadLetterWork(t.id,this.owner,i);return}let s=this.now()+Math.max(Ds(t.attempts,this.random()),i.retryAfterMs??0);if(i.retryWithoutAttempt){e.deferWork(t.id,this.owner,i,s);return}e.retryWork(t.id,this.owner,i,s);}}};function ut(n,e){return Number.isSafeInteger(n)&&n>0?n:e}function Ms(n){if(n instanceof N)return {category:n.category,message:n.message};let e=n&&typeof n=="object"?n:null;return {category:typeof e?.category=="string"?e.category:"runtime_error",message:uo(n),retryAfterMs:typeof e?.retryAfterMs=="number"&&Number.isFinite(e.retryAfterMs)?Math.max(0,e.retryAfterMs):void 0,retryWithoutAttempt:e?.retryWithoutAttempt===true}}function Ds(n,e){let t=Math.min(Ts,500*2**Math.max(0,n-1)),o=Math.floor(t*.2*Math.max(0,Math.min(1,e)));return t+o}function uo(n){return n instanceof Error?n.message:String(n)}var js=250;function fo(n,e=process.env){let t=mo(join(homedir(),".devflow","config.json")),o=mo(join(n,".devflow","config.json")),r=pt(e.DEVFLOW_HOOK_PROFILE)??pt(o.profile)??pt(t.profile)??"standard",i=Number(e.DEVFLOW_HOOK_ACK_BUDGET_MS??o.acknowledgementBudgetMs??t.acknowledgementBudgetMs),s=Number.isSafeInteger(i)&&i>0?Math.min(i,5e3):js,a=new Set([...mt(t.disabledHandlers),...mt(o.disabledHandlers),...mt(e.DEVFLOW_DISABLED_HOOK_HANDLERS?.split(","))].map(Ls).filter(c=>!!c));return {profile:r,acknowledgementBudgetMs:s,disabledHandlers:a}}async function Re(n,e,t,o){let r,i=new Promise(s=>{r=setTimeout(()=>{console.error(`[devflow-hook] ${n} exceeded ${e}ms acknowledgement budget`),s(o());},e),r.unref();});try{return await Promise.race([Promise.resolve().then(t),i])}finally{r&&clearTimeout(r);}}async function ho(n,e=process.env){let t=e.DEVFLOW_HOST_ADAPTER??(e.CLAUDE_PROJECT_DIR||e.CLAUDE_PLUGIN_ROOT||e.CLAUDE_CODE_ENTRYPOINT?"claude-code":void 0),o=await selectHostAdapter({projectRoot:n,env:e,explicitHost:t});if(o.status==="failed")throw new Error(`host_adapter_selection_failed:${o.code}:${o.reason}`);let r=await o.adapter.capabilities({projectRoot:n,env:e,explicitHost:t});return {hostId:o.adapter.id,capabilities:new Map(r.map(i=>[i.capability,i])),profiles:new Set(o.adapter.hooks?.profileSupport??[])}}function go(n,e,t){let o=Ns(n,e.profile);if(!t.profiles.has(e.profile))return {enabled:false,policy:"fail_open",reason:`hook_profile_${e.profile}_unsupported_by_${t.hostId}`,fallback:"host_event_continues_without_devflow_handler"};if(e.disabledHandlers.has(n))return {enabled:false,policy:"fail_open",reason:"hook_handler_disabled",fallback:"host_event_continues_without_devflow_handler"};if(e.profile==="minimal"&&!Fs.has(n))return {enabled:false,policy:"fail_open",reason:"hook_handler_not_in_minimal_profile",fallback:"critical_receipts_only"};let r=$s[n];if(!r)return {enabled:true,policy:o};let i=t.capabilities.get(r);return !i||i.status!=="supported"?{enabled:false,policy:"fail_open",reason:i?.reason??`${r}_unsupported_by_${t.hostId}`,fallback:i?.fallback??"host_event_continues_without_native_hook_processing"}:{enabled:true,policy:o}}var Fs=new Set(["session-start","user-prompt-submit","stop","session-end","memory-snapshot"]),$s={"session-start":"hooks.session_start","user-prompt-submit":"hooks.prompt_submit","pre-tool-use":"hooks.pre_tool_use","post-tool-use":"hooks.post_tool_use","post-tool-use-failure":"hooks.post_tool_use",stop:"hooks.stop","session-end":"hooks.session_end"};function Ns(n,e){return n==="user-prompt-submit"||n==="stop"||n==="session-end"?"enqueue_and_open":n==="pre-tool-use"&&e==="strict"?"fail_closed":"fail_open"}function mo(n){if(!existsSync(n))return {};try{let t=JSON.parse(readFileSync$1(n,"utf8")).hooks;return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return {}}}function pt(n){return n==="minimal"||n==="standard"||n==="strict"?n:void 0}function mt(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):[]}function Ls(n){let e=n.trim().replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase();return ({sessionstart:"session-start",userpromptsubmit:"user-prompt-submit",pretooluse:"pre-tool-use",posttooluse:"post-tool-use",posttoolusefailure:"post-tool-use-failure",sessionend:"session-end",precompact:"pre-compact",memorysnapshot:"memory-snapshot"}[e.replace(/-/g,"")]??e)||void 0}function yo(n){let e;try{e=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});let t=e.getActiveContextReceipt(n.projectRoot,n.sessionId,n.executionId);if(!t)return null;let o=n.toolName==="Read"?zs(n.toolInput):void 0,r=o?t.selectedFiles?.find(l=>qs(n.projectRoot,l,o)):void 0,i=Js(n.toolName),s=r?"code":t.canonicalNextAction===i?"action":null,a=r??(s==="action"?i:void 0);if(!s||!a)return null;let c=[t.contextHash,t.requestId??"",s,a,n.toolUseId??`${n.sessionId}:${n.executionId??t.executionId}`].join("\0");return e.recordContextSelectionEvent({id:`ctxsel:${createHash("sha256").update(c).digest("hex").slice(0,32)}`,projectRoot:n.projectRoot,sessionId:n.sessionId,executionId:t.executionId,requestId:t.requestId,selectionType:s,candidateId:a,toolName:n.toolName,toolUseId:n.toolUseId,selectedAt:Date.now()}),s}catch{return null}finally{try{e?.close();}catch{}}}function zs(n){for(let e of ["file_path","path"]){let t=n[e];if(typeof t=="string"&&t.trim())return t.trim()}}function qs(n,e,t){let o=resolve(n,e),r=isAbsolute(t)?resolve(t):resolve(n,t);return o===r}function Js(n){return n.startsWith("mcp__")?n.split("__").at(-1)??n:n}var da=600*1e3,ua=2e3,pa=250,ma=2e3,fa=1e3,vo=1024*1024,ha=2*1024*1024,ga=6e4,ya=100,va={Agent:"get_project_context",Bash:"get_project_context",Glob:"get_project_context",Grep:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"};function ba(n){switch(n){case "Read":case "Glob":return "file_read";case "Write":case "Edit":case "NotebookEdit":return "file_write";case "Bash":return "bash_command";case "Agent":return "subagent";case "Skill":return "skill_invoke";default:return "tool_use"}}function gt(n){return typeof n=="string"&&n.trim().length>0}function Sa(n,e,t=process.env,o){if(!n.startsWith("mcp__devflow__"))return e;let r=e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{};if(gt(r.projectRoot))return r;let i=gt(t.CLAUDE_PROJECT_DIR)?t.CLAUDE_PROJECT_DIR:o;return gt(i)&&(r.projectRoot=i),r}var yt=class{constructor(e,t){this.socketIdentity=null;this.pidIdentity=null;this.server=null;this.activeSessionIds=new Set;this.eventMap=[];this.idleTimer=null;this.telemetryFlushTimer=null;this.successfulTelemetryOperations=0;this.shutdownPromise=null;this.explicitMemoryGate=null;this.memoryWarmup=null;this.explicitIntentFlush=null;this.hostRuntime=null;this.memoryTurnSpoolTimer=null;this.sessionFinalizeSpoolTimer=null;this.projectRoot=e,this.socketPath=getDaemonSocketPath(e),this.pidPath=getDaemonPidPath(e),this.telemetry=new O,this.runtimeStore=new T(this.projectRoot),this.serverManager=new oe(e),this.hookRuntime=fo(e),this.initialSessionInput=t,this.workRuntime=new ke({projectRoot:e,handlers:{"memory.explicit_commit":async({item:o})=>{await this.persistMemoryTurnItem(o.payload);},"memory.turn_capture":async({item:o})=>{await this.persistMemoryTurnItem(o.payload);},"memory.explicit_enrichment":async({item:o})=>{let r=o.payload;if(typeof r?.observationId!="string"||!r.observationId)throw new N("invalid_payload","Explicit enrichment requires observationId");await(await this.getMemoryGate()).enrichExplicitMemoryObservation(r.observationId);},"session.bootstrap":async({item:o})=>{await this.bootstrapSessionWork(o.payload);},"memory.vector_backfill":async()=>{await(await this.getMemoryGate()).backfillObservationVectors({batchSize:32});},"memory.turn_distill":async({item:o})=>{await J({projectRoot:this.projectRoot,sessionId:o.sessionId,trigger:"session_end",memory:await this.getMemoryGate()}),await this.refreshMemorySnapshot("memory_turn_distill");},"session.finalize":async({item:o})=>{await this.finalizeSessionWork(o.payload,o.id);},"telemetry.reconcile":async()=>{await this.flushTelemetry();}}});}async start(){this.hostRuntime=await ho(this.projectRoot),mkdirSync(dirname(this.socketPath),{recursive:true,mode:448}),await this.cleanStaleStartupResources(),this.server=createServer(e=>this.handleConnection(e));try{await this.listen(),this.writePidFile(),Kt(this.projectRoot,process.pid);}catch(e){throw await this.closeServer(),this.cleanupOwnedResources(),e}if(this.server.on("error",e=>{console.error("[devflow-daemon] Server error:",e.message);}),console.error("[devflow-daemon] Listening on",this.socketPath),await this.telemetry.flushAndAggregate(),this.telemetryFlushTimer=setInterval(()=>{this.flushTelemetry();},ga),this.telemetryFlushTimer.unref(),prepareEmbeddingModel().then(e=>{console.error(`[devflow-daemon] Embedding model ready (${e.source}) at ${e.cacheRoot}`);}).catch(e=>{console.error("[devflow-daemon] Embedding model unavailable; lexical retrieval remains active:",e.message);}),this.workRuntime.start(),this.initialSessionInput){let e=this.initialSessionInput;this.initialSessionInput=void 0,this.handleRequest({type:"session-start",input:e});}this.drainSessionStartSpool(),this.scheduleMemoryTurnSpoolDrain(0),this.scheduleSessionFinalizeSpoolDrain(0),this.resetIdleTimer();}handleConnection(e){let t="",o=false,r=false,i=0,s=Promise.resolve();e.setEncoding("utf8");let a=()=>{r||(r=true,clearTimeout(c),e.destroy());},c=setTimeout(()=>{a();},ua).unref(),l=async u=>{if(!r){r=true,clearTimeout(c);try{await this.writeFrame(e,u);}catch{}finally{e.destroy();}}};e.on("data",u=>{if(r)return;t+=u;let d=t.split(`
|
|
26
|
+
`);if(t=d.pop()??"",Buffer.byteLength(t,"utf8")>vo){a();return}if(d.length===0)return;let p=0;for(let f of d){let h=Buffer.byteLength(f,"utf8");if(h>vo){a();return}p+=h+1;}if(i+p>ha){a();return}i+=p,s=s.then(async()=>{for(let f of d){if(r)return;if(!o){let h;try{h=JSON.parse(f);}catch{await l({error:"handshake_invalid"});return}if(h?.type!=="hello"||typeof h.rootPath!="string"){await l({error:"handshake_invalid"});return}if(h.rootPath!==this.projectRoot){await l({error:"handshake_root_mismatch",expected:this.projectRoot});return}o=true,clearTimeout(c),this.resetIdleTimer();continue}if(f.trim())try{let h=JSON.parse(f),v=await this.handleRequest(h);v!==null&&!r&&await this.writeFrame(e,v);}catch(h){r||await this.writeFrame(e,{error:h.message});}}}).catch(()=>{a();}).finally(()=>{i-=p;});}),e.on("close",()=>clearTimeout(c)),e.on("error",()=>{});}writeFrame(e,t){return new Promise((o,r)=>{if(e.destroyed||!e.writable){r(new Error("Socket is not writable"));return}let i=false,s=true,a=false,c=setTimeout(()=>{e.destroy(),u(new Error("Timed out writing daemon response"));},fa),l=()=>{clearTimeout(c),e.off("close",d),e.off("error",p),e.off("drain",f);},u=v=>{a||!v&&(!i||!s)||(a=true,l(),v?r(v):o());},d=()=>u(new Error("Socket closed during write")),p=v=>u(v),f=()=>{s=true,u();};e.once("close",d),e.once("error",p),e.write(`${JSON.stringify(t)}
|
|
27
|
+
`,v=>{if(v){u(v);return}i=true,u();})||(s=false,e.once("drain",f));})}async cleanStaleStartupResources(){let e=this.getPathIdentity(this.socketPath);if(e){if(await this.isSocketAcceptingConnections())throw new Error(`Daemon socket already active for ${this.projectRoot}`);this.removePathIfOwned(this.socketPath,e,"stale socket");}let t=this.getPathIdentity(this.pidPath);t&&this.removePathIfOwned(this.pidPath,t,"stale PID file");}getPathIdentity(e){try{let t=lstatSync(e);return {dev:t.dev,ino:t.ino}}catch(t){if(t.code==="ENOENT")return null;throw t}}pathMatchesIdentity(e,t){if(!t)return false;try{let o=this.getPathIdentity(e);return o?.dev===t.dev&&o.ino===t.ino}catch(o){return console.error("[devflow-daemon] Failed to verify path ownership:",o.message),false}}writePidFile(){let e=openSync(this.pidPath,"wx",384);try{writeFileSync(e,`${process.pid}
|
|
28
|
+
`);let t=fstatSync(e);this.pidIdentity={dev:t.dev,ino:t.ino};}finally{closeSync(e);}}removePathIfOwned(e,t,o,r){try{return !this.pathMatchesIdentity(e,t)||r!==void 0&&readFileSync(e,"utf8")!==r||!this.pathMatchesIdentity(e,t)?!1:(unlinkSync(e),!0)}catch(i){return i.code!=="ENOENT"&&console.error(`[devflow-daemon] Failed to remove ${o}:`,i.message),false}}isSocketAcceptingConnections(){return new Promise((e,t)=>{let o=createConnection(this.socketPath),r=setTimeout(()=>{o.destroy(),t(new Error(`Timed out probing daemon socket ${this.socketPath}`));},pa),i=s=>{clearTimeout(r),o.destroy(),e(s);};o.once("connect",()=>i(true)),o.once("error",s=>{let a=s.code;a==="ENOENT"||a==="ECONNREFUSED"?i(false):(clearTimeout(r),t(s));});})}listen(){return new Promise((e,t)=>{let o=this.server;if(!o){t(new Error("Daemon server is not initialized"));return}let r=s=>{o.off("listening",i),t(s);},i=()=>{o.off("error",r);try{let s=this.getPathIdentity(this.socketPath);if(!s)throw new Error(`Daemon socket missing after listen: ${this.socketPath}`);this.socketIdentity=s,e();}catch(s){t(s);}};o.once("error",r),o.once("listening",i),o.listen(this.socketPath);})}resetIdleTimer(){this.idleTimer&&clearTimeout(this.idleTimer),this.idleTimer=null,!(this.activeSessionIds.size>0)&&(this.idleTimer=setTimeout(()=>{console.error("[devflow-daemon] Idle timeout, exiting"),this.shutdown();},da).unref());}async handleRequest(e){let t=this.hostRuntime;if(!t)return this.hookFailureResponse(e.type,{enabled:false,policy:"fail_open",reason:"host_adapter_not_ready",fallback:"host_event_continues_without_devflow_handler"});let o=go(e.type,this.hookRuntime,t);if(!o.enabled)return this.hookFailureResponse(e.type,o);try{switch(e.type){case "pre-tool-use":return this.handlePreToolUse(e.input);case "post-tool-use":return await this.handlePostToolUse(e.input)??{status:"ok"};case "post-tool-use-failure":return await this.handlePostToolUseFailure(e.input)??{status:"ok"};case "stop":return Re("Stop",this.hookRuntime.acknowledgementBudgetMs,async()=>await this.handleStop(e.input??"")??{status:"ok"},()=>({status:"degraded",reason:"hook_budget_exceeded",fallback:"background_processing"}));case "memory-snapshot":return this.handleMemorySnapshot();case "session-start":return this.handleSessionStart(e.input??"");case "session-end":return Re("SessionEnd",this.hookRuntime.acknowledgementBudgetMs,()=>this.handleSessionEnd(e.input??""),()=>({status:"degraded",reason:"hook_budget_exceeded",fallback:"durable_session_recovery"}));case "user-prompt-submit":return Re("UserPromptSubmit",this.hookRuntime.acknowledgementBudgetMs,()=>this.handleUserPromptSubmit(e.input),()=>({hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow",additionalContext:"DevFlow background processing exceeded its acknowledgement budget; continue in degraded mode and do not claim an unreceipted memory save."}}));case "pre-compact":return this.handlePreCompact(e.input);default:return {error:"unknown request type"}}}catch(r){return this.hookFailureResponse(e.type,o,r)}}async drainSessionStartSpool(){for(;;){let e=to(this.projectRoot);if(!e)return;try{let t=await this.handleRequest({type:"session-start",input:e.input});if(t&&"status"in t&&t.status==="degraded")throw new Error(`session_start_degraded:${String(t.reason??"unknown")}`);no(e),console.error(`[devflow-daemon] SessionStart accepted from durable spool: ${e.receiptId}`);}catch(t){oo(e),console.error("[devflow-daemon] SessionStart spool deferred:",t.message);return}}}hookFailureResponse(e,t,o){let r=o instanceof Error?o.message:t.reason??"hook_handler_unavailable",i=t.fallback??(t.policy==="enqueue_and_open"?"durable_background_processing":"host_event_continues");return e==="pre-tool-use"?{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:t.policy==="fail_closed"?"deny":"allow",permissionDecisionReason:r,additionalContext:`DevFlow hook degraded: ${r}; fallback=${i}.`}}:e==="user-prompt-submit"?{hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow",additionalContext:`DevFlow hook degraded: ${r}; fallback=${i}. Do not claim unreceipted work completed.`}}:{status:"degraded",reason:r,fallback:i}}async handlePreToolUse(e){try{if(!e||e.trim()==="")return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}};let t=JSON.parse(e);t.tool_input=Sa(t.tool_name,t.tool_input,process.env,this.projectRoot);let o=this.trackSession(t.session_id),r="";if(t.tool_name==="Skill"){let R=t.tool_input?.skill,I=R?fe(R):null;I&&(r=this.startSkillExecution(o,I));}let i=this.runtimeStore.get(o);t.tool_name.startsWith("mcp__devflow__")&&(t.tool_input._devflow_session_id=o,t.tool_input._devflow_execution_id=i?.executionId??o,t.tool_use_id&&(t.tool_input._devflow_tool_use_id=t.tool_use_id));let s=t.tool_name.startsWith("mcp__"),a=s?t.tool_name.replace(/^mcp__[^_]+__/,""):void 0,c=new q(this.projectRoot,o,i?.executionId),l=c.getPhase(),u=Qn({toolName:t.tool_name,toolInput:t.tool_input,projectRoot:this.projectRoot}),d=u?{permissionDecision:"deny",reason:u}:c.evaluate(t.tool_name,s),p;if(d.permissionDecision==="deny"?p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:d.reason??"MCP context required"}}:d.additionalContext?p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:d.additionalContext}}:p={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}},r){let R=p.hookSpecificOutput,I=typeof R.additionalContext=="string"?R.additionalContext:"";R.additionalContext=I?`${I}
|
|
29
|
+
${r}`:r;}t.tool_name.startsWith("mcp__devflow__")&&(p.hookSpecificOutput.updatedInput=t.tool_input);let f={...t.tool_input};delete f._devflow_session_id,delete f._devflow_execution_id,delete f._devflow_tool_use_id;let h=i?.executionId??o,b={eventId:Y(o,t.tool_use_id),executionId:h,sessionId:o,projectRoot:this.projectRoot,toolUseId:t.tool_use_id,timestamp:Date.now(),toolName:t.tool_name,toolType:s?"mcp":t.tool_name==="Agent"?"subagent":"direct",isMcpTool:s,mcpToolName:a,mcpEnforced:s&&l==="context_gathering",mcpFallback:!s&&l==="context_gathering",kind:ba(t.tool_name),input:f,duration:0,blocked:p&&p.hookSpecificOutput?.permissionDecision==="deny"},w=await this.telemetry.sendEvent({...b,blockReason:b.blocked?u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED":void 0,error:b.blocked?u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED":void 0});return w&&!b.blocked&&(this.eventMap.push({toolName:t.tool_name,toolUseId:t.tool_use_id,eventId:w,sessionId:o,timestamp:b.timestamp}),this.noteTelemetryOperation()),w&&b.blocked&&await this.telemetry.completeEvent({eventId:w,sessionId:o,error:u?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-b.timestamp,completedAt:Date.now()}),p}catch{return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}}trackSession(e){let t=e?.trim()||(this.activeSessionIds.size===1?[...this.activeSessionIds][0]:"");if(!t)throw new Error("session_id_required");return this.registerSession(t),t}registerSession(e){this.activeSessionIds.has(e)||(this.activeSessionIds.size===0&&ie(this.projectRoot,{bypassCount:0}),this.activeSessionIds.add(e),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null),this.serverManager.addRef(e),this.telemetry.sendSessionStart(e,this.projectRoot,Date.now()).catch(()=>{})),this.runtimeStore.registerSession(e);}startSkillExecution(e,t){let o=this.runtimeStore.get(e)?.executionId,r=this.runtimeStore.startExecution(e,t,Ot(t));return r.executionId&&r.executionId!==o&&this.telemetry.sendExecutionStart(r.executionId,e,t,r.lastActivityAt,this.projectRoot,r.requiredMcpTools).catch(()=>{}),formatSkillRuntimeOverlay(createSkillRuntimeOverlay(t,this.projectRoot))}async handleSessionStart(e){try{let t=JSON.parse(e);if(typeof t.session_id!="string"||!t.session_id.trim())return {error:"session_id_required"};let o=t.session_id.trim();this.registerSession(o);let r=`session-start:${createHash("sha256").update(`${this.projectRoot}\0${o}`).digest("hex").slice(0,24)}`,i=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50}),s="pending";try{s=i.enqueueWork({idempotencyKey:r,kind:"session.bootstrap",projectRoot:this.projectRoot,sessionId:o,payload:{sessionId:o}}).state;}finally{i.close();}return {status:s==="completed"?"completed":"accepted",receiptId:r,workState:s}}catch{return {error:"session_start_invalid"}}}popEventFromMap(e,t,o){let r=this.eventMap.filter(s=>s.toolName===e&&s.sessionId===t);if(r.length===0)return null;let i=o?r.find(s=>s.toolUseId===o):r.sort((s,a)=>s.timestamp-a.timestamp)[0];return i?(this.eventMap=this.eventMap.filter(s=>s.eventId!==i.eventId),i):null}enforcePostToolUse(e){if(!va[e])return null;let t=Math.floor(Date.now()/1e3),o=Pe(this.projectRoot,s=>t-(s.lastMcpCall??0)<30?s:{...s,bypassCount:(s.bypassCount??0)+1});if(!o.applied||!o.changed)return null;let r=o.receipt.bypassCount??0;if(r===1)return null;let i;switch(e){case "Agent":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u4F7F\u7528\u4E86 Agent \u5B50\u4EE3\u7406\u6267\u884C\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Bash":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Bash \u547D\u4EE4\u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Glob":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Glob \u5339\u914D\u6587\u4EF6\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "Grep":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86 Grep \u641C\u7D22\u4EE3\u7801\u3002\u4E0B\u6B21\u8BF7\u7528 get_project_context MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;case "WebSearch":case "WebFetch":i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u4F60\u521A\u624D\u7528\u4E86\u7F51\u7EDC\u641C\u7D22\u3002\u4E0B\u6B21\u8BF7\u7528 get_knowledge MCP \u5DE5\u5177\u66FF\u4EE3\u3002`;break;default:i=`\u7B2C ${r} \u6B21\u8FDD\u89C4\uFF1A\u8BF7\u4F7F\u7528 DevFlow MCP \u5DE5\u5177\u66FF\u4EE3\u76F4\u63A5\u8C03\u7528\u3002`;}return r>=3?i=`${i} \u5DF2\u8FBE\u5230\u6700\u5927\u8FDD\u89C4\u6B21\u6570\uFF0C\u540E\u7EED\u7ED5\u8FC7\u5C06\u88AB\u786C\u963B\u6B62\u3002`:r>=2?i=`${i} \u4E0B\u6B21\u8FDD\u89C4\u5C06\u88AB\u963B\u6B62\u3002`:i=`${i} \u8BF7\u7ACB\u5373\u7EA0\u6B63\u3002`,i}async handlePostToolUse(e){if(!e)return null;let t;try{t=JSON.parse(e);}catch{return null}let o=t.tool_name||"",r=t.tool_input||{},i=t.tool_response,s=this.trackSession(t.session_id);if(yo({projectRoot:this.projectRoot,sessionId:s,executionId:this.runtimeStore.get(s)?.executionId,toolName:o,toolInput:r,toolUseId:t.tool_use_id}),o==="Skill"){let S=r?.skill,k=S?fe(S):null;k&&(this.startSkillExecution(s,k),ie(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0}));}o.startsWith("mcp__")&&new q(this.projectRoot).recordMcpCall();let a=this.popEventFromMap(o,s,t.tool_use_id);if(a){let S=typeof i=="string"?i:JSON.stringify(i),k=S.length>5e3?{_truncated:true,_originalSize:S.length,text:S.slice(0,5e3)}:i,y=Date.now()-a.timestamp;await this.telemetry.completeEvent({eventId:a.eventId,sessionId:s,output:k,duration:y,completedAt:Date.now()})&&this.noteTelemetryOperation();}let c=typeof i=="object"&&i!==null?i:null,l=c?.exitCode,u=c?.stderr,d=/^\s*(ls|cat|pwd|cd|echo|head|tail|wc|which|whoami|date|env|printenv|id|hostname|uname)\b/,p=r.command||"",f=JSON.stringify(i),h=Buffer.byteLength(f,"utf8"),v=this.countResults(i),b,w,R=true;if(o.startsWith("mcp__"))b="mcp_call",w={mcpTool:o.replace(/^mcp__[^_]+__/,""),query:r.query??null,resultCount:v,resultSizeBytes:h};else if(o==="Read"||o==="Write"||o==="Edit")b=o==="Read"?"file_read":"file_write",w={filePath:r.file_path??null,fileContentSize:h};else if(o==="Bash"){let S=d.test(p),k=l!==void 0&&l!==0;R=!S||k,b=k?"bash_error":"bash_command",w={command:p||o,exitCode:l??null,stderr:u??null};}else o==="Agent"?(b="subagent",w={subagentType:r.subagent_type??null,description:typeof r.description=="string"?r.description.slice(0,200):null}):o==="WebSearch"||o==="WebFetch"?(b=o==="WebSearch"?"web_search":"web_fetch",w={query:typeof r.query=="string"?r.query.slice(0,200):null}):(R=false,b="tool_use",w={});if(R){let S={id:t.tool_use_id?`memory:${Y(s,t.tool_use_id)}`:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:s,tool:o,kind:b,payload:w,command:p||void 0,exitCode:l,stderr:u??void 0,durationMs:0,createdAt:Date.now()};this.postMemoryEvent(S);}let I=bn({toolName:o,toolResponse:i,sessionId:s,toolUseId:t.tool_use_id,runtimeStore:this.runtimeStore}),x=this.enforcePostToolUse(o);x&&console.error("[devflow-daemon] Enforcement:",x);let H=[I,x].filter(S=>!!S).join(`
|
|
30
|
+
|
|
31
|
+
`);return H?{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:H}}:null}async handlePostToolUseFailure(e){let t;try{t=JSON.parse(e);}catch{return null}let o=this.trackSession(t.session_id),r=t.tool_name??"unknown",i=t.error??`${r} failed`,s=this.popEventFromMap(r,o,t.tool_use_id);if(s)await this.telemetry.completeEvent({eventId:s.eventId,sessionId:o,error:i,duration:Date.now()-s.timestamp,completedAt:Date.now()})&&this.noteTelemetryOperation();else {let a=Y(o,t.tool_use_id);await this.telemetry.sendEvent({eventId:a,executionId:this.runtimeStore.get(o)?.executionId??o,sessionId:o,projectRoot:this.projectRoot,toolUseId:t.tool_use_id,timestamp:Date.now(),toolName:r,toolType:r.startsWith("mcp__")?"mcp":"direct",isMcpTool:r.startsWith("mcp__"),mcpToolName:r.startsWith("mcp__")?r.replace(/^mcp__[^_]+__/,""):void 0,mcpEnforced:false,mcpFallback:false,kind:"error",input:t.tool_input??{},duration:0,error:i,blocked:false});}return this.postMemoryEvent({id:t.tool_use_id?`memory:${Y(o,t.tool_use_id)}`:`evt:${Date.now()}:${Math.random().toString(36).slice(2,7)}`,sessionId:o,tool:r,command:typeof t.tool_input?.command=="string"?t.tool_input.command:r,exitCode:-1,stderr:i,durationMs:s?Date.now()-s.timestamp:0,createdAt:Date.now(),kind:r==="Bash"?"bash_error":"tool_use",payload:{command:t.tool_input?.command??r,exitCode:-1,stderr:i}}),null}countResults(e){if(!e)return 0;let t=e;if(typeof e=="string")try{t=JSON.parse(e);}catch{return 1}let o=t,r=["files","results","data","result","memories","nodes","chunks","findings","symbols"],i=Array.isArray(o.data)?o.data:o.structuredContent??o;if(Array.isArray(i))return i.length;if(typeof i=="object"&&i!==null){let s=i,a=0,c=false;for(let l of r)Array.isArray(s[l])&&(c=true,a+=s[l].length);for(let[,l]of Object.entries(s))l&&typeof l=="object"&&!Array.isArray(l)&&(a+=this.countResults(l));return a>0?a:c?0:Object.keys(s).length>0?1:0}return 0}async postMemoryEvent(e){M(`/api/memory/session-events?rootPath=${encodeURIComponent(this.projectRoot)}`,e);try{await(await this.getMemoryGate()).recordEvent(e);}catch(t){console.error("[devflow-daemon] Local memory event write failed:",t.message);}}async getMemoryGate(){let e=this.explicitMemoryGate??=new MemoryGate(this.projectRoot);return this.memoryWarmup??=e.forceWarmUp().catch(t=>{throw this.memoryWarmup=null,t}),await this.memoryWarmup,e}async handleUserPromptSubmit(e){let t=[];try{let o=JSON.parse(e),r=typeof o.prompt=="string"?o.prompt:"",i=typeof o.session_id=="string"&&o.session_id.trim()?this.trackSession(o.session_id):null,s=Mn(r),a=!1;if(r.trim()&&i)try{let c=it({projectRoot:this.projectRoot,sessionId:i,prompt:r});if(c){let l=c;if(c.explicitContent&&c.turn.status==="pending")try{l=await st({projectRoot:this.projectRoot,payload:{operation:"commit_explicit",turnId:c.turn.turnId,eventId:c.turn.eventId,sessionId:i,prompt:r.trim().slice(0,4e3),explicitContent:c.explicitContent,createdAt:c.turn.createdAt},memory:await this.getMemoryGate()});}catch(u){console.error("[devflow-daemon] Explicit memory commit deferred:",u.message);}t.push(l.additionalContext),a=l.skipSkillRouting;}}catch(c){a=!!me(r);try{let u=io(this.projectRoot,{sessionId:i,prompt:r,createdAt:Date.now()});t.push(`DevFlow memory turn status=accepted; durable=true; receiptId=${u}; canonicalMemory=false; SQLite queue replay pending. Do not claim memory success without a canonical receipt.`),this.scheduleMemoryTurnSpoolDrain(250),console.error("[devflow-daemon] Memory turn spooled after database contention:",c.message);}catch(u){t.push("DevFlow memory turn status=degraded; durable=false; no canonical receipt exists. Do not claim memory success."),console.error("[devflow-daemon] Memory turn persistence unavailable:",u.message);}}if(i&&s&&!a){let c=this.startSkillExecution(i,s.skillName);c&&t.push(c);}}catch{}return {hookSpecificOutput:{hookEventName:"UserPromptSubmit",permissionDecision:"allow",...t.length?{additionalContext:t.join(`
|
|
32
|
+
`)}:{}}}}async handlePreCompact(e){let t;try{let s=JSON.parse(e);typeof s.session_id=="string"&&s.session_id.trim()&&(t=s.session_id.trim());}catch{}await this.flushTelemetry(),this.startExplicitIntentFlush(),await this.explicitIntentFlush;let o=await this.getMemoryGate(),r=await J({projectRoot:this.projectRoot,sessionId:t,trigger:"pre_compact",memory:o}),i=Xt(r);return {hookSpecificOutput:{hookEventName:"PreCompact",...i?{additionalContext:i}:{}}}}async persistMemoryTurnItem(e){if(!e||typeof e!="object")throw new Error("memory_turn_payload_invalid");let t=e;if(t.operation!=="capture_prompt"&&t.operation!=="commit_explicit"||typeof t.turnId!="string"||typeof t.eventId!="string"||typeof t.sessionId!="string"||typeof t.prompt!="string"||typeof t.createdAt!="number")throw new Error("memory_turn_payload_invalid");await st({projectRoot:this.projectRoot,payload:t,memory:await this.getMemoryGate()});}scheduleMemoryTurnSpoolDrain(e){this.memoryTurnSpoolTimer||(this.memoryTurnSpoolTimer=setTimeout(()=>{this.memoryTurnSpoolTimer=null,this.drainMemoryTurnSpool();},e),this.memoryTurnSpoolTimer.unref());}async drainMemoryTurnSpool(){for(;;){let e=so(this.projectRoot);if(!e)return;try{it({projectRoot:this.projectRoot,sessionId:e.payload.sessionId,prompt:e.payload.prompt}),ao(e),this.workRuntime.drainOnce();}catch(t){co(e),console.error("[devflow-daemon] Memory turn spool replay deferred:",t.message),this.scheduleMemoryTurnSpoolDrain(1e3);return}}}async bootstrapSessionWork(e){if(!e||typeof e!="object"||typeof e.sessionId!="string")throw new Error("session_bootstrap_payload_invalid");let t=e.sessionId,o=await this.getMemoryGate();await o.ensureSession(t,this.projectRoot,"Host session"),await o.releasePendingDistillLeases(t),await this.refreshMemorySnapshot("session_bootstrap");}noteTelemetryOperation(){this.successfulTelemetryOperations++,this.successfulTelemetryOperations>=ya&&this.flushTelemetry();}async flushTelemetry(){this.successfulTelemetryOperations=0,await this.telemetry.flushAndAggregate();}startExplicitIntentFlush(){this.explicitIntentFlush||(this.explicitIntentFlush=this.flushExplicitMemoryIntents().finally(()=>{this.explicitIntentFlush=null;}));}async handleStop(e){let t=null,o=false,r;try{let i=JSON.parse(e);typeof i.session_id=="string"&&i.session_id.trim()&&(t=i.session_id.trim()),o=i.stop_hook_active===!0,typeof i.transcript_path=="string"&&i.transcript_path.trim()&&(r=i.transcript_path.trim());}catch{}if(t??=this.activeSessionIds.size===1?[...this.activeSessionIds][0]:null,this.startExplicitIntentFlush(),t){let i=Bn(this.projectRoot,t);if(i)return i;let s=Sn({projectRoot:this.projectRoot,sessionId:t,transcriptPath:r,runtimeStore:this.runtimeStore});if(s)return s;let a=this.runtimeStore.completeExecution(t);if(a?.executionId){let c=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50}),l={};try{let u=c.listSessionMemoryTurnsForReconciliation(this.projectRoot,t);l={...He(u),evidenceDegradations:a.evidenceDegradations,evidenceContractOutcomes:a.evidenceOutcomes};}finally{c.close();}await this.telemetry.sendExecutionComplete(a.executionId,"completed",Date.now(),l),this.deleteContextReceipt(t,a.executionId);}}return null}async flushExplicitMemoryIntents(){this.flushTelemetry();let e=Tn(this.projectRoot);if(e)try{let t=this.explicitMemoryGate??=new MemoryGate(this.projectRoot);await t.forceWarmUp();let o=!1;for(;e.intents.length>0;){let r=e.intents[0];if(r.turnId){let s=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:50});try{let a=s.getMemoryTurn(r.turnId);if(!a||a.status!=="pending"){console.error(`[devflow-daemon] Dropping stale legacy memory intent for ${r.turnId}: ${a?.status??"missing"}`),We(e);continue}}finally{s.close();}}let i=await t.saveExplicitMemoryIntent(r.content,r.sessionId,r.eventId);if(o=!0,r.turnId){let s=openGlobalDevFlowDatabase();try{s.commitMemoryTurn({turnId:r.turnId,receiptId:ot(r.turnId,"committed",[i.id]),memoryIds:[i.id],source:"explicit_intent",reason:"explicit_user_request_retry"});try{await t.enrichExplicitMemoryObservation(i.id);}catch(a){s.enqueueWork({idempotencyKey:`explicit-enrichment:${this.projectRoot}:${i.id}`,kind:"memory.explicit_enrichment",projectRoot:this.projectRoot,sessionId:r.sessionId,turnId:r.turnId,payload:{observationId:i.id},maxAttempts:20}),console.error("[devflow-daemon] Explicit memory enrichment deferred:",a.message);}}finally{s.close();}}We(e);}o&&await this.refreshMemorySnapshot("legacy_explicit_memory_commit");}catch(t){console.error("[devflow-daemon] Explicit memory intent save failed:",t.message);}}deleteContextReceipt(e,t){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),o.deleteContextReceipt(this.projectRoot,e,t);}catch{}finally{o?.close();}}async refreshMemorySnapshot(e){try{let t=loadConfig(this.projectRoot).sessionStart?.injectMemories??!0,o=this.explicitMemoryGate??=new MemoryGate(this.projectRoot);return await Se({projectRoot:this.projectRoot,memory:o,injectConfig:t,reason:e})}catch(t){return console.error("[devflow-daemon] Memory snapshot refresh degraded:",t.message),et({projectRoot:this.projectRoot,reason:e,load:async()=>{throw t}})}}async handleMemorySnapshot(){let e=await this.refreshMemorySnapshot("memory_snapshot_request"),{snapshot:t}=e;return {status:t.status==="ready"||t.status==="disabled"?"ok":t.status,enabled:t.status!=="disabled",markdown:t.markdown,memoryIds:t.memoryIds,memoryCount:t.memoryIds.length,conflicts:t.conflicts,snapshot:t,persisted:e.persisted}}async handleSessionEnd(e){let t=null;try{let s=JSON.parse(e);typeof s.session_id=="string"&&s.session_id.trim()&&(t=s.session_id.trim());}catch{}t??=this.activeSessionIds.size===1?[...this.activeSessionIds][0]:null;let o=t===null?this.activeSessionIds.size<=1:this.activeSessionIds.size<=1&&this.activeSessionIds.has(t),r=t?this.runtimeStore.get(t)?.executionId:void 0,i=pe(e,this.projectRoot,o,r);return i?.workState==="spooled"&&this.scheduleSessionFinalizeSpoolDrain(250),t&&(this.serverManager.removeRef(t),this.activeSessionIds.delete(t),this.eventMap=this.eventMap.filter(s=>s.sessionId!==t)),this.activeSessionIds.size===0&&i?.workState!=="spooled"?setImmediate(()=>{this.workRuntime.drainOnce().finally(()=>{this.shutdown();});}):this.resetIdleTimer(),i??{status:"ok"}}async finalizeSessionWork(e,t){if(!e||typeof e!="object")throw new Error("session_finalize_payload_invalid");let o=e;if(typeof o.inputJson!="string"||typeof o.sessionId!="string")throw new Error("session_finalize_payload_invalid");let r=await this.getMemoryGate();await Rn(o.inputJson,this.projectRoot,o.cleanupSharedState!==false,{telemetry:this.telemetry,memory:r,executionId:o.executionId});try{await this.refreshMemorySnapshot("session_finalization");}catch(s){console.error("[devflow-daemon] Session finalization snapshot refresh degraded:",s.message);}let i=openGlobalDevFlowDatabase();try{i.completeSessionClosure(this.projectRoot,o.sessionId,t);}finally{i.close();}}scheduleSessionFinalizeSpoolDrain(e){this.sessionFinalizeSpoolTimer||(this.sessionFinalizeSpoolTimer=setTimeout(()=>{this.sessionFinalizeSpoolTimer=null,this.drainSessionFinalizeSpool();},e),this.sessionFinalizeSpoolTimer.unref());}async drainSessionFinalizeSpool(){for(;;){let e=mn(this.projectRoot);if(!e)return;try{if(!pe(e.payload.inputJson,this.projectRoot,e.payload.cleanupSharedState,e.payload.executionId,!1))throw new Error("session_finalize_spool_rejected");fn(e),this.workRuntime.drainOnce();}catch(t){hn(e),console.error("[devflow-daemon] Session finalize spool replay deferred:",t.message),this.scheduleSessionFinalizeSpoolDrain(1e3);return}}}shutdown(){return this.shutdownPromise?this.shutdownPromise:(this.shutdownPromise=this.performShutdown(),this.shutdownPromise)}async performShutdown(){this.workRuntime.stop(),this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null),this.telemetryFlushTimer&&(clearInterval(this.telemetryFlushTimer),this.telemetryFlushTimer=null),this.memoryTurnSpoolTimer&&(clearTimeout(this.memoryTurnSpoolTimer),this.memoryTurnSpoolTimer=null),this.sessionFinalizeSpoolTimer&&(clearTimeout(this.sessionFinalizeSpoolTimer),this.sessionFinalizeSpoolTimer=null),await this.flushTelemetry(),await this.closeServer(),this.cleanupOwnedResources(),await this.serverManager.stop(),await this.explicitIntentFlush,this.explicitMemoryGate?.close(),this.explicitMemoryGate=null,this.telemetry.close(),process.exit(0);}closeServer(){let e=this.server;return !e||!e.listening||!this.pathMatchesIdentity(this.socketPath,this.socketIdentity)?Promise.resolve():(this.server=null,new Promise(t=>{let o=false,r=()=>{o||(o=true,clearTimeout(i),t());},i=setTimeout(r,ma);e.close(r);}))}cleanupOwnedResources(){try{Yt(this.projectRoot,process.pid);}catch(e){console.error("[devflow-daemon] Failed to unregister:",e.message);}this.removePathIfOwned(this.socketPath,this.socketIdentity,"socket"),this.removePathIfOwned(this.pidPath,this.pidIdentity,"PID file",`${process.pid}
|
|
33
|
+
`);}};if(process.env.DEVFLOW_HOOK_DAEMON_DISABLE_AUTOSTART!=="1"){let n=process.argv[2]||process.env.CLAUDE_PROJECT_DIR||process.cwd(),e=new yt(n,process.argv[3]);process.once("SIGTERM",()=>{e.shutdown();}),process.once("SIGINT",()=>{e.shutdown();}),e.start().catch(t=>{console.error("[devflow-daemon] Failed to start:",t),process.exit(1);});}export{yt as HookDaemon,Sa as injectProjectRootIfMissing};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {createHash,randomUUID}from'node:crypto';import {readFileSync,openSync,constants,fstatSync,closeSync,writeFileSync,fsyncSync,unlinkSync,lstatSync,mkdirSync,chmodSync,renameSync,rmSync}from'node:fs';import {resolve,join,dirname,isAbsolute,basename}from'node:path';import {getProjectStateDir}from'@devflow-tools/sdk';var S=1,v="memory-snapshot-v1.json",B=512*1024,V=256*1024,q=2e3,ce=500,de=10,ue=240,me=300*1e3,le=720*60*60*1e3,P=2147483647,he=100,X=250,Q=3e4,fe=10,w=new Map;function Z(e){return e.currentUid===void 0?{ownerSafe:true,modeSafe:true}:{ownerSafe:e.ownerUid===e.currentUid,modeSafe:(e.mode&18)===0}}function h(e){return resolve(e)}function p(e){return createHash("sha256").update(h(e)).digest("hex").slice(0,16)}function C(e,t={}){let o=p(e),n=t.stateRoot?join(t.stateRoot,o):getProjectStateDir(h(e));return join(n,v)}function b(e,t){let n=(e instanceof Error?e.message:"").replace(/[\r\n\t]+/gu," ").trim().slice(0,160);return n?`${t}:${n}`:t}function L(e,t){return Array.isArray(e)&&e.length<=t&&e.every(o=>typeof o=="string"&&o.length>0&&o.length<=512)}function ye(e){if(!e||typeof e!="object"||Array.isArray(e))return false;let t=e;return typeof t.id=="string"&&t.id.length>0&&t.id.length<=512&&typeof t.kind=="string"&&t.kind.length>0&&t.kind.length<=128&&(t.family===void 0||typeof t.family=="string"&&t.family.length>0&&t.family.length<=256)&&(t.entity===void 0||typeof t.entity=="string"&&t.entity.length>0&&t.entity.length<=256)&&L(t.memoryIds,100)&&(t.status==="withheld"||t.status==="resolved")&&(t.summary===void 0||typeof t.summary=="string"&&t.summary.length<=2e3)}function pe(e){if(!e||typeof e!="object"||Array.isArray(e))return false;let t=e;return typeof t.reason=="string"&&t.reason.length>0&&t.reason.length<=512&&(t.stale===void 0||typeof t.stale=="boolean")}function T(e,t,o){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e,r=h(t),s=p(r),a=n.generation===void 0?0:n.generation;return n.version!==S||n.projectRoot!==r||n.projectHash!==s||typeof n.markdown!="string"||Buffer.byteLength(n.markdown,"utf8")>V||!L(n.memoryIds,q)||!Array.isArray(n.conflicts)||n.conflicts.length>ce||!n.conflicts.every(ye)||typeof n.generatedAt!="number"||!Number.isFinite(n.generatedAt)||n.generatedAt<0||n.generatedAt>o+me||!Number.isInteger(a)||a<0||a>P||!["ready","pending","degraded","disabled"].includes(String(n.status))||n.degradation!==void 0&&!pe(n.degradation)?null:{...n,generation:a}}function $(e,t,o,n,r=0){let s=h(e);return {version:S,projectRoot:s,projectHash:p(s),markdown:"",memoryIds:[],conflicts:[],generatedAt:n,generation:r,status:t,degradation:{reason:o}}}function l(e,t={}){let o=t.now??Date.now(),n=C(e,t),r;try{r=openSync(n,constants.O_RDONLY|constants.O_NOFOLLOW);let s=fstatSync(r);if(!s.isFile()||s.size<=0||s.size>B)throw new Error("cache_size_invalid");let a=Z({...typeof process.getuid=="function"?{currentUid:process.getuid()}:{},ownerUid:s.uid,mode:s.mode});if(!a.ownerSafe)throw new Error("cache_owner_invalid");if(!a.modeSafe)throw new Error("cache_permissions_unsafe");let c=JSON.parse(readFileSync(r,"utf8")),d=T(c,e,o);if(!d)throw new Error("cache_schema_invalid");return d.status==="ready"&&o-d.generatedAt>le?{snapshot:{...d,status:"degraded",degradation:{reason:"cache_stale",stale:!0}},source:"cache",valid:!0,stale:!0}:{snapshot:d,source:"cache",valid:!0,stale:!1}}catch(s){let c=s.code==="ENOENT";return {snapshot:$(e,c?"pending":"degraded",c?"cache_missing":b(s,"cache_invalid"),o),source:"none",valid:false,stale:false}}finally{if(r!==void 0)try{closeSync(r);}catch{}}}function I(e){if(!Number.isInteger(e)||e<0||e>=P)throw new Error("memory_snapshot_generation_exhausted");return e+1}function ge(e){let t=dirname(e);mkdirSync(t,{recursive:true,mode:448}),chmodSync(t,448);}function D(e){ge(e);let t=`${e}.lock`,o={pid:process.pid,createdAt:Date.now(),token:randomUUID()},n=JSON.stringify(o),r;try{return r=openSync(t,"wx",384),writeFileSync(r,n),fsyncSync(r),{fd:r,path:t,contents:n}}catch(s){if(r!==void 0){try{closeSync(r);}catch{}try{unlinkSync(t);}catch{}}if(s.code==="EEXIST")return null;throw s}}function Se(e){if(!e||typeof e!="object"||Array.isArray(e))return false;let t=e;return Number.isInteger(t.pid)&&Number(t.pid)>0&&typeof t.createdAt=="number"&&Number.isFinite(t.createdAt)&&typeof t.token=="string"&&t.token.length>0}function we(e){try{return process.kill(e,0),!1}catch(t){return t.code==="ESRCH"}}function Me(e){return !e.canonicalCachePath||!e.directoryIsSafe||!e.lockIsRegularFile||!e.metadataValid||!e.contentsUnchanged||!e.ownerDead&&!e.stale?false:e.currentUid!==void 0?e.directoryUid===e.currentUid&&e.lockUid===e.currentUid:true}function be(e){return isAbsolute(e)&&resolve(e)===e&&basename(e)===v&&/^[a-f0-9]{16}$/u.test(basename(dirname(e)))}function ee(e,t){let o=`${e}.lock`;try{let n=lstatSync(dirname(e)),r=lstatSync(o),s=readFileSync(o,"utf8"),a=null;try{let F=JSON.parse(s);Se(F)&&(a=F);}catch{}let c=a?.createdAt??r.mtimeMs,d=Date.now()-c>t,u=a?we(a.pid):!1,m=readFileSync(o,"utf8")===s,i=typeof process.getuid=="function"?process.getuid():void 0,f=Z({...i!==void 0?{currentUid:i}:{},ownerUid:n.uid,mode:n.mode});return Me({canonicalCachePath:be(e),directoryIsSafe:n.isDirectory()&&!n.isSymbolicLink()&&f.modeSafe,lockIsRegularFile:r.isFile()&&!r.isSymbolicLink(),metadataValid:a!==null,ownerDead:u,stale:d,contentsUnchanged:m,...i!==void 0?{currentUid:i}:{},directoryUid:n.uid,lockUid:r.uid})?(unlinkSync(o),!0):!1}catch{return false}}function te(e){try{closeSync(e.fd);}catch{}try{readFileSync(e.path,"utf8")===e.contents&&unlinkSync(e.path);}catch{}}function _e(e,t,o){let n=D(e);if(!n&&ee(e,t.lockStaleMs??Q)&&(n=D(e)),!n)throw new Error("memory_snapshot_cache_lock_busy");try{return o()}finally{te(n);}}function ke(e){return new Promise(t=>setTimeout(t,e))}function R(e,t,o,n){let r=Number.isFinite(e)?Math.floor(e):t;return Math.min(n,Math.max(o,r))}async function Ce(e,t){let o=R(t.lockTimeoutMs,he,0,X),n=R(t.lockRetryMs,fe,1,X),r=R(t.lockStaleMs,Q,0,Number.MAX_SAFE_INTEGER),s=Date.now()+o;for(;;){let a=D(e);if(a)return a;if(ee(e,r))continue;let c=s-Date.now();if(c<=0)throw new Error("memory_snapshot_cache_lock_timeout");await ke(Math.min(n,c));}}async function G(e,t,o){let n=await Ce(e,t);try{return await o()}finally{te(n);}}function N(e,t,o,n){let r=n.now??Date.now(),s=h(e),a={version:S,projectRoot:s,projectHash:p(s),markdown:t.markdown,memoryIds:t.memoryIds??[],conflicts:t.conflicts??[],generatedAt:r,generation:o,status:t.status??"ready",...t.degradation?{degradation:t.degradation}:{}};if(!T(a,e,r))throw new Error("memory_snapshot_payload_invalid");let c=JSON.stringify(a);if(Buffer.byteLength(c,"utf8")>B)throw new Error("memory_snapshot_cache_too_large");let d=C(e,n),u=dirname(d);mkdirSync(u,{recursive:true,mode:448}),chmodSync(u,448);let m=join(u,`.${v}.${process.pid}.${randomUUID()}.tmp`),i;try{i=openSync(m,"wx",384),writeFileSync(i,c),fsyncSync(i),closeSync(i),i=void 0,chmodSync(m,384),renameSync(m,d),chmodSync(d,384);let f;try{f=openSync(u,"r");try{fsyncSync(f);}catch{}}finally{f!==void 0&&closeSync(f);}return a}finally{if(i!==void 0)try{closeSync(i);}catch{}rmSync(m,{force:true});}}function Pe(e,t,o={}){let n=C(e,o);return _e(n,o,()=>{let r=l(e,o),s=o.fixedGeneration??I(r.valid?r.snapshot.generation:0);if(!Number.isInteger(s)||s<0||s>P)throw new Error("memory_snapshot_generation_invalid");if(o.fixedGeneration!==void 0&&r.valid&&s<=r.snapshot.generation)throw new Error("memory_snapshot_fixed_generation_not_advanced");return N(e,t,s,o)})}function Re(e,t){let n=(w.get(e)??Promise.resolve()).catch(()=>{}).then(t),r=n.then(()=>{},()=>{});return w.set(e,r),n.finally(()=>{w.get(e)===r&&w.delete(e);})}function O(e,t,o,n,r){return e.valid?e.snapshot.generation>r?{...e,persisted:false}:{...e,snapshot:{...e.snapshot,status:"degraded",degradation:{reason:o,stale:e.stale||void 0}},persisted:false}:{snapshot:$(t,"degraded",o,n,r),source:"none",valid:false,stale:false,persisted:false}}async function Oe(e){let t=C(e.projectRoot,e.cacheOptions);return Re(t,async()=>{let o=l(e.projectRoot,e.cacheOptions),n=o.valid?o.snapshot.generation:0,r;try{r=await e.load();}catch(s){let a=b(s,`refresh_failed:${e.reason}`);try{return await G(t,e.cacheOptions??{},()=>{let c=l(e.projectRoot,e.cacheOptions);if(c.valid)return O(c,e.projectRoot,a,e.cacheOptions?.now??Date.now(),n);let d=I(n),u=$(e.projectRoot,"degraded",a,e.cacheOptions?.now??Date.now(),d);return {snapshot:N(e.projectRoot,u,d,e.cacheOptions??{}),source:"cache",valid:!0,stale:!1,persisted:!0}})}catch(c){let d=l(e.projectRoot,e.cacheOptions);return O(d,e.projectRoot,b(c,a),e.cacheOptions?.now??Date.now(),n)}}try{return await G(t,e.cacheOptions??{},()=>{let s=l(e.projectRoot,e.cacheOptions);if(s.valid&&s.snapshot.generation>n)return {...s,persisted:!1};let a=I(Math.max(n,s.valid?s.snapshot.generation:0));return {snapshot:N(e.projectRoot,r,a,e.cacheOptions??{}),source:"cache",valid:!0,stale:!1,persisted:!0}})}catch(s){let a=l(e.projectRoot,e.cacheOptions);return O(a,e.projectRoot,b(s,`refresh_commit_failed:${e.reason}`),e.cacheOptions?.now??Date.now(),n)}})}async function Le(e){return Oe({projectRoot:e.projectRoot,reason:e.reason,cacheOptions:e.cacheOptions,load:async()=>{if(e.injectConfig===false)return {status:"disabled",markdown:"",memoryIds:[],conflicts:[]};let t=typeof e.injectConfig=="object"?e.injectConfig:{},o=Number.isFinite(t.topN)?Math.max(0,Math.floor(t.topN)):10,n=Number.isFinite(t.budgetTokens)?Math.max(1,Math.floor(t.budgetTokens)):800,r=await e.memory.getAll({purpose:"session_bootstrap",budgetTokens:n,limit:o}),a=Number.isInteger(r.truncatedCount)&&r.truncatedCount>=0?r.truncatedCount:null,c=r.memories.length===0&&a!==0,d=a!==null&&a>0?"snapshot_results_truncated":"snapshot_truncation_unknown",u=(r.conflicts??[]).map(i=>({id:i.id,kind:i.kind,family:i.family,entity:i.entity,memoryIds:i.memoryIds,status:i.status,...i.summary?{summary:i.summary}:{}})),m=c?`## Project memory
|
|
2
|
+
DevFlow memory snapshot=degraded; reason=${d}. Memory result completeness is not authoritative; do not conclude that the project has no memories.`:r.memories.length===0&&u.length>0?`## Project memory
|
|
3
|
+
${u.length} explicit preference conflict(s) are withheld from automatic guidance; an explicit choice is required.`:r.memories.length===0?`## Project memory
|
|
4
|
+
\u672C\u9879\u76EE\u6682\u65E0\u8BB0\u5FC6`:`## Project memory (auto-injected, ${r.memories.length} items, ${r.tokenCount} tokens)
|
|
5
|
+
${r.memories.map(i=>`- **${i.title||i.type}**: ${i.content} (confidence ${i.confidence.toFixed(2)}, ${i.source})`).join(`
|
|
6
|
+
`)}`;return {status:c?"degraded":"ready",markdown:m,memoryIds:r.memories.map(i=>i.id),conflicts:u,...c?{degradation:{reason:d}}:{}}}})}function Ee(e){if(!e)return true;try{return JSON.parse(readFileSync(e,"utf8")).sessionStart?.injectMemories??!0}catch{return true}}function Ae(e,t,o){if(!t.trim())return null;try{let n=JSON.parse(t);if(n.status!=="ok"&&n.status!=="degraded")return null;if(n.enabled===!1){let s=h(e);return {version:S,projectRoot:s,projectHash:p(s),markdown:"",memoryIds:[],conflicts:[],generatedAt:o,generation:0,status:"disabled"}}let r=T(n.snapshot,e,o);if(r)return r;if(n.status==="ok"&&typeof n.markdown=="string"&&n.markdown.length>0&&Buffer.byteLength(n.markdown,"utf8")<=V){let s=h(e);return {version:S,projectRoot:s,projectHash:p(s),markdown:n.markdown,memoryIds:L(n.memoryIds,q)?n.memoryIds:[],conflicts:[],generatedAt:o,generation:0,status:"ready"}}}catch{}return null}function E(e,t){return [...(e??t).replace(/[\r\n\t|]+/gu," ").trim()||t].slice(0,ue).join("")}function je(e){if(e.length===0)return "";let t=e.slice(0,de),o=t.map(n=>{let r=E(n.family,"unknown"),s=E(n.entity,"unknown"),a=E(n.summary,"Explicit choice required.");return `- family=${r}; entity=${s}; status=${n.status}; summary=${a}`});return e.length>t.length&&o.push(`- ${e.length-t.length} additional conflict(s) omitted from SessionStart output.`),`## Withheld preference conflicts (${e.length})
|
|
7
|
+
${o.join(`
|
|
8
|
+
`)}`}function Ie(e){let t=e.now??Date.now();if(Ee(e.configPath)===false)return "";let o=Ae(e.projectRoot,e.daemonResponse??"",t),n=o?{snapshot:o,source:"daemon"}:l(e.projectRoot,{...e.cacheOptions,now:t}),{snapshot:r}=n;if(r.status==="disabled")return `## Project memory
|
|
9
|
+
DevFlow memory snapshot=pending; source=${n.source}; reason=previous_snapshot_disabled. Memory availability is not yet known; do not conclude that the project has no memories.`;let s=new Date(r.generatedAt).toISOString(),a=r.degradation?.reason?`; reason=${r.degradation.reason}`:"",c=`DevFlow memory snapshot=${r.status}; source=${n.source}; generatedAt=${s}${a}.`,d=je(r.conflicts);return r.markdown?[r.markdown,d,c].filter(Boolean).join(`
|
|
10
|
+
`):["## Project memory",d,`${c} Memory availability is not yet known; do not conclude that the project has no memories.`].filter(Boolean).join(`
|
|
11
|
+
`)}if(process.env.DEVFLOW_MEMORY_SNAPSHOT_CLI==="1"){let[,,e,t,o]=process.argv;e!=="session-start"||!t?process.exitCode=2:process.stdout.write(Ie({projectRoot:t,configPath:o,daemonResponse:process.env.DEVFLOW_MEMORY_RESPONSE}));}export{v as MEMORY_SNAPSHOT_CACHE_FILE,S as MEMORY_SNAPSHOT_CACHE_VERSION,Z as evaluatePlatformPathPermissions,C as getMemorySnapshotCachePath,l as readMemorySnapshotCache,Oe as refreshMemorySnapshotCache,Le as refreshProjectMemorySnapshot,Ie as renderSessionStartMemory,Me as shouldRecoverAbandonedCacheLock,Pe as writeMemorySnapshotCache};
|