@devflow-tools/cli 0.17.7 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -2
  3. package/dist/commands/context.d.ts +1 -1
  4. package/dist/commands/context.d.ts.map +1 -1
  5. package/dist/commands/context.js +8 -2
  6. package/dist/commands/context.js.map +1 -1
  7. package/dist/commands/db.js +1 -1
  8. package/dist/commands/db.js.map +1 -1
  9. package/dist/commands/docs.d.ts.map +1 -1
  10. package/dist/commands/docs.js +2 -0
  11. package/dist/commands/docs.js.map +1 -1
  12. package/dist/commands/doctor.d.ts.map +1 -1
  13. package/dist/commands/doctor.js +34 -44
  14. package/dist/commands/doctor.js.map +1 -1
  15. package/dist/commands/graph.js +1 -1
  16. package/dist/commands/graph.js.map +1 -1
  17. package/dist/commands/index-cmd.js +1 -1
  18. package/dist/commands/index-cmd.js.map +1 -1
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +2 -1
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/knowledge.d.ts +1 -1
  23. package/dist/commands/knowledge.d.ts.map +1 -1
  24. package/dist/commands/knowledge.js +21 -5
  25. package/dist/commands/knowledge.js.map +1 -1
  26. package/dist/commands/memory.d.ts.map +1 -1
  27. package/dist/commands/memory.js +3 -2
  28. package/dist/commands/memory.js.map +1 -1
  29. package/dist/commands/plugin-memory-hints.js +3 -0
  30. package/dist/commands/plugin-memory-hints.js.map +1 -1
  31. package/dist/commands/workflow.js +1 -1
  32. package/dist/commands/workflow.js.map +1 -1
  33. package/dist/index.js +1 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/plugin-files/.claude-plugin/plugin.json +1 -1
  36. package/dist/plugin-files/dist/command-registry.json +5 -5
  37. package/dist/plugin-files/dist/hooks/enforcer-summary.js +3 -3
  38. package/dist/plugin-files/dist/hooks/hook-client.js +3 -3
  39. package/dist/plugin-files/dist/hooks/hook-daemon.js +27 -25
  40. package/dist/plugin-files/dist/hooks/post-tool-use-failure.js +2 -2
  41. package/dist/plugin-files/dist/hooks/post-tool-use.js +6 -6
  42. package/dist/plugin-files/dist/hooks/pre-compact.js +2 -2
  43. package/dist/plugin-files/dist/hooks/pre-tool-use.js +4 -4
  44. package/dist/plugin-files/dist/hooks/server-bootstrap.js +22 -22
  45. package/dist/plugin-files/dist/hooks/session-end.js +6 -6
  46. package/dist/plugin-files/dist/hooks/stop.js +10 -10
  47. package/dist/plugin-files/dist/hooks/user-prompt-submit.js +11 -9
  48. package/dist/plugin-files/package.json +28 -19
  49. package/package.json +39 -29
