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