@devflow-tools/cli 0.18.33 → 0.18.34

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,4 +1,4 @@
1
- import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync,rmSync,linkSync,renameSync}from'fs';import {join as join$1,dirname as dirname$1}from'path';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {getLocalApiKey,getDevFlowStateRoot,projectClaudeToolName,resolveClaudeToolName,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getProjectStateDir,readRuntimeState}from'@devflow-tools/sdk';import {request}from'node:http';import {existsSync as existsSync$1,mkdirSync as mkdirSync$1,appendFileSync,chmodSync,readFileSync as readFileSync$1,writeFileSync as writeFileSync$1,renameSync as renameSync$1}from'node:fs';import {join,resolve,basename,relative,sep,dirname,isAbsolute,normalize}from'node:path';import {maybeRunDiagnosticLogCleanup,rotateDiagnosticLogFile,emitSemanticControlLog}from'@devflow-tools/telemetry';import {fileURLToPath}from'url';import {randomUUID,createHash}from'crypto';import {createHash as createHash$1}from'node:crypto';import {homedir}from'node:os';import {DatabaseSync}from'node:sqlite';function L(i,t,e){try{let n=openGlobalDevFlowDatabase();try{n.insertEvent({kind:i,timestamp:Date.now(),duration:e,success:t.success!==!1,metadata:t});}finally{n.close();}}catch{}}var rt=getLocalApiKey(),J=join(getDevFlowStateRoot(),"errors");async function ie(i,t,e={}){let n=e.endpoint??process.env.DEVFLOW_SERVER_URL?.trim()??st();if(!n)return {delivered:false,suppressed:false,fallbackReason:"runtime_not_ready"};let o=e.timeout??1500,r=e.durableMirror??true,s=e.maxRetries??(r?0:2),a=e.circuitBreaker??true,c=acquireRuntimeHttpCircuit(n,i);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 at(n,i,t,o),a&&registerRuntimeHttpSuccess(n,i).transitioned&&L("http_circuit_transition",{endpoint:n,path:new URL(i,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 ct(Math.min(100*2**u,1e3));}if(!l)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!a)return te(i,l),{delivered:false,suppressed:false,fallbackReason:l.message};let d=registerRuntimeHttpFailure(n,i,e.fallbackReason??(r?"local_durable_mirror":"http_delivery_failed"));return d.transitioned&&(te(i,l),L("http_circuit_transition",{endpoint:n,path:new URL(i,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 st(){let i=readRuntimeState();return i?.status==="ready"&&i.dashboardAvailable?i.url:void 0}function at(i,t,e,n){return new Promise((o,r)=>{let s=JSON.stringify(e),a=new URL(t,i),c=false,l=u=>{c||(c=true,u?r(u):o());},d=request({hostname:a.hostname,port:a.port,path:a.pathname+a.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":rt,"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 te(i,t){try{existsSync$1(J)||mkdirSync$1(J,{recursive:!0});let e=join(J,"http-errors.log"),n=`${new Date().toISOString()} | ${i} | ${t.message}
2
- `;rotateDiagnosticLogFile({path:e,maxBytes:50*1024*1024,maxFiles:5,incomingBytes:Buffer.byteLength(n)}),appendFileSync(e,n);}catch{}}function ct(i){return new Promise(t=>setTimeout(t,i))}var ae=1e4,ft=3e4,P=500,N=class{constructor(t){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=t?.apiUrl,this.cacheDir=t?.cacheDir??join$1(getDevFlowStateRoot(),"global","telemetry-cache"),this.database=t?.database??null,this.ownsDatabase=!t?.database;let e=t?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(t){let e={...t,input:this.truncateInput(t.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),t.eventId):null}async sendExecutionStart(t,e,n,o,r=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let a={executionId:t,sessionId:e,skillName:n,startedAt:o,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(),o){let r={executionId:t,status:e,finishedAt:n,metadata:o},s=this.commitOrCache("execution_complete",r);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",r),s}async sendSessionStart(t,e,n){let o={id:t,projectRoot:e,startedAt:n,label:e.split("/").pop()??"unknown"},r=this.commitOrCache("session_start",o);return r&&this.postHttp("/api/telemetry/sessions",o),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},o=this.commitOrCache("session_end",n);return o&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(t)}/close`,{finishedAt:e})),o}async flushCache(){try{let e=this.getDatabase(),n=e.listTelemetryFailures({unresolvedOnly:!0,limit:P}).reverse();for(let o of n)try{this.applyOperation(o.operation,o.payload),e.resolveTelemetryFailure(o.id);}catch{}e.trimTelemetryFailures(P);}catch{}let t=(existsSync(this.cacheDir)?readdirSync(this.cacheDir):[]).filter(e=>e.endsWith(".json")).map(e=>{let n=join$1(this.cacheDir,e);try{return {cacheFile:n,envelope:mt(JSON.parse(readFileSync(n,"utf8")))}}catch{return null}}).filter(e=>e!==null).sort((e,n)=>e.envelope.timestamp-n.envelope.timestamp||ce(e.envelope.operation)-ce(n.envelope.operation));for(let{cacheFile:e,envelope:n}of t)try{let o=this.getDatabase();o.insertTelemetryFailure({id:n.id,operation:n.operation,payload:n.payload,error:n.failure,createdAt:n.timestamp}),this.applyOperation(n.operation,n.payload),o.resolveTelemetryFailure(n.id),unlinkSync(e);}catch{}this.database?.aggregatePendingToolMetrics();}aggregateMetrics(){return this.getDatabase().aggregatePendingToolMetrics()}async flushAndAggregate(){await this.flushCache(),this.aggregateMetrics();}close(){this.ownsDatabase&&this.database?.close(),this.database=null;}getDatabase(){return this.database??=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:this.busyTimeoutMs}),this.database}commitOrCache(t,e){try{return this.applyOperation(t,e),!0}catch(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:le(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(le(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 o=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";t.ensureSession({id:n,projectRoot:o,label:o==="unknown"?void 0:o.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(t,e,n){let o=Date.now(),r={id:`failure:${o}:${Math.random().toString(36).slice(2,11)}`,operation:t,payload:e,failure:n instanceof Error?n.message:String(n),timestamp:o};try{let s=this.getDatabase();s.insertTelemetryFailure({id:r.id,operation:t,payload:e,error:r.failure,createdAt:o}),s.trimTelemetryFailures(P),this.scheduleRetry();return}catch{}try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let s=join$1(this.cacheDir,`${o}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(s,JSON.stringify(r,null,2),{mode:384}),this.trimRetryCache(),this.scheduleRetry();}catch{}}trimRetryCache(){try{let t=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of t.slice(0,Math.max(0,t.length-P)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},ft).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){ie(t,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(t){let e=JSON.stringify(t);return e===void 0||e.length<=ae?t:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,ae)}...`}}};function ce(i){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(i)}function le(i){return `hook-run:${i}`}function mt(i){if(!i||typeof i!="object")throw new Error("Invalid telemetry cache envelope");let t=i;if(typeof t.id!="string"||typeof t.operation!="string"||t.payload===void 0||typeof t.failure!="string"||typeof t.timestamp!="number")throw new Error("Invalid telemetry cache envelope");return t}function C(i){return i??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function R(i){return getProjectStateDir(C(i))}var E=emitSemanticControlLog;var Et=2,It=1;function wt(){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 de(i=wt()){let t=[join$1(i,"dist","command-registry.json"),join$1(i,"command-registry.json")];for(let e of t)try{if(!existsSync(e))continue;let n=JSON.parse(readFileSync(e,"utf8"));if(n.version!==Et&&n.version!==It||!xt(n.commands)){E({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 n.commands}catch(n){E({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:n.message,fallback:"next_registry_candidate"}});}return null}function xt(i){return !i||typeof i!="object"||Array.isArray(i)?false:Object.values(i).every(t=>{if(!t||typeof t!="object"||Array.isArray(t))return false;let e=t;return M(e.mcpTools)&&M(e.blockedNative)&&(e.source===void 0||e.source==="core"||e.source==="plugin")&&(e.requiresContext===void 0||typeof e.requiresContext=="boolean")&&(e.runtimePackages===void 0||M(e.runtimePackages))&&(e.hostTools===void 0||Dt(e.hostTools))&&(e.evidenceMode===void 0||["static","runtime","mixed"].includes(e.evidenceMode))})}function Dt(i){return !!i&&typeof i=="object"&&!Array.isArray(i)&&Object.entries(i).every(([t,e])=>t.length>0&&M(e))}function M(i){return Array.isArray(i)&&i.every(t=>typeof t=="string"&&t.length>0)}function ue(i){let t=de();return t?t[i]?.mcpTools??[]:[]}function me(i){return Buffer.from(i,"utf8").toString("base64url")}function At(i,t,e){let n=t?.trim();if(n){let o=/^[a-zA-Z0-9:._-]{1,192}$/.test(n)?n:`tool-${createHash("sha256").update(n.slice(0,1024)).digest("hex").slice(0,32)}`;return `${i}:${o}`}return `${i}:legacy-${e}-${randomUUID().slice(0,8)}`}function Re(i){return `${i}:legacy-journal`}var x=class{constructor(t){this.projectRoot=t;this.sessions=new Map;this.sessionsDir=join$1(R(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 o=Date.now(),r={sessionId:e,projectRoot:this.projectRoot,requiredMcpTools:[],evidenceObligations:[],evidenceDegradations:[],evidenceOutcomes:[],startedAt:o,lastActivityAt:o};return this.sessions.set(e,r),this.persist(r),r}startExecution(t,e,n){let o=this.registerSession(t);return (!o.executionId||o.skillName!==e)&&(o.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),o.skillName=e,o.requiredMcpTools=[...new Set(n)],delete o.contextInitialization,o.lastActivityAt=Date.now(),this.persist(o),o}beginContextInitialization(t,e){let n=this.registerSession(t);return n.contextInitialization={startedAt:Date.now(),...e?{toolUseId:e}:{}},n.lastActivityAt=Date.now(),this.persist(n),n}completeContextInitialization(t,e){let n=this.get(t);return n?(e&&n.contextInitialization?.toolUseId&&n.contextInitialization.toolUseId!==e||(delete n.contextInitialization,n.lastActivityAt=Date.now(),this.persist(n)),n):null}bindTaskIdentity(t,e){let n=this.registerSession(t);return n.activeTurnId=e.turnId,n.activeRequestId=e.requestId,n.intentArtifactHash=e.intentArtifactHash,n.lastActivityAt=Date.now(),this.persist(n),n}get(t){let e=t.trim();if(!e)return null;let n=this.sessions.get(e);if(n)return this.replayEvidenceJournal(n),n;let o=this.snapshotPath(e);if(!existsSync(o))return null;try{let r=JSON.parse(readFileSync(o,"utf8"));return r.sessionId!==e||r.projectRoot!==this.projectRoot?null:(r.requiredMcpTools=Array.isArray(r.requiredMcpTools)?r.requiredMcpTools:[],r.evidenceObligations=he(r.evidenceObligations),r.evidenceDegradations=ye(r.evidenceDegradations),r.evidenceOutcomes=ve(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,delete e.contextInitialization,e.requiredMcpTools=[],e.lastActivityAt=Date.now(),this.persist(e),n}addEvidenceObligation(t,e,n=Date.now(),o){let r=this.registerSession(t),a=(o?void 0:r.evidenceObligations.find(l=>l.contractId===e.id))?.obligationId??At(e.id,o,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,o,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(o)?o:"";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 o=n.evidenceObligations.find(s=>s.obligationId===e);if(!o)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:o.contractId,at:r},`resolve\0${e}`),this.replayEvidenceJournal(n),n.lastActivityAt=r,this.persist(n),true}resolveDegradedEvidence(t,e){let n=this.get(t),o=n?.evidenceDegradations.find(s=>s.obligationId===e);if(!n||!o)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:o.contractId,at:r},`resolve-degraded\0${e}\0${r}`),this.replayEvidenceJournal(n),n.lastActivityAt=r,this.persist(n),true}degradeEvidenceObligation(t,e,n,o=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:o,reason:a},`degrade\0${e}\0${a}`),this.replayEvidenceJournal(r),r.lastActivityAt=o,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,`${me(t)}.json`)}evidenceJournalDir(t){return join$1(this.sessionsDir,"evidence-journal",me(t))}appendEvidenceEvent(t,e,n){let o=this.evidenceJournalDir(t);mkdirSync(o,{recursive:true,mode:448});let r=createHash("sha256").update(n).digest("hex"),s=join$1(o,`${e.kind}-${r}.json`);if(existsSync(s))return;let a=join$1(o,`.${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=he(t.evidenceObligations),t.evidenceDegradations=ye(t.evidenceDegradations),t.evidenceOutcomes=ve(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 o=n.flatMap(r=>{try{let s=readFileSync(join$1(e,r),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let a=Ct(JSON.parse(s));return a?[a]:[]}catch{return []}}).sort((r,s)=>r.at-s.at||be(r.kind)-be(s.kind));for(let r of o)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 o=t.evidenceObligations.find(s=>s.obligationId===e.obligationId);if(e.kind==="correction"){if(!o||n||o.correctionFingerprint===e.fingerprint)return;o.attempt+=1,o.correctionRequested=true,o.correctionRequestedAt=e.at,o.correctionFingerprint=e.fingerprint,o.violations=e.violations;return}let r=o?.attempt??n?.attempt??0;if(e.kind==="resolve"&&n?.status==="degraded")t.evidenceOutcomes=t.evidenceOutcomes.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations=t.evidenceDegradations.filter(s=>s.obligationId!==e.obligationId);else if(n)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:o?.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),n=`${e}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(n,JSON.stringify(t),{mode:384}),renameSync(n,e);}};function he(i){return Array.isArray(i)?i.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)||!Ee(e.contract))return [];let n=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:Re(e.contractId),o=typeof e.correctionTranscriptHash=="string"?e.correctionTranscriptHash:void 0,r=e.correctionFingerprint??o;return r!==void 0&&!/^[a-f0-9]{64}$/.test(r)?[]:[{...e,obligationId:n,correctionFingerprint:r}]}).slice(-8):[]}function ye(i){return Array.isArray(i)?i.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 ve(i){return Array.isArray(i)?i.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 Ct(i){if(!i||typeof i!="object")return null;let t=i,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 o={obligationId:typeof t.obligationId=="string"&&t.obligationId.length>0&&t.obligationId.length<=384?t.obligationId:Re(t.contractId),contractId:t.contractId,at:t.at};if(e==="add")return Ee(t.contract)?{kind:e,...o,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,...o,fingerprint:r,violations:t.violations}:null}return e==="resolve"?{kind:e,...o}:typeof t.reason=="string"&&t.reason.length<=240?{kind:e,...o,reason:t.reason}:null}function be(i){return i==="add"?0:i==="correction"?1:2}function Ee(i){if(!i||typeof i!="object")return false;let t=i,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(o=>typeof o=="string"&&o.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 U(i){if(!i||typeof i!="object"||Array.isArray(i))return {};let t=i,e={};for(let n of ["lastMcpCall","bypassCount"])if(n in t){let o=t[n];if(o==null)continue;e[n]=typeof o=="number"&&Number.isFinite(o)&&o>=0?o:0;}return e}function Tt(i,t){return i.lastMcpCall===t.lastMcpCall&&i.bypassCount===t.bypassCount}function Ie(i,t,e){let n=e instanceof Error?e.message:String(e);E({event:"hook.runtime.degraded",identity:{projectRoot:i},level:"warn",timestamp:Date.now(),data:{stage:"enforcement_receipt",operation:t,reason:n,fallback:"fail_open"}});}function we(i,t,e){let n;try{n=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let o={},r=n.updateHookReceipt(i,a=>(o=U(a),U(t(o)))),s=U(r);return {receipt:s,applied:!0,changed:!Tt(o,s)}}catch(o){return Ie(i,e,o),{receipt:{},applied:false,changed:false}}finally{try{n?.close();}catch{}}}function xe(i){let t;try{return t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),U(t.getHookReceipt(i))}catch(e){return Ie(i,"update",e),{}}finally{try{t?.close();}catch{}}}function Ft(i,t){return we(i,()=>t,"write").applied}function Lt(i,t){return we(i,t,"update")}var G={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"},jt=new Set(["Write","Edit","NotebookEdit"]),Pt=new Set(["failed","timeout","unavailable"]);function Nt(i){switch(i){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}var H=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 n=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(n&&n.expiresAt>Date.now())return "context_ready";n&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{t?.close();}catch{}}let e=new x(this.projectRoot).get(this.sessionId);return e?.executionId===this.executionId&&e.contextInitialization?"context_initializing":"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_initializing"&&G[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_INITIALIZING",reason:`DevFlow context initialization is in progress. Wait for ${projectClaudeToolName("get_project_context")} to complete, then retry ${t}.`};if(n==="context_gathering"&&G[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_REQUIRED",reason:`DevFlow context required. Call ${projectClaudeToolName("get_project_context")}, then retry ${t}.`};if(n==="context_ready"){if(jt.has(t)){let c=this.evaluateRequiredAction();if(c)return c}return {permissionDecision:"allow"}}let o=G[t];if(!o)return {permissionDecision:"allow"};let r=Lt(this.projectRoot,c=>({...c,bypassCount:(c.bypassCount??0)+1}));if(!r.applied)return {permissionDecision:"allow"};let s=r.receipt.bypassCount??0,a=Nt(t);return s>=a?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${t}\uFF0C\u5EFA\u8BAE\u7528 ${projectClaudeToolName(o)} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){Ft(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}recordDomainActionOutcome(t,e,n,o){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=o?.trim()?`${o.trim()}:${e}`:`${t}:${e}:${a}`,l=s.actionAttempts??[];return r.upsertContextReceipt({...s,actionAttempts:l.some(d=>d.id===c||o&&d.toolUseId===o&&d.status===e)?l:[...l,{id:c,tool:t,status:e,attemptedAt:a,toolUseId:o,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 ${projectClaudeToolName("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 o=(t.actionAttempts??[]).filter(r=>r.tool===e.tool&&Pt.has(r.status));if(o.length>0){let r=o.at(-1),s={missedTool:e.tool,failedAttemptCount:o.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 ${projectClaudeToolName(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 ${projectClaudeToolName(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 o=n.getContextReceipt(t.projectRoot,t.sessionId,t.executionId);if(!o||o.contextHash!==t.contextHash||o.actionDegradation)return;n.upsertContextReceipt({...o,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 Bt=10*1024*1024,zt=5;function Gt(i){return createHash$1("sha256").update(i).digest("hex").slice(0,16)}function De(i){return join(homedir(),".devflow","logs","hook-debug",`${Gt(i)}.jsonl`)}function ke(i,t,e={}){let n=e.maxBytes??Bt,o=e.maxFiles??zt;mkdirSync$1(dirname(i),{recursive:true,mode:448});let r=Buffer.byteLength(t);rotateDiagnosticLogFile({path:i,maxBytes:n,maxFiles:o,incomingBytes:r}),appendFileSync(i,t,{mode:384}),chmodSync(i,384);}var Y="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function Se(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}function Oe(i){let t=i.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 Ae(i,t){return t?`evt_tool_${createHash("sha256").update(`${i}\0${t}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var Zt=new Set(["Write","Edit","NotebookEdit"]),Ce=`Claude native memory writes are disabled for this project. Use DevFlow explicit memory or ${projectClaudeToolName("memory_commit_turn")} so a canonical receipt is created.`;function Pe(i){if(!Zt.has(i.toolName))return null;let t=en(i.toolInput);if(!t)return null;let e=tn(t,i.projectRoot),n=resolve(i.projectRoot,".claude");if(Te(e,n)&&basename(e).toLocaleUpperCase("en-US")==="MEMORY.MD")return Ce;let o=resolve(i.home??homedir(),".claude","projects");return Te(e,o)&&relative(o,e).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?Ce:null}function en(i){for(let t of ["file_path","notebook_path","path"]){let e=i[t];if(typeof e=="string"&&e.trim())return e.trim()}return null}function tn(i,t){return resolve(isAbsolute(i)?i:resolve(t,i))}function Te(i,t){let e=relative(t,i);return e===""||!e.startsWith(`..${sep}`)&&e!==".."&&!isAbsolute(e)}function Ue(i){let t=dn(i.toolName,i.toolInput),e=t?un(i.projectRoot,i.toolName,i.toolInput):void 0;if(!t||!e||!i.toolUseId)return {allowed:true};let n=gn(e),o,r=0,s,a;try{a=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:100,readonly:!0});let l=a.getActiveContextReceipt(i.projectRoot,i.sessionId,i.executionId);o=l?.contextHash,r=l?.issuedAt??0,s=l?.canonicalAction?.binding.operationTargets?.find(d=>fn(i.projectRoot,d.path,e));}catch{}finally{try{a?.close();}catch{}}let c={toolUseId:i.toolUseId,sessionId:i.sessionId,executionId:i.executionId,operation:t,path:e,before:n,contextReceipt:o,observedAt:Date.now()};if(yn(i.projectRoot,c),t==="edit"||t==="write"||t==="delete"){let l=vn(i.projectRoot,e),d=l?.success&&l.operation==="delete"&&!l.after.exists&&l.completedAt>=r,u=s?.expectedState==="existing"&&!n.exists||s?.expectedState==="missing"&&n.exists||!!(s?.contentHash&&n.hash!==s.contentHash);if(d||s?.expectedState==="existing"&&!n.exists)return Ne(i,c,"DEVFLOW_FILE_STATE_DELETED","The target was deleted after the active Context receipt. Refresh project context before editing or recreating it.");if(u)return Ne(i,c,"DEVFLOW_FILE_STATE_STALE","The target state no longer matches the active Context receipt. Refresh project context before overwriting it.")}return He(i,c,true),{allowed:true,pending:c}}function Ne(i,t,e,n){return He(i,t,false,e),{allowed:false,reasonCode:e,reason:n,pending:t}}function He(i,t,e,n){E({event:"canonical.action.validated",identity:{projectRoot:i.projectRoot,sessionId:i.sessionId,executionId:i.executionId,contextReceipt:t.contextReceipt},level:e?"info":"warn",timestamp:Date.now(),data:{stage:"host_file_state_precondition",valid:e,operation:t.operation,targetPath:relative(i.projectRoot,t.path),targetExists:t.before.exists,targetHash:t.before.hash,reason:n,toolUseId:t.toolUseId}});}function dn(i,t){if(i==="Read")return "read";if(i==="Edit"||i==="NotebookEdit")return "edit";if(i==="Write")return "write";if(i==="Delete"||i==="Bash"&&qe(t.command))return "delete"}function un(i,t,e){let n=pn(e,["file_path","filePath","notebook_path","path","targetPath"])??(t==="Bash"?qe(e.command):void 0);if(!n)return;let o=isAbsolute(n)?normalize(n):resolve(i,n),r=relative(i,o);return r.startsWith("..")||isAbsolute(r)?void 0:o}function qe(i){return typeof i!="string"?void 0:/(?:^|[;&|]\s*)\s*(?:rm|unlink)\s+(?:-[A-Za-z]+\s+)*(?:--\s+)?(["']?)([^\s;&|"']+)\1/u.exec(i)?.[2]}function pn(i,t){for(let e of t){let n=i[e];if(typeof n=="string"&&n.trim())return n.trim()}}function gn(i){if(!existsSync$1(i))return {exists:false};try{return {exists:!0,hash:createHash$1("sha256").update(readFileSync$1(i)).digest("hex")}}catch{return {exists:true}}}function fn(i,t,e){return (isAbsolute(t)?normalize(t):resolve(i,t))===normalize(e)}function We(i){return join(R(i),"file-state")}function Je(i){return join(We(i),"pending.json")}function mn(i){return join(We(i),"observations.jsonl")}function hn(i){try{return JSON.parse(readFileSync$1(Je(i),"utf8"))}catch{return {}}}function yn(i,t){let e=Je(i);mkdirSync$1(dirname(e),{recursive:true});let n=hn(i);n[t.toolUseId]=t,bn(e,JSON.stringify(n));}function vn(i,t){try{let e=readFileSync$1(mn(i),"utf8").trim().split(`
3
- `);for(let n=e.length-1;n>=0;n-=1){let o=JSON.parse(e[n]);if(o.path===t)return o}}catch{}}function bn(i,t){let e=`${i}.${process.pid}.${Date.now()}.tmp`;writeFileSync$1(e,t,{encoding:"utf8",mode:384}),renameSync$1(e,i);}var In=new Set(["delivered","cancelled","rejected"]),wn=new Set(["cancelled","rejected"]),xn=new Set(["Write","Edit","NotebookEdit","Bash"]);function ee(i,t,e,n){if(!xn.has(e)||!t.trim())return null;let o=join(i,".devflow","delivery-line","state.db");if(!existsSync$1(o))return null;let r;try{r=new DatabaseSync(o,{readOnly:!0,timeout:250});let s=r.prepare("SELECT id, payload, updated_at FROM delivery_cases").all(),a=new Set;if(!!r.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'delivery_workflow_bindings'").get()){let p=r.prepare("SELECT case_id, source_path, aliases FROM delivery_workflow_bindings WHERE status = 'enforced'").all();for(let g of p){let m=[];try{m=JSON.parse(g.aliases);}catch{}(g.source_path===i||m.includes(i))&&a.add(g.case_id);}}let l=[];for(let p of s){let g=JSON.parse(p.payload),m=a.has(p.id);(g.sessionId===t||t===p.id||m)&&l.push({id:p.id,payload:g,updatedAt:typeof p.updated_at=="number"?p.updated_at:typeof g.updatedAt=="number"?g.updatedAt:0});let b=typeof g.stage=="string"?g.stage:"unknown";if(!In.has(b)){if(n&&b==="executing"){let y=r.prepare("SELECT id, lease_owner, fencing_token FROM delivery_tasks WHERE case_id = ? AND lease_expires_at > ? AND lease_owner IS NOT NULL AND fencing_token > 0 LIMIT 1").get(p.id,Date.now()),f=typeof g.sessionId=="string"?g.sessionId:void 0,I=typeof g.executionId=="string"?g.executionId:void 0,S=n===y?.id||n===y?.lease_owner||n===I,W=t===p.id||t===f;if(y?.id&&S&&W)return null}if(g.sessionId===t||t===p.id||m)return {code:"DELIVERY_AUTHORITY_REQUIRED",caseId:p.id,stage:b,message:`Delivery case ${p.id} is ${b}; use the Delivery task lease before modifying files.`}}}let d=l.sort((p,g)=>g.updatedAt-p.updatedAt)[0],u=typeof d?.payload.stage=="string"?d.payload.stage:void 0;return d&&u&&wn.has(u)?{code:"DELIVERY_AUTHORITY_REQUIRED",caseId:d.id,stage:u,message:`Delivery case ${d.id} is ${u}; start a new Delivery case or session before modifying files.`}:null}catch{return {code:"DELIVERY_AUTHORITY_UNAVAILABLE",caseId:"unknown",stage:"unknown",message:"Delivery state cannot be read; file writes are blocked until runtime health is restored."}}finally{r?.close();}}function T(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function Ve(i){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:i}}}function Tn(i){let t=R(i);return existsSync(t)||mkdirSync(t,{recursive:true}),t}function Fn(i,t,e,n,o,r){let s=join$1(Tn(i),"event-map.json"),a=[];try{existsSync(s)&&(a=JSON.parse(readFileSync(s,"utf-8")));}catch{}a.push({sessionId:t,toolName:e,toolUseId:n,eventId:o,timestamp:r}),writeFileSync(s,JSON.stringify(a));}function Ln(i){switch(i){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 jn(i){let t=Se();try{if(!i||i.trim()==="")return T();let e=JSON.parse(i),n=Date.now();try{maybeRunDiagnosticLogCleanup(C(),{now:n});}catch{}let o=C(),r=new N,s=resolveClaudeToolName(e.tool_name,e.tool_input),a=s.status==="unsupported"?void 0:s.canonicalName;a&&(typeof e.tool_input.projectRoot!="string"||!e.tool_input.projectRoot.trim())&&(e.tool_input.projectRoot=o);let c=e.session_id?.trim();if(!c)return Ve(Y);let l=new x(o),d=l.get(c)!==null;if(l.registerSession(c),d||await r.sendSessionStart(c,o,Date.now()),e.tool_name==="Skill"){let v=e.tool_input?.skill,h=v?Oe(v):null;if(h){let _=l.get(c)?.executionId,A=l.startExecution(c,h,ue(h));A.executionId&&A.executionId!==_&&await r.sendExecutionStart(A.executionId,c,h,A.lastActivityAt,o,A.requiredMcpTools);}}let u=l.get(c);a==="get_project_context"&&l.beginContextInitialization(c,e.tool_use_id),a&&(e.tool_input._devflow_session_id=c,e.tool_input._devflow_execution_id=u?.executionId??c,u?.activeTurnId&&(e.tool_input._devflow_turn_id=u.activeTurnId),u?.activeRequestId&&(e.tool_input._devflow_request_id=u.activeRequestId),u?.intentArtifactHash&&(e.tool_input._devflow_intent_artifact_hash=u.intentArtifactHash),u?.skillName&&(e.tool_input._devflow_active_skill=u.skillName),e.tool_use_id&&(e.tool_input._devflow_tool_use_id=e.tool_use_id));let p=e.tool_name.startsWith("mcp__"),g=a,m=l.get(c),b=new H(o,c,m?.executionId),y=b.getPhase(),f,I,S=ee(o,c,e.tool_name,m?.executionId);if(S)I=S.code,f={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:`${S.message} Resolve the case blocker or obtain an authorized task lease before retrying.`}};else {let v=Pe({toolName:e.tool_name,toolInput:e.tool_input,projectRoot:o}),h=Ue({projectRoot:o,sessionId:c,executionId:m?.executionId,toolUseId:e.tool_use_id,toolName:e.tool_name,toolInput:e.tool_input}),_=v?{permissionDecision:"deny",reason:v}:h.allowed?b.evaluate(e.tool_name,p):{permissionDecision:"deny",reason:h.reason,reasonCode:h.reasonCode};_.permissionDecision==="deny"?(I=v?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":_.reasonCode??"DEVFLOW_CONTEXT_REQUIRED",f={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:_.reason??"MCP context required"}}):_.additionalContext?f=Ve(_.additionalContext):f=T();}a&&(f.hookSpecificOutput.updatedInput=e.tool_input),t&&f.hookSpecificOutput.permissionDecision==="allow"&&(f.hookSpecificOutput.additionalContext=Y);let W=m?.executionId??c,O={eventId:Ae(c,e.tool_use_id),executionId:W,sessionId:c,projectRoot:o,toolUseId:e.tool_use_id,timestamp:Date.now(),toolName:e.tool_name,toolType:p?"mcp":e.tool_name==="Agent"?"subagent":"direct",isMcpTool:p,mcpToolName:g,mcpEnforced:p&&(y==="context_gathering"||y==="context_initializing"),mcpFallback:!p&&(y==="context_gathering"||y==="context_initializing"),kind:Ln(e.tool_name),input:e.tool_input,duration:0,blocked:f.hookSpecificOutput.permissionDecision==="deny",blockReason:f.hookSpecificOutput.permissionDecision==="deny"?I??"DEVFLOW_CONTEXT_REQUIRED":void 0},F=await r.sendEvent(O);F&&!O.blocked&&Fn(o,c,e.tool_name,e.tool_use_id,F,O.timestamp),F&&O.blocked&&await r.completeEvent({eventId:F,sessionId:c,error:I??"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-O.timestamp,completedAt:Date.now()});try{let v=xe(o),h={ts:n,tool:e.tool_name,sessionId:c,skill:u?.skillName??"(none)",requiredTools:u?.requiredMcpTools??[],isMcp:p,enforce:u?.executionId!==void 0,stateless:u?.executionId===void 0&&!p&&e.tool_name!=="Skill",bypassCount:v.bypassCount??0,decision:f.hookSpecificOutput.permissionDecision,env_CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd()};ke(De(o),`${JSON.stringify(h)}
4
- `);}catch{}return f}catch{try{let e=JSON.parse(i),n=C(),o=ee(n,String(e.session_id??""),String(e.tool_name??""),void 0);if(o)return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:o.message}}}catch{}return T()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let i=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 jn(t);i(JSON.stringify(e));}),process.stdin.on("error",()=>{i(JSON.stringify(T())),process.exit(0);}),setTimeout(()=>{i(JSON.stringify(T())),process.exit(0);},4e3).unref();}export{jn as handlePreToolUse};
1
+ import {existsSync,readdirSync,readFileSync,unlinkSync,mkdirSync,writeFileSync,rmSync,linkSync,renameSync}from'fs';import {join as join$1,dirname as dirname$1}from'path';import {openGlobalDevFlowDatabase}from'@devflow-tools/database';import {getLocalApiKey,getDevFlowStateRoot,projectClaudeToolName,resolveClaudeToolName,acquireRuntimeHttpCircuit,registerRuntimeHttpSuccess,registerRuntimeHttpFailure,getProjectStateDir,readRuntimeState}from'@devflow-tools/sdk';import {request}from'node:http';import {existsSync as existsSync$1,mkdirSync as mkdirSync$1,appendFileSync,chmodSync,readFileSync as readFileSync$1,writeFileSync as writeFileSync$1,renameSync as renameSync$1}from'node:fs';import {join,resolve,basename,relative,sep,dirname,isAbsolute,normalize}from'node:path';import {maybeRunDiagnosticLogCleanup,rotateDiagnosticLogFile,emitSemanticControlLog}from'@devflow-tools/telemetry';import {fileURLToPath}from'url';import {randomUUID,createHash}from'crypto';import {createHash as createHash$1}from'node:crypto';import {homedir}from'node:os';import {DatabaseSync}from'node:sqlite';function L(i,t,e){try{let n=openGlobalDevFlowDatabase();try{n.insertEvent({kind:i,timestamp:Date.now(),duration:e,success:t.success!==!1,metadata:t});}finally{n.close();}}catch{}}var rt=getLocalApiKey(),J=join(getDevFlowStateRoot(),"errors");async function ie(i,t,e={}){let n=e.endpoint??process.env.DEVFLOW_SERVER_URL?.trim()??st();if(!n)return {delivered:false,suppressed:false,fallbackReason:"runtime_not_ready"};let o=e.timeout??1500,r=e.durableMirror??true,s=e.maxRetries??(r?0:2),c=e.circuitBreaker??true,a=acquireRuntimeHttpCircuit(n,i);if(c&&!a.allowed)return {delivered:false,suppressed:true,fallbackReason:a.state.fallbackReason};let l;for(let d=0;d<=s;d+=1)try{return await at(n,i,t,o),c&&registerRuntimeHttpSuccess(n,i).transitioned&&L("http_circuit_transition",{endpoint:n,path:new URL(i,n).pathname,previous:a.state.status,status:"closed",failures:0}),{delivered:!0,suppressed:!1}}catch(g){l=g instanceof Error?g:new Error(String(g)),d<s&&await ct(Math.min(100*2**d,1e3));}if(!l)return {delivered:false,suppressed:false,fallbackReason:"unknown_http_failure"};if(!c)return te(i,l),{delivered:false,suppressed:false,fallbackReason:l.message};let u=registerRuntimeHttpFailure(n,i,e.fallbackReason??(r?"local_durable_mirror":"http_delivery_failed"));return u.transitioned&&(te(i,l),L("http_circuit_transition",{endpoint:n,path:new URL(i,n).pathname,previous:a.state.status,status:"open",failures:u.state.failures,openUntil:u.state.openUntil,fallbackReason:u.state.fallbackReason})),{delivered:false,suppressed:false,fallbackReason:u.state.fallbackReason}}function st(){let i=readRuntimeState();return i?.status==="ready"&&i.dashboardAvailable?i.url:void 0}function at(i,t,e,n){return new Promise((o,r)=>{let s=JSON.stringify(e),c=new URL(t,i),a=false,l=d=>{a||(a=true,d?r(d):o());},u=request({hostname:c.hostname,port:c.port,path:c.pathname+c.search,method:"POST",headers:{"Content-Type":"application/json","X-API-Key":rt,"Content-Length":Buffer.byteLength(s)},timeout:n},d=>{d.on("error",l),d.on("end",()=>{let g=d.statusCode??0;l(g>=200&&g<300?void 0:new Error(`HTTP ${g}`));}),d.resume();});u.on("error",l),u.on("timeout",()=>u.destroy(new Error(`HTTP mirror timed out after ${n}ms`))),u.write(s),u.end();})}function te(i,t){try{existsSync$1(J)||mkdirSync$1(J,{recursive:!0});let e=join(J,"http-errors.log"),n=`${new Date().toISOString()} | ${i} | ${t.message}
2
+ `;rotateDiagnosticLogFile({path:e,maxBytes:50*1024*1024,maxFiles:5,incomingBytes:Buffer.byteLength(n)}),appendFileSync(e,n);}catch{}}function ct(i){return new Promise(t=>setTimeout(t,i))}var ae=1e4,ft=3e4,P=500,$=class{constructor(t){this.retryScheduled=false;this.metricAggregationScheduled=false;this.apiUrl=t?.apiUrl,this.cacheDir=t?.cacheDir??join$1(getDevFlowStateRoot(),"global","telemetry-cache"),this.database=t?.database??null,this.ownsDatabase=!t?.database;let e=t?.busyTimeoutMs??Number(process.env.DEVFLOW_TELEMETRY_DB_BUSY_TIMEOUT_MS);this.busyTimeoutMs=Number.isSafeInteger(e)&&e>=0?e:100;}async sendEvent(t){let e={...t,input:this.truncateInput(t.input)};return this.commitOrCache("tool_call",e)?(this.postHttp("/api/telemetry/tool-call",e),t.eventId):null}async sendExecutionStart(t,e,n,o,r=process.env.CLAUDE_PROJECT_DIR??process.cwd(),s=[]){let c={executionId:t,sessionId:e,skillName:n,startedAt:o,projectRoot:r,requiredMcpTools:s};this.commitOrCache("execution_start",c)&&this.postHttp("/api/telemetry/skill-execution/start",c);}async sendExecutionComplete(t,e="completed",n=Date.now(),o){let r={executionId:t,status:e,finishedAt:n,metadata:o},s=this.commitOrCache("execution_complete",r);return s&&this.postHttp("/api/telemetry/skill-execution/complete-reconciled",r),s}async sendSessionStart(t,e,n){let o={id:t,projectRoot:e,startedAt:n,label:e.split("/").pop()??"unknown"},r=this.commitOrCache("session_start",o);return r&&this.postHttp("/api/telemetry/sessions",o),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},o=this.commitOrCache("session_end",n);return o&&(this.getDatabase().aggregatePendingToolMetrics(),this.postHttp(`/api/telemetry/sessions/${encodeURIComponent(t)}/close`,{finishedAt:e})),o}async flushCache(){try{let e=this.getDatabase(),n=e.listTelemetryFailures({unresolvedOnly:!0,limit:P}).reverse();for(let o of n)try{this.applyOperation(o.operation,o.payload),e.resolveTelemetryFailure(o.id);}catch{}e.trimTelemetryFailures(P);}catch{}let t=(existsSync(this.cacheDir)?readdirSync(this.cacheDir):[]).filter(e=>e.endsWith(".json")).map(e=>{let n=join$1(this.cacheDir,e);try{return {cacheFile:n,envelope:mt(JSON.parse(readFileSync(n,"utf8")))}}catch{return null}}).filter(e=>e!==null).sort((e,n)=>e.envelope.timestamp-n.envelope.timestamp||ce(e.envelope.operation)-ce(n.envelope.operation));for(let{cacheFile:e,envelope:n}of t)try{let o=this.getDatabase();o.insertTelemetryFailure({id:n.id,operation:n.operation,payload:n.payload,error:n.failure,createdAt:n.timestamp}),this.applyOperation(n.operation,n.payload),o.resolveTelemetryFailure(n.id),unlinkSync(e);}catch{}this.database?.aggregatePendingToolMetrics();}aggregateMetrics(){return this.getDatabase().aggregatePendingToolMetrics()}async flushAndAggregate(){await this.flushCache(),this.aggregateMetrics();}close(){this.ownsDatabase&&this.database?.close(),this.database=null;}getDatabase(){return this.database??=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:this.busyTimeoutMs}),this.database}commitOrCache(t,e){try{return this.applyOperation(t,e),!0}catch(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:le(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(le(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 o=typeof e.projectRoot=="string"&&e.projectRoot.trim()?e.projectRoot:typeof e.input?.projectRoot=="string"&&e.input.projectRoot.trim()?e.input.projectRoot:process.env.CLAUDE_PROJECT_DIR??"unknown";t.ensureSession({id:n,projectRoot:o,label:o==="unknown"?void 0:o.split("/").pop(),startedAt:Number(e.startedAt??e.timestamp??Date.now())});}cacheOperation(t,e,n){let o=Date.now(),r={id:`failure:${o}:${Math.random().toString(36).slice(2,11)}`,operation:t,payload:e,failure:n instanceof Error?n.message:String(n),timestamp:o};try{let s=this.getDatabase();s.insertTelemetryFailure({id:r.id,operation:t,payload:e,error:r.failure,createdAt:o}),s.trimTelemetryFailures(P),this.scheduleRetry();return}catch{}try{existsSync(this.cacheDir)||mkdirSync(this.cacheDir,{recursive:!0});let s=join$1(this.cacheDir,`${o}_${Math.random().toString(36).slice(2,11)}.json`);writeFileSync(s,JSON.stringify(r,null,2),{mode:384}),this.trimRetryCache(),this.scheduleRetry();}catch{}}trimRetryCache(){try{let t=readdirSync(this.cacheDir).filter(e=>e.endsWith(".json")).sort();for(let e of t.slice(0,Math.max(0,t.length-P)))unlinkSync(join$1(this.cacheDir,e));}catch{}}scheduleRetry(){this.retryScheduled||(this.retryScheduled=true,setTimeout(()=>{this.retryScheduled=false,this.flushCache();},ft).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){ie(t,e,{endpoint:this.apiUrl,fallbackReason:"telemetry_already_committed_locally"});}truncateInput(t){let e=JSON.stringify(t);return e===void 0||e.length<=ae?t:{_truncated:true,_original_size:e.length,_preview:`${e.substring(0,ae)}...`}}};function ce(i){return ["session_start","execution_start","tool_call","complete_event","execution_complete","session_end"].indexOf(i)}function le(i){return `hook-run:${i}`}function mt(i){if(!i||typeof i!="object")throw new Error("Invalid telemetry cache envelope");let t=i;if(typeof t.id!="string"||typeof t.operation!="string"||t.payload===void 0||typeof t.failure!="string"||typeof t.timestamp!="number")throw new Error("Invalid telemetry cache envelope");return t}function C(i){return i??process.env.CLAUDE_PROJECT_DIR??process.cwd()}function E(i){return getProjectStateDir(C(i))}var I=emitSemanticControlLog;var Et=2,It=1;function wt(){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 de(i=wt()){let t=[join$1(i,"dist","command-registry.json"),join$1(i,"command-registry.json")];for(let e of t)try{if(!existsSync(e))continue;let n=JSON.parse(readFileSync(e,"utf8"));if(n.version!==Et&&n.version!==It||!xt(n.commands)){I({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 n.commands}catch(n){I({event:"hook.runtime.degraded",identity:{projectRoot:process.env.CLAUDE_PROJECT_DIR||process.cwd()},level:"warn",timestamp:Date.now(),data:{stage:"command_registry",reason:n.message,fallback:"next_registry_candidate"}});}return null}function xt(i){return !i||typeof i!="object"||Array.isArray(i)?false:Object.values(i).every(t=>{if(!t||typeof t!="object"||Array.isArray(t))return false;let e=t;return M(e.mcpTools)&&M(e.blockedNative)&&(e.source===void 0||e.source==="core"||e.source==="plugin")&&(e.requiresContext===void 0||typeof e.requiresContext=="boolean")&&(e.runtimePackages===void 0||M(e.runtimePackages))&&(e.hostTools===void 0||Dt(e.hostTools))&&(e.evidenceMode===void 0||["static","runtime","mixed"].includes(e.evidenceMode))})}function Dt(i){return !!i&&typeof i=="object"&&!Array.isArray(i)&&Object.entries(i).every(([t,e])=>t.length>0&&M(e))}function M(i){return Array.isArray(i)&&i.every(t=>typeof t=="string"&&t.length>0)}function ue(i){let t=de();return t?t[i]?.mcpTools??[]:[]}function me(i){return Buffer.from(i,"utf8").toString("base64url")}function At(i,t,e){let n=t?.trim();if(n){let o=/^[a-zA-Z0-9:._-]{1,192}$/.test(n)?n:`tool-${createHash("sha256").update(n.slice(0,1024)).digest("hex").slice(0,32)}`;return `${i}:${o}`}return `${i}:legacy-${e}-${randomUUID().slice(0,8)}`}function Re(i){return `${i}:legacy-journal`}var D=class{constructor(t){this.projectRoot=t;this.sessions=new Map;this.sessionsDir=join$1(E(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 o=Date.now(),r={sessionId:e,projectRoot:this.projectRoot,requiredMcpTools:[],evidenceObligations:[],evidenceDegradations:[],evidenceOutcomes:[],startedAt:o,lastActivityAt:o};return this.sessions.set(e,r),this.persist(r),r}startExecution(t,e,n){let o=this.registerSession(t);return (!o.executionId||o.skillName!==e)&&(o.executionId=`exec_${Date.now()}_${randomUUID().slice(0,8)}`),o.skillName=e,o.requiredMcpTools=[...new Set(n)],delete o.contextInitialization,o.lastActivityAt=Date.now(),this.persist(o),o}beginContextInitialization(t,e){let n=this.registerSession(t);return n.contextInitialization={startedAt:Date.now(),...e?{toolUseId:e}:{}},n.lastActivityAt=Date.now(),this.persist(n),n}completeContextInitialization(t,e){let n=this.get(t);return n?(e&&n.contextInitialization?.toolUseId&&n.contextInitialization.toolUseId!==e||(delete n.contextInitialization,n.lastActivityAt=Date.now(),this.persist(n)),n):null}bindTaskIdentity(t,e){let n=this.registerSession(t);return n.activeTurnId=e.turnId,n.activeRequestId=e.requestId,n.intentArtifactHash=e.intentArtifactHash,n.lastActivityAt=Date.now(),this.persist(n),n}get(t){let e=t.trim();if(!e)return null;let n=this.sessions.get(e);if(n)return this.replayEvidenceJournal(n),n;let o=this.snapshotPath(e);if(!existsSync(o))return null;try{let r=JSON.parse(readFileSync(o,"utf8"));return r.sessionId!==e||r.projectRoot!==this.projectRoot?null:(r.requiredMcpTools=Array.isArray(r.requiredMcpTools)?r.requiredMcpTools:[],r.evidenceObligations=he(r.evidenceObligations),r.evidenceDegradations=ye(r.evidenceDegradations),r.evidenceOutcomes=ve(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,delete e.contextInitialization,e.requiredMcpTools=[],e.lastActivityAt=Date.now(),this.persist(e),n}addEvidenceObligation(t,e,n=Date.now(),o){let r=this.registerSession(t),c=(o?void 0:r.evidenceObligations.find(l=>l.contractId===e.id))?.obligationId??At(e.id,o,n);this.appendEvidenceEvent(t,{kind:"add",obligationId:c,contractId:e.id,at:n,contract:e},`add\0${c}`),this.replayEvidenceJournal(r);let a=r.evidenceObligations.find(l=>l.obligationId===c);return a?(r.lastActivityAt=Date.now(),this.persist(r),structuredClone(a)):null}listEvidenceObligations(t){return (this.get(t)?.evidenceObligations??[]).map(e=>structuredClone(e))}markEvidenceCorrection(t,e,n,o,r=Date.now()){let s=this.get(t),c=s?.evidenceObligations.find(u=>u.obligationId===e);if(!s||!c)return null;let a=/^[a-f0-9]{64}$/.test(o)?o:"";if(!a)return null;this.appendEvidenceEvent(t,{kind:"correction",obligationId:e,contractId:c.contractId,at:r,fingerprint:a,violations:n.slice(0,16).map(u=>u.slice(0,240))},`correction\0${e}\0${a}`),this.replayEvidenceJournal(s),s.lastActivityAt=r,this.persist(s);let l=s.evidenceObligations.find(u=>u.obligationId===e);return l?structuredClone(l):null}resolveEvidenceObligation(t,e){let n=this.get(t);if(!n)return false;let o=n.evidenceObligations.find(s=>s.obligationId===e);if(!o)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:o.contractId,at:r},`resolve\0${e}`),this.replayEvidenceJournal(n),n.lastActivityAt=r,this.persist(n),true}resolveDegradedEvidence(t,e){let n=this.get(t),o=n?.evidenceDegradations.find(s=>s.obligationId===e);if(!n||!o)return false;let r=Date.now();return this.appendEvidenceEvent(t,{kind:"resolve",obligationId:e,contractId:o.contractId,at:r},`resolve-degraded\0${e}\0${r}`),this.replayEvidenceJournal(n),n.lastActivityAt=r,this.persist(n),true}degradeEvidenceObligation(t,e,n,o=Date.now()){let r=this.get(t),s=r?.evidenceObligations.find(a=>a.obligationId===e);if(!r||!s)return false;let c=n.slice(0,240);return this.appendEvidenceEvent(t,{kind:"degrade",obligationId:e,contractId:s.contractId,at:o,reason:c},`degrade\0${e}\0${c}`),this.replayEvidenceJournal(r),r.lastActivityAt=o,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,`${me(t)}.json`)}evidenceJournalDir(t){return join$1(this.sessionsDir,"evidence-journal",me(t))}appendEvidenceEvent(t,e,n){let o=this.evidenceJournalDir(t);mkdirSync(o,{recursive:true,mode:448});let r=createHash("sha256").update(n).digest("hex"),s=join$1(o,`${e.kind}-${r}.json`);if(existsSync(s))return;let c=join$1(o,`.${process.pid}.${randomUUID()}.tmp`);writeFileSync(c,JSON.stringify(e),{mode:384});try{linkSync(c,s);}catch(a){if(a.code!=="EEXIST")throw a}finally{rmSync(c,{force:true});}}replayEvidenceJournal(t){t.evidenceObligations=he(t.evidenceObligations),t.evidenceDegradations=ye(t.evidenceDegradations),t.evidenceOutcomes=ve(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 o=n.flatMap(r=>{try{let s=readFileSync(join$1(e,r),"utf8");if(Buffer.byteLength(s,"utf8")>64*1024)return [];let c=Ct(JSON.parse(s));return c?[c]:[]}catch{return []}}).sort((r,s)=>r.at-s.at||be(r.kind)-be(s.kind));for(let r of o)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(c=>c.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 o=t.evidenceObligations.find(s=>s.obligationId===e.obligationId);if(e.kind==="correction"){if(!o||n||o.correctionFingerprint===e.fingerprint)return;o.attempt+=1,o.correctionRequested=true,o.correctionRequestedAt=e.at,o.correctionFingerprint=e.fingerprint,o.violations=e.violations;return}let r=o?.attempt??n?.attempt??0;if(e.kind==="resolve"&&n?.status==="degraded")t.evidenceOutcomes=t.evidenceOutcomes.filter(s=>s.obligationId!==e.obligationId),t.evidenceDegradations=t.evidenceDegradations.filter(s=>s.obligationId!==e.obligationId);else if(n)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:o?.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),n=`${e}.${process.pid}.${randomUUID()}.tmp`;writeFileSync(n,JSON.stringify(t),{mode:384}),renameSync(n,e);}};function he(i){return Array.isArray(i)?i.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)||!Ee(e.contract))return [];let n=typeof e.obligationId=="string"&&e.obligationId.length>0&&e.obligationId.length<=384?e.obligationId:Re(e.contractId),o=typeof e.correctionTranscriptHash=="string"?e.correctionTranscriptHash:void 0,r=e.correctionFingerprint??o;return r!==void 0&&!/^[a-f0-9]{64}$/.test(r)?[]:[{...e,obligationId:n,correctionFingerprint:r}]}).slice(-8):[]}function ye(i){return Array.isArray(i)?i.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 ve(i){return Array.isArray(i)?i.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 Ct(i){if(!i||typeof i!="object")return null;let t=i,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 o={obligationId:typeof t.obligationId=="string"&&t.obligationId.length>0&&t.obligationId.length<=384?t.obligationId:Re(t.contractId),contractId:t.contractId,at:t.at};if(e==="add")return Ee(t.contract)?{kind:e,...o,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,...o,fingerprint:r,violations:t.violations}:null}return e==="resolve"?{kind:e,...o}:typeof t.reason=="string"&&t.reason.length<=240?{kind:e,...o,reason:t.reason}:null}function be(i){return i==="add"?0:i==="correction"?1:2}function Ee(i){if(!i||typeof i!="object")return false;let t=i,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(o=>typeof o=="string"&&o.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 U(i){if(!i||typeof i!="object"||Array.isArray(i))return {};let t=i,e={};for(let n of ["lastMcpCall","bypassCount"])if(n in t){let o=t[n];if(o==null)continue;e[n]=typeof o=="number"&&Number.isFinite(o)&&o>=0?o:0;}return e}function Tt(i,t){return i.lastMcpCall===t.lastMcpCall&&i.bypassCount===t.bypassCount}function Ie(i,t,e){let n=e instanceof Error?e.message:String(e);I({event:"hook.runtime.degraded",identity:{projectRoot:i},level:"warn",timestamp:Date.now(),data:{stage:"enforcement_receipt",operation:t,reason:n,fallback:"fail_open"}});}function we(i,t,e){let n;try{n=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250});let o={},r=n.updateHookReceipt(i,c=>(o=U(c),U(t(o)))),s=U(r);return {receipt:s,applied:!0,changed:!Tt(o,s)}}catch(o){return Ie(i,e,o),{receipt:{},applied:false,changed:false}}finally{try{n?.close();}catch{}}}function xe(i){let t;try{return t=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:250}),U(t.getHookReceipt(i))}catch(e){return Ie(i,"update",e),{}}finally{try{t?.close();}catch{}}}function Ft(i,t){return we(i,()=>t,"write").applied}function Lt(i,t){return we(i,t,"update")}var G={Grep:"get_project_context",Glob:"get_project_context",Agent:"get_project_context",Bash:"get_project_context",WebSearch:"get_knowledge",WebFetch:"get_knowledge"},jt=new Set(["Write","Edit","NotebookEdit"]),Pt=new Set(["failed","timeout","unavailable"]);function $t(i){switch(i){case "WebSearch":case "WebFetch":return 1;case "Agent":return 3;case "Grep":case "Glob":return 3;case "Bash":return 5;default:return 2}}var H=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 n=t.getContextReceipt(this.projectRoot,this.sessionId,this.executionId);if(n&&n.expiresAt>Date.now())return "context_ready";n&&t.deleteContextReceipt(this.projectRoot,this.sessionId,this.executionId);}catch{}finally{try{t?.close();}catch{}}let e=new D(this.projectRoot).get(this.sessionId);return e?.executionId===this.executionId&&e.contextInitialization?"context_initializing":"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_initializing"&&G[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_INITIALIZING",reason:`DevFlow context initialization is in progress. Wait for ${projectClaudeToolName("get_project_context")} to complete, then retry ${t}.`};if(n==="context_gathering"&&G[t])return {permissionDecision:"deny",reasonCode:"DEVFLOW_CONTEXT_REQUIRED",reason:`DevFlow context required. Call ${projectClaudeToolName("get_project_context")}, then retry ${t}.`};if(n==="context_ready"){if(jt.has(t)){let a=this.evaluateRequiredAction();if(a)return a}return {permissionDecision:"allow"}}let o=G[t];if(!o)return {permissionDecision:"allow"};let r=Lt(this.projectRoot,a=>({...a,bypassCount:(a.bypassCount??0)+1}));if(!r.applied)return {permissionDecision:"allow"};let s=r.receipt.bypassCount??0,c=$t(t);return s>=c?{permissionDecision:"allow",additionalContext:`\u5DF2 ${s} \u6B21\u76F4\u63A5\u4F7F\u7528 ${t}\uFF0C\u5EFA\u8BAE\u7528 ${projectClaudeToolName(o)} \u83B7\u53D6\u66F4\u7CBE\u786E\u7684\u4E0A\u4E0B\u6587\u3002`}:{permissionDecision:"allow"}}recordMcpCall(){Ft(this.projectRoot,{lastMcpCall:Math.floor(Date.now()/1e3),bypassCount:0});}recordDomainActionOutcome(t,e,n,o){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 c=Date.now(),a=o?.trim()?`${o.trim()}:${e}`:`${t}:${e}:${c}`,l=s.actionAttempts??[];return r.upsertContextReceipt({...s,actionAttempts:l.some(u=>u.id===a||o&&u.toolUseId===o&&u.status===e)?l:[...l,{id:a,tool:t,status:e,attemptedAt:c,toolUseId:o,reason:n?.slice(0,500)}].slice(-20),actionSatisfiedAt:e==="succeeded"?c: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 ${projectClaudeToolName("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 o=(t.actionAttempts??[]).filter(r=>r.tool===e.tool&&Pt.has(r.status));if(o.length>0){let r=o.at(-1),s={missedTool:e.tool,failedAttemptCount:o.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 ${projectClaudeToolName(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 ${projectClaudeToolName(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 o=n.getContextReceipt(t.projectRoot,t.sessionId,t.executionId);if(!o||o.contextHash!==t.contextHash||o.actionDegradation)return;n.upsertContextReceipt({...o,actionDegradation:e});let r=n.getSkillExecution(t.executionId);if(!r)return;let s=r.metadata&&typeof r.metadata=="object"?r.metadata:{},c=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:[...c,e]}});}catch{}finally{try{n?.close();}catch{}}}};var Bt=10*1024*1024,zt=5;function Gt(i){return createHash$1("sha256").update(i).digest("hex").slice(0,16)}function De(i){return join(homedir(),".devflow","logs","hook-debug",`${Gt(i)}.jsonl`)}function ke(i,t,e={}){let n=e.maxBytes??Bt,o=e.maxFiles??zt;mkdirSync$1(dirname(i),{recursive:true,mode:448});let r=Buffer.byteLength(t);rotateDiagnosticLogFile({path:i,maxBytes:n,maxFiles:o,incomingBytes:r}),appendFileSync(i,t,{mode:384}),chmodSync(i,384);}var Y="WARNING: DevFlow is in degraded mode (daemon unreachable): 4-Gate enforcement and memory prefetch cache are unavailable. Run `devflow doctor` for details.";function Se(){return process.env.DEVFLOW_HOOK_DEGRADED==="1"}function Oe(i){let t=i.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 Ae(i,t){return t?`evt_tool_${createHash("sha256").update(`${i}\0${t}`).digest("hex").slice(0,24)}`:`evt_${Date.now()}_${Math.random().toString(36).slice(2,11)}`}var Zt=new Set(["Write","Edit","NotebookEdit"]),Ce=`Claude native memory writes are disabled for this project. Use DevFlow explicit memory or ${projectClaudeToolName("memory_commit_turn")} so a canonical receipt is created.`;function Pe(i){if(!Zt.has(i.toolName))return null;let t=en(i.toolInput);if(!t)return null;let e=tn(t,i.projectRoot),n=resolve(i.projectRoot,".claude");if(Te(e,n)&&basename(e).toLocaleUpperCase("en-US")==="MEMORY.MD")return Ce;let o=resolve(i.home??homedir(),".claude","projects");return Te(e,o)&&relative(o,e).split(sep).some(s=>s.toLocaleLowerCase("en-US")==="memory")?Ce:null}function en(i){for(let t of ["file_path","notebook_path","path"]){let e=i[t];if(typeof e=="string"&&e.trim())return e.trim()}return null}function tn(i,t){return resolve(isAbsolute(i)?i:resolve(t,i))}function Te(i,t){let e=relative(t,i);return e===""||!e.startsWith(`..${sep}`)&&e!==".."&&!isAbsolute(e)}function Ue(i){let t=dn(i.toolName,i.toolInput),e=t?un(i.projectRoot,i.toolName,i.toolInput):void 0;if(!t||!e||!i.toolUseId)return {allowed:true};let n=gn(e),o,r=0,s,c;try{c=openGlobalDevFlowDatabase(void 0,{busyTimeoutMs:100,readonly:!0});let l=c.getActiveContextReceipt(i.projectRoot,i.sessionId,i.executionId);o=l?.contextHash,r=l?.issuedAt??0,s=l?.canonicalAction?.binding.operationTargets?.find(u=>fn(i.projectRoot,u.path,e));}catch{}finally{try{c?.close();}catch{}}let a={toolUseId:i.toolUseId,sessionId:i.sessionId,executionId:i.executionId,operation:t,path:e,before:n,contextReceipt:o,observedAt:Date.now()};if(yn(i.projectRoot,a),t==="edit"||t==="write"||t==="delete"){let l=vn(i.projectRoot,e),u=l?.success&&l.operation==="delete"&&!l.after.exists&&l.completedAt>=r,d=s?.expectedState==="existing"&&!n.exists||s?.expectedState==="missing"&&n.exists||!!(s?.contentHash&&n.hash!==s.contentHash);if(u||s?.expectedState==="existing"&&!n.exists)return $e(i,a,"DEVFLOW_FILE_STATE_DELETED","The target was deleted after the active Context receipt. Refresh project context before editing or recreating it.");if(d)return $e(i,a,"DEVFLOW_FILE_STATE_STALE","The target state no longer matches the active Context receipt. Refresh project context before overwriting it.")}return He(i,a,true),{allowed:true,pending:a}}function $e(i,t,e,n){return He(i,t,false,e),{allowed:false,reasonCode:e,reason:n,pending:t}}function He(i,t,e,n){I({event:"canonical.action.validated",identity:{projectRoot:i.projectRoot,sessionId:i.sessionId,executionId:i.executionId,contextReceipt:t.contextReceipt},level:e?"info":"warn",timestamp:Date.now(),data:{stage:"host_file_state_precondition",valid:e,operation:t.operation,targetPath:relative(i.projectRoot,t.path),targetExists:t.before.exists,targetHash:t.before.hash,reason:n,toolUseId:t.toolUseId}});}function dn(i,t){if(i==="Read")return "read";if(i==="Edit"||i==="NotebookEdit")return "edit";if(i==="Write")return "write";if(i==="Delete"||i==="Bash"&&qe(t.command))return "delete"}function un(i,t,e){let n=pn(e,["file_path","filePath","notebook_path","path","targetPath"])??(t==="Bash"?qe(e.command):void 0);if(!n)return;let o=isAbsolute(n)?normalize(n):resolve(i,n),r=relative(i,o);return r.startsWith("..")||isAbsolute(r)?void 0:o}function qe(i){return typeof i!="string"?void 0:/(?:^|[;&|]\s*)\s*(?:rm|unlink)\s+(?:-[A-Za-z]+\s+)*(?:--\s+)?(["']?)([^\s;&|"']+)\1/u.exec(i)?.[2]}function pn(i,t){for(let e of t){let n=i[e];if(typeof n=="string"&&n.trim())return n.trim()}}function gn(i){if(!existsSync$1(i))return {exists:false};try{return {exists:!0,hash:createHash$1("sha256").update(readFileSync$1(i)).digest("hex")}}catch{return {exists:true}}}function fn(i,t,e){return (isAbsolute(t)?normalize(t):resolve(i,t))===normalize(e)}function We(i){return join(E(i),"file-state")}function Je(i){return join(We(i),"pending.json")}function mn(i){return join(We(i),"observations.jsonl")}function hn(i){try{return JSON.parse(readFileSync$1(Je(i),"utf8"))}catch{return {}}}function yn(i,t){let e=Je(i);mkdirSync$1(dirname(e),{recursive:true});let n=hn(i);n[t.toolUseId]=t,bn(e,JSON.stringify(n));}function vn(i,t){try{let e=readFileSync$1(mn(i),"utf8").trim().split(`
3
+ `);for(let n=e.length-1;n>=0;n-=1){let o=JSON.parse(e[n]);if(o.path===t)return o}}catch{}}function bn(i,t){let e=`${i}.${process.pid}.${Date.now()}.tmp`;writeFileSync$1(e,t,{encoding:"utf8",mode:384}),renameSync$1(e,i);}var In=new Set(["delivered","cancelled","rejected"]),wn=new Set(["cancelled","rejected"]),xn=new Set(["Write","Edit","NotebookEdit","Bash"]);function Dn(i,t){if(i!=="Bash"||typeof t?.command!="string")return false;let n="git show [A-Za-z0-9._/:@{}^~+\\-]+(?: 2>/dev/null)?";return new RegExp(`^${n}(?: \\|\\| ${n})*$`,"u").test(t.command)}function ee(i,t,e,n,o){if(!xn.has(e)||!t.trim()||Dn(e,o))return null;let r=join(i,".devflow","delivery-line","state.db");if(!existsSync$1(r))return null;let s;try{s=new DatabaseSync(r,{readOnly:!0,timeout:250});let c=s.prepare("SELECT id, payload, updated_at FROM delivery_cases").all(),a=new Set;if(!!s.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'delivery_workflow_bindings'").get()){let f=s.prepare("SELECT case_id, source_path, aliases FROM delivery_workflow_bindings WHERE status = 'enforced'").all();for(let p of f){let v=[];try{v=JSON.parse(p.aliases);}catch{}(p.source_path===i||v.includes(i))&&a.add(p.case_id);}}let u=[];for(let f of c){let p=JSON.parse(f.payload),v=a.has(f.id);(p.sessionId===t||t===f.id||v)&&u.push({id:f.id,payload:p,updatedAt:typeof f.updated_at=="number"?f.updated_at:typeof p.updatedAt=="number"?p.updatedAt:0});let y=typeof p.stage=="string"?p.stage:"unknown";if(!In.has(y)){if(n&&y==="executing"){let m=s.prepare("SELECT id, lease_owner, fencing_token FROM delivery_tasks WHERE case_id = ? AND lease_expires_at > ? AND lease_owner IS NOT NULL AND fencing_token > 0 LIMIT 1").get(f.id,Date.now()),w=typeof p.sessionId=="string"?p.sessionId:void 0,O=typeof p.executionId=="string"?p.executionId:void 0,W=n===m?.id||n===m?.lease_owner||n===O,_=t===f.id||t===w;if(m?.id&&W&&_)return null}if(p.sessionId===t||t===f.id||v)return {code:"DELIVERY_AUTHORITY_REQUIRED",caseId:f.id,stage:y,message:`Delivery case ${f.id} is ${y}; use the Delivery task lease before modifying files.`}}}let d=u.sort((f,p)=>p.updatedAt-f.updatedAt)[0],g=typeof d?.payload.stage=="string"?d.payload.stage:void 0;return d&&g&&wn.has(g)?{code:"DELIVERY_AUTHORITY_REQUIRED",caseId:d.id,stage:g,message:`Delivery case ${d.id} is ${g}; start a new Delivery case or session before modifying files.`}:null}catch{return {code:"DELIVERY_AUTHORITY_UNAVAILABLE",caseId:"unknown",stage:"unknown",message:"Delivery state cannot be read; file writes are blocked until runtime health is restored."}}finally{s?.close();}}function T(){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow"}}}function Ve(i){return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:i}}}function Fn(i){let t=E(i);return existsSync(t)||mkdirSync(t,{recursive:true}),t}function Ln(i,t,e,n,o,r){let s=join$1(Fn(i),"event-map.json"),c=[];try{existsSync(s)&&(c=JSON.parse(readFileSync(s,"utf-8")));}catch{}c.push({sessionId:t,toolName:e,toolUseId:n,eventId:o,timestamp:r}),writeFileSync(s,JSON.stringify(c));}function jn(i){switch(i){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 Pn(i){let t=Se();try{if(!i||i.trim()==="")return T();let e=JSON.parse(i),n=Date.now();try{maybeRunDiagnosticLogCleanup(C(),{now:n});}catch{}let o=C(),r=new $,s=resolveClaudeToolName(e.tool_name,e.tool_input),c=s.status==="unsupported"?void 0:s.canonicalName;c&&(typeof e.tool_input.projectRoot!="string"||!e.tool_input.projectRoot.trim())&&(e.tool_input.projectRoot=o);let a=e.session_id?.trim();if(!a)return Ve(Y);let l=new D(o),u=l.get(a)!==null;if(l.registerSession(a),u||await r.sendSessionStart(a,o,Date.now()),e.tool_name==="Skill"){let b=e.tool_input?.skill,h=b?Oe(b):null;if(h){let R=l.get(a)?.executionId,A=l.startExecution(a,h,ue(h));A.executionId&&A.executionId!==R&&await r.sendExecutionStart(A.executionId,a,h,A.lastActivityAt,o,A.requiredMcpTools);}}let d=l.get(a);c==="get_project_context"&&l.beginContextInitialization(a,e.tool_use_id),c&&(e.tool_input._devflow_session_id=a,e.tool_input._devflow_execution_id=d?.executionId??a,d?.activeTurnId&&(e.tool_input._devflow_turn_id=d.activeTurnId),d?.activeRequestId&&(e.tool_input._devflow_request_id=d.activeRequestId),d?.intentArtifactHash&&(e.tool_input._devflow_intent_artifact_hash=d.intentArtifactHash),d?.skillName&&(e.tool_input._devflow_active_skill=d.skillName),e.tool_use_id&&(e.tool_input._devflow_tool_use_id=e.tool_use_id));let g=e.tool_name.startsWith("mcp__"),f=c,p=l.get(a),v=new H(o,a,p?.executionId),y=v.getPhase(),m,w,O=ee(o,a,e.tool_name,p?.executionId,e.tool_input);if(O)w=O.code,m={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:`${O.message} Resolve the case blocker or obtain an authorized task lease before retrying.`}};else {let b=Pe({toolName:e.tool_name,toolInput:e.tool_input,projectRoot:o}),h=Ue({projectRoot:o,sessionId:a,executionId:p?.executionId,toolUseId:e.tool_use_id,toolName:e.tool_name,toolInput:e.tool_input}),R=b?{permissionDecision:"deny",reason:b}:h.allowed?v.evaluate(e.tool_name,g):{permissionDecision:"deny",reason:h.reason,reasonCode:h.reasonCode};R.permissionDecision==="deny"?(w=b?"DEVFLOW_CANONICAL_MEMORY_REQUIRED":R.reasonCode??"DEVFLOW_CONTEXT_REQUIRED",m={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:R.reason??"MCP context required"}}):R.additionalContext?m=Ve(R.additionalContext):m=T();}c&&(m.hookSpecificOutput.updatedInput=e.tool_input),t&&m.hookSpecificOutput.permissionDecision==="allow"&&(m.hookSpecificOutput.additionalContext=Y);let W=p?.executionId??a,_={eventId:Ae(a,e.tool_use_id),executionId:W,sessionId:a,projectRoot:o,toolUseId:e.tool_use_id,timestamp:Date.now(),toolName:e.tool_name,toolType:g?"mcp":e.tool_name==="Agent"?"subagent":"direct",isMcpTool:g,mcpToolName:f,mcpEnforced:g&&(y==="context_gathering"||y==="context_initializing"),mcpFallback:!g&&(y==="context_gathering"||y==="context_initializing"),kind:jn(e.tool_name),input:e.tool_input,duration:0,blocked:m.hookSpecificOutput.permissionDecision==="deny",blockReason:m.hookSpecificOutput.permissionDecision==="deny"?w??"DEVFLOW_CONTEXT_REQUIRED":void 0},F=await r.sendEvent(_);F&&!_.blocked&&Ln(o,a,e.tool_name,e.tool_use_id,F,_.timestamp),F&&_.blocked&&await r.completeEvent({eventId:F,sessionId:a,error:w??"DEVFLOW_CONTEXT_REQUIRED",duration:Date.now()-_.timestamp,completedAt:Date.now()});try{let b=xe(o),h={ts:n,tool:e.tool_name,sessionId:a,skill:d?.skillName??"(none)",requiredTools:d?.requiredMcpTools??[],isMcp:g,enforce:d?.executionId!==void 0,stateless:d?.executionId===void 0&&!g&&e.tool_name!=="Skill",bypassCount:b.bypassCount??0,decision:m.hookSpecificOutput.permissionDecision,env_CLAUDE_PLUGIN_ROOT:process.env.CLAUDE_PLUGIN_ROOT??"(unset)",cwd:process.cwd()};ke(De(o),`${JSON.stringify(h)}
4
+ `);}catch{}return m}catch{try{let e=JSON.parse(i),n=C(),o=ee(n,String(e.session_id??""),String(e.tool_name??""),void 0,e.tool_input);if(o)return {hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:o.message}}}catch{}return T()}}if(process.argv[1]?.endsWith("pre-tool-use")||process.argv[1]?.endsWith("pre-tool-use.js")){let i=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 Pn(t);i(JSON.stringify(e));}),process.stdin.on("error",()=>{i(JSON.stringify(T())),process.exit(0);}),setTimeout(()=>{i(JSON.stringify(T())),process.exit(0);},4e3).unref();}export{Pn as handlePreToolUse};
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/claude-code-plugin",
3
- "version": "0.18.33",
3
+ "version": "0.18.34",
4
4
  "description": "Claude Code hooks and skills for the DevFlow development intelligence runtime.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -12,20 +12,20 @@
12
12
  "verify:runtime-dependencies": "node --import tsx scripts/verify-runtime-dependencies.ts"
13
13
  },
14
14
  "dependencies": {
15
- "@devflow-tools/benchmark": "0.18.33",
16
- "@devflow-tools/context-engine": "0.18.33",
17
- "@devflow-tools/database": "0.18.33",
18
- "@devflow-tools/mcp-server": "0.18.33",
19
- "@devflow-tools/memory-engine": "0.18.33",
20
- "@devflow-tools/sdk": "0.18.33",
21
- "@devflow-tools/semantic-engine": "0.18.33",
22
- "@devflow-tools/server": "0.18.33",
23
- "@devflow-tools/task-runtime": "0.18.33",
24
- "@devflow-tools/telemetry": "0.18.33",
25
- "@devflow-tools/workflow-engine": "0.18.33"
15
+ "@devflow-tools/benchmark": "0.18.34",
16
+ "@devflow-tools/context-engine": "0.18.34",
17
+ "@devflow-tools/database": "0.18.34",
18
+ "@devflow-tools/mcp-server": "0.18.34",
19
+ "@devflow-tools/memory-engine": "0.18.34",
20
+ "@devflow-tools/sdk": "0.18.34",
21
+ "@devflow-tools/semantic-engine": "0.18.34",
22
+ "@devflow-tools/server": "0.18.34",
23
+ "@devflow-tools/task-runtime": "0.18.34",
24
+ "@devflow-tools/telemetry": "0.18.34",
25
+ "@devflow-tools/workflow-engine": "0.18.34"
26
26
  },
27
27
  "devDependencies": {
28
- "@devflow-tools/devflow": "0.18.33"
28
+ "@devflow-tools/devflow": "0.18.34"
29
29
  },
30
30
  "allowScripts": {
31
31
  "better-sqlite3@12.11.1": true,
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: devflow:approve
3
+ description: Approve the current DevFlow artifact through the trusted user channel
4
+ argument-hint: <decision-id>
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ /devflow:approve $ARGUMENTS
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: devflow:decide
3
+ description: Resolve the current DevFlow clarification through the trusted user channel
4
+ argument-hint: <decision-id> <option-id> | <decision-id> -- <answer>
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ /devflow:decide $ARGUMENTS
@@ -44,8 +44,8 @@ description: 通过可审计 Delivery Line 将需求推进到验证完成的 int
44
44
  - 如果 pending decision 的 `options` 为空,这是自由文本澄清,不要伪造选择项。要求用户在同一 Claude 会话提交规范命令:`/devflow:decide <decisionId> -- <answer>`;host hook 会签名该 `UserPromptSubmit` 并消费 pending decision。
45
45
  - 如果一个澄清问题本身适合有限选项但当前 `options` 为空,先调用 `delivery_propose_options` 提交至少两个带稳定 `id`/`label` 的候选,再使用上述 `AskUserQuestion` 流程。
46
46
  - 无论哪种可信用户通道,命令或交互处理成功后都必须重新调用 `delivery_status`,以返回的 `currentTurn` 和 `nextActions` 继续。
47
- - `/devflow:approve`、`/devflow:reject`、`/devflow:revise`、`/devflow:cancel` `/devflow:exit` 目前仍走对应的 gated Delivery 操作;不要把它们当作澄清答案,也不要通过普通 MCP mutation 模拟可信用户事件。
48
- - 只有用户明确同意时才能调用 `mcp__plugin_devflow_devflow__delivery_approve`;不得代替用户批准。
47
+ - artifact 审批只使用 `delivery_status.pendingDecisions` 返回的精确 `command`,格式为 `/devflow:approve <decisionId>`;拒绝格式为 `/devflow:reject <decisionId> -- <reason>`。不得省略 decisionId,不得使用普通 `AskUserQuestion` 代替 artifact 审批,也不得由 agent 调用 MCP mutation 模拟用户批准或拒绝。
48
+ - `/devflow:revise`、`/devflow:cancel` 和 `/devflow:exit` 尚未注册为可信命令;仅使用当前 `nextActions` 已实现的路径,不得向用户展示不存在的命令。
49
49
  - 审批返回后不要结束会话:立即读取同一次返回的 `stage` 和 `nextActions`,按其允许的下一步继续推进;只有 `nextActions` 为空或用户明确暂停时才结束。
50
50
  - `mcp__plugin_devflow_devflow__delivery_advance` 用于推进已满足的状态,`mcp__plugin_devflow_devflow__delivery_resume` 只恢复已经具备运行条件的 gate 或 task。
51
51
  - 失败任务只通过 `mcp__plugin_devflow_devflow__delivery_retry_task` 重试;取消和导出分别使用 `mcp__plugin_devflow_devflow__delivery_cancel` 与 `mcp__plugin_devflow_devflow__delivery_export`。
@@ -54,7 +54,7 @@ description: 通过可审计 Delivery Line 将需求推进到验证完成的 int
54
54
  ## 可用操作
55
55
 
56
56
  - 澄清和设计:`delivery_propose_options`、`delivery_answer`、`delivery_revise`、`delivery_compare_options`
57
- - Gate 决策:`delivery_approve`、`delivery_reject`
57
+ - Gate 决策:向用户展示 `pendingDecisions[].command`;用户通过 `/devflow:approve` 或 `/devflow:reject` 决策
58
58
  - 状态和执行:`delivery_status`、`delivery_advance`、`delivery_resume`、`delivery_retry_task`
59
59
  - 外部变更:`delivery_import_external_change`
60
60
  - 交付收尾:`delivery_export`、`delivery_cancel`
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: devflow:reject
3
+ description: Reject the current DevFlow artifact through the trusted user channel
4
+ argument-hint: <decision-id> -- <reason>
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ /devflow:reject $ARGUMENTS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devflow-tools/cli",
3
- "version": "0.18.33",
3
+ "version": "0.18.34",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "devflow": "./bin/devflow.cjs"
@@ -14,38 +14,38 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@colbymchenry/codegraph": "^1.1.1",
17
- "@devflow-tools/adapters": "0.18.33",
18
- "@devflow-tools/benchmark": "0.18.33",
19
- "@devflow-tools/context-engine": "0.18.33",
20
- "@devflow-tools/database": "0.18.33",
21
- "@devflow-tools/delivery-line": "0.18.33",
22
- "@devflow-tools/knowledge-engine": "0.18.33",
23
- "@devflow-tools/mcp-server": "0.18.33",
24
- "@devflow-tools/memory-engine": "0.18.33",
25
- "@devflow-tools/plugin-animation": "0.18.33",
26
- "@devflow-tools/plugin-css": "0.18.33",
27
- "@devflow-tools/plugin-docker": "0.18.33",
28
- "@devflow-tools/plugin-electron": "0.18.33",
29
- "@devflow-tools/plugin-git": "0.18.33",
30
- "@devflow-tools/plugin-graphql": "0.18.33",
31
- "@devflow-tools/plugin-nest": "0.18.33",
32
- "@devflow-tools/plugin-nextjs": "0.18.33",
33
- "@devflow-tools/plugin-performance": "0.18.33",
34
- "@devflow-tools/plugin-react": "0.18.33",
35
- "@devflow-tools/plugin-tailwind": "0.18.33",
36
- "@devflow-tools/plugin-taro": "0.18.33",
37
- "@devflow-tools/plugin-ui-layout": "0.18.33",
38
- "@devflow-tools/plugin-vue": "0.18.33",
39
- "@devflow-tools/sdk": "0.18.33",
40
- "@devflow-tools/server": "0.18.33",
41
- "@devflow-tools/telemetry": "0.18.33",
42
- "@devflow-tools/workflow-engine": "0.18.33",
17
+ "@devflow-tools/adapters": "0.18.34",
18
+ "@devflow-tools/benchmark": "0.18.34",
19
+ "@devflow-tools/context-engine": "0.18.34",
20
+ "@devflow-tools/database": "0.18.34",
21
+ "@devflow-tools/delivery-line": "0.18.34",
22
+ "@devflow-tools/knowledge-engine": "0.18.34",
23
+ "@devflow-tools/mcp-server": "0.18.34",
24
+ "@devflow-tools/memory-engine": "0.18.34",
25
+ "@devflow-tools/plugin-animation": "0.18.34",
26
+ "@devflow-tools/plugin-css": "0.18.34",
27
+ "@devflow-tools/plugin-docker": "0.18.34",
28
+ "@devflow-tools/plugin-electron": "0.18.34",
29
+ "@devflow-tools/plugin-git": "0.18.34",
30
+ "@devflow-tools/plugin-graphql": "0.18.34",
31
+ "@devflow-tools/plugin-nest": "0.18.34",
32
+ "@devflow-tools/plugin-nextjs": "0.18.34",
33
+ "@devflow-tools/plugin-performance": "0.18.34",
34
+ "@devflow-tools/plugin-react": "0.18.34",
35
+ "@devflow-tools/plugin-tailwind": "0.18.34",
36
+ "@devflow-tools/plugin-taro": "0.18.34",
37
+ "@devflow-tools/plugin-ui-layout": "0.18.34",
38
+ "@devflow-tools/plugin-vue": "0.18.34",
39
+ "@devflow-tools/sdk": "0.18.34",
40
+ "@devflow-tools/server": "0.18.34",
41
+ "@devflow-tools/telemetry": "0.18.34",
42
+ "@devflow-tools/workflow-engine": "0.18.34",
43
43
  "@inquirer/prompts": "^7.10.1",
44
44
  "chalk": "^5.3.0",
45
45
  "commander": "^12.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@devflow-tools/devflow": "0.18.33",
48
+ "@devflow-tools/devflow": "0.18.34",
49
49
  "typescript": "^5.5.0",
50
50
  "vitest": "^2.0.0"
51
51
  },
@@ -53,7 +53,7 @@
53
53
  "dist",
54
54
  "bin"
55
55
  ],
56
- "gitHead": "0f72e1dea93dca19da4da544d3efe4e6e33a1ac8",
56
+ "gitHead": "4bef753de830e4e881bd150c9b090ab0953139c1",
57
57
  "description": "Command-line interface for DevFlow development intelligence and diagnostics.",
58
58
  "license": "MIT",
59
59
  "repository": {