@@ -1,4 +1,4 @@
1
- import {getLocalApiKey,resolveRuntimeEndpoint,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure}from'@devflow-tools/sdk';import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync}from'fs';import {join as join$1}from'path';import {homedir as homedir$1}from'os';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {request}from'node:http';import {existsSync as existsSync$1,mkdirSync as mkdirSync$1,appendFileSync}from'node:fs';import {join}from'node:path';import {homedir}from'node:os';import {MemoryGate}from'@devflow-tools/memory-engine';import {createHash}from'node:crypto';function b(s){return s??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function g(s,r,e){try{let t=openGlobalDevFlowDatabase();try{t.insertEvent({kind:s,timestamp:Date.now(),duration:e,success:r.success!==!1,metadata:r});}finally{t.close();}}catch{}}var W=getLocalApiKey(),y=join(homedir(),".devflow","errors");async function k(s,r,e={}){let t=e.endpoint??resolveRuntimeEndpoint().url,o=e.timeout??1500,n=e.durableMirror??true,i=e.maxRetries??(n?0:2),a=e.circuitBreaker??true,c=acquireRuntimeHttpCircuit(t,s);if(a&&!c.allowed)return {delivered:false,suppressed:true,fallbackReason:c.state.fallbackReason};let d;for(let l=0;l<=i;l+=1)try{return await J(t,s,r,o),a&&registerRuntimeHttpSuccess(t,s).transitioned&&g("http_circuit_transition",{endpoint:t,path:new URL(s,t).pathname,previous:c.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(m){d=m instanceof Error?m:new Error(String(m)),l<i&&await V(Math.min(100*2**l,1e3));}if(!d)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return w(s,d),{delivered:false,suppressed:false,fallbackReason:d.message};let u=registerRuntimeHttpFailure(t,s,e.fallbackReason??(n?"local_durable_mirror":"http_delivery_failed"));return u.transitioned&&(w(s,d),g("http_circuit_transition",{endpoint:t,path:new URL(s,t).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 J(s,r,e,t){return new Promise((o,n)=>{let i=JSON.stringify(e),a=new URL(r,s),c=false,d=l=>{c||(c=true,l?n(l):o());},u=request({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":W,"Content-Length":Buffer.byteLength(i)},timeout:t},l=>{l.on("error",d),l.on("end",()=>{let m=l.statusCode??0;d(m>=200&&m<300?void 0:new Error(`HTTP ${m}`));}),l.resume();});u.on("error",d),u.on("timeout",()=>u.destroy(new Error(`HTTP mirror timed out after ${t}ms`))),u.write(i),u.end();})}function w(s,r){try{existsSync$1(y)||mkdirSync$1(y,{recursive:!0}),appendFileSync(join(y,"http-errors.log"),`${new Date().toISOString()} | ${s} | ${r.message}
2
- `);}catch{}}function V(s){return new Promise(r=>setTimeout(r,s))}var O=1e4,X=3e4,f=500,h=class{constructor(r){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=r?.apiUrl,this.cacheDir=r?.cacheDir??join$1(process.env.DEVFLOW_STATE_DIR??join$1(homedir$1(),".devflow","global"),"telemetry-cache"),this.legacyCacheDir=r?.legacyCacheDir??(r?.cacheDir?null:join$1(homedir$1(),".devflow","telemetry-cache")),this.database=r?.database??null,this.ownsDatabase=!r?.database;let e=r?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(r){let e={...r,input:this.truncateInput(r.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),r.eventId):null}async sendExecutionStart(r,e,t,o,n=process.env.CLAUDE_PROJECT_DIR??process.cwd(),i=[]){let a={executionId:r,sessionId:e,skillName:t,startedAt:o,projectRoot:n,requiredMcpTools:i};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(r,e="completed",t=Date.now(),o){let n={executionId:r,status:e,finishedAt:t,metadata:o},i=this.commitOrCache("execution_complete",n);return i&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",n),i}async sendSessionStart(r,e,t){let o={id:r,projectRoot:e,startedAt:t,label:e.split("/").pop()??"unknown"},n=this.commitOrCache("session_start",o);return n&&this.postHttp("/api/telemetry/sessions",o),n}async completeEvent(r){let e=this.commitOrCache("complete_event",r);return e&&(this.postHttp("/api/telemetry/tool-call/output",r),this.scheduleMetricAggregation()),e}async endSession(r,e=Date.now()){let t={sessionId:r,finishedAt:e},o=this.commitOrCache("session_end",t);return o&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(r)}/close`,{finishedAt:e})),o}async flushCache(){try{let t=this.getDatabase(),o=t.listTelemetryFailures({unresolvedOnly:!0,limit:f}).reverse();for(let n of o)try{this.applyOperation(n.operation,n.payload),t.resolveTelemetryFailure(n.id);}catch{}t.trimTelemetryFailures(f);}catch{}let e=[...new Set([this.cacheDir,this.legacyCacheDir].filter(t=>!!t))].filter(t=>existsSync(t)).flatMap(t=>readdirSync(t).filter(o=>o.endsWith(".json")).map(o=>{let n=join$1(t,o);try{return {cacheFile:n,envelope:Z(JSON.parse(readFileSync(n,"utf8")),o)}}catch{return null}})).filter(t=>t!==null).sort((t,o)=>t.envelope.timestamp-o.envelope.timestamp||x(t.envelope.operation)-x(o.envelope.operation));for(let{cacheFile:t,envelope:o}of e)try{let n=this.getDatabase();n.insertTelemetryFailure({id:o.id,operation:o.operation,payload:o.payload,error:o.failure,createdAt:o.timestamp}),this.applyOperation(o.operation,o.payload),n.resolveTelemetryFailure(o.id),unlinkSync(t);}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(r,e){try{return this.applyOperation(r,e),!0}catch(t){return this.cacheOperation(r,e,t),false}}applyOperation(r,e){let t=this.getDatabase();switch(r){case "tool_call":this.ensureParentSession(t,e),t.insertToolCallEvent(e);return;case "execution_start":this.ensureParentSession(t,e),t.insertSkillExecution({executionId:e.executionId,sessionId:e.sessionId,skillName:e.skillName,startedAt:e.startedAt,status:"running",requiredMcpTools:e.requiredMcpTools});return;case "execution_complete":t.reconcileSkillExecution(e.executionId,e.status,e.finishedAt,e.metadata);return;case "session_start":t.ensureSession(e),t.insertRun({id:M(e.id),source:"hook",tool:"session",input:{projectRoot:e.projectRoot},status:"active",startedAt:e.startedAt,tokenUsed:0,metadata:{sessionId:e.id,projectRoot:e.projectRoot}});return;case "complete_event":if(!t.updateToolCallEvent(e.eventId,{output:e.output===void 0?void 0:JSON.stringify(e.output),error:e.error,failureCategory:e.failureCategory,duration:e.duration}))throw new Error(`Tool call event ${e.eventId} is not available for completion`);return;case "session_end":t.closeSession(e.sessionId,e.finishedAt),t.updateRun(M(e.sessionId),{status:"completed",finishedAt:e.finishedAt});return}}ensureParentSession(r,e){let t=typeof e.sessionId=="string"?e.sessionId.trim():"";if(!t)throw new Error("Canonical session ID is required for telemetry");let o=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";r.ensureSession({id:t,projectRoot:o,label:o==="unknown"?void 0:o.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(r,e,t){let o=Date.now(),n={id:`failure:${o}:${Math.random().toString(36).slice(2,11)}`,operation:r,payload:e,failure:t instanceof Error?t.message:String(t),timestamp:o};try{let i=this.getDatabase();i.insertTelemetryFailure({id:n.id,operation:r,payload:e,error:n.failure,createdAt:o}),i.trimTelemetryFailures(f),this.scheduleRetry();return}catch{}try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let i=join$1(this.cacheDir,`${o}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(i,JSON.stringify(n,null,2),{mode:384}),this.trimCompatibilityCache(),this.scheduleRetry();}catch{}}trimCompatibilityCache(){try{let r=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of r.slice(0,Math.max(0,r.length-f)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},X).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(r,e){k(r,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(r){let e=JSON.stringify(r);return e===void 0||e.length<=O?r:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,O)}...`}}};function x(s){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(s)}function M(s){return `hook-run:${s}`}function Z(s,r){if(!s||typeof s!="object")throw new Error("Invalid telemetry cache envelope");let e=s;if(typeof e.operation=="string"&&e.payload!==void 0)return e;let t=e.type==="tool_call"?"tool_call":e.type==="execution_start"?"execution_start":null;if(!t)throw new Error("Unknown legacy telemetry cache operation");let o=e.payload??{},n=Number(o.timestamp??o.startedAt??Date.now());return {id:`legacy-cache:${r}`,operation:t,payload:o,failure:"Replayed legacy HTTP-first telemetry cache entry",timestamp:n}}async function A(s){let r=!s.memory,e=s.memory??new MemoryGate(s.projectRoot),t=0,o=0;try{await e.forceWarmUp(),s.trigger==="session_end"&&(t=await e.releasePendingDistillLeases(s.sessionId)),o=e.getPendingEventCount(s.sessionId,s.trigger!=="session_end");}finally{r&&e.close();}let n=Date.now(),i=s.trigger==="session_end"&&s.sessionId?`distill:session_end:${createHash("sha256").update(`${s.projectRoot}\0${s.sessionId}`).digest("hex").slice(0,24)}`:`distill:${n}:${Math.random().toString(36).slice(2,10)}`,a={id:i,pendingEvents:o,releasedLeases:t,trigger:s.trigger,sessionId:s.sessionId,details:s.details};try{let c=openGlobalDevFlowDatabase();try{c.recordMemoryDistillCheckpoint({id:i,projectRoot:s.projectRoot,sessionId:s.sessionId,trigger:s.trigger,pendingEvents:o,releasedLeases:t,details:s.details,createdAt:n}),c.insertEvent({kind:"memory_distill_requested",timestamp:n,success:!0,metadata:{...a,projectRoot:s.projectRoot}});}finally{c.close();}}catch(c){if(s.strictPersistence)throw c}return a}function P(s){if(s.pendingEvents===0)return "";let r=s.sessionId?`\uFF0CsessionId=${s.sessionId}`:"";return `Memory distill checkpoint: ${s.pendingEvents} \u4E2A\u4E8B\u4EF6\u5F85\u63D0\u70BC${r}\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`}var F="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function j(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}async function re(s="",r=b()){let e;try{let i=JSON.parse(s);typeof i.session_id=="string"&&i.session_id.trim()&&(e=i.session_id.trim());}catch{}let t=new h;try{await t.flushAndAggregate();}finally{t.close();}let o=await A({projectRoot:r,sessionId:e,trigger:"pre_compact"}),n=[j()?F:"",P(o)].filter(Boolean).join(`
1
+ import {getLocalApiKey,getDevFlowStateRoot,resolveRuntimeEndpoint,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure}from'@devflow-tools/sdk';import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync}from'fs';import {join as join$1}from'path';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {request}from'node:http';import {existsSync as existsSync$1,mkdirSync as mkdirSync$1,appendFileSync}from'node:fs';import {join}from'node:path';import {MemoryGate}from'@devflow-tools/memory-engine';import {createHash}from'node:crypto';function b(s){return s??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function p(s,r,e){try{let t=openGlobalDevFlowDatabase();try{t.insertEvent({kind:s,timestamp:Date.now(),duration:e,success:r.success!==!1,metadata:r});}finally{t.close();}}catch{}}var G=getLocalApiKey(),y=join(getDevFlowStateRoot(),"errors");async function k(s,r,e={}){let t=e.endpoint??resolveRuntimeEndpoint().url,o=e.timeout??1500,n=e.durableMirror??true,i=e.maxRetries??(n?0:2),a=e.circuitBreaker??true,c=acquireRuntimeHttpCircuit(t,s);if(a&&!c.allowed)return {delivered:false,suppressed:true,fallbackReason:c.state.fallbackReason};let d;for(let l=0;l<=i;l+=1)try{return await J(t,s,r,o),a&&registerRuntimeHttpSuccess(t,s).transitioned&&p("http_circuit_transition",{endpoint:t,path:new URL(s,t).pathname,previous:c.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(m){d=m instanceof Error?m:new Error(String(m)),l<i&&await W(Math.min(100*2**l,1e3));}if(!d)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return w(s,d),{delivered:false,suppressed:false,fallbackReason:d.message};let u=registerRuntimeHttpFailure(t,s,e.fallbackReason??(n?"local_durable_mirror":"http_delivery_failed"));return u.transitioned&&(w(s,d),p("http_circuit_transition",{endpoint:t,path:new URL(s,t).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 J(s,r,e,t){return new Promise((o,n)=>{let i=JSON.stringify(e),a=new URL(r,s),c=false,d=l=>{c||(c=true,l?n(l):o());},u=request({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":G,"Content-Length":Buffer.byteLength(i)},timeout:t},l=>{l.on("error",d),l.on("end",()=>{let m=l.statusCode??0;d(m>=200&&m<300?void 0:new Error(`HTTP ${m}`));}),l.resume();});u.on("error",d),u.on("timeout",()=>u.destroy(new Error(`HTTP mirror timed out after ${t}ms`))),u.write(i),u.end();})}function w(s,r){try{existsSync$1(y)||mkdirSync$1(y,{recursive:!0}),appendFileSync(join(y,"http-errors.log"),`${new Date().toISOString()} | ${s} | ${r.message}
2
+ `);}catch{}}function W(s){return new Promise(r=>setTimeout(r,s))}var C=1e4,z=3e4,f=500,h=class{constructor(r){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=r?.apiUrl,this.cacheDir=r?.cacheDir??join$1(getDevFlowStateRoot(),"global","telemetry-cache"),this.database=r?.database??null,this.ownsDatabase=!r?.database;let e=r?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(r){let e={...r,input:this.truncateInput(r.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),r.eventId):null}async sendExecutionStart(r,e,t,o,n=process.env.CLAUDE_PROJECT_DIR??process.cwd(),i=[]){let a={executionId:r,sessionId:e,skillName:t,startedAt:o,projectRoot:n,requiredMcpTools:i};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(r,e="completed",t=Date.now(),o){let n={executionId:r,status:e,finishedAt:t,metadata:o},i=this.commitOrCache("execution_complete",n);return i&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",n),i}async sendSessionStart(r,e,t){let o={id:r,projectRoot:e,startedAt:t,label:e.split("/").pop()??"unknown"},n=this.commitOrCache("session_start",o);return n&&this.postHttp("/api/telemetry/sessions",o),n}async completeEvent(r){let e=this.commitOrCache("complete_event",r);return e&&(this.postHttp("/api/telemetry/tool-call/output",r),this.scheduleMetricAggregation()),e}async endSession(r,e=Date.now()){let t={sessionId:r,finishedAt:e},o=this.commitOrCache("session_end",t);return o&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(r)}/close`,{finishedAt:e})),o}async flushCache(){try{let e=this.getDatabase(),t=e.listTelemetryFailures({unresolvedOnly:!0,limit:f}).reverse();for(let o of t)try{this.applyOperation(o.operation,o.payload),e.resolveTelemetryFailure(o.id);}catch{}e.trimTelemetryFailures(f);}catch{}let r=(existsSync(this.cacheDir)?readdirSync(this.cacheDir):[]).filter(e=>e.endsWith(".json")).map(e=>{let t=join$1(this.cacheDir,e);try{return {cacheFile:t,envelope:Z(JSON.parse(readFileSync(t,"utf8")))}}catch{return null}}).filter(e=>e!==null).sort((e,t)=>e.envelope.timestamp-t.envelope.timestamp||O(e.envelope.operation)-O(t.envelope.operation));for(let{cacheFile:e,envelope:t}of r)try{let o=this.getDatabase();o.insertTelemetryFailure({id:t.id,operation:t.operation,payload:t.payload,error:t.failure,createdAt:t.timestamp}),this.applyOperation(t.operation,t.payload),o.resolveTelemetryFailure(t.id),unlinkSync(e);}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(r,e){try{return this.applyOperation(r,e),!0}catch(t){return this.cacheOperation(r,e,t),false}}applyOperation(r,e){let t=this.getDatabase();switch(r){case "tool_call":this.ensureParentSession(t,e),t.insertToolCallEvent(e);return;case "execution_start":this.ensureParentSession(t,e),t.insertSkillExecution({executionId:e.executionId,sessionId:e.sessionId,skillName:e.skillName,startedAt:e.startedAt,status:"running",requiredMcpTools:e.requiredMcpTools});return;case "execution_complete":t.reconcileSkillExecution(e.executionId,e.status,e.finishedAt,e.metadata);return;case "session_start":t.ensureSession(e),t.insertRun({id:x(e.id),source:"hook",tool:"session",input:{projectRoot:e.projectRoot},status:"active",startedAt:e.startedAt,tokenUsed:0,metadata:{sessionId:e.id,projectRoot:e.projectRoot}});return;case "complete_event":if(!t.updateToolCallEvent(e.eventId,{output:e.output===void 0?void 0:JSON.stringify(e.output),error:e.error,failureCategory:e.failureCategory,duration:e.duration}))throw new Error(`Tool call event ${e.eventId} is not available for completion`);return;case "session_end":t.closeSession(e.sessionId,e.finishedAt),t.updateRun(x(e.sessionId),{status:"completed",finishedAt:e.finishedAt});return}}ensureParentSession(r,e){let t=typeof e.sessionId=="string"?e.sessionId.trim():"";if(!t)throw new Error("Canonical session ID is required for telemetry");let o=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";r.ensureSession({id:t,projectRoot:o,label:o==="unknown"?void 0:o.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(r,e,t){let o=Date.now(),n={id:`failure:${o}:${Math.random().toString(36).slice(2,11)}`,operation:r,payload:e,failure:t instanceof Error?t.message:String(t),timestamp:o};try{let i=this.getDatabase();i.insertTelemetryFailure({id:n.id,operation:r,payload:e,error:n.failure,createdAt:o}),i.trimTelemetryFailures(f),this.scheduleRetry();return}catch{}try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let i=join$1(this.cacheDir,`${o}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(i,JSON.stringify(n,null,2),{mode:384}),this.trimRetryCache(),this.scheduleRetry();}catch{}}trimRetryCache(){try{let r=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of r.slice(0,Math.max(0,r.length-f)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},z).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(r,e){k(r,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(r){let e=JSON.stringify(r);return e===void 0||e.length<=C?r:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,C)}...`}}};function O(s){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(s)}function x(s){return `hook-run:${s}`}function Z(s){if(!s||typeof s!="object")throw new Error("Invalid telemetry cache envelope");let r=s;if(typeof r.id!="string"||typeof r.operation!="string"||r.payload===void 0||typeof r.failure!="string"||typeof r.timestamp!="number")throw new Error("Invalid telemetry cache envelope");return r}async function M(s){let r=!s.memory,e=s.memory??new MemoryGate(s.projectRoot),t=0,o=0;try{await e.forceWarmUp(),s.trigger==="session_end"&&(t=await e.releasePendingDistillLeases(s.sessionId)),o=e.getPendingEventCount(s.sessionId,s.trigger!=="session_end");}finally{r&&e.close();}let n=Date.now(),i=s.trigger==="session_end"&&s.sessionId?`distill:session_end:${createHash("sha256").update(`${s.projectRoot}\0${s.sessionId}`).digest("hex").slice(0,24)}`:`distill:${n}:${Math.random().toString(36).slice(2,10)}`,a={id:i,pendingEvents:o,releasedLeases:t,trigger:s.trigger,sessionId:s.sessionId,details:s.details};try{let c=openGlobalDevFlowDatabase();try{c.recordMemoryDistillCheckpoint({id:i,projectRoot:s.projectRoot,sessionId:s.sessionId,trigger:s.trigger,pendingEvents:o,releasedLeases:t,details:s.details,createdAt:n}),c.insertEvent({kind:"memory_distill_requested",timestamp:n,success:!0,metadata:{...a,projectRoot:s.projectRoot}});}finally{c.close();}}catch(c){if(s.strictPersistence)throw c}return a}function P(s){if(s.pendingEvents===0)return "";let r=s.sessionId?`\uFF0CsessionId=${s.sessionId}`:"";return `Memory distill checkpoint: ${s.pendingEvents} \u4E2A\u4E8B\u4EF6\u5F85\u63D0\u70BC${r}\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`}var A="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function F(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}async function re(s="",r=b()){let e;try{let i=JSON.parse(s);typeof i.session_id=="string"&&i.session_id.trim()&&(e=i.session_id.trim());}catch{}let t=new h;try{await t.flushAndAggregate();}finally{t.close();}let o=await M({projectRoot:r,sessionId:e,trigger:"pre_compact"}),n=[F()?A:"",P(o)].filter(Boolean).join(`
3
3
 
4
4
  `);return {hookSpecificOutput:{hookEventName:"PreCompact",...n?{additionalContext:n}:{}}}}if(process.argv[1]?.endsWith("pre-compact")||process.argv[1]?.endsWith("pre-compact.js")){let s=console.log,r=console.info,e=()=>{console.log=s,console.info=r;};console.log=console.error.bind(console),console.info=console.error.bind(console);let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",o=>{t+=o;}),process.stdin.on("end",()=>{re(t.trim()||process.argv[2]||"").then(o=>{e(),s(JSON.stringify(o)),process.exit(0);}).catch(()=>{e(),process.exit(0);});}),process.stdin.on("error",()=>{e(),process.exit(0);}),setTimeout(()=>process.exit(0),14e3).unref();}export{re as handlePreCompact};
@@ -1,4 +1,4 @@
1
- import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync,rmSync,linkSync,renameSync}from'fs';import {join as join$1,dirname as dirname$1}from'path';import {homedir as homedir$1}from'os';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {request}from'node:http';import {mkdirSync as mkdirSync$1,existsSync as existsSync$1,statSync,appendFileSync,chmodSync,readFileSync as readFileSync$1,rmSync as rmSync$1,renameSync as renameSync$1,writeFileSync as writeFileSync$1}from'node:fs';import {join,resolve,basename,relative,sep,dirname,isAbsolute,normalize}from'node:path';import {homedir}from'node:os';import {getLocalApiKey,resolveRuntimeEndpoint,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getProjectStateDir}from'@devflow-tools/sdk';import {fileURLToPath}from'url';import {emitSemanticControlLog}from'@devflow-tools/telemetry';import {createHash as createHash$1}from'node:crypto';import {randomUUID,createHash}from'crypto';function O(n,t,e){try{let o=openGlobalDevFlowDatabase();try{o.insertEvent({kind:n,timestamp:Date.now(),duration:e,success:t.success!==!1,metadata:t});}finally{o.close();}}catch{}}var ct=getLocalApiKey(),$=join(homedir(),".devflow","errors");async function oe(n,t,e={}){let o=e.endpoint??resolveRuntimeEndpoint().url,i=e.timeout??1500,r=e.durableMirror??true,s=e.maxRetries??(r?0:2),a=e.circuitBreaker??true,l=acquireRuntimeHttpCircuit(o,n);if(a&&!l.allowed)return {delivered:false,suppressed:true,fallbackReason:l.state.fallbackReason};let c;for(let u=0;u<=s;u+=1)try{return await lt(o,n,t,i),a&&registerRuntimeHttpSuccess(o,n).transitioned&&O("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:l.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(p){c=p instanceof Error?p:new Error(String(p)),u<s&&await dt(Math.min(100*2**u,1e3));}if(!c)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return te(n,c),{delivered:false,suppressed:false,fallbackReason:c.message};let d=registerRuntimeHttpFailure(o,n,e.fallbackReason??(r?"local_durable_mirror":"http_delivery_failed"));return d.transitioned&&(te(n,c),O("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:l.state.status,status:"open",failures:d.state.failures,openUntil:d.state.openUntil,fallbackReason:d.state.fallbackReason})),{delivered:false,suppressed:false,fallbackReason:d.state.fallbackReason}}function lt(n,t,e,o){return new Promise((i,r)=>{let s=JSON.stringify(e),a=new URL(t,n),l=false,c=u=>{l||(l=true,u?r(u):i());},d=request({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":ct,"Content-Length":Buffer.byteLength(s)},timeout:o},u=>{u.on("error",c),u.on("end",()=>{let p=u.statusCode??0;c(p>=200&&p<300?void 0:new Error(`HTTP ${p}`));}),u.resume();});d.on("error",c),d.on("timeout",()=>d.destroy(new Error(`HTTP mirror timed out after ${o}ms`))),d.write(s),d.end();})}function te(n,t){try{existsSync$1($)||mkdirSync$1($,{recursive:!0}),appendFileSync(join($,"http-errors.log"),`${new Date().toISOString()} | ${n} | ${t.message}
2
- `);}catch{}}function dt(n){return new Promise(t=>setTimeout(t,n))}var ce=1e4,mt=3e4,k=500,A=class{constructor(t){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=t?.apiUrl,this.cacheDir=t?.cacheDir??join$1(process.env.DEVFLOW_STATE_DIR??join$1(homedir$1(),".devflow","global"),"telemetry-cache"),this.legacyCacheDir=t?.legacyCacheDir??(t?.cacheDir?null:join$1(homedir$1(),".devflow","telemetry-cache")),this.database=t?.database??null,this.ownsDatabase=!t?.database;let e=t?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(t){let e={...t,input:this.truncateInput(t.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),t.eventId):null}async sendExecutionStart(t,e,o,i,r=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:t,sessionId:e,skillName:o,startedAt:i,projectRoot:r,requiredMcpTools:s};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(t,e="completed",o=Date.now(),i){let r={executionId:t,status:e,finishedAt:o,metadata:i},s=this.commitOrCache("execution_complete",r);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",r),s}async sendSessionStart(t,e,o){let i={id:t,projectRoot:e,startedAt:o,label:e.split("/").pop()??"unknown"},r=this.commitOrCache("session_start",i);return r&&this.postHttp("/api/telemetry/sessions",i),r}async completeEvent(t){let e=this.commitOrCache("complete_event",t);return e&&(this.postHttp("/api/telemetry/tool-call/output",t),this.scheduleMetricAggregation()),e}async endSession(t,e=Date.now()){let o={sessionId:t,finishedAt:e},i=this.commitOrCache("session_end",o);return i&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(t)}/close`,{finishedAt:e})),i}async flushCache(){try{let o=this.getDatabase(),i=o.listTelemetryFailures({unresolvedOnly:!0,limit:k}).reverse();for(let r of i)try{this.applyOperation(r.operation,r.payload),o.resolveTelemetryFailure(r.id);}catch{}o.trimTelemetryFailures(k);}catch{}let e=[...new Set([this.cacheDir,this.legacyCacheDir].filter(o=>!!o))].filter(o=>existsSync(o)).flatMap(o=>readdirSync(o).filter(i=>i.endsWith(".json")).map(i=>{let r=join$1(o,i);try{return {cacheFile:r,envelope:ht(JSON.parse(readFileSync(r,"utf8")),i)}}catch{return null}})).filter(o=>o!==null).sort((o,i)=>o.envelope.timestamp-i.envelope.timestamp||le(o.envelope.operation)-le(i.envelope.operation));for(let{cacheFile:o,envelope:i}of e)try{let r=this.getDatabase();r.insertTelemetryFailure({id:i.id,operation:i.operation,payload:i.payload,error:i.failure,createdAt:i.timestamp}),this.applyOperation(i.operation,i.payload),r.resolveTelemetryFailure(i.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(t,e){try{return this.applyOperation(t,e),!0}catch(o){return this.cacheOperation(t,e,o),false}}applyOperation(t,e){let o=this.getDatabase();switch(t){case "tool_call":this.ensureParentSession(o,e),o.insertToolCallEvent(e);return;case "execution_start":this.ensureParentSession(o,e),o.insertSkillExecution({executionId:e.executionId,sessionId:e.sessionId,skillName:e.skillName,startedAt:e.startedAt,status:"running",requiredMcpTools:e.requiredMcpTools});return;case "execution_complete":o.reconcileSkillExecution(e.executionId,e.status,e.finishedAt,e.metadata);return;case "session_start":o.ensureSession(e),o.insertRun({id:de(e.id),source:"hook",tool:"session",input:{projectRoot:e.projectRoot},status:"active",startedAt:e.startedAt,tokenUsed:0,metadata:{sessionId:e.id,projectRoot:e.projectRoot}});return;case "complete_event":if(!o.updateToolCallEvent(e.eventId,{output:e.output===void 0?void 0:JSON.stringify(e.output),error:e.error,failureCategory:e.failureCategory,duration:e.duration}))throw new Error(`Tool call event ${e.eventId} is not available for completion`);return;case "session_end":o.closeSession(e.sessionId,e.finishedAt),o.updateRun(de(e.sessionId),{status:"completed",finishedAt:e.finishedAt});return}}ensureParentSession(t,e){let o=typeof e.sessionId=="string"?e.sessionId.trim():"";if(!o)throw new Error("Canonical session ID is required for telemetry");let i=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";t.ensureSession({id:o,projectRoot:i,label:i==="unknown"?void 0:i.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(t,e,o){let i=Date.now(),r={id:`failure:${i}:${Math.random().toString(36).slice(2,11)}`,operation:t,payload:e,failure:o instanceof Error?o.message:String(o),timestamp:i};try{let s=this.getDatabase();s.insertTelemetryFailure({id:r.id,operation:t,payload:e,error:r.failure,createdAt:i}),s.trimTelemetryFailures(k),this.scheduleRetry();return}catch{}try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let s=join$1(this.cacheDir,`${i}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(s,JSON.stringify(r,null,2),{mode:384}),this.trimCompatibilityCache(),this.scheduleRetry();}catch{}}trimCompatibilityCache(){try{let t=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of t.slice(0,Math.max(0,t.length-k)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},mt).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(t,e){oe(t,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(t){let e=JSON.stringify(t);return e===void 0||e.length<=ce?t:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,ce)}...`}}};function le(n){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(n)}function de(n){return `hook-run:${n}`}function ht(n,t){if(!n||typeof n!="object")throw new Error("Invalid telemetry cache envelope");let e=n;if(typeof e.operation=="string"&&e.payload!==void 0)return e;let o=e.type==="tool_call"?"tool_call":e.type==="execution_start"?"execution_start":null;if(!o)throw new Error("Unknown legacy telemetry cache operation");let i=e.payload??{},r=Number(i.timestamp??i.startedAt??Date.now());return {id:`legacy-cache:${t}`,operation:o,payload:i,failure:"Replayed legacy HTTP-first telemetry cache entry",timestamp:r}}function N(n){return n??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function f(n){return process.env.DEVFLOW_STATE_DIR??getProjectStateDir(N(n))}var Et=2,Dt=1;function It(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{return join$1(dirname$1(fileURLToPath(import.meta.url)),"..","..")}catch{return process.cwd()}}function ue(n=It()){let t=[join$1(n,"dist","command-registry.json"),join$1(n,"command-registry.json")];for(let e of t)try{if(!existsSync(e))continue;let o=JSON.parse(readFileSync(e,"utf8"));if(o.version!==Et&&o.version!==Dt||!xt(o.commands)){emitSemanticControlLog({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:"contract_mismatch",registryPath:e}});continue}return o.commands}catch(o){emitSemanticControlLog({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:o.message,fallback:"next_registry_candidate"}});}return null}function xt(n){return !n||typeof n!="object"||Array.isArray(n)?false:Object.values(n).every(t=>{if(!t||typeof t!="object"||Array.isArray(t))return false;let e=t;return C(e.mcpTools)&&C(e.blockedNative)&&(e.source===void 0||e.source==="core"||e.source==="plugin")&&(e.requiresContext===void 0||typeof e.requiresContext=="boolean")&&(e.runtimePackages===void 0||C(e.runtimePackages))&&(e.hostTools===void 0||wt(e.hostTools))&&(e.evidenceMode===void 0||["static","runtime","mixed"].includes(e.evidenceMode))})}function wt(n){return !!n&&typeof n=="object"&&!Array.isArray(n)&&Object.entries(n).every(([t,e])=>t.length>0&&C(e))}function C(n){return Array.isArray(n)&&n.every(t=>typeof t=="string"&&t.length>0)}function pe(n){let t=ue();return t?t[n]?.mcpTools??[]:[]}function D(n){if(!n||typeof n!="object"||Array.isArray(n))return {};let t=n,e={};for(let o of ["lastMcpCall","bypassCount"])if(o in t){let i=t[o];if(i==null)continue;e[o]=typeof i=="number"&&Number.isFinite(i)&&i>=0?i:0;}return e}function kt(n,t){return n.lastMcpCall===t.lastMcpCall&&n.bypassCount===t.bypassCount}function At(n){try{return existsSync(n)?D(JSON.parse(readFileSync(n,"utf-8"))):{}}catch{return {}}}function me(n,t,e){let o=e instanceof Error?e.message:String(e);emitSemanticControlLog({event:"hook.runtime.degraded",identity:{projectRoot:n},level:"warn",timestamp:Date.now(),data:{stage:"enforcement_receipt",operation:t,reason:o,fallback:"fail_open"}});}function ge(n){let t=f(n);for(let e of ["receipt.json","receipt-lock.sqlite","receipt-lock.sqlite-shm","receipt-lock.sqlite-wal"])try{existsSync(join$1(t,e))&&unlinkSync(join$1(t,e));}catch{}}function he(n,t){if(n.getHookReceipt(t)){ge(t);return}let e=join$1(f(t),"receipt.json");if(!existsSync(e))return;let o=At(e);n.updateHookReceipt(t,()=>o),ge(t);}function ye(n,t,e){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),he(o,n);let i={},r=o.updateHookReceipt(n,a=>(i=D(a),D(t(i)))),s=D(r);return {receipt:s,applied:!0,changed:!kt(i,s)}}catch(i){return me(n,e,i),{receipt:{},applied:false,changed:false}}finally{try{o?.close();}catch{}}}function ve(n){let t;try{return t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),he(t,n),D(t.getHookReceipt(n))}catch(e){return me("update",e),{}}finally{try{t?.close();}catch{}}}function Ct(n,t){return ye(n,()=>t,"write").applied}function Tt(n,t){return ye(n,t,"update")}var fe={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"},Ft=new Set(["Write","Edit","NotebookEdit"]),jt=new Set(["failed","timeout","unavailable"]);function Mt(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 T=class{constructor(t,e,o){this.projectRoot=t;this.sessionId=e;this.executionId=o;}getPhase(){if(!this.sessionId||!this.executionId)return "idle";let t;try{t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let e=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(e&&e.expiresAt>Date.now())return "context_ready";e&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{t?.close();}catch{}}return "context_gathering"}getContextReceipt(){if(!this.sessionId||!this.executionId)return null;let t;try{t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let e=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);return e&&e.expiresAt>Date.now()?e:(e&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId),null)}catch{return null}finally{try{t?.close();}catch{}}}evaluate(t,e){let o=this.getPhase();if(e||t==="Skill")return {permissionDecision:"allow"};if(o==="context_gathering"&&fe[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_REQUIRED",reason:`DevFlow context required. Call mcp__devflow__get_project_context, then retry ${t}.`};if(o==="context_ready"){if(Ft.has(t)){let l=this.evaluateRequiredAction();if(l)return l}return {permissionDecision:"allow"}}let i=fe[t];if(!i)return {permissionDecision:"allow"};let r=Tt(this.projectRoot,l=>({...l,bypassCount:(l.bypassCount??0)+1}));if(!r.applied)return {permissionDecision:"allow"};let s=r.receipt.bypassCount??0,a=Mt(t);return s>=a?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${t}\uFF0C\u5EFA\u8BAE\u7528 mcp__devflow__${i} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){Ct(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}recordDomainActionOutcome(t,e,o,i){if(!this.sessionId||!this.executionId)return false;let r;try{r=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let s=r.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(!s||s.expiresAt<=Date.now()||s.canonicalAction?.tool!==t)return !1;let a=Date.now(),l=i?.trim()?`${i.trim()}:${e}`:`${t}:${e}:${a}`,c=s.actionAttempts??[];return r.upsertContextReceipt({...s,actionAttempts:c.some(d=>d.id===l||i&&d.toolUseId===i&&d.status===e)?c:[...c,{id:l,tool:t,status:e,attemptedAt:a,toolUseId:i,reason:o?.slice(0,500)}].slice(-20),actionSatisfiedAt:e==="succeeded"?a:s.actionSatisfiedAt,actionDegradation:e==="succeeded"?void 0:s.actionDegradation}),!0}catch{return false}finally{try{r?.close();}catch{}}}evaluateRequiredAction(){let t=this.getContextReceipt(),e=t?.canonicalAction;if(!t||!e||!e.required||e.status!=="required")return null;let o=e.binding;if(o.requiredContextReceipt!==t.contextHash||o.projectRoot!==this.projectRoot||o.sessionId!==this.sessionId||o.requestId!==t.requestId||o.executionId&&o.executionId!==this.executionId)return {permissionDecision:"deny",reasonCode:"DEVFLOW_ACTION_BINDING_STALE",reason:"DevFlow canonical action binding is stale or mismatched. Call mcp__devflow__get_project_context again before writing."};if(t.actionSatisfiedAt)return null;if(t.actionDegradation?.authorizedByContextReceipt===t.contextHash)return {permissionDecision:"allow",additionalContext:`DevFlow degraded fallback authorized by context receipt ${t.contextHash}: ${t.actionDegradation.reason}`};let i=(t.actionAttempts??[]).filter(r=>r.tool===e.tool&&jt.has(r.status));if(i.length>0){let r=i.at(-1),s={missedTool:e.tool,failedAttemptCount:i.length,reason:`${r.status}:${r.reason??"canonical domain action did not complete"}`,authorizedByContextReceipt:t.contextHash,authorizedAt:Date.now()};return this.persistDegradation(t,s),{permissionDecision:"allow",additionalContext:`DevFlow canonical tool mcp__devflow__${e.tool} ${r.status}; degraded direct write authorized by context receipt ${t.contextHash}. Preserve the action contract and verification plan.`}}return {permissionDecision:"deny",reasonCode:"DEVFLOW_REQUIRED_ACTION",reason:`DevFlow required action not completed. Call mcp__devflow__${e.tool} using context receipt ${t.contextHash}, then retry the write. Direct fallback is allowed only after unavailable, failed, or timeout evidence.`}}persistDegradation(t,e){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let i=o.getContextReceipt(t.projectRoot,t.sessionId,t.executionId);if(!i||i.contextHash!==t.contextHash||i.actionDegradation)return;o.upsertContextReceipt({...i,actionDegradation:e});let r=o.getSkillExecution(t.executionId);if(!r)return;let s=r.metadata&&typeof r.metadata=="object"?r.metadata:{},a=Array.isArray(s.requiredActionDegradations)?s.requiredActionDegradations:[];o.updateSkillExecution(t.executionId,{missedMcpTools:[...new Set([...r.missedMcpTools??[],e.missedTool])],failedToolCalls:Math.max(r.failedToolCalls??0,e.failedAttemptCount),fallbackCount:(r.fallbackCount??0)+1,fallbackReasons:[...new Set([...r.fallbackReasons??[],`required_action_${e.reason}`])],metadata:{...s,requiredActionDegradations:[...a,e]}});}catch{}finally{try{o?.close();}catch{}}}};var Wt=10*1024*1024,Bt=5;function Gt(n){return createHash$1("sha256").update(n).digest("hex").slice(0,16)}function Re(n){return join(homedir(),".devflow","logs","hook-debug",`${Gt(n)}.jsonl`)}function Ee(n,t,e={}){let o=e.maxBytes??Wt,i=e.maxFiles??Bt;mkdirSync$1(dirname(n),{recursive:true,mode:448});let r=Buffer.byteLength(t),s=existsSync$1(n)?statSync(n).size:0;s>0&&s+r>o&&Vt(n,i),appendFileSync(n,t,{mode:384}),chmodSync(n,384);}function Vt(n,t){if(t<=1){rmSync$1(n,{force:true});return}rmSync$1(`${n}.${t-1}`,{force:true});for(let e=t-2;e>=1;e-=1){let o=`${n}.${e}`;existsSync$1(o)&&renameSync$1(o,`${n}.${e+1}`);}existsSync$1(n)&&renameSync$1(n,`${n}.1`);}var J="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function De(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}function Se(n){return Buffer.from(n,"utf8").toString("base64url")}function Xt(n,t,e){let o=t?.trim();if(o){let i=/^[a-zA-Z0-9:._-]{1,192}$/.test(o)?o:`tool-${createHash("sha256").update(o.slice(0,1024)).digest("hex").slice(0,32)}`;return `${n}:${i}`}return `${n}:legacy-${e}-${randomUUID().slice(0,8)}`}function Fe(n){return `${n}:legacy-journal`}var j=class{constructor(t){this.projectRoot=t;this.sessions=new Map;this.sessionsDir=join$1(f(t),"hook-sessions");}registerSession(t){let e=t.trim();if(!e)throw new Error("session_id_required");let o=this.get(e);if(o)return o.lastActivityAt=Date.now(),this.persist(o),o;let i=Date.now(),r={sessionId:e,projectRoot:this.projectRoot,requiredMcpTools:[],evidenceObligations:[],evidenceDegradations:[],evidenceOutcomes:[],startedAt:i,lastActivityAt:i};return this.sessions.set(e,r),this.persist(r),r}startExecution(t,e,o){let i=this.registerSession(t);return (!i.executionId||i.skillName!==e)&&(i.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),i.skillName=e,i.requiredMcpTools=[...new Set(o)],i.lastActivityAt=Date.now(),this.persist(i),i}bindTaskIdentity(t,e){let o=this.registerSession(t);return o.activeTurnId=e.turnId,o.activeRequestId=e.requestId,o.intentArtifactHash=e.intentArtifactHash,o.lastActivityAt=Date.now(),this.persist(o),o}get(t){let e=t.trim();if(!e)return null;let o=this.sessions.get(e);if(o)return this.replayEvidenceJournal(o),o;let i=this.snapshotPath(e);if(!existsSync(i))return null;try{let r=JSON.parse(readFileSync(i,"utf8"));return r.sessionId!==e||r.projectRoot!==this.projectRoot?null:(r.requiredMcpTools=Array.isArray(r.requiredMcpTools)?r.requiredMcpTools:[],r.evidenceObligations=Oe(r.evidenceObligations),r.evidenceDegradations=ke(r.evidenceDegradations),r.evidenceOutcomes=Ae(r.evidenceOutcomes),this.replayEvidenceJournal(r),this.sessions.set(e,r),r)}catch{return null}}completeExecution(t){let e=this.get(t);if(!e)return null;let o=structuredClone(e);return delete e.executionId,delete e.skillName,e.requiredMcpTools=[],e.lastActivityAt=Date.now(),this.persist(e),o}addEvidenceObligation(t,e,o=Date.now(),i){let r=this.registerSession(t),a=(i?void 0:r.evidenceObligations.find(c=>c.contractId===e.id))?.obligationId??Xt(e.id,i,o);this.appendEvidenceEvent(t,{kind:"add",obligationId:a,contractId:e.id,at:o,contract:e},`add\0${a}`),this.replayEvidenceJournal(r);let l=r.evidenceObligations.find(c=>c.obligationId===a);return l?(r.lastActivityAt=Date.now(),this.persist(r),structuredClone(l)):null}listEvidenceObligations(t){return (this.get(t)?.evidenceObligations??[]).map(e=>structuredClone(e))}markEvidenceCorrection(t,e,o,i,r=Date.now()){let s=this.get(t),a=s?.evidenceObligations.find(d=>d.obligationId===e);if(!s||!a)return null;let l=/^[a-f0-9]{64}$/.test(i)?i:"";if(!l)return null;this.appendEvidenceEvent(t,{kind:"correction",obligationId:e,contractId:a.contractId,at:r,fingerprint:l,violations:o.slice(0,16).map(d=>d.slice(0,240))},`correction\0${e}\0${l}`),this.replayEvidenceJournal(s),s.lastActivityAt=r,this.persist(s);let c=s.evidenceObligations.find(d=>d.obligationId===e);return c?structuredClone(c):null}resolveEvidenceObligation(t,e){let o=this.get(t);if(!o)return false;let i=o.evidenceObligations.find(s=>s.obligationId===e);if(!i)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:i.contractId,at:r},`resolve\0${e}`),this.replayEvidenceJournal(o),o.lastActivityAt=r,this.persist(o),true}resolveDegradedEvidence(t,e){let o=this.get(t),i=o?.evidenceDegradations.find(s=>s.obligationId===e);if(!o||!i)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:i.contractId,at:r},`resolve-degraded\0${e}\0${r}`),this.replayEvidenceJournal(o),o.lastActivityAt=r,this.persist(o),true}degradeEvidenceObligation(t,e,o,i=Date.now()){let r=this.get(t),s=r?.evidenceObligations.find(l=>l.obligationId===e);if(!r||!s)return false;let a=o.slice(0,240);return this.appendEvidenceEvent(t,{kind:"degrade",obligationId:e,contractId:s.contractId,at:i,reason:a},`degrade\0${e}\0${a}`),this.replayEvidenceJournal(r),r.lastActivityAt=i,this.persist(r),true}removeSession(t){let e=t.trim();e&&(this.sessions.delete(e),rmSync(this.snapshotPath(e),{force:true}),rmSync(this.evidenceJournalDir(e),{recursive:true,force:true}));}list(){return [...this.sessions.values()]}snapshotPath(t){return join$1(this.sessionsDir,`${Se(t)}.json`)}evidenceJournalDir(t){return join$1(this.sessionsDir,"evidence-journal",Se(t))}appendEvidenceEvent(t,e,o){let i=this.evidenceJournalDir(t);mkdirSync(i,{recursive:true,mode:448});let r=createHash("sha256").update(o).digest("hex"),s=join$1(i,`${e.kind}-${r}.json`);if(existsSync(s))return;let a=join$1(i,`.${process.pid}.${randomUUID()}.tmp`);writeFileSync(a,JSON.stringify(e),{mode:384});try{linkSync(a,s);}catch(l){if(l.code!=="EEXIST")throw l}finally{rmSync(a,{force:true});}}replayEvidenceJournal(t){t.evidenceObligations=Oe(t.evidenceObligations),t.evidenceDegradations=ke(t.evidenceDegradations),t.evidenceOutcomes=Ae(t.evidenceOutcomes);let e=this.evidenceJournalDir(t.sessionId);if(!existsSync(e))return;let o;try{o=readdirSync(e).filter(r=>/^(?:add|correction|resolve|degrade)-[a-f0-9]{64}\.json$/.test(r)).slice(0,4096);}catch{return}let i=o.flatMap(r=>{try{let s=readFileSync(join$1(e,r),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let a=Qt(JSON.parse(s));return a?[a]:[]}catch{return []}}).sort((r,s)=>r.at-s.at||Ce(r.kind)-Ce(s.kind));for(let r of i)this.applyEvidenceEvent(t,r);t.evidenceObligations=t.evidenceObligations.slice(-8),t.evidenceDegradations=t.evidenceDegradations.slice(-20),t.evidenceOutcomes=t.evidenceOutcomes.slice(-20);}applyEvidenceEvent(t,e){let o=t.evidenceOutcomes.find(s=>s.obligationId===e.obligationId);if(e.kind==="add"){if(o)return;let s=t.evidenceObligations.find(a=>a.obligationId===e.obligationId);s?(s.contract=e.contract,s.promptedAt=Math.min(s.promptedAt,e.at)):t.evidenceObligations.push({obligationId:e.obligationId,contractId:e.contractId,contract:e.contract,promptedAt:e.at,attempt:0,correctionRequested:false,violations:[]});return}let i=t.evidenceObligations.find(s=>s.obligationId===e.obligationId);if(e.kind==="correction"){if(!i||o||i.correctionFingerprint===e.fingerprint)return;i.attempt+=1,i.correctionRequested=true,i.correctionRequestedAt=e.at,i.correctionFingerprint=e.fingerprint,i.violations=e.violations;return}let r=i?.attempt??o?.attempt??0;if(e.kind==="resolve"&&o?.status==="degraded")t.evidenceOutcomes=t.evidenceOutcomes.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations=t.evidenceDegradations.filter(s=>s.obligationId!==e.obligationId);else if(o)return;e.kind==="degrade"?(t.evidenceObligations=t.evidenceObligations.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations.push({obligationId:e.obligationId,contractId:e.contractId,reason:e.reason,degradedAt:e.at,attempt:r,contract:i?.contract})):t.evidenceObligations=t.evidenceObligations.filter(s=>s.obligationId!==e.obligationId),t.evidenceOutcomes.push({obligationId:e.obligationId,contractId:e.contractId,status:e.kind==="resolve"?"resolved":"degraded",completedAt:e.at,attempt:r,...e.kind==="degrade"?{reason:e.reason}:{}});}persist(t){mkdirSync(this.sessionsDir,{recursive:true,mode:448});let e=this.snapshotPath(t.sessionId),o=`${e}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(o,JSON.stringify(t),{mode:384}),renameSync(o,e);}};function Oe(n){return Array.isArray(n)?n.flatMap(t=>{if(!t||typeof t!="object")return [];let e=t;if(typeof e.contractId!="string"||e.contractId.length===0||e.contractId.length>128||typeof e.promptedAt!="number"||typeof e.attempt!="number"||typeof e.correctionRequested!="boolean"||!Array.isArray(e.violations)||!je(e.contract))return [];let o=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:Fe(e.contractId),i=typeof e.correctionTranscriptHash=="string"?e.correctionTranscriptHash:void 0,r=e.correctionFingerprint??i;return r!==void 0&&!/^[a-f0-9]{64}$/.test(r)?[]:[{...e,obligationId:o,correctionFingerprint:r}]}).slice(-8):[]}function ke(n){return Array.isArray(n)?n.filter(t=>{if(!t||typeof t!="object")return false;let e=t;return typeof e.obligationId=="string"&&typeof e.contractId=="string"&&typeof e.reason=="string"&&typeof e.degradedAt=="number"&&typeof e.attempt=="number"}).slice(-20):[]}function Ae(n){return Array.isArray(n)?n.filter(t=>{if(!t||typeof t!="object")return false;let e=t;return typeof e.obligationId=="string"&&typeof e.contractId=="string"&&(e.status==="resolved"||e.status==="degraded")&&typeof e.completedAt=="number"&&typeof e.attempt=="number"&&(e.reason===void 0||typeof e.reason=="string")}).slice(-20):[]}function Qt(n){if(!n||typeof n!="object")return null;let t=n,e=t.kind;if(e!=="add"&&e!=="correction"&&e!=="resolve"&&e!=="degrade"||typeof t.contractId!="string"||t.contractId.length>128||typeof t.at!="number")return null;let i={obligationId:typeof t.obligationId=="string"&&t.obligationId.length>0&&t.obligationId.length<=384?t.obligationId:Fe(t.contractId),contractId:t.contractId,at:t.at};if(e==="add")return je(t.contract)?{kind:e,...i,contract:t.contract}:null;if(e==="correction"){let r=typeof t.fingerprint=="string"?t.fingerprint:t.transcriptHash;return typeof r=="string"&&/^[a-f0-9]{64}$/.test(r)&&Array.isArray(t.violations)&&t.violations.every(s=>typeof s=="string"&&s.length<=240)?{kind:e,...i,fingerprint:r,violations:t.violations}:null}return e==="resolve"?{kind:e,...i}:typeof t.reason=="string"&&t.reason.length<=240?{kind:e,...i,reason:t.reason}:null}function Ce(n){return n==="add"?0:n==="correction"?1:2}function je(n){if(!n||typeof n!="object")return false;let t=n,e=t.requiredSections,o=t.prohibitedClaims;return 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(e)&&e.length===3&&e[0]==="\u5DE5\u5177\u53D1\u73B0"&&e[1]==="\u6A21\u578B\u5047\u8BBE"&&e[2]==="\u9700\u8981\u8FD0\u884C\u65F6\u9A8C\u8BC1"&&Array.isArray(o)&&o.length<=16&&o.every(i=>typeof i=="string"&&i.length<=128)&&typeof t.canonicalReport=="string"&&Buffer.byteLength(t.canonicalReport,"utf8")<=48*1024&&!!t.correctionPolicy&&t.correctionPolicy.maxAttempts===1&&t.correctionPolicy.repeatedViolation==="fail_open"}function Me(n){let t=n.trim().replace(/^\//,"");if(!t.startsWith("devflow:"))return null;let e=t.slice(8).replace(/^devflow-/,"");return /^[a-z0-9][a-z0-9-]*$/i.test(e)?`devflow:${e.toLowerCase()}`:null}function Pe(n,t){return t?`evt_tool_${createHash("sha256").update(`${n}\0${t}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var nn=new Set(["Write","Edit","NotebookEdit"]),$e="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 qe(n){if(!nn.has(n.toolName))return null;let t=on(n.toolInput);if(!t)return null;let e=rn(t,n.projectRoot),o=resolve(n.projectRoot,".claude");if(Ne(e,o)&&basename(e).toLocaleUpperCase("en-US")==="MEMORY.MD")return $e;let i=resolve(n.home??homedir(),".claude","projects");return Ne(e,i)&&relative(i,e).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?$e:null}function on(n){for(let t of ["file_path","notebook_path","path"]){let e=n[t];if(typeof e=="string"&&e.trim())return e.trim()}return null}function rn(n,t){return resolve(isAbsolute(n)?n:resolve(t,n))}function Ne(n,t){let e=relative(t,n);return e===""||!e.startsWith(`..${sep}`)&&e!==".."&&!isAbsolute(e)}function Ge(n){let t=gn(n.toolName,n.toolInput),e=t?fn(n.projectRoot,n.toolName,n.toolInput):void 0;if(!t||!e||!n.toolUseId)return {allowed:true};let o=hn(e),i,r=0,s,a;try{a=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:100,readonly:!0});let c=a.getActiveContextReceipt(n.projectRoot,n.sessionId,n.executionId);i=c?.contextHash,r=c?.issuedAt??0,s=c?.canonicalAction?.binding.operationTargets?.find(d=>yn(n.projectRoot,d.path,e));}catch{}finally{try{a?.close();}catch{}}let l={toolUseId:n.toolUseId,sessionId:n.sessionId,executionId:n.executionId,operation:t,path:e,before:o,contextReceipt:i,observedAt:Date.now()};if(_n(n.projectRoot,l),t==="edit"||t==="write"||t==="delete"){let c=Rn(n.projectRoot,e),d=c?.success&&c.operation==="delete"&&!c.after.exists&&c.completedAt>=r,u=s?.expectedState==="existing"&&!o.exists||s?.expectedState==="missing"&&o.exists||!!(s?.contentHash&&o.hash!==s.contentHash);if(d||s?.expectedState==="existing"&&!o.exists)return Je(n,l,"DEVFLOW_FILE_STATE_DELETED","The target was deleted after the active Context receipt. Refresh project context before editing or recreating it.");if(u)return Je(n,l,"DEVFLOW_FILE_STATE_STALE","The target state no longer matches the active Context receipt. Refresh project context before overwriting it.")}return Ve(n,l,true),{allowed:true,pending:l}}function Je(n,t,e,o){return Ve(n,t,false,e),{allowed:false,reasonCode:e,reason:o,pending:t}}function Ve(n,t,e,o){emitSemanticControlLog({event:"canonical.action.validated",identity:{projectRoot:n.projectRoot,sessionId:n.sessionId,executionId:n.executionId,contextReceipt:t.contextReceipt},level:e?"info":"warn",timestamp:Date.now(),data:{stage:"host_file_state_precondition",valid:e,operation:t.operation,targetPath:relative(n.projectRoot,t.path),targetExists:t.before.exists,targetHash:t.before.hash,reason:o,toolUseId:t.toolUseId}});}function gn(n,t){if(n==="Read")return "read";if(n==="Edit"||n==="NotebookEdit")return "edit";if(n==="Write")return "write";if(n==="Delete"||n==="Bash"&&ze(t.command))return "delete"}function fn(n,t,e){let o=mn(e,["file_path","filePath","notebook_path","path","targetPath"])??(t==="Bash"?ze(e.command):void 0);if(!o)return;let i=isAbsolute(o)?normalize(o):resolve(n,o),r=relative(n,i);return r.startsWith("..")||isAbsolute(r)?void 0:i}function ze(n){return typeof n!="string"?void 0:/(?:^|[;&|]\s*)\s*(?:rm|unlink)\s+(?:-[A-Za-z]+\s+)*(?:--\s+)?(["']?)([^\s;&|"']+)\1/u.exec(n)?.[2]}function mn(n,t){for(let e of t){let o=n[e];if(typeof o=="string"&&o.trim())return o.trim()}}function hn(n){if(!existsSync$1(n))return {exists:false};try{return {exists:!0,hash:createHash$1("sha256").update(readFileSync$1(n)).digest("hex")}}catch{return {exists:true}}}function yn(n,t,e){return (isAbsolute(t)?normalize(t):resolve(n,t))===normalize(e)}function Ke(n){return join(f(n),"file-state")}function Ye(n){return join(Ke(n),"pending.json")}function vn(n){return join(Ke(n),"observations.jsonl")}function bn(n){try{return JSON.parse(readFileSync$1(Ye(n),"utf8"))}catch{return {}}}function _n(n,t){let e=Ye(n);mkdirSync$1(dirname(e),{recursive:true});let o=bn(n);o[t.toolUseId]=t,En(e,JSON.stringify(o));}function Rn(n,t){try{let e=readFileSync$1(vn(n),"utf8").trim().split(`
3
- `);for(let o=e.length-1;o>=0;o-=1){let i=JSON.parse(e[o]);if(i.path===t)return i}}catch{}}function En(n,t){let e=`${n}.${process.pid}.${Date.now()}.tmp`;writeFileSync$1(e,t,{encoding:"utf8",mode:384}),renameSync$1(e,n);}function I(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function Xe(n){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:n}}}function Sn(n){let t=f(n);return existsSync(t)||mkdirSync(t,{recursive:true}),t}function On(n,t,e,o,i,r){let s=join$1(Sn(n),"event-map.json"),a=[];try{existsSync(s)&&(a=JSON.parse(readFileSync(s,"utf-8")));}catch{}a.push({sessionId:t,toolName:e,toolUseId:o,eventId:i,timestamp:r}),writeFileSync(s,JSON.stringify(a));}function kn(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"}}async function An(n){let t=De();try{if(!n||n.trim()==="")return I();let e=JSON.parse(n),o=Date.now(),i=N(),r=new A;e.tool_name.startsWith("mcp__devflow__")&&(typeof e.tool_input.projectRoot!="string"||!e.tool_input.projectRoot.trim())&&(e.tool_input.projectRoot=i);let s=e.session_id?.trim();if(!s)return Xe(J);let a=new j(i),l=a.get(s)!==null;if(a.registerSession(s),l||await r.sendSessionStart(s,i,Date.now()),e.tool_name==="Skill"){let S=e.tool_input?.skill,y=S?Me(S):null;if(y){let et=a.get(s)?.executionId,E=a.startExecution(s,y,pe(y));E.executionId&&E.executionId!==et&&await r.sendExecutionStart(E.executionId,s,y,E.lastActivityAt,i,E.requiredMcpTools);}}let c=a.get(s);e.tool_name.startsWith("mcp__devflow__")&&(e.tool_input._devflow_session_id=s,e.tool_input._devflow_execution_id=c?.executionId??s,c?.activeTurnId&&(e.tool_input._devflow_turn_id=c.activeTurnId),c?.activeRequestId&&(e.tool_input._devflow_request_id=c.activeRequestId),c?.intentArtifactHash&&(e.tool_input._devflow_intent_artifact_hash=c.intentArtifactHash),c?.skillName&&(e.tool_input._devflow_active_skill=c.skillName),e.tool_use_id&&(e.tool_input._devflow_tool_use_id=e.tool_use_id));let d=e.tool_name.startsWith("mcp__"),u=d?e.tool_name.replace(/^mcp__[^_]+__/,""):void 0,p=new T(i,s,c?.executionId),Y=p.getPhase(),g,x=qe({toolName:e.tool_name,toolInput:e.tool_input,projectRoot:i}),P=Ge({projectRoot:i,sessionId:s,executionId:c?.executionId,toolUseId:e.tool_use_id,toolName:e.tool_name,toolInput:e.tool_input}),h=x?{permissionDecision:"deny",reason:x}:P.allowed?p.evaluate(e.tool_name,d):{permissionDecision:"deny",reason:P.reason,reasonCode:P.reasonCode};h.permissionDecision==="deny"?g={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:h.reason??"MCP context required"}}:h.additionalContext?g=Xe(h.additionalContext):g=I(),e.tool_name.startsWith("mcp__devflow__")&&(g.hookSpecificOutput.updatedInput=e.tool_input),t&&g.hookSpecificOutput.permissionDecision==="allow"&&(g.hookSpecificOutput.additionalContext=J);let Ze=c?.executionId??s,R={eventId:Pe(s,e.tool_use_id),executionId:Ze,sessionId:s,projectRoot:i,toolUseId:e.tool_use_id,timestamp:Date.now(),toolName:e.tool_name,toolType:d?"mcp":e.tool_name==="Agent"?"subagent":"direct",isMcpTool:d,mcpToolName:u,mcpEnforced:d&&Y==="context_gathering",mcpFallback:!d&&Y==="context_gathering",kind:kn(e.tool_name),input:e.tool_input,duration:0,blocked:g.hookSpecificOutput.permissionDecision==="deny",blockReason:g.hookSpecificOutput.permissionDecision==="deny"?x?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":h.reasonCode??"DEVFLOW_CONTEXT_REQUIRED":void 0},w=await r.sendEvent(R);w&&!R.blocked&&On(i,s,e.tool_name,e.tool_use_id,w,R.timestamp),w&&R.blocked&&await r.completeEvent({eventId:w,sessionId:s,error:x?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":h.reasonCode??"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-R.timestamp,completedAt:Date.now()});try{let S=ve(i),y={ts:o,tool:e.tool_name,sessionId:s,skill:c?.skillName??"(none)",requiredTools:c?.requiredMcpTools??[],isMcp:d,enforce:c?.executionId!==void 0,stateless:c?.executionId===void 0&&!d&&e.tool_name!=="Skill",bypassCount:S.bypassCount??0,decision:g.hookSpecificOutput.permissionDecision,env_CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd()};Ee(Re(i),`${JSON.stringify(y)}
4
- `);}catch{}return g}catch{return I()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let n=console.log.bind(console);console.log=console.error.bind(console),console.info=console.error.bind(console);let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",e=>{t+=e;}),process.stdin.on("end",async()=>{let e=await An(t);n(JSON.stringify(e));}),process.stdin.on("error",()=>{n(JSON.stringify(I())),process.exit(0);}),setTimeout(()=>{n(JSON.stringify(I())),process.exit(0);},4e3).unref();}export{An as handlePreToolUse};
1
+ import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync,rmSync,linkSync,renameSync}from'fs';import {join as join$1,dirname as dirname$1}from'path';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {getLocalApiKey,getDevFlowStateRoot,resolveRuntimeEndpoint,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getProjectStateDir}from'@devflow-tools/sdk';import {request}from'node:http';import {mkdirSync as mkdirSync$1,existsSync as existsSync$1,statSync,appendFileSync,chmodSync,readFileSync as readFileSync$1,rmSync as rmSync$1,renameSync as renameSync$1,writeFileSync as writeFileSync$1}from'node:fs';import {join,resolve,basename,relative,sep,dirname,isAbsolute,normalize}from'node:path';import {fileURLToPath}from'url';import {emitSemanticControlLog}from'@devflow-tools/telemetry';import {createHash as createHash$1}from'node:crypto';import {homedir}from'node:os';import {randomUUID,createHash}from'crypto';function D(n,t,e){try{let o=openGlobalDevFlowDatabase();try{o.insertEvent({kind:n,timestamp:Date.now(),duration:e,success:t.success!==!1,metadata:t});}finally{o.close();}}catch{}}var ot=getLocalApiKey(),L=join(getDevFlowStateRoot(),"errors");async function te(n,t,e={}){let o=e.endpoint??resolveRuntimeEndpoint().url,r=e.timeout??1500,i=e.durableMirror??true,s=e.maxRetries??(i?0:2),a=e.circuitBreaker??true,l=acquireRuntimeHttpCircuit(o,n);if(a&&!l.allowed)return {delivered:false,suppressed:true,fallbackReason:l.state.fallbackReason};let c;for(let u=0;u<=s;u+=1)try{return await rt(o,n,t,r),a&&registerRuntimeHttpSuccess(o,n).transitioned&&D("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:l.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(p){c=p instanceof Error?p:new Error(String(p)),u<s&&await it(Math.min(100*2**u,1e3));}if(!c)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return Z(n,c),{delivered:false,suppressed:false,fallbackReason:c.message};let d=registerRuntimeHttpFailure(o,n,e.fallbackReason??(i?"local_durable_mirror":"http_delivery_failed"));return d.transitioned&&(Z(n,c),D("http_circuit_transition",{endpoint:o,path:new URL(n,o).pathname,previous:l.state.status,status:"open",failures:d.state.failures,openUntil:d.state.openUntil,fallbackReason:d.state.fallbackReason})),{delivered:false,suppressed:false,fallbackReason:d.state.fallbackReason}}function rt(n,t,e,o){return new Promise((r,i)=>{let s=JSON.stringify(e),a=new URL(t,n),l=false,c=u=>{l||(l=true,u?i(u):r());},d=request({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":ot,"Content-Length":Buffer.byteLength(s)},timeout:o},u=>{u.on("error",c),u.on("end",()=>{let p=u.statusCode??0;c(p>=200&&p<300?void 0:new Error(`HTTP ${p}`));}),u.resume();});d.on("error",c),d.on("timeout",()=>d.destroy(new Error(`HTTP mirror timed out after ${o}ms`))),d.write(s),d.end();})}function Z(n,t){try{existsSync$1(L)||mkdirSync$1(L,{recursive:!0}),appendFileSync(join(L,"http-errors.log"),`${new Date().toISOString()} | ${n} | ${t.message}
2
+ `);}catch{}}function it(n){return new Promise(t=>setTimeout(t,n))}var ie=1e4,ut=3e4,k=500,O=class{constructor(t){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=t?.apiUrl,this.cacheDir=t?.cacheDir??join$1(getDevFlowStateRoot(),"global","telemetry-cache"),this.database=t?.database??null,this.ownsDatabase=!t?.database;let e=t?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(t){let e={...t,input:this.truncateInput(t.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),t.eventId):null}async sendExecutionStart(t,e,o,r,i=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:t,sessionId:e,skillName:o,startedAt:r,projectRoot:i,requiredMcpTools:s};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(t,e="completed",o=Date.now(),r){let i={executionId:t,status:e,finishedAt:o,metadata:r},s=this.commitOrCache("execution_complete",i);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",i),s}async sendSessionStart(t,e,o){let r={id:t,projectRoot:e,startedAt:o,label:e.split("/").pop()??"unknown"},i=this.commitOrCache("session_start",r);return i&&this.postHttp("/api/telemetry/sessions",r),i}async completeEvent(t){let e=this.commitOrCache("complete_event",t);return e&&(this.postHttp("/api/telemetry/tool-call/output",t),this.scheduleMetricAggregation()),e}async endSession(t,e=Date.now()){let o={sessionId:t,finishedAt:e},r=this.commitOrCache("session_end",o);return r&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(t)}/close`,{finishedAt:e})),r}async flushCache(){try{let e=this.getDatabase(),o=e.listTelemetryFailures({unresolvedOnly:!0,limit:k}).reverse();for(let r of o)try{this.applyOperation(r.operation,r.payload),e.resolveTelemetryFailure(r.id);}catch{}e.trimTelemetryFailures(k);}catch{}let t=(existsSync(this.cacheDir)?readdirSync(this.cacheDir):[]).filter(e=>e.endsWith(".json")).map(e=>{let o=join$1(this.cacheDir,e);try{return {cacheFile:o,envelope:pt(JSON.parse(readFileSync(o,"utf8")))}}catch{return null}}).filter(e=>e!==null).sort((e,o)=>e.envelope.timestamp-o.envelope.timestamp||se(e.envelope.operation)-se(o.envelope.operation));for(let{cacheFile:e,envelope:o}of t)try{let r=this.getDatabase();r.insertTelemetryFailure({id:o.id,operation:o.operation,payload:o.payload,error:o.failure,createdAt:o.timestamp}),this.applyOperation(o.operation,o.payload),r.resolveTelemetryFailure(o.id),unlinkSync(e);}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(t,e){try{return this.applyOperation(t,e),!0}catch(o){return this.cacheOperation(t,e,o),false}}applyOperation(t,e){let o=this.getDatabase();switch(t){case "tool_call":this.ensureParentSession(o,e),o.insertToolCallEvent(e);return;case "execution_start":this.ensureParentSession(o,e),o.insertSkillExecution({executionId:e.executionId,sessionId:e.sessionId,skillName:e.skillName,startedAt:e.startedAt,status:"running",requiredMcpTools:e.requiredMcpTools});return;case "execution_complete":o.reconcileSkillExecution(e.executionId,e.status,e.finishedAt,e.metadata);return;case "session_start":o.ensureSession(e),o.insertRun({id:ae(e.id),source:"hook",tool:"session",input:{projectRoot:e.projectRoot},status:"active",startedAt:e.startedAt,tokenUsed:0,metadata:{sessionId:e.id,projectRoot:e.projectRoot}});return;case "complete_event":if(!o.updateToolCallEvent(e.eventId,{output:e.output===void 0?void 0:JSON.stringify(e.output),error:e.error,failureCategory:e.failureCategory,duration:e.duration}))throw new Error(`Tool call event ${e.eventId} is not available for completion`);return;case "session_end":o.closeSession(e.sessionId,e.finishedAt),o.updateRun(ae(e.sessionId),{status:"completed",finishedAt:e.finishedAt});return}}ensureParentSession(t,e){let o=typeof e.sessionId=="string"?e.sessionId.trim():"";if(!o)throw new Error("Canonical session ID is required for telemetry");let r=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";t.ensureSession({id:o,projectRoot:r,label:r==="unknown"?void 0:r.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(t,e,o){let r=Date.now(),i={id:`failure:${r}:${Math.random().toString(36).slice(2,11)}`,operation:t,payload:e,failure:o instanceof Error?o.message:String(o),timestamp:r};try{let s=this.getDatabase();s.insertTelemetryFailure({id:i.id,operation:t,payload:e,error:i.failure,createdAt:r}),s.trimTelemetryFailures(k),this.scheduleRetry();return}catch{}try{existsSync(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.trimRetryCache(),this.scheduleRetry();}catch{}}trimRetryCache(){try{let t=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of t.slice(0,Math.max(0,t.length-k)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},ut).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(t,e){te(t,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(t){let e=JSON.stringify(t);return e===void 0||e.length<=ie?t:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,ie)}...`}}};function se(n){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(n)}function ae(n){return `hook-run:${n}`}function pt(n){if(!n||typeof n!="object")throw new Error("Invalid telemetry cache envelope");let t=n;if(typeof t.id!="string"||typeof t.operation!="string"||t.payload===void 0||typeof t.failure!="string"||typeof t.timestamp!="number")throw new Error("Invalid telemetry cache envelope");return t}function $(n){return n??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function f(n){return getProjectStateDir($(n))}var m=emitSemanticControlLog;var bt=2,_t=1;function Rt(){if(process.env.CLAUDE_PLUGIN_ROOT)return process.env.CLAUDE_PLUGIN_ROOT;try{return join$1(dirname$1(fileURLToPath(import.meta.url)),"..","..")}catch{return process.cwd()}}function ce(n=Rt()){let t=[join$1(n,"dist","command-registry.json"),join$1(n,"command-registry.json")];for(let e of t)try{if(!existsSync(e))continue;let o=JSON.parse(readFileSync(e,"utf8"));if(o.version!==bt&&o.version!==_t||!Et(o.commands)){m({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:"contract_mismatch",registryPath:e}});continue}return o.commands}catch(o){m({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:o.message,fallback:"next_registry_candidate"}});}return null}function Et(n){return !n||typeof n!="object"||Array.isArray(n)?false:Object.values(n).every(t=>{if(!t||typeof t!="object"||Array.isArray(t))return false;let e=t;return A(e.mcpTools)&&A(e.blockedNative)&&(e.source===void 0||e.source==="core"||e.source==="plugin")&&(e.requiresContext===void 0||typeof e.requiresContext=="boolean")&&(e.runtimePackages===void 0||A(e.runtimePackages))&&(e.hostTools===void 0||wt(e.hostTools))&&(e.evidenceMode===void 0||["static","runtime","mixed"].includes(e.evidenceMode))})}function wt(n){return !!n&&typeof n=="object"&&!Array.isArray(n)&&Object.entries(n).every(([t,e])=>t.length>0&&A(e))}function A(n){return Array.isArray(n)&&n.every(t=>typeof t=="string"&&t.length>0)}function le(n){let t=ce();return t?t[n]?.mcpTools??[]:[]}function C(n){if(!n||typeof n!="object"||Array.isArray(n))return {};let t=n,e={};for(let o of ["lastMcpCall","bypassCount"])if(o in t){let r=t[o];if(r==null)continue;e[o]=typeof r=="number"&&Number.isFinite(r)&&r>=0?r:0;}return e}function xt(n,t){return n.lastMcpCall===t.lastMcpCall&&n.bypassCount===t.bypassCount}function ue(n,t,e){let o=e instanceof Error?e.message:String(e);m({event:"hook.runtime.degraded",identity:{projectRoot:n},level:"warn",timestamp:Date.now(),data:{stage:"enforcement_receipt",operation:t,reason:o,fallback:"fail_open"}});}function pe(n,t,e){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let r={},i=o.updateHookReceipt(n,a=>(r=C(a),C(t(r)))),s=C(i);return {receipt:s,applied:!0,changed:!xt(r,s)}}catch(r){return ue(n,e,r),{receipt:{},applied:false,changed:false}}finally{try{o?.close();}catch{}}}function ge(n){let t;try{return t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),C(t.getHookReceipt(n))}catch(e){return ue(n,"update",e),{}}finally{try{t?.close();}catch{}}}function It(n,t){return pe(n,()=>t,"write").applied}function Dt(n,t){return pe(n,t,"update")}var de={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"},St=new Set(["Write","Edit","NotebookEdit"]),kt=new Set(["failed","timeout","unavailable"]);function Ot(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 T=class{constructor(t,e,o){this.projectRoot=t;this.sessionId=e;this.executionId=o;}getPhase(){if(!this.sessionId||!this.executionId)return "idle";let t;try{t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let e=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(e&&e.expiresAt>Date.now())return "context_ready";e&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{t?.close();}catch{}}return "context_gathering"}getContextReceipt(){if(!this.sessionId||!this.executionId)return null;let t;try{t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let e=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);return e&&e.expiresAt>Date.now()?e:(e&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId),null)}catch{return null}finally{try{t?.close();}catch{}}}evaluate(t,e){let o=this.getPhase();if(e||t==="Skill")return {permissionDecision:"allow"};if(o==="context_gathering"&&de[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_REQUIRED",reason:`DevFlow context required. Call mcp__devflow__get_project_context, then retry ${t}.`};if(o==="context_ready"){if(St.has(t)){let l=this.evaluateRequiredAction();if(l)return l}return {permissionDecision:"allow"}}let r=de[t];if(!r)return {permissionDecision:"allow"};let i=Dt(this.projectRoot,l=>({...l,bypassCount:(l.bypassCount??0)+1}));if(!i.applied)return {permissionDecision:"allow"};let s=i.receipt.bypassCount??0,a=Ot(t);return s>=a?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${t}\uFF0C\u5EFA\u8BAE\u7528 mcp__devflow__${r} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){It(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}recordDomainActionOutcome(t,e,o,r){if(!this.sessionId||!this.executionId)return false;let i;try{i=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let s=i.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(!s||s.expiresAt<=Date.now()||s.canonicalAction?.tool!==t)return !1;let a=Date.now(),l=r?.trim()?`${r.trim()}:${e}`:`${t}:${e}:${a}`,c=s.actionAttempts??[];return i.upsertContextReceipt({...s,actionAttempts:c.some(d=>d.id===l||r&&d.toolUseId===r&&d.status===e)?c:[...c,{id:l,tool:t,status:e,attemptedAt:a,toolUseId:r,reason:o?.slice(0,500)}].slice(-20),actionSatisfiedAt:e==="succeeded"?a:s.actionSatisfiedAt,actionDegradation:e==="succeeded"?void 0:s.actionDegradation}),!0}catch{return false}finally{try{i?.close();}catch{}}}evaluateRequiredAction(){let t=this.getContextReceipt(),e=t?.canonicalAction;if(!t||!e||!e.required||e.status!=="required")return null;let o=e.binding;if(o.requiredContextReceipt!==t.contextHash||o.projectRoot!==this.projectRoot||o.sessionId!==this.sessionId||o.requestId!==t.requestId||o.executionId&&o.executionId!==this.executionId)return {permissionDecision:"deny",reasonCode:"DEVFLOW_ACTION_BINDING_STALE",reason:"DevFlow canonical action binding is stale or mismatched. Call mcp__devflow__get_project_context again before writing."};if(t.actionSatisfiedAt)return null;if(t.actionDegradation?.authorizedByContextReceipt===t.contextHash)return {permissionDecision:"allow",additionalContext:`DevFlow degraded fallback authorized by context receipt ${t.contextHash}: ${t.actionDegradation.reason}`};let r=(t.actionAttempts??[]).filter(i=>i.tool===e.tool&&kt.has(i.status));if(r.length>0){let i=r.at(-1),s={missedTool:e.tool,failedAttemptCount:r.length,reason:`${i.status}:${i.reason??"canonical domain action did not complete"}`,authorizedByContextReceipt:t.contextHash,authorizedAt:Date.now()};return this.persistDegradation(t,s),{permissionDecision:"allow",additionalContext:`DevFlow canonical tool mcp__devflow__${e.tool} ${i.status}; degraded direct write authorized by context receipt ${t.contextHash}. Preserve the action contract and verification plan.`}}return {permissionDecision:"deny",reasonCode:"DEVFLOW_REQUIRED_ACTION",reason:`DevFlow required action not completed. Call mcp__devflow__${e.tool} using context receipt ${t.contextHash}, then retry the write. Direct fallback is allowed only after unavailable, failed, or timeout evidence.`}}persistDegradation(t,e){let o;try{o=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let r=o.getContextReceipt(t.projectRoot,t.sessionId,t.executionId);if(!r||r.contextHash!==t.contextHash||r.actionDegradation)return;o.upsertContextReceipt({...r,actionDegradation:e});let i=o.getSkillExecution(t.executionId);if(!i)return;let s=i.metadata&&typeof i.metadata=="object"?i.metadata:{},a=Array.isArray(s.requiredActionDegradations)?s.requiredActionDegradations:[];o.updateSkillExecution(t.executionId,{missedMcpTools:[...new Set([...i.missedMcpTools??[],e.missedTool])],failedToolCalls:Math.max(i.failedToolCalls??0,e.failedAttemptCount),fallbackCount:(i.fallbackCount??0)+1,fallbackReasons:[...new Set([...i.fallbackReasons??[],`required_action_${e.reason}`])],metadata:{...s,requiredActionDegradations:[...a,e]}});}catch{}finally{try{o?.close();}catch{}}}};var $t=10*1024*1024,Nt=5;function Ht(n){return createHash$1("sha256").update(n).digest("hex").slice(0,16)}function he(n){return join(homedir(),".devflow","logs","hook-debug",`${Ht(n)}.jsonl`)}function ve(n,t,e={}){let o=e.maxBytes??$t,r=e.maxFiles??Nt;mkdirSync$1(dirname(n),{recursive:true,mode:448});let i=Buffer.byteLength(t),s=existsSync$1(n)?statSync(n).size:0;s>0&&s+i>o&&Ut(n,r),appendFileSync(n,t,{mode:384}),chmodSync(n,384);}function Ut(n,t){if(t<=1){rmSync$1(n,{force:true});return}rmSync$1(`${n}.${t-1}`,{force:true});for(let e=t-2;e>=1;e-=1){let o=`${n}.${e}`;existsSync$1(o)&&renameSync$1(o,`${n}.${e+1}`);}existsSync$1(n)&&renameSync$1(n,`${n}.1`);}var U="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function ye(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}function Ee(n){return Buffer.from(n,"utf8").toString("base64url")}function Vt(n,t,e){let o=t?.trim();if(o){let r=/^[a-zA-Z0-9:._-]{1,192}$/.test(o)?o:`tool-${createHash("sha256").update(o.slice(0,1024)).digest("hex").slice(0,32)}`;return `${n}:${r}`}return `${n}:legacy-${e}-${randomUUID().slice(0,8)}`}function ke(n){return `${n}:legacy-journal`}var j=class{constructor(t){this.projectRoot=t;this.sessions=new Map;this.sessionsDir=join$1(f(t),"hook-sessions");}registerSession(t){let e=t.trim();if(!e)throw new Error("session_id_required");let o=this.get(e);if(o)return o.lastActivityAt=Date.now(),this.persist(o),o;let r=Date.now(),i={sessionId:e,projectRoot:this.projectRoot,requiredMcpTools:[],evidenceObligations:[],evidenceDegradations:[],evidenceOutcomes:[],startedAt:r,lastActivityAt:r};return this.sessions.set(e,i),this.persist(i),i}startExecution(t,e,o){let r=this.registerSession(t);return (!r.executionId||r.skillName!==e)&&(r.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),r.skillName=e,r.requiredMcpTools=[...new Set(o)],r.lastActivityAt=Date.now(),this.persist(r),r}bindTaskIdentity(t,e){let o=this.registerSession(t);return o.activeTurnId=e.turnId,o.activeRequestId=e.requestId,o.intentArtifactHash=e.intentArtifactHash,o.lastActivityAt=Date.now(),this.persist(o),o}get(t){let e=t.trim();if(!e)return null;let o=this.sessions.get(e);if(o)return this.replayEvidenceJournal(o),o;let r=this.snapshotPath(e);if(!existsSync(r))return null;try{let i=JSON.parse(readFileSync(r,"utf8"));return i.sessionId!==e||i.projectRoot!==this.projectRoot?null:(i.requiredMcpTools=Array.isArray(i.requiredMcpTools)?i.requiredMcpTools:[],i.evidenceObligations=we(i.evidenceObligations),i.evidenceDegradations=xe(i.evidenceDegradations),i.evidenceOutcomes=Ie(i.evidenceOutcomes),this.replayEvidenceJournal(i),this.sessions.set(e,i),i)}catch{return null}}completeExecution(t){let e=this.get(t);if(!e)return null;let o=structuredClone(e);return delete e.executionId,delete e.skillName,e.requiredMcpTools=[],e.lastActivityAt=Date.now(),this.persist(e),o}addEvidenceObligation(t,e,o=Date.now(),r){let i=this.registerSession(t),a=(r?void 0:i.evidenceObligations.find(c=>c.contractId===e.id))?.obligationId??Vt(e.id,r,o);this.appendEvidenceEvent(t,{kind:"add",obligationId:a,contractId:e.id,at:o,contract:e},`add\0${a}`),this.replayEvidenceJournal(i);let l=i.evidenceObligations.find(c=>c.obligationId===a);return l?(i.lastActivityAt=Date.now(),this.persist(i),structuredClone(l)):null}listEvidenceObligations(t){return (this.get(t)?.evidenceObligations??[]).map(e=>structuredClone(e))}markEvidenceCorrection(t,e,o,r,i=Date.now()){let s=this.get(t),a=s?.evidenceObligations.find(d=>d.obligationId===e);if(!s||!a)return null;let l=/^[a-f0-9]{64}$/.test(r)?r:"";if(!l)return null;this.appendEvidenceEvent(t,{kind:"correction",obligationId:e,contractId:a.contractId,at:i,fingerprint:l,violations:o.slice(0,16).map(d=>d.slice(0,240))},`correction\0${e}\0${l}`),this.replayEvidenceJournal(s),s.lastActivityAt=i,this.persist(s);let c=s.evidenceObligations.find(d=>d.obligationId===e);return c?structuredClone(c):null}resolveEvidenceObligation(t,e){let o=this.get(t);if(!o)return false;let r=o.evidenceObligations.find(s=>s.obligationId===e);if(!r)return false;let i=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:r.contractId,at:i},`resolve\0${e}`),this.replayEvidenceJournal(o),o.lastActivityAt=i,this.persist(o),true}resolveDegradedEvidence(t,e){let o=this.get(t),r=o?.evidenceDegradations.find(s=>s.obligationId===e);if(!o||!r)return false;let i=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:r.contractId,at:i},`resolve-degraded\0${e}\0${i}`),this.replayEvidenceJournal(o),o.lastActivityAt=i,this.persist(o),true}degradeEvidenceObligation(t,e,o,r=Date.now()){let i=this.get(t),s=i?.evidenceObligations.find(l=>l.obligationId===e);if(!i||!s)return false;let a=o.slice(0,240);return this.appendEvidenceEvent(t,{kind:"degrade",obligationId:e,contractId:s.contractId,at:r,reason:a},`degrade\0${e}\0${a}`),this.replayEvidenceJournal(i),i.lastActivityAt=r,this.persist(i),true}removeSession(t){let e=t.trim();e&&(this.sessions.delete(e),rmSync(this.snapshotPath(e),{force:true}),rmSync(this.evidenceJournalDir(e),{recursive:true,force:true}));}list(){return [...this.sessions.values()]}snapshotPath(t){return join$1(this.sessionsDir,`${Ee(t)}.json`)}evidenceJournalDir(t){return join$1(this.sessionsDir,"evidence-journal",Ee(t))}appendEvidenceEvent(t,e,o){let r=this.evidenceJournalDir(t);mkdirSync(r,{recursive:true,mode:448});let i=createHash("sha256").update(o).digest("hex"),s=join$1(r,`${e.kind}-${i}.json`);if(existsSync(s))return;let a=join$1(r,`.${process.pid}.${randomUUID()}.tmp`);writeFileSync(a,JSON.stringify(e),{mode:384});try{linkSync(a,s);}catch(l){if(l.code!=="EEXIST")throw l}finally{rmSync(a,{force:true});}}replayEvidenceJournal(t){t.evidenceObligations=we(t.evidenceObligations),t.evidenceDegradations=xe(t.evidenceDegradations),t.evidenceOutcomes=Ie(t.evidenceOutcomes);let e=this.evidenceJournalDir(t.sessionId);if(!existsSync(e))return;let o;try{o=readdirSync(e).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(e,i),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let a=Bt(JSON.parse(s));return a?[a]:[]}catch{return []}}).sort((i,s)=>i.at-s.at||De(i.kind)-De(s.kind));for(let i of r)this.applyEvidenceEvent(t,i);t.evidenceObligations=t.evidenceObligations.slice(-8),t.evidenceDegradations=t.evidenceDegradations.slice(-20),t.evidenceOutcomes=t.evidenceOutcomes.slice(-20);}applyEvidenceEvent(t,e){let o=t.evidenceOutcomes.find(s=>s.obligationId===e.obligationId);if(e.kind==="add"){if(o)return;let s=t.evidenceObligations.find(a=>a.obligationId===e.obligationId);s?(s.contract=e.contract,s.promptedAt=Math.min(s.promptedAt,e.at)):t.evidenceObligations.push({obligationId:e.obligationId,contractId:e.contractId,contract:e.contract,promptedAt:e.at,attempt:0,correctionRequested:false,violations:[]});return}let r=t.evidenceObligations.find(s=>s.obligationId===e.obligationId);if(e.kind==="correction"){if(!r||o||r.correctionFingerprint===e.fingerprint)return;r.attempt+=1,r.correctionRequested=true,r.correctionRequestedAt=e.at,r.correctionFingerprint=e.fingerprint,r.violations=e.violations;return}let i=r?.attempt??o?.attempt??0;if(e.kind==="resolve"&&o?.status==="degraded")t.evidenceOutcomes=t.evidenceOutcomes.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations=t.evidenceDegradations.filter(s=>s.obligationId!==e.obligationId);else if(o)return;e.kind==="degrade"?(t.evidenceObligations=t.evidenceObligations.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations.push({obligationId:e.obligationId,contractId:e.contractId,reason:e.reason,degradedAt:e.at,attempt:i,contract:r?.contract})):t.evidenceObligations=t.evidenceObligations.filter(s=>s.obligationId!==e.obligationId),t.evidenceOutcomes.push({obligationId:e.obligationId,contractId:e.contractId,status:e.kind==="resolve"?"resolved":"degraded",completedAt:e.at,attempt:i,...e.kind==="degrade"?{reason:e.reason}:{}});}persist(t){mkdirSync(this.sessionsDir,{recursive:true,mode:448});let e=this.snapshotPath(t.sessionId),o=`${e}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(o,JSON.stringify(t),{mode:384}),renameSync(o,e);}};function we(n){return Array.isArray(n)?n.flatMap(t=>{if(!t||typeof t!="object")return [];let e=t;if(typeof e.contractId!="string"||e.contractId.length===0||e.contractId.length>128||typeof e.promptedAt!="number"||typeof e.attempt!="number"||typeof e.correctionRequested!="boolean"||!Array.isArray(e.violations)||!Oe(e.contract))return [];let o=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:ke(e.contractId),r=typeof e.correctionTranscriptHash=="string"?e.correctionTranscriptHash:void 0,i=e.correctionFingerprint??r;return i!==void 0&&!/^[a-f0-9]{64}$/.test(i)?[]:[{...e,obligationId:o,correctionFingerprint:i}]}).slice(-8):[]}function xe(n){return Array.isArray(n)?n.filter(t=>{if(!t||typeof t!="object")return false;let e=t;return typeof e.obligationId=="string"&&typeof e.contractId=="string"&&typeof e.reason=="string"&&typeof e.degradedAt=="number"&&typeof e.attempt=="number"}).slice(-20):[]}function Ie(n){return Array.isArray(n)?n.filter(t=>{if(!t||typeof t!="object")return false;let e=t;return typeof e.obligationId=="string"&&typeof e.contractId=="string"&&(e.status==="resolved"||e.status==="degraded")&&typeof e.completedAt=="number"&&typeof e.attempt=="number"&&(e.reason===void 0||typeof e.reason=="string")}).slice(-20):[]}function Bt(n){if(!n||typeof n!="object")return null;let t=n,e=t.kind;if(e!=="add"&&e!=="correction"&&e!=="resolve"&&e!=="degrade"||typeof t.contractId!="string"||t.contractId.length>128||typeof t.at!="number")return null;let r={obligationId:typeof t.obligationId=="string"&&t.obligationId.length>0&&t.obligationId.length<=384?t.obligationId:ke(t.contractId),contractId:t.contractId,at:t.at};if(e==="add")return Oe(t.contract)?{kind:e,...r,contract:t.contract}:null;if(e==="correction"){let i=typeof t.fingerprint=="string"?t.fingerprint:t.transcriptHash;return typeof i=="string"&&/^[a-f0-9]{64}$/.test(i)&&Array.isArray(t.violations)&&t.violations.every(s=>typeof s=="string"&&s.length<=240)?{kind:e,...r,fingerprint:i,violations:t.violations}:null}return e==="resolve"?{kind:e,...r}:typeof t.reason=="string"&&t.reason.length<=240?{kind:e,...r,reason:t.reason}:null}function De(n){return n==="add"?0:n==="correction"?1:2}function Oe(n){if(!n||typeof n!="object")return false;let t=n,e=t.requiredSections,o=t.prohibitedClaims;return 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(e)&&e.length===3&&e[0]==="\u5DE5\u5177\u53D1\u73B0"&&e[1]==="\u6A21\u578B\u5047\u8BBE"&&e[2]==="\u9700\u8981\u8FD0\u884C\u65F6\u9A8C\u8BC1"&&Array.isArray(o)&&o.length<=16&&o.every(r=>typeof r=="string"&&r.length<=128)&&typeof t.canonicalReport=="string"&&Buffer.byteLength(t.canonicalReport,"utf8")<=48*1024&&!!t.correctionPolicy&&t.correctionPolicy.maxAttempts===1&&t.correctionPolicy.repeatedViolation==="fail_open"}function Ae(n){let t=n.trim().replace(/^\//,"");if(!t.startsWith("devflow:"))return null;let e=t.slice(8).replace(/^devflow-/,"");return /^[a-z0-9][a-z0-9-]*$/i.test(e)?`devflow:${e.toLowerCase()}`:null}function Ce(n,t){return t?`evt_tool_${createHash("sha256").update(`${n}\0${t}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var Yt=new Set(["Write","Edit","NotebookEdit"]),Te="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 Le(n){if(!Yt.has(n.toolName))return null;let t=Xt(n.toolInput);if(!t)return null;let e=Qt(t,n.projectRoot),o=resolve(n.projectRoot,".claude");if(Fe(e,o)&&basename(e).toLocaleUpperCase("en-US")==="MEMORY.MD")return Te;let r=resolve(n.home??homedir(),".claude","projects");return Fe(e,r)&&relative(r,e).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?Te:null}function Xt(n){for(let t of ["file_path","notebook_path","path"]){let e=n[t];if(typeof e=="string"&&e.trim())return e.trim()}return null}function Qt(n,t){return resolve(isAbsolute(n)?n:resolve(t,n))}function Fe(n,t){let e=relative(t,n);return e===""||!e.startsWith(`..${sep}`)&&e!==".."&&!isAbsolute(e)}function Ue(n){let t=an(n.toolName,n.toolInput),e=t?cn(n.projectRoot,n.toolName,n.toolInput):void 0;if(!t||!e||!n.toolUseId)return {allowed:true};let o=dn(e),r,i=0,s,a;try{a=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:100,readonly:!0});let c=a.getActiveContextReceipt(n.projectRoot,n.sessionId,n.executionId);r=c?.contextHash,i=c?.issuedAt??0,s=c?.canonicalAction?.binding.operationTargets?.find(d=>un(n.projectRoot,d.path,e));}catch{}finally{try{a?.close();}catch{}}let l={toolUseId:n.toolUseId,sessionId:n.sessionId,executionId:n.executionId,operation:t,path:e,before:o,contextReceipt:r,observedAt:Date.now()};if(fn(n.projectRoot,l),t==="edit"||t==="write"||t==="delete"){let c=mn(n.projectRoot,e),d=c?.success&&c.operation==="delete"&&!c.after.exists&&c.completedAt>=i,u=s?.expectedState==="existing"&&!o.exists||s?.expectedState==="missing"&&o.exists||!!(s?.contentHash&&o.hash!==s.contentHash);if(d||s?.expectedState==="existing"&&!o.exists)return $e(n,l,"DEVFLOW_FILE_STATE_DELETED","The target was deleted after the active Context receipt. Refresh project context before editing or recreating it.");if(u)return $e(n,l,"DEVFLOW_FILE_STATE_STALE","The target state no longer matches the active Context receipt. Refresh project context before overwriting it.")}return qe(n,l,true),{allowed:true,pending:l}}function $e(n,t,e,o){return qe(n,t,false,e),{allowed:false,reasonCode:e,reason:o,pending:t}}function qe(n,t,e,o){m({event:"canonical.action.validated",identity:{projectRoot:n.projectRoot,sessionId:n.sessionId,executionId:n.executionId,contextReceipt:t.contextReceipt},level:e?"info":"warn",timestamp:Date.now(),data:{stage:"host_file_state_precondition",valid:e,operation:t.operation,targetPath:relative(n.projectRoot,t.path),targetExists:t.before.exists,targetHash:t.before.hash,reason:o,toolUseId:t.toolUseId}});}function an(n,t){if(n==="Read")return "read";if(n==="Edit"||n==="NotebookEdit")return "edit";if(n==="Write")return "write";if(n==="Delete"||n==="Bash"&&Je(t.command))return "delete"}function cn(n,t,e){let o=ln(e,["file_path","filePath","notebook_path","path","targetPath"])??(t==="Bash"?Je(e.command):void 0);if(!o)return;let r=isAbsolute(o)?normalize(o):resolve(n,o),i=relative(n,r);return i.startsWith("..")||isAbsolute(i)?void 0:r}function Je(n){return typeof n!="string"?void 0:/(?:^|[;&|]\s*)\s*(?:rm|unlink)\s+(?:-[A-Za-z]+\s+)*(?:--\s+)?(["']?)([^\s;&|"']+)\1/u.exec(n)?.[2]}function ln(n,t){for(let e of t){let o=n[e];if(typeof o=="string"&&o.trim())return o.trim()}}function dn(n){if(!existsSync$1(n))return {exists:false};try{return {exists:!0,hash:createHash$1("sha256").update(readFileSync$1(n)).digest("hex")}}catch{return {exists:true}}}function un(n,t,e){return (isAbsolute(t)?normalize(t):resolve(n,t))===normalize(e)}function We(n){return join(f(n),"file-state")}function Ve(n){return join(We(n),"pending.json")}function pn(n){return join(We(n),"observations.jsonl")}function gn(n){try{return JSON.parse(readFileSync$1(Ve(n),"utf8"))}catch{return {}}}function fn(n,t){let e=Ve(n);mkdirSync$1(dirname(e),{recursive:true});let o=gn(n);o[t.toolUseId]=t,hn(e,JSON.stringify(o));}function mn(n,t){try{let e=readFileSync$1(pn(n),"utf8").trim().split(`
3
+ `);for(let o=e.length-1;o>=0;o-=1){let r=JSON.parse(e[o]);if(r.path===t)return r}}catch{}}function hn(n,t){let e=`${n}.${process.pid}.${Date.now()}.tmp`;writeFileSync$1(e,t,{encoding:"utf8",mode:384}),renameSync$1(e,n);}function E(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function Be(n){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:n}}}function Rn(n){let t=f(n);return existsSync(t)||mkdirSync(t,{recursive:true}),t}function En(n,t,e,o,r,i){let s=join$1(Rn(n),"event-map.json"),a=[];try{existsSync(s)&&(a=JSON.parse(readFileSync(s,"utf-8")));}catch{}a.push({sessionId:t,toolName:e,toolUseId:o,eventId:r,timestamp:i}),writeFileSync(s,JSON.stringify(a));}function wn(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"}}async function xn(n){let t=ye();try{if(!n||n.trim()==="")return E();let e=JSON.parse(n),o=Date.now(),r=$(),i=new O;e.tool_name.startsWith("mcp__devflow__")&&(typeof e.tool_input.projectRoot!="string"||!e.tool_input.projectRoot.trim())&&(e.tool_input.projectRoot=r);let s=e.session_id?.trim();if(!s)return Be(U);let a=new j(r),l=a.get(s)!==null;if(a.registerSession(s),l||await i.sendSessionStart(s,r,Date.now()),e.tool_name==="Skill"){let I=e.tool_input?.skill,v=I?Ae(I):null;if(v){let Ke=a.get(s)?.executionId,R=a.startExecution(s,v,le(v));R.executionId&&R.executionId!==Ke&&await i.sendExecutionStart(R.executionId,s,v,R.lastActivityAt,r,R.requiredMcpTools);}}let c=a.get(s);e.tool_name.startsWith("mcp__devflow__")&&(e.tool_input._devflow_session_id=s,e.tool_input._devflow_execution_id=c?.executionId??s,c?.activeTurnId&&(e.tool_input._devflow_turn_id=c.activeTurnId),c?.activeRequestId&&(e.tool_input._devflow_request_id=c.activeRequestId),c?.intentArtifactHash&&(e.tool_input._devflow_intent_artifact_hash=c.intentArtifactHash),c?.skillName&&(e.tool_input._devflow_active_skill=c.skillName),e.tool_use_id&&(e.tool_input._devflow_tool_use_id=e.tool_use_id));let d=e.tool_name.startsWith("mcp__"),u=d?e.tool_name.replace(/^mcp__[^_]+__/,""):void 0,p=new T(r,s,c?.executionId),z=p.getPhase(),g,w=Le({toolName:e.tool_name,toolInput:e.tool_input,projectRoot:r}),M=Ue({projectRoot:r,sessionId:s,executionId:c?.executionId,toolUseId:e.tool_use_id,toolName:e.tool_name,toolInput:e.tool_input}),h=w?{permissionDecision:"deny",reason:w}:M.allowed?p.evaluate(e.tool_name,d):{permissionDecision:"deny",reason:M.reason,reasonCode:M.reasonCode};h.permissionDecision==="deny"?g={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:h.reason??"MCP context required"}}:h.additionalContext?g=Be(h.additionalContext):g=E(),e.tool_name.startsWith("mcp__devflow__")&&(g.hookSpecificOutput.updatedInput=e.tool_input),t&&g.hookSpecificOutput.permissionDecision==="allow"&&(g.hookSpecificOutput.additionalContext=U);let ze=c?.executionId??s,_={eventId:Ce(s,e.tool_use_id),executionId:ze,sessionId:s,projectRoot:r,toolUseId:e.tool_use_id,timestamp:Date.now(),toolName:e.tool_name,toolType:d?"mcp":e.tool_name==="Agent"?"subagent":"direct",isMcpTool:d,mcpToolName:u,mcpEnforced:d&&z==="context_gathering",mcpFallback:!d&&z==="context_gathering",kind:wn(e.tool_name),input:e.tool_input,duration:0,blocked:g.hookSpecificOutput.permissionDecision==="deny",blockReason:g.hookSpecificOutput.permissionDecision==="deny"?w?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":h.reasonCode??"DEVFLOW_CONTEXT_REQUIRED":void 0},x=await i.sendEvent(_);x&&!_.blocked&&En(r,s,e.tool_name,e.tool_use_id,x,_.timestamp),x&&_.blocked&&await i.completeEvent({eventId:x,sessionId:s,error:w?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":h.reasonCode??"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-_.timestamp,completedAt:Date.now()});try{let I=ge(r),v={ts:o,tool:e.tool_name,sessionId:s,skill:c?.skillName??"(none)",requiredTools:c?.requiredMcpTools??[],isMcp:d,enforce:c?.executionId!==void 0,stateless:c?.executionId===void 0&&!d&&e.tool_name!=="Skill",bypassCount:I.bypassCount??0,decision:g.hookSpecificOutput.permissionDecision,env_CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd()};ve(he(r),`${JSON.stringify(v)}
4
+ `);}catch{}return g}catch{return E()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let n=console.log.bind(console);console.log=console.error.bind(console),console.info=console.error.bind(console);let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",e=>{t+=e;}),process.stdin.on("end",async()=>{let e=await xn(t);n(JSON.stringify(e));}),process.stdin.on("error",()=>{n(JSON.stringify(E())),process.exit(0);}),setTimeout(()=>{n(JSON.stringify(E())),process.exit(0);},4e3).unref();}export{xn as handlePreToolUse};
@@ -1,6 +1,6 @@
1
- import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHash}from'node:crypto';import {mkdirSync,writeFileSync,existsSync}from'node:fs';import {request}from'node:http';import {createRequire}from'node:module';import {homedir}from'node:os';import {join}from'node:path';import {writeRuntimeEndpointState,readRuntimeEndpointState,updateRuntimeEndpointStatus,resolveRuntimeEndpoint}from'@devflow-tools/sdk';import {emitSemanticControlLog}from'@devflow-tools/telemetry';var{DatabaseSync:q}=createRequire(import.meta.url)("node:sqlite"),K=75,j=400,$=2e3,Y=300*1e3,X=1e3,J=1e3,Z=15e3,ee=["--yes","@devflow-tools/server","--devflow-instance-token"],C=process.env.CLAUDE_PROJECT_DIR||process.cwd();function v(e){let n=e instanceof Error?e.message:String(e);emitSemanticControlLog({event:"hook.runtime.degraded",identity:{projectRoot:C},level:"warn",timestamp:Date.now(),data:{stage:"server_bootstrap",reason:n,fallback:"mcp_stdio_or_existing_server"}});}function d(e,n,t){emitSemanticControlLog({event:e==="warn"?"hook.runtime.degraded":"hook.runtime.completed",identity:{projectRoot:C},level:e,timestamp:Date.now(),data:{stage:n,...t}});}function re(e){return createHash("sha256").update(e).digest("hex").slice(0,16)}function te(e){let n=new q(e);n.exec(`PRAGMA busy_timeout = ${K}`);let t=n.prepare(`
1
+ import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHash}from'node:crypto';import {mkdirSync,writeFileSync,existsSync}from'node:fs';import {request}from'node:http';import {createRequire}from'node:module';import {join}from'node:path';import {getDevFlowStateRoot,writeRuntimeEndpointState,readRuntimeEndpointState,updateRuntimeEndpointStatus,resolveRuntimeEndpoint}from'@devflow-tools/sdk';import {emitSemanticControlLog}from'@devflow-tools/telemetry';var g=emitSemanticControlLog;var{DatabaseSync:z}=createRequire(import.meta.url)("node:sqlite"),K=75,$=400,Y=2e3,X=300*1e3,J=1e3,Z=1e3,ee=15e3,re=["--yes","@devflow-tools/server","--devflow-instance-token"],M=process.env.CLAUDE_PROJECT_DIR||process.cwd();function h(e){let n=e instanceof Error?e.message:String(e);g({event:"hook.runtime.degraded",identity:{projectRoot:M},level:"warn",timestamp:Date.now(),data:{stage:"server_bootstrap",reason:n,fallback:"mcp_stdio_or_existing_server"}});}function d(e,n,t){g({event:e==="warn"?"hook.runtime.degraded":"hook.runtime.completed",identity:{projectRoot:M},level:e,timestamp:Date.now(),data:{stage:n,...t}});}function te(e){return createHash("sha256").update(e).digest("hex").slice(0,16)}function ne(e){let n=new z(e);n.exec(`PRAGMA busy_timeout = ${K}`);let t=n.prepare(`
2
2
  SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'server_bootstrap_state'
3
- `).get();if(t?.sql&&!t.sql.includes("'terminating'")){n.exec("BEGIN IMMEDIATE");try{n.exec("ALTER TABLE server_bootstrap_state RENAME TO server_bootstrap_state_legacy"),A(n),n.exec(`
3
+ `).get();if(t?.sql&&!t.sql.includes("'terminating'")){n.exec("BEGIN IMMEDIATE");try{n.exec("ALTER TABLE server_bootstrap_state RENAME TO server_bootstrap_state_legacy"),L(n),n.exec(`
4
4
  INSERT INTO server_bootstrap_state (
5
5
  id, token, state, owner_pid, wrapper_pid, process_group_id, server_pid,
6
6
  created_at, updated_at
@@ -9,7 +9,7 @@ import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHas
9
9
  id, token, state, owner_pid, wrapper_pid, process_group_id, server_pid,
10
10
  created_at, updated_at
11
11
  FROM server_bootstrap_state_legacy
12
- `),n.exec("DROP TABLE server_bootstrap_state_legacy"),n.exec("COMMIT");}catch(r){try{n.exec("ROLLBACK");}catch{}throw r}}else t||A(n);return n}function A(e){e.exec(`
12
+ `),n.exec("DROP TABLE server_bootstrap_state_legacy"),n.exec("COMMIT");}catch(r){try{n.exec("ROLLBACK");}catch{}throw r}}else t||L(n);return n}function L(e){e.exec(`
13
13
  CREATE TABLE IF NOT EXISTS server_bootstrap_state (
14
14
  id INTEGER PRIMARY KEY CHECK (id = 1),
15
15
  token TEXT NOT NULL,
@@ -21,7 +21,7 @@ import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHas
21
21
  created_at INTEGER NOT NULL,
22
22
  updated_at INTEGER NOT NULL
23
23
  )
24
- `);}function ne(e){return e.prepare(`
24
+ `);}function oe(e){return e.prepare(`
25
25
  SELECT
26
26
  token,
27
27
  state,
@@ -33,46 +33,46 @@ import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHas
33
33
  updated_at AS updatedAt
34
34
  FROM server_bootstrap_state
35
35
  WHERE id = 1
36
- `).get()}function c(e){return Number(e.changes)}function oe(e){if(!Number.isSafeInteger(e)||e<=1)return false;try{return process.kill(e,0),!0}catch{return false}}function y(){let e=execFileSync("ps",["-axo","pid=,pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:500}),n=[];for(let t of e.split(`
37
- `)){let r=t.match(/^\s*(\d+)\s+(\d+)\s+(.+)$/);if(!r)continue;let o=Number(r[1]),p=Number(r[2]);!Number.isSafeInteger(o)||!Number.isSafeInteger(p)||n.push({pid:o,processGroupId:p,command:r[3]});}return n}function se(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function x(e,n){let t=se(n);return new RegExp(`(?:^|\\s)--devflow-instance-token(?:=|\\s+)${t}(?:\\s|$)`).test(e)}function S(e){return /(?:@devflow-tools\/server|devflow-server|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js)/.test(e)}function L(e){return /(?:^|\s)(?:\S*[\\/])?devflow-server(?:-child)?(?:\s|$)|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js/.test(e)}function ie(e){let n=y().filter(r=>S(r.command)&&x(r.command,e)),t=new Map;for(let r of n){let o=t.get(r.processGroupId)??[];o.push(r),t.set(r.processGroupId,o);}return [...t.entries()].map(([r,o])=>({processGroupId:r,processes:o})).sort((r,o)=>o.processes.length-r.processes.length)}function R(e,n){return ie(e).find(t=>n===void 0||t.processGroupId===n)}function E(e,n){let t=D(e,n);if(!t)return;let r=t.processes.find(o=>o.pid!==t.wrapperPid&&L(o.command))??t.processes.find(o=>o.pid===t.wrapperPid&&L(o.command));if(r)return {wrapperPid:t.wrapperPid,processGroupId:t.processGroupId,serverPid:r.pid,processes:t.processes}}function D(e,n){let t=R(e,n);if(!t)return;let r=t.processes.find(o=>o.pid===t.processGroupId&&S(o.command));if(r)return {wrapperPid:r.pid,processGroupId:r.processGroupId,processes:t.processes}}function h(e){if(!oe(e))return false;try{return execFileSync("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:250}).trim().includes("server-bootstrap")}catch{return false}}function U(){return new Promise(e=>{let n=false,t=r=>{n||(n=true,e(r));};try{let r=process.env.DEVFLOW_SERVER_BOOTSTRAP_HEALTH_URL??new URL("/api/health",P()).toString(),o=request(r,{method:"GET",timeout:j},p=>{p.resume(),t((p.statusCode??500)>=200&&(p.statusCode??500)<300);});o.on("timeout",()=>o.destroy(new Error("health timeout"))),o.on("error",()=>t(!1)),o.end();}catch{t(false);}})}async function ae(e){let n=false;try{e.exec("BEGIN IMMEDIATE"),n=!0;let t=await U(),r=ne(e);if(t){if(r?.state==="running"||r?.state==="launching"){let s=E(r.token,r.processGroupId??void 0);if(s){e.prepare(`
36
+ `).get()}function p(e){return Number(e.changes)}function se(e){if(!Number.isSafeInteger(e)||e<=1)return false;try{return process.kill(e,0),!0}catch{return false}}function G(){let e=execFileSync("ps",["-axo","pid=,pgid=,command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:500}),n=[];for(let t of e.split(`
37
+ `)){let r=t.match(/^\s*(\d+)\s+(\d+)\s+(.+)$/);if(!r)continue;let o=Number(r[1]),c=Number(r[2]);!Number.isSafeInteger(o)||!Number.isSafeInteger(c)||n.push({pid:o,processGroupId:c,command:r[3]});}return n}function ie(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function x(e,n){let t=ie(n);return new RegExp(`(?:^|\\s)--devflow-instance-token(?:=|\\s+)${t}(?:\\s|$)`).test(e)}function S(e){return /(?:@devflow-tools\/server|devflow-server|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js)/.test(e)}function A(e){return /(?:^|\s)(?:\S*[\\/])?devflow-server(?:-child)?(?:\s|$)|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js/.test(e)}function ae(e){let n=G().filter(r=>S(r.command)&&x(r.command,e)),t=new Map;for(let r of n){let o=t.get(r.processGroupId)??[];o.push(r),t.set(r.processGroupId,o);}return [...t.entries()].map(([r,o])=>({processGroupId:r,processes:o})).sort((r,o)=>o.processes.length-r.processes.length)}function R(e,n){return ae(e).find(t=>n===void 0||t.processGroupId===n)}function E(e,n){let t=I(e,n);if(!t)return;let r=t.processes.find(o=>o.pid!==t.wrapperPid&&A(o.command))??t.processes.find(o=>o.pid===t.wrapperPid&&A(o.command));if(r)return {wrapperPid:t.wrapperPid,processGroupId:t.processGroupId,serverPid:r.pid,processes:t.processes}}function I(e,n){let t=R(e,n);if(!t)return;let r=t.processes.find(o=>o.pid===t.processGroupId&&S(o.command));if(r)return {wrapperPid:r.pid,processGroupId:r.processGroupId,processes:t.processes}}function T(e){if(!se(e))return false;try{return execFileSync("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:250}).trim().includes("server-bootstrap")}catch{return false}}function U(){return new Promise(e=>{let n=false,t=r=>{n||(n=true,e(r));};try{let r=process.env.DEVFLOW_SERVER_BOOTSTRAP_HEALTH_URL??new URL("/api/health",D()).toString(),o=request(r,{method:"GET",timeout:$},c=>{c.resume(),t((c.statusCode??500)>=200&&(c.statusCode??500)<300);});o.on("timeout",()=>o.destroy(new Error("health timeout"))),o.on("error",()=>t(!1)),o.end();}catch{t(false);}})}async function ce(e){let n=false;try{e.exec("BEGIN IMMEDIATE"),n=!0;let t=await U(),r=oe(e);if(t){if(r?.state==="running"||r?.state==="launching"){let s=E(r.token,r.processGroupId??void 0);if(s){e.prepare(`
38
38
  UPDATE server_bootstrap_state
39
39
  SET state = 'running', owner_pid = ?, wrapper_pid = ?, process_group_id = ?, server_pid = ?,
40
40
  updated_at = ?
41
41
  WHERE id = 1 AND token = ? AND state = ?
42
- `).run(process.pid,s.wrapperPid,s.processGroupId,s.serverPid,Date.now(),r.token,r.state);let i=P();writeRuntimeEndpointState({url:i,port:Number(new URL(i).port||13337),pid:s.serverPid,processGroupId:s.processGroupId,ownerToken:r.token,status:"healthy"});}else r.state==="running"&&e.prepare(`
42
+ `).run(process.pid,s.wrapperPid,s.processGroupId,s.serverPid,Date.now(),r.token,r.state);let i=D();writeRuntimeEndpointState({url:i,port:Number(new URL(i).port||13337),pid:s.serverPid,processGroupId:s.processGroupId,ownerToken:r.token,status:"healthy"});}else r.state==="running"&&e.prepare(`
43
43
  DELETE FROM server_bootstrap_state
44
44
  WHERE id = 1 AND token = ? AND state = 'running'
45
- `).run(r.token);}return e.exec("COMMIT"),n=!1,{action:"skip"}}if(r?.state==="launching"){if(h(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=r.processGroupId??void 0,i=E(r.token,s);if(i){let u=e.prepare(`
45
+ `).run(r.token);}return e.exec("COMMIT"),n=!1,{action:"skip"}}if(r?.state==="launching"){if(T(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=r.processGroupId??void 0,i=E(r.token,s);if(i){let u=e.prepare(`
46
46
  UPDATE server_bootstrap_state
47
47
  SET state = 'running', owner_pid = ?, wrapper_pid = ?, process_group_id = ?,
48
48
  server_pid = ?, updated_at = ?
49
49
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
50
- `).run(process.pid,i.wrapperPid,i.processGroupId,i.serverPid,Date.now(),r.token,r.ownerPid);if(c(u)!==1)throw new Error("launch intent changed before adoption");return e.exec("COMMIT"),n=!1,d("info","server_process_adopted",{processGroupId:i.processGroupId}),{action:"skip"}}let a=D(r.token,s);if(a&&Date.now()-r.createdAt<Y)return e.exec("COMMIT"),n=!1,{action:"skip"};if(a){let u=e.prepare(`
50
+ `).run(process.pid,i.wrapperPid,i.processGroupId,i.serverPid,Date.now(),r.token,r.ownerPid);if(p(u)!==1)throw new Error("launch intent changed before adoption");return e.exec("COMMIT"),n=!1,d("info","server_process_adopted",{processGroupId:i.processGroupId}),{action:"skip"}}let a=I(r.token,s);if(a&&Date.now()-r.createdAt<X)return e.exec("COMMIT"),n=!1,{action:"skip"};if(a){let u=e.prepare(`
51
51
  UPDATE server_bootstrap_state
52
52
  SET state = 'terminating', owner_pid = ?, process_group_id = ?, updated_at = ?
53
53
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
54
- `).run(process.pid,a.processGroupId,Date.now(),r.token,r.ownerPid);if(c(u)!==1)throw new Error("launch intent changed before cleanup claim");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:a.processGroupId}}e.prepare(`
54
+ `).run(process.pid,a.processGroupId,Date.now(),r.token,r.ownerPid);if(p(u)!==1)throw new Error("launch intent changed before cleanup claim");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:a.processGroupId}}e.prepare(`
55
55
  DELETE FROM server_bootstrap_state
56
56
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
57
- `).run(r.token,r.ownerPid);}else if(r?.state==="terminating"){if(h(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=R(r.token);if(s){let i=e.prepare(`
57
+ `).run(r.token,r.ownerPid);}else if(r?.state==="terminating"){if(T(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=R(r.token);if(s){let i=e.prepare(`
58
58
  UPDATE server_bootstrap_state
59
59
  SET owner_pid = ?, process_group_id = ?, updated_at = ?
60
60
  WHERE id = 1 AND token = ? AND state = 'terminating' AND owner_pid = ?
61
- `).run(process.pid,s.processGroupId,Date.now(),r.token,r.ownerPid);if(c(i)!==1)throw new Error("cleanup ownership changed during recovery");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:s.processGroupId}}e.prepare(`
61
+ `).run(process.pid,s.processGroupId,Date.now(),r.token,r.ownerPid);if(p(i)!==1)throw new Error("cleanup ownership changed during recovery");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:s.processGroupId}}e.prepare(`
62
62
  DELETE FROM server_bootstrap_state
63
63
  WHERE id = 1 AND token = ? AND state = 'terminating' AND owner_pid = ?
64
64
  `).run(r.token,r.ownerPid);}else if(r?.state==="running"){let s=E(r.token);if(s)return e.prepare(`
65
65
  UPDATE server_bootstrap_state
66
66
  SET owner_pid = ?, wrapper_pid = ?, process_group_id = ?, server_pid = ?, updated_at = ?
67
67
  WHERE id = 1 AND token = ? AND state = 'running'
68
- `).run(process.pid,s.wrapperPid,s.processGroupId,s.serverPid,Date.now(),r.token),e.exec("COMMIT"),n=!1,{action:"skip"};let i=R(r.token);if(i&&!h(r.ownerPid)){let a=e.prepare(`
68
+ `).run(process.pid,s.wrapperPid,s.processGroupId,s.serverPid,Date.now(),r.token),e.exec("COMMIT"),n=!1,{action:"skip"};let i=R(r.token);if(i&&!T(r.ownerPid)){let a=e.prepare(`
69
69
  UPDATE server_bootstrap_state
70
70
  SET state = 'terminating', owner_pid = ?, process_group_id = ?, updated_at = ?
71
71
  WHERE id = 1 AND token = ? AND state = 'running' AND owner_pid = ?
72
- `).run(process.pid,i.processGroupId,Date.now(),r.token,r.ownerPid);if(c(a)!==1)throw new Error("running cleanup ownership changed");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:i.processGroupId}}e.prepare(`
72
+ `).run(process.pid,i.processGroupId,Date.now(),r.token,r.ownerPid);if(p(a)!==1)throw new Error("running cleanup ownership changed");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:i.processGroupId}}e.prepare(`
73
73
  DELETE FROM server_bootstrap_state
74
74
  WHERE id = 1 AND token = ? AND state = 'running' AND owner_pid = ?
75
- `).run(r.token,r.ownerPid);}let o=randomUUID(),p=Date.now();return e.prepare(`
75
+ `).run(r.token,r.ownerPid);}let o=randomUUID(),c=Date.now();return e.prepare(`
76
76
  INSERT INTO server_bootstrap_state (
77
77
  id, token, state, owner_pid, wrapper_pid, process_group_id, server_pid,
78
78
  created_at, updated_at
@@ -86,24 +86,24 @@ import {spawn,execFileSync}from'node:child_process';import {randomUUID,createHas
86
86
  server_pid = NULL,
87
87
  created_at = excluded.created_at,
88
88
  updated_at = excluded.updated_at
89
- `).run(o,process.pid,p,p),e.exec("COMMIT"),n=!1,{action:"launch",token:o}}finally{if(n)try{e.exec("ROLLBACK");}catch{}}}function pe(e){return new Promise((n,t)=>{let r;try{let o=ce(e);r=spawn(o.command,o.args,{detached:!0,env:{...process.env,DEVFLOW_INSTANCE_TOKEN:e},stdio:["ignore","inherit","inherit"]});}catch(o){t(o);return}r.once("spawn",()=>n(r)),r.once("error",t);})}function ce(e){if(!de()){let n=createRequire(import.meta.url),r=[process.env.DEVFLOW_SERVER_ENTRY,ue(()=>n.resolve("@devflow-tools/server/dist/main.js")),join(process.cwd(),"apps","server","dist","main.js"),join(process.cwd(),"node_modules","@devflow-tools","server","dist","main.js")].filter(o=>!!o).find(o=>existsSync(o));if(r)return {command:process.execPath,args:[r,"--devflow-instance-token",e]}}return {command:"npx",args:[...ee,e]}}function de(){return process.env.DEVFLOW_SERVER_BOOTSTRAP_FORCE_NPX==="1"||!!process.env.DEVFLOW_TEST_NPX_TRACE||Object.keys(process.env).some(e=>e.startsWith("DEVFLOW_SERVER_BOOTSTRAP_TEST_"))}function ue(e){try{return e()}catch{return}}function P(){let e=resolveRuntimeEndpoint();return e.source==="environment"?e.url:readRuntimeEndpointState()?.url??e.url}async function m(e,n){let t=Date.now()+n;for(;Date.now()<t;){if(e())return true;await new Promise(r=>setTimeout(r,10));}return e()}async function N(e){let n=process.env[e];if(!n)return;writeFileSync(n,`${process.pid}
90
- `);let t=process.env.DEVFLOW_SERVER_BOOTSTRAP_TEST_CONTINUE_FILE;if(!t)return;if(!await m(()=>existsSync(t),Z))throw new Error(`test checkpoint timed out: ${e}`)}async function le(e,n){let t;return await m(()=>{let o=E(e,n);return o?(t=o,true):false},$)?t:void 0}function _e(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
89
+ `).run(o,process.pid,c,c),e.exec("COMMIT"),n=!1,{action:"launch",token:o}}finally{if(n)try{e.exec("ROLLBACK");}catch{}}}function pe(e){return new Promise((n,t)=>{let r;try{let o=de(e);r=spawn(o.command,o.args,{detached:!0,env:{...process.env,DEVFLOW_INSTANCE_TOKEN:e},stdio:["ignore","inherit","inherit"]});}catch(o){t(o);return}r.once("spawn",()=>n(r)),r.once("error",t);})}function de(e){if(!ue()){let n=createRequire(import.meta.url),r=[process.env.DEVFLOW_SERVER_ENTRY,le(()=>n.resolve("@devflow-tools/server/dist/main.js")),join(process.cwd(),"apps","server","dist","main.js"),join(process.cwd(),"node_modules","@devflow-tools","server","dist","main.js")].filter(o=>!!o).find(o=>existsSync(o));if(r)return {command:process.execPath,args:[r,"--devflow-instance-token",e]}}return {command:"npx",args:[...re,e]}}function ue(){return process.env.DEVFLOW_SERVER_BOOTSTRAP_FORCE_NPX==="1"||!!process.env.DEVFLOW_TEST_NPX_TRACE||Object.keys(process.env).some(e=>e.startsWith("DEVFLOW_SERVER_BOOTSTRAP_TEST_"))}function le(e){try{return e()}catch{return}}function D(){let e=resolveRuntimeEndpoint();return e.source==="environment"?e.url:readRuntimeEndpointState()?.url??e.url}async function f(e,n){let t=Date.now()+n;for(;Date.now()<t;){if(e())return true;await new Promise(r=>setTimeout(r,10));}return e()}async function k(e){let n=process.env[e];if(!n)return;writeFileSync(n,`${process.pid}
90
+ `);let t=process.env.DEVFLOW_SERVER_BOOTSTRAP_TEST_CONTINUE_FILE;if(!t)return;if(!await f(()=>existsSync(t),ee))throw new Error(`test checkpoint timed out: ${e}`)}async function _e(e,n){let t;return await f(()=>{let o=E(e,n);return o?(t=o,true):false},Y)?t:void 0}function Ee(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
91
91
  UPDATE server_bootstrap_state
92
92
  SET wrapper_pid = ?, process_group_id = ?, server_pid = NULL, updated_at = ?
93
93
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
94
- `).run(t.wrapperPid,t.processGroupId,Date.now(),n,process.pid);if(c(o)!==1)throw new Error("launch intent ownership changed before wrapper persistence");e.exec("COMMIT"),r=!1;}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function Ee(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
94
+ `).run(t.wrapperPid,t.processGroupId,Date.now(),n,process.pid);if(p(o)!==1)throw new Error("launch intent ownership changed before wrapper persistence");e.exec("COMMIT"),r=!1;}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function fe(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
95
95
  UPDATE server_bootstrap_state
96
96
  SET state = 'running', wrapper_pid = ?, process_group_id = ?, server_pid = ?,
97
97
  updated_at = ?
98
98
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
99
- `).run(t.wrapperPid,t.processGroupId,t.serverPid,Date.now(),n,process.pid);if(c(o)!==1)throw new Error("launch intent ownership changed before promotion");e.exec("COMMIT"),r=!1;}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function fe(e,n){let t=false;try{e.exec("BEGIN IMMEDIATE"),t=!0,e.prepare(`
99
+ `).run(t.wrapperPid,t.processGroupId,t.serverPid,Date.now(),n,process.pid);if(p(o)!==1)throw new Error("launch intent ownership changed before promotion");e.exec("COMMIT"),r=!1;}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function me(e,n){let t=false;try{e.exec("BEGIN IMMEDIATE"),t=!0,e.prepare(`
100
100
  DELETE FROM server_bootstrap_state
101
101
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
102
- `).run(n,process.pid),e.exec("COMMIT"),t=!1;}finally{if(t)try{e.exec("ROLLBACK");}catch{}}}function me(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
102
+ `).run(n,process.pid),e.exec("COMMIT"),t=!1;}finally{if(t)try{e.exec("ROLLBACK");}catch{}}}function we(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
103
103
  UPDATE server_bootstrap_state
104
104
  SET state = 'terminating', owner_pid = ?, updated_at = ?
105
105
  WHERE id = 1 AND token = ? AND state = 'launching' AND owner_pid = ?
106
- `).run(process.pid,Date.now(),n,t);return e.exec("COMMIT"),r=!1,c(o)===1}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function we(e,n){let t=false;try{e.exec("BEGIN IMMEDIATE"),t=!0;let r=e.prepare(`
106
+ `).run(process.pid,Date.now(),n,t);return e.exec("COMMIT"),r=!1,p(o)===1}finally{if(r)try{e.exec("ROLLBACK");}catch{}}}function ge(e,n){let t=false;try{e.exec("BEGIN IMMEDIATE"),t=!0;let r=e.prepare(`
107
107
  DELETE FROM server_bootstrap_state
108
108
  WHERE id = 1 AND token = ? AND state = 'terminating' AND owner_pid = ?
109
- `).run(n,process.pid);return e.exec("COMMIT"),t=!1,c(r)===1}finally{if(t)try{e.exec("ROLLBACK");}catch{}}}function w(e){return y().filter(n=>n.processGroupId===e)}function k(e,n){return w(e).some(t=>S(t.command)&&x(t.command,n))}async function Te(e,n){if(!k(e,n))return false;d("warn","server_process_cleanup",{processGroupId:e});try{process.kill(-e,"SIGTERM");}catch{}if(await m(()=>w(e).length===0,X))return true;if(!k(e,n))return false;try{process.kill(-e,"SIGKILL");}catch{}return m(()=>w(e).length===0,J)}async function O(e,n,t){return w(t).length===0||await Te(t,n)?we(e,n):false}async function ge(){let e=join(homedir(),".devflow");mkdirSync(e,{recursive:true});let n=te(join(e,"server-bootstrap.sqlite")),t,r,o=false;try{for(;;){let a=await ae(n);if(a.action==="skip")return;if(a.action==="cleanup"){if(!await O(n,a.token,a.processGroupId))throw new Error("claimed server process group cleanup did not complete");continue}t=a.token;break}if(await N("DEVFLOW_SERVER_BOOTSTRAP_TEST_INTENT_READY_FILE"),r=await pe(t),!r.pid)throw new Error("server launcher returned no PID");let p=r.pid,s=P();writeRuntimeEndpointState({url:s,port:Number(new URL(s).port||13337),pid:r.pid,processGroupId:p,ownerToken:t,status:"launching"});let i=await le(t,p);if(!i){let a=D(t,p);if(!a)throw new Error("npx process group ownership could not be validated");_e(n,t,a),r.unref(),d("warn","server_launch_warming",{wrapperPid:a.wrapperPid});return}await N("DEVFLOW_SERVER_BOOTSTRAP_TEST_AFTER_SPAWN_READY_FILE"),Ee(n,t,i),o=!0,writeRuntimeEndpointState({url:s,port:Number(new URL(s).port||13337),pid:i.serverPid,processGroupId:i.processGroupId,ownerToken:t,status:await U()?"healthy":"launching"}),r.unref(),d("info","server_launch_background",{wrapperPid:i.wrapperPid,serverPid:i.serverPid});}catch(p){if(t&&r?.pid&&!o){let s=false;try{s=me(n,t,process.pid);}catch(i){v(i);}s?(await O(n,t,r.pid)||d("warn","server_cleanup_incomplete",{processGroupId:r.pid}),readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped")):(d("warn","server_cleanup_claim_lost",{tokenHash:re(t)}),r.unref());}else if(t&&!r){try{fe(n,t);}catch(i){v(i);}readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped");}throw p}finally{try{n.close();}catch{}}}ge().catch(v).then(()=>{process.exitCode=0;},()=>{process.exitCode=0;});
109
+ `).run(n,process.pid);return e.exec("COMMIT"),t=!1,p(r)===1}finally{if(t)try{e.exec("ROLLBACK");}catch{}}}function m(e){return G().filter(n=>n.processGroupId===e)}function N(e,n){return m(e).some(t=>S(t.command)&&x(t.command,n))}async function Te(e,n){if(!N(e,n))return false;d("warn","server_process_cleanup",{processGroupId:e});try{process.kill(-e,"SIGTERM");}catch{}if(await f(()=>m(e).length===0,J))return true;if(!N(e,n))return false;try{process.kill(-e,"SIGKILL");}catch{}return f(()=>m(e).length===0,Z)}async function O(e,n,t){return m(t).length===0||await Te(t,n)?ge(e,n):false}async function ve(){let e=getDevFlowStateRoot();mkdirSync(e,{recursive:true});let n=ne(join(e,"server-bootstrap.sqlite")),t,r,o=false;try{for(;;){let a=await ce(n);if(a.action==="skip")return;if(a.action==="cleanup"){if(!await O(n,a.token,a.processGroupId))throw new Error("claimed server process group cleanup did not complete");continue}t=a.token;break}if(await k("DEVFLOW_SERVER_BOOTSTRAP_TEST_INTENT_READY_FILE"),r=await pe(t),!r.pid)throw new Error("server launcher returned no PID");let c=r.pid,s=D();writeRuntimeEndpointState({url:s,port:Number(new URL(s).port||13337),pid:r.pid,processGroupId:c,ownerToken:t,status:"launching"});let i=await _e(t,c);if(!i){let a=I(t,c);if(!a)throw new Error("npx process group ownership could not be validated");Ee(n,t,a),r.unref(),d("warn","server_launch_warming",{wrapperPid:a.wrapperPid});return}await k("DEVFLOW_SERVER_BOOTSTRAP_TEST_AFTER_SPAWN_READY_FILE"),fe(n,t,i),o=!0,writeRuntimeEndpointState({url:s,port:Number(new URL(s).port||13337),pid:i.serverPid,processGroupId:i.processGroupId,ownerToken:t,status:await U()?"healthy":"launching"}),r.unref(),d("info","server_launch_background",{wrapperPid:i.wrapperPid,serverPid:i.serverPid});}catch(c){if(t&&r?.pid&&!o){let s=false;try{s=we(n,t,process.pid);}catch(i){h(i);}s?(await O(n,t,r.pid)||d("warn","server_cleanup_incomplete",{processGroupId:r.pid}),readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped")):(d("warn","server_cleanup_claim_lost",{tokenHash:te(t)}),r.unref());}else if(t&&!r){try{me(n,t);}catch(i){h(i);}readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped");}throw c}finally{try{n.close();}catch{}}}ve().catch(h).then(()=>{process.exitCode=0;},()=>{process.exitCode=0;});