@devflow-tools/cli 0.17.0 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +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,rmSync as rmSync$1,renameSync as renameSync$1}from'node:fs';import {join,resolve,basename,relative,sep,dirname,isAbsolute}from'node:path';import {homedir}from'node:os';import {getLocalApiKey,resolveRuntimeEndpoint,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getProjectStateDir}from'@devflow-tools/sdk';import {fileURLToPath}from'url';import {createHash as createHash$1}from'node:crypto';import {randomUUID,createHash}from'crypto';function k(o,t,e){try{let n=openGlobalDevFlowDatabase();try{n.insertEvent({kind:o,timestamp:Date.now(),duration:e,success:t.success!==!1,metadata:t});}finally{n.close();}}catch{}}var Ve=getLocalApiKey(),M=join(homedir(),".devflow","errors");async function X(o,t,e={}){let n=e.endpoint??resolveRuntimeEndpoint().url,i=e.timeout??1500,r=e.durableMirror??true,s=e.maxRetries??(r?0:2),a=e.circuitBreaker??true,c=acquireRuntimeHttpCircuit(n,o);if(a&&!c.allowed)return {delivered:false,suppressed:true,fallbackReason:c.state.fallbackReason};let l;for(let u=0;u<=s;u+=1)try{return await Ke(n,o,t,i),a&&registerRuntimeHttpSuccess(n,o).transitioned&&k("http_circuit_transition",{endpoint:n,path:new URL(o,n).pathname,previous:c.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(p){l=p instanceof Error?p:new Error(String(p)),u<s&&await Ye(Math.min(100*2**u,1e3));}if(!l)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return K(o,l),{delivered:false,suppressed:false,fallbackReason:l.message};let d=registerRuntimeHttpFailure(n,o,e.fallbackReason??(r?"local_durable_mirror":"http_delivery_failed"));return d.transitioned&&(K(o,l),k("http_circuit_transition",{endpoint:n,path:new URL(o,n).pathname,previous:c.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 Ke(o,t,e,n){return new Promise((i,r)=>{let s=JSON.stringify(e),a=new URL(t,o),c=false,l=u=>{c||(c=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":Ve,"Content-Length":Buffer.byteLength(s)},timeout:n},u=>{u.on("error",l),u.on("end",()=>{let p=u.statusCode??0;l(p>=200&&p<300?void 0:new Error(`HTTP ${p}`));}),u.resume();});d.on("error",l),d.on("timeout",()=>d.destroy(new Error(`HTTP mirror timed out after ${n}ms`))),d.write(s),d.end();})}function K(o,t){try{existsSync$1(M)||mkdirSync$1(M,{recursive:!0}),appendFileSync(join(M,"http-errors.log"),`${new Date().toISOString()} | ${o} | ${t.message}
2
- `);}catch{}}function Ye(o){return new Promise(t=>setTimeout(t,o))}var ne=1e4,tt=3e4,S=500,O=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,n,i,r=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:t,sessionId:e,skillName:n,startedAt:i,projectRoot:r,requiredMcpTools:s};this.commitOrCache("execution_start",a)&&this.postHttp("/api/telemetry/skill-execution/start",a);}async sendExecutionComplete(t,e="completed",n=Date.now(),i){let r={executionId:t,status:e,finishedAt:n,metadata:i},s=this.commitOrCache("execution_complete",r);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",r),s}async sendSessionStart(t,e,n){let i={id:t,projectRoot:e,startedAt:n,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 n={sessionId:t,finishedAt:e},i=this.commitOrCache("session_end",n);return i&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(t)}/close`,{finishedAt:e})),i}async flushCache(){try{let n=this.getDatabase(),i=n.listTelemetryFailures({unresolvedOnly:!0,limit:S}).reverse();for(let r of i)try{this.applyOperation(r.operation,r.payload),n.resolveTelemetryFailure(r.id);}catch{}n.trimTelemetryFailures(S);}catch{}let e=[...new Set([this.cacheDir,this.legacyCacheDir].filter(n=>!!n))].filter(n=>existsSync(n)).flatMap(n=>readdirSync(n).filter(i=>i.endsWith(".json")).map(i=>{let r=join$1(n,i);try{return {cacheFile:r,envelope:nt(JSON.parse(readFileSync(r,"utf8")),i)}}catch{return null}})).filter(n=>n!==null).sort((n,i)=>n.envelope.timestamp-i.envelope.timestamp||oe(n.envelope.operation)-oe(i.envelope.operation));for(let{cacheFile:n,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(n);}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(n){return this.cacheOperation(t,e,n),false}}applyOperation(t,e){let n=this.getDatabase();switch(t){case "tool_call":this.ensureParentSession(n,e),n.insertToolCallEvent(e);return;case "execution_start":this.ensureParentSession(n,e),n.insertSkillExecution({executionId:e.executionId,sessionId:e.sessionId,skillName:e.skillName,startedAt:e.startedAt,status:"running",requiredMcpTools:e.requiredMcpTools});return;case "execution_complete":n.reconcileSkillExecution(e.executionId,e.status,e.finishedAt,e.metadata);return;case "session_start":n.ensureSession(e),n.insertRun({id:ie(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(!n.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":n.closeSession(e.sessionId,e.finishedAt),n.updateRun(ie(e.sessionId),{status:"completed",finishedAt:e.finishedAt});return}}ensureParentSession(t,e){let n=typeof e.sessionId=="string"?e.sessionId.trim():"";if(!n)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:n,projectRoot:i,label:i==="unknown"?void 0:i.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(t,e,n){let i=Date.now(),r={id:`failure:${i}:${Math.random().toString(36).slice(2,11)}`,operation:t,payload:e,failure:n instanceof Error?n.message:String(n),timestamp:i};try{let s=this.getDatabase();s.insertTelemetryFailure({id:r.id,operation:t,payload:e,error:r.failure,createdAt:i}),s.trimTelemetryFailures(S),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-S)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},tt).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){X(t,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(t){let e=JSON.stringify(t);return e===void 0||e.length<=ne?t:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,ne)}...`}}};function oe(o){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(o)}function ie(o){return `hook-run:${o}`}function nt(o,t){if(!o||typeof o!="object")throw new Error("Invalid telemetry cache envelope");let e=o;if(typeof e.operation=="string"&&e.payload!==void 0)return e;let n=e.type==="tool_call"?"tool_call":e.type==="execution_start"?"execution_start":null;if(!n)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:n,payload:i,failure:"Replayed legacy HTTP-first telemetry cache entry",timestamp:r}}function j(o){return o??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function g(o){return process.env.DEVFLOW_STATE_DIR??getProjectStateDir(j(o))}var ct=2,lt=1;function dt(){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 re(o=dt()){let t=[join$1(o,"dist","command-registry.json"),join$1(o,"command-registry.json")];for(let e of t)try{if(!existsSync(e))continue;let n=JSON.parse(readFileSync(e,"utf8"));if(n.version!==ct&&n.version!==lt||!ut(n.commands)){console.error(`[devflow] command registry contract mismatch: ${e}`);continue}return n.commands}catch(n){console.error(`[devflow] command registry load failed: ${n.message}`);}return null}function ut(o){return !o||typeof o!="object"||Array.isArray(o)?false:Object.values(o).every(t=>{if(!t||typeof t!="object"||Array.isArray(t))return false;let e=t;return $(e.mcpTools)&&$(e.blockedNative)&&(e.source===void 0||e.source==="core"||e.source==="plugin")&&(e.requiresContext===void 0||typeof e.requiresContext=="boolean")&&(e.runtimePackages===void 0||$(e.runtimePackages))&&(e.evidenceMode===void 0||["static","runtime","mixed"].includes(e.evidenceMode))})}function $(o){return Array.isArray(o)&&o.every(t=>typeof t=="string"&&t.length>0)}function se(o){let t=re();return t?t[o]?.mcpTools??[]:[]}function E(o){if(!o||typeof o!="object"||Array.isArray(o))return {};let t=o,e={};for(let n of ["lastMcpCall","bypassCount"])if(n in t){let i=t[n];if(i==null)continue;e[n]=typeof i=="number"&&Number.isFinite(i)&&i>=0?i:0;}return e}function gt(o,t){return o.lastMcpCall===t.lastMcpCall&&o.bypassCount===t.bypassCount}function ft(o){try{return existsSync(o)?E(JSON.parse(readFileSync(o,"utf-8"))):{}}catch{return {}}}function le(o,t){let e=t instanceof Error?t.message:String(t);console.error(`[devflow] Receipt ${o} skipped: ${e}`);}function ae(o){let t=g(o);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 de(o,t){if(o.getHookReceipt(t)){ae(t);return}let e=join$1(g(t),"receipt.json");if(!existsSync(e))return;let n=ft(e);o.updateHookReceipt(t,()=>n),ae(t);}function ue(o,t,e){let n;try{n=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),de(n,o);let i={},r=n.updateHookReceipt(o,a=>(i=E(a),E(t(i)))),s=E(r);return {receipt:s,applied:!0,changed:!gt(i,s)}}catch(i){return le(e,i),{receipt:{},applied:false,changed:false}}finally{try{n?.close();}catch{}}}function pe(o){let t;try{return t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),de(t,o),E(t.getHookReceipt(o))}catch(e){return le("update",e),{}}finally{try{t?.close();}catch{}}}function ht(o,t){return ue(o,()=>t,"write").applied}function yt(o,t){return ue(o,t,"update")}var ce={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"},vt=new Set(["Write","Edit","NotebookEdit"]),bt=new Set(["failed","timeout","unavailable"]);function _t(o){switch(o){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}var C=class{constructor(t,e,n){this.projectRoot=t;this.sessionId=e;this.executionId=n;}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 n=this.getPhase();if(e||t==="Skill")return {permissionDecision:"allow"};if(n==="context_gathering"&&ce[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_REQUIRED",reason:`DevFlow context required. Call mcp__devflow__get_project_context, then retry ${t}.`};if(n==="context_ready"){if(vt.has(t)){let c=this.evaluateRequiredAction();if(c)return c}return {permissionDecision:"allow"}}let i=ce[t];if(!i)return {permissionDecision:"allow"};let r=yt(this.projectRoot,c=>({...c,bypassCount:(c.bypassCount??0)+1}));if(!r.applied)return {permissionDecision:"allow"};let s=r.receipt.bypassCount??0,a=_t(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(){ht(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}recordDomainActionOutcome(t,e,n,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(),c=i?.trim()?`${i.trim()}:${e}`:`${t}:${e}:${a}`,l=s.actionAttempts??[];return r.upsertContextReceipt({...s,actionAttempts:l.some(d=>d.id===c||i&&d.toolUseId===i&&d.status===e)?l:[...l,{id:c,tool:t,status:e,attemptedAt:a,toolUseId:i,reason:n?.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 n=e.binding;if(n.requiredContextReceipt!==t.contextHash||n.projectRoot!==this.projectRoot||n.sessionId!==this.sessionId||n.requestId!==t.requestId||n.executionId&&n.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&&bt.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 n;try{n=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let i=n.getContextReceipt(t.projectRoot,t.sessionId,t.executionId);if(!i||i.contextHash!==t.contextHash||i.actionDegradation)return;n.upsertContextReceipt({...i,actionDegradation:e});let r=n.getSkillExecution(t.executionId);if(!r)return;let s=r.metadata&&typeof r.metadata=="object"?r.metadata:{},a=Array.isArray(s.requiredActionDegradations)?s.requiredActionDegradations:[];n.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{n?.close();}catch{}}}};var Ot=10*1024*1024,Ct=5;function At(o){return createHash$1("sha256").update(o).digest("hex").slice(0,16)}function fe(o){return join(homedir(),".devflow","logs","hook-debug",`${At(o)}.jsonl`)}function he(o,t,e={}){let n=e.maxBytes??Ot,i=e.maxFiles??Ct;mkdirSync$1(dirname(o),{recursive:true,mode:448});let r=Buffer.byteLength(t),s=existsSync$1(o)?statSync(o).size:0;s>0&&s+r>n&&Tt(o,i),appendFileSync(o,t,{mode:384}),chmodSync(o,384);}function Tt(o,t){if(t<=1){rmSync$1(o,{force:true});return}rmSync$1(`${o}.${t-1}`,{force:true});for(let e=t-2;e>=1;e-=1){let n=`${o}.${e}`;existsSync$1(n)&&renameSync$1(n,`${o}.${e+1}`);}existsSync$1(o)&&renameSync$1(o,`${o}.1`);}var q="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 Re(o){return Buffer.from(o,"utf8").toString("base64url")}function $t(o,t,e){let n=t?.trim();if(n){let i=/^[a-zA-Z0-9:._-]{1,192}$/.test(n)?n:`tool-${createHash("sha256").update(n.slice(0,1024)).digest("hex").slice(0,32)}`;return `${o}:${i}`}return `${o}:legacy-${e}-${randomUUID().slice(0,8)}`}function ke(o){return `${o}:legacy-journal`}var T=class{constructor(t){this.projectRoot=t;this.sessions=new Map;this.sessionsDir=join$1(g(t),"hook-sessions");}registerSession(t){let e=t.trim();if(!e)throw new Error("session_id_required");let n=this.get(e);if(n)return n.lastActivityAt=Date.now(),this.persist(n),n;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,n){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(n)],i.lastActivityAt=Date.now(),this.persist(i),i}get(t){let e=t.trim();if(!e)return null;let n=this.sessions.get(e);if(n)return this.replayEvidenceJournal(n),n;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=Ee(r.evidenceObligations),r.evidenceDegradations=De(r.evidenceDegradations),r.evidenceOutcomes=we(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 n=structuredClone(e);return delete e.executionId,delete e.skillName,e.requiredMcpTools=[],e.lastActivityAt=Date.now(),this.persist(e),n}addEvidenceObligation(t,e,n=Date.now(),i){let r=this.registerSession(t),a=(i?void 0:r.evidenceObligations.find(l=>l.contractId===e.id))?.obligationId??$t(e.id,i,n);this.appendEvidenceEvent(t,{kind:"add",obligationId:a,contractId:e.id,at:n,contract:e},`add\0${a}`),this.replayEvidenceJournal(r);let c=r.evidenceObligations.find(l=>l.obligationId===a);return c?(r.lastActivityAt=Date.now(),this.persist(r),structuredClone(c)):null}listEvidenceObligations(t){return (this.get(t)?.evidenceObligations??[]).map(e=>structuredClone(e))}markEvidenceCorrection(t,e,n,i,r=Date.now()){let s=this.get(t),a=s?.evidenceObligations.find(d=>d.obligationId===e);if(!s||!a)return null;let c=/^[a-f0-9]{64}$/.test(i)?i:"";if(!c)return null;this.appendEvidenceEvent(t,{kind:"correction",obligationId:e,contractId:a.contractId,at:r,fingerprint:c,violations:n.slice(0,16).map(d=>d.slice(0,240))},`correction\0${e}\0${c}`),this.replayEvidenceJournal(s),s.lastActivityAt=r,this.persist(s);let l=s.evidenceObligations.find(d=>d.obligationId===e);return l?structuredClone(l):null}resolveEvidenceObligation(t,e){let n=this.get(t);if(!n)return false;let i=n.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(n),n.lastActivityAt=r,this.persist(n),true}degradeEvidenceObligation(t,e,n,i=Date.now()){let r=this.get(t),s=r?.evidenceObligations.find(c=>c.obligationId===e);if(!r||!s)return false;let a=n.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,`${Re(t)}.json`)}evidenceJournalDir(t){return join$1(this.sessionsDir,"evidence-journal",Re(t))}appendEvidenceEvent(t,e,n){let i=this.evidenceJournalDir(t);mkdirSync(i,{recursive:true,mode:448});let r=createHash("sha256").update(n).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(c){if(c.code!=="EEXIST")throw c}finally{rmSync(a,{force:true});}}replayEvidenceJournal(t){t.evidenceObligations=Ee(t.evidenceObligations),t.evidenceDegradations=De(t.evidenceDegradations),t.evidenceOutcomes=we(t.evidenceOutcomes);let e=this.evidenceJournalDir(t.sessionId);if(!existsSync(e))return;let n;try{n=readdirSync(e).filter(r=>/^(?:add|correction|resolve|degrade)-[a-f0-9]{64}\.json$/.test(r)).slice(0,4096);}catch{return}let i=n.flatMap(r=>{try{let s=readFileSync(join$1(e,r),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let a=Nt(JSON.parse(s));return a?[a]:[]}catch{return []}}).sort((r,s)=>r.at-s.at||Ie(r.kind)-Ie(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 n=t.evidenceOutcomes.find(s=>s.obligationId===e.obligationId);if(e.kind==="add"){if(n)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||n||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??0;t.evidenceObligations=t.evidenceObligations.filter(s=>s.obligationId!==e.obligationId),!n&&(e.kind==="degrade"&&t.evidenceDegradations.push({obligationId:e.obligationId,contractId:e.contractId,reason:e.reason,degradedAt:e.at,attempt:r}),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),n=`${e}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(n,JSON.stringify(t),{mode:384}),renameSync(n,e);}};function Ee(o){return Array.isArray(o)?o.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)||!Se(e.contract))return [];let n=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:ke(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:n,correctionFingerprint:r}]}).slice(-8):[]}function De(o){return Array.isArray(o)?o.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 we(o){return Array.isArray(o)?o.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 Nt(o){if(!o||typeof o!="object")return null;let t=o,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:ke(t.contractId),contractId:t.contractId,at:t.at};if(e==="add")return Se(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 Ie(o){return o==="add"?0:o==="correction"?1:2}function Se(o){if(!o||typeof o!="object")return false;let t=o,e=t.requiredSections,n=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(n)&&n.length<=16&&n.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 Oe(o){let t=o.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(o,t){return t?`evt_tool_${createHash("sha256").update(`${o}\0${t}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var qt=new Set(["Write","Edit","NotebookEdit"]),Ae="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 $e(o){if(!qt.has(o.toolName))return null;let t=Ut(o.toolInput);if(!t)return null;let e=Wt(t,o.projectRoot),n=resolve(o.projectRoot,".claude");if(Te(e,n)&&basename(e).toLocaleUpperCase("en-US")==="MEMORY.MD")return Ae;let i=resolve(o.home??homedir(),".claude","projects");return Te(e,i)&&relative(i,e).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?Ae:null}function Ut(o){for(let t of ["file_path","notebook_path","path"]){let e=o[t];if(typeof e=="string"&&e.trim())return e.trim()}return null}function Wt(o,t){return resolve(isAbsolute(o)?o:resolve(t,o))}function Te(o,t){let e=relative(t,o);return e===""||!e.startsWith(`..${sep}`)&&e!==".."&&!isAbsolute(e)}function D(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function Ne(o){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:o}}}function Vt(o){let t=g(o);return existsSync(t)||mkdirSync(t,{recursive:true}),t}function Kt(o,t,e,n,i,r){let s=join$1(Vt(o),"event-map.json"),a=[];try{existsSync(s)&&(a=JSON.parse(readFileSync(s,"utf-8")));}catch{}a.push({sessionId:t,toolName:e,toolUseId:n,eventId:i,timestamp:r}),writeFileSync(s,JSON.stringify(a));}function Yt(o){switch(o){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 Xt(o){let t=ye();try{if(!o||o.trim()==="")return D();let e=JSON.parse(o),n=Date.now(),i=j(),r=new O;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 Ne(q);let a=new T(i),c=a.get(s)!==null;if(a.registerSession(s),c||await r.sendSessionStart(s,i,Date.now()),e.tool_name==="Skill"){let x=e.tool_input?.skill,h=x?Oe(x):null;if(h){let He=a.get(s)?.executionId,R=a.startExecution(s,h,se(h));R.executionId&&R.executionId!==He&&await r.sendExecutionStart(R.executionId,s,h,R.lastActivityAt,i,R.requiredMcpTools);}}let l=a.get(s);e.tool_name.startsWith("mcp__devflow__")&&(e.tool_input._devflow_session_id=s,e.tool_input._devflow_execution_id=l?.executionId??s,l?.skillName&&(e.tool_input._devflow_active_skill=l.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 C(i,s,l?.executionId),J=p.getPhase(),m,w=$e({toolName:e.tool_name,toolInput:e.tool_input,projectRoot:i}),f=w?{permissionDecision:"deny",reason:w}:p.evaluate(e.tool_name,d);f.permissionDecision==="deny"?m={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:f.reason??"MCP context required"}}:f.additionalContext?m=Ne(f.additionalContext):m=D(),e.tool_name.startsWith("mcp__devflow__")&&(m.hookSpecificOutput.updatedInput=e.tool_input),t&&m.hookSpecificOutput.permissionDecision==="allow"&&(m.hookSpecificOutput.additionalContext=q);let Le=l?.executionId??s,_={eventId:Ce(s,e.tool_use_id),executionId:Le,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&&J==="context_gathering",mcpFallback:!d&&J==="context_gathering",kind:Yt(e.tool_name),input:e.tool_input,duration:0,blocked:m.hookSpecificOutput.permissionDecision==="deny",blockReason:m.hookSpecificOutput.permissionDecision==="deny"?w?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":f.reasonCode??"DEVFLOW_CONTEXT_REQUIRED":void 0},I=await r.sendEvent(_);I&&!_.blocked&&Kt(i,s,e.tool_name,e.tool_use_id,I,_.timestamp),I&&_.blocked&&await r.completeEvent({eventId:I,sessionId:s,error:w?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":f.reasonCode??"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-_.timestamp,completedAt:Date.now()});try{let x=pe(i),h={ts:n,tool:e.tool_name,sessionId:s,skill:l?.skillName??"(none)",requiredTools:l?.requiredMcpTools??[],isMcp:d,enforce:l?.executionId!==void 0,stateless:l?.executionId===void 0&&!d&&e.tool_name!=="Skill",bypassCount:x.bypassCount??0,decision:m.hookSpecificOutput.permissionDecision,env_CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd()};he(fe(i),`${JSON.stringify(h)}
3
- `);}catch{}return m}catch{return D()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let o=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 Xt(t);o(JSON.stringify(e));}),process.stdin.on("error",()=>{o(JSON.stringify(D())),process.exit(0);}),setTimeout(()=>{o(JSON.stringify(D())),process.exit(0);},4e3).unref();}export{Xt 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 {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,6 +1,6 @@
1
- import {spawn,execFileSync}from'node:child_process';import {randomUUID}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';var{DatabaseSync:B}=createRequire(import.meta.url)("node:sqlite"),V=75,Q=400,z=2e3,$=300*1e3,q=1e3,K=1e3,j=15e3,Y=["--yes","@devflow-tools/server","--devflow-instance-token"];function g(e){let n=e instanceof Error?e.message:String(e);console.error(`[devflow] Server bootstrap skipped: ${n}`);}function X(e){let n=new B(e);n.exec(`PRAGMA busy_timeout = ${V}`);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 {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(`
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"),I(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"),A(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}from'node
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||I(n);return n}function I(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||A(n);return n}function A(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}from'node
21
21
  created_at INTEGER NOT NULL,
22
22
  updated_at INTEGER NOT NULL
23
23
  )
24
- `);}function J(e){return e.prepare(`
24
+ `);}function ne(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}from'node
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 Z(e){if(!Number.isSafeInteger(e)||e<=1)return false;try{return process.kill(e,0),!0}catch{return false}}function M(){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]),a=Number(r[2]);!Number.isSafeInteger(o)||!Number.isSafeInteger(a)||n.push({pid:o,processGroupId:a,command:r[3]});}return n}function ee(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function G(e,n){let t=ee(n);return new RegExp(`(?:^|\\s)--devflow-instance-token(?:=|\\s+)${t}(?:\\s|$)`).test(e)}function v(e){return /(?:@devflow-tools\/server|devflow-server|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js)/.test(e)}function P(e){return /(?:^|\s)(?:\S*[\\/])?devflow-server(?:-child)?(?:\s|$)|[\\/]apps[\\/]server[\\/]dist[\\/]main\.js|[\\/]@devflow-tools[\\/]server[\\/]dist[\\/]main\.js/.test(e)}function re(e){let n=M().filter(r=>v(r.command)&&G(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 S(e,n){return re(e).find(t=>n===void 0||t.processGroupId===n)}function f(e,n){let t=h(e,n);if(!t)return;let r=t.processes.find(o=>o.pid!==t.wrapperPid&&P(o.command))??t.processes.find(o=>o.pid===t.wrapperPid&&P(o.command));if(r)return {wrapperPid:t.wrapperPid,processGroupId:t.processGroupId,serverPid:r.pid,processes:t.processes}}function h(e,n){let t=S(e,n);if(!t)return;let r=t.processes.find(o=>o.pid===t.processGroupId&&v(o.command));if(r)return {wrapperPid:r.pid,processGroupId:r.processGroupId,processes:t.processes}}function T(e){if(!Z(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 y(){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",R()).toString(),o=request(r,{method:"GET",timeout:Q},a=>{a.resume(),t((a.statusCode??500)>=200&&(a.statusCode??500)<300);});o.on("timeout",()=>o.destroy(new Error("health timeout"))),o.on("error",()=>t(!1)),o.end();}catch{t(false);}})}async function te(e){let n=false;try{e.exec("BEGIN IMMEDIATE"),n=!0;let t=await y(),r=J(e);if(t){if(r?.state==="running"||r?.state==="launching"){let s=f(r.token,r.processGroupId??void 0);if(s){e.prepare(`
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(`
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=R();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=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(`
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(T(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=r.processGroupId??void 0,i=f(r.token,s);if(i){let d=e.prepare(`
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(`
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(d)!==1)throw new Error("launch intent changed before adoption");return e.exec("COMMIT"),n=!1,console.error(`[devflow] Adopted server process group ${i.processGroupId}`),{action:"skip"}}let p=h(r.token,s);if(p&&Date.now()-r.createdAt<$)return e.exec("COMMIT"),n=!1,{action:"skip"};if(p){let d=e.prepare(`
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(`
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,p.processGroupId,Date.now(),r.token,r.ownerPid);if(c(d)!==1)throw new Error("launch intent changed before cleanup claim");return e.exec("COMMIT"),n=!1,{action:"cleanup",token:r.token,processGroupId:p.processGroupId}}e.prepare(`
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(`
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(T(r.ownerPid))return e.exec("COMMIT"),n=!1,{action:"skip"};let s=S(r.token);if(s){let i=e.prepare(`
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(`
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
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(`
62
62
  DELETE FROM server_bootstrap_state
63
63
  WHERE id = 1 AND token = ? AND state = 'terminating' AND owner_pid = ?
64
- `).run(r.token,r.ownerPid);}else if(r?.state==="running"){let s=f(r.token);if(s)return e.prepare(`
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=S(r.token);if(i&&!T(r.ownerPid)){let p=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&&!h(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(p)!==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(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(`
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(),a=Date.now();return e.prepare(`
75
+ `).run(r.token,r.ownerPid);}let o=randomUUID(),p=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}from'node
86
86
  server_pid = NULL,
87
87
  created_at = excluded.created_at,
88
88
  updated_at = excluded.updated_at
89
- `).run(o,process.pid,a,a),e.exec("COMMIT"),n=!1,{action:"launch",token:o}}finally{if(n)try{e.exec("ROLLBACK");}catch{}}}function ne(e){return new Promise((n,t)=>{let r;try{let o=oe(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 oe(e){if(!se()){let n=createRequire(import.meta.url),r=[process.env.DEVFLOW_SERVER_ENTRY,ie(()=>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:[...Y,e]}}function se(){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 ie(e){try{return e()}catch{return}}function R(){let e=resolveRuntimeEndpoint();return e.source==="environment"?e.url:readRuntimeEndpointState()?.url??e.url}async function _(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 A(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 _(()=>existsSync(t),j))throw new Error(`test checkpoint timed out: ${e}`)}async function pe(e,n){let t;return await _(()=>{let o=f(e,n);return o?(t=o,true):false},z)?t:void 0}function ae(e,n,t){let r=false;try{e.exec("BEGIN IMMEDIATE"),r=!0;let o=e.prepare(`
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(`
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 ce(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(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(`
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 de(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(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(`
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 ue(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 me(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 le(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,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(`
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 m(e){return M().filter(n=>n.processGroupId===e)}function N(e,n){return m(e).some(t=>v(t.command)&&G(t.command,n))}async function fe(e,n){if(!N(e,n))return false;console.error(`[devflow] Terminating untracked server process group ${e}`);try{process.kill(-e,"SIGTERM");}catch{}if(await _(()=>m(e).length===0,q))return true;if(!N(e,n))return false;try{process.kill(-e,"SIGKILL");}catch{}return _(()=>m(e).length===0,K)}async function L(e,n,t){return m(t).length===0||await fe(t,n)?le(e,n):false}async function Ee(){let e=join(homedir(),".devflow");mkdirSync(e,{recursive:true});let n=X(join(e,"server-bootstrap.sqlite")),t,r,o=false;try{for(;;){let p=await te(n);if(p.action==="skip")return;if(p.action==="cleanup"){if(!await L(n,p.token,p.processGroupId))throw new Error("claimed server process group cleanup did not complete");continue}t=p.token;break}if(await A("DEVFLOW_SERVER_BOOTSTRAP_TEST_INTENT_READY_FILE"),r=await ne(t),!r.pid)throw new Error("server launcher returned no PID");let a=r.pid,s=R();writeRuntimeEndpointState({url:s,port:Number(new URL(s).port||13337),pid:r.pid,processGroupId:a,ownerToken:t,status:"launching"});let i=await pe(t,a);if(!i){let p=h(t,a);if(!p)throw new Error("npx process group ownership could not be validated");ae(n,t,p),r.unref(),console.error(`[devflow] Server package launch still warming (PID ${p.wrapperPid})`);return}await A("DEVFLOW_SERVER_BOOTSTRAP_TEST_AFTER_SPAWN_READY_FILE"),ce(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 y()?"healthy":"launching"}),r.unref(),console.error(`[devflow] Server starting in background (PID ${i.wrapperPid})`);}catch(a){if(t&&r?.pid&&!o){let s=false;try{s=ue(n,t,process.pid);}catch(i){g(i);}s?(await L(n,t,r.pid)||console.error(`[devflow] Server process group ${r.pid} cleanup did not complete`),readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped")):(console.error(`[devflow] Server cleanup claim lost for token ${t}`),r.unref());}else if(t&&!r){try{de(n,t);}catch(i){g(i);}readRuntimeEndpointState()?.ownerToken===t&&updateRuntimeEndpointStatus("stopped");}throw a}finally{try{n.close();}catch{}}}Ee().catch(g).then(()=>{process.exitCode=0;},()=>{process.exitCode=0;});
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;});