@dezycro-ai/agent-plugin 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gateway/proxy.js +12 -12
- package/dist/hooks/lib/router.js +9 -9
- package/package.json +1 -1
package/dist/gateway/proxy.js
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var Se=Object.create;var z=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var xe=Object.getPrototypeOf,we=Object.prototype.hasOwnProperty;var Re=(n,e)=>{for(var t in e)z(n,t,{get:e[t],enumerable:!0})},oe=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ce(e))!we.call(n,o)&&o!==t&&z(n,o,{get:()=>e[o],enumerable:!(r=ve(e,o))||r.enumerable});return n};var c=(n,e,t)=>(t=n!=null?Se(xe(n)):{},oe(e||!n||!n.__esModule?z(t,"default",{value:n,enumerable:!0}):t,n)),Ee=n=>oe(z({},"__esModule",{value:!0}),n);var Oe={};Re(Oe,{Gateway:()=>F,createGatewayServer:()=>Le});module.exports=Ee(Oe);var ye=c(require("node:http")),ke=c(require("node:fs")),Te=c(require("node:path")),be=require("node:stream");var G=c(require("fs")),se=c(require("os")),g=c(require("path")),J=class n{constructor(e){this.repoRoot=e;this.config=n.readJson(g.join(e,".dezycro","config.json"))}repoRoot;config;static at(e=process.cwd()){return new n(n.findRepoRoot(e)??g.resolve(e))}get workspaceId(){return n.env("DZ_WORKSPACE_ID")??n.str(this.config?.workspaceId)}get tenantId(){return n.env("DZ_TENANT_ID")??n.str(this.config?.tenantId)}get projectId(){return n.str(this.config?.projectId)}get apiUrl(){let e=n.env("DZ_API_URL");if(e)return n.trimSlash(e);let t=Array.isArray(this.config?.environments)?this.config?.environments:[],r=t.find(s=>n.isObj(s)&&s.default===!0)??t[0],o=n.isObj(r)?n.str(r.apiUrl):null;return o?n.trimSlash(o):null}get token(){let e=n.env("DZ_TOKEN");if(e)return e;let t=[g.join(this.repoRoot,".dezycro","companion-token.local.json"),g.join(se.homedir(),".dezycro","token.json")];for(let r of t){let o=n.str(n.readJson(r)?.token);if(o)return o}return null}activeFeature(){let e=n.readJson(g.join(this.repoRoot,".dezycro","active-feature.json")),t=n.str(e?.featureId);if(!t)return null;let r=n.str(e?.workspaceId)??this.workspaceId;return r?{workspaceId:r,featureId:t,active:e?.active===!0}:null}connection(){let e=this.apiUrl;if(!e)return{error:"no apiUrl (set DZ_API_URL or .dezycro/config.json environments[].apiUrl)"};let t=this.workspaceId;if(!t)return{error:"no workspaceId (set DZ_WORKSPACE_ID or .dezycro/config.json workspaceId)"};let r=this.token;return r?{apiUrl:e,workspaceId:t,token:r}:{error:"no token (run `dezycro setup` or set DZ_TOKEN)"}}static findRepoRoot(e){let t=g.resolve(e||process.cwd());for(let r=0;r<64;r+=1){if(G.existsSync(g.join(t,".dezycro")))return t;let o=g.dirname(t);if(o===t)return null;t=o}return null}static readJson(e){try{return JSON.parse(G.readFileSync(e,"utf8"))}catch{return null}}static isObj(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}static str(e){return typeof e=="string"&&e.length>0?e:null}static env(e){let t=process.env[e];return t&&t.length>0?t:null}static trimSlash(e){return e.replace(/\/$/,"")}};var d={MessageStart:"message_start",ContentBlockStart:"content_block_start",ContentBlockDelta:"content_block_delta",ContentBlockStop:"content_block_stop",MessageDelta:"message_delta",MessageStop:"message_stop"},$={User:"user",Assistant:"assistant",System:"system"},y={Text:"text",ToolUse:"tool_use"},H={Text:"text_delta",InputJson:"input_json_delta"},x={ToolUse:"tool_use",EndTurn:"end_turn"};var ie={UpdateTask:"update_task"},ae={Status:"status"},q={Done:"DONE",Pushed:"PUSHED"};var b={SpecPublished:"specPublished",VerifiedRecently:"verifiedRecently"};var w={Anthropic:"anthropic",OpenAI:"openai"};var X={Health:"/__dz/health",Stop:"/__dz/stop"},R={EventStream:"text/event-stream",Json:"application/json"};var k=class n{constructor(e){this.skills=e}skills;apply(e,t){let r=n.lastUserText(e),o=this.triggeredSkills(r),s=this.build(r);return s&&n.appendToLastUserMessage(e,t,s),{text:s,triggers:o}}triggeredSkills(e){let t=[];for(let r of Object.keys(this.skills??{}))e.includes(r)&&t.push(r);return t}static composition(e){return{toolDefChars:n.toolDefChars(e),systemChars:n.systemChars(e),...n.tailComposition(e)}}static emptyComposition(){return{toolDefChars:0,systemChars:0,tailResultChars:0,tailTextChars:0,freshToolChars:0}}static maxToolResultChars(e){return n.tailComposition(e).freshToolChars}static toolDefChars(e){return Array.isArray(e.tools)&&e.tools.length?JSON.stringify(e.tools).length:0}static systemChars(e){let t=e.system;if(typeof t=="string")return t.length;if(!Array.isArray(t))return 0;let r=0;for(let o of t)o&&typeof o.text=="string"&&(r+=o.text.length);return r}static tailComposition(e){let t=n.lastUserContent(e);if(typeof t=="string")return{tailResultChars:0,tailTextChars:t.length,freshToolChars:0};if(!Array.isArray(t))return{tailResultChars:0,tailTextChars:0,freshToolChars:0};let r=0,o=0,s=0;for(let i of t)if(i)if(i.type==="tool_result"){let a=n.textLength(i.content);r+=a,s=Math.max(s,a)}else typeof i.text=="string"&&(o+=i.text.length);return{tailResultChars:r,tailTextChars:o,freshToolChars:s}}static lastUserContent(e){let t=Array.isArray(e.messages)?e.messages:null;if(!t)return null;let r=t.length-1;for(;r>=0&&t[r].role!==$.User;)r-=1;if(r<0)return null;let o=t[r].content;return typeof o=="string"||Array.isArray(o)?o:null}static textLength(e){if(typeof e=="string")return e.length;if(!Array.isArray(e))return 0;let t=0;for(let r of e)r&&typeof r.text=="string"&&(t+=r.text.length);return t}build(e){let t=[];for(let[r,o]of Object.entries(this.skills??{}))e.includes(r)&&t.push(o);return t.join(`
|
|
2
2
|
`)}static lastUserText(e){let t=Array.isArray(e.messages)?e.messages:null;if(!t)return"";for(let r=t.length-1;r>=0;r-=1){let o=t[r];if(o.role===$.User){if(typeof o.content=="string")return o.content;if(Array.isArray(o.content))return o.content.map(s=>typeof s=="string"?s:"text"in s&&typeof s.text=="string"?s.text:"").join(" ")}}return""}static appendToLastUserMessage(e,t,r){if(!r)return e;let o=Array.isArray(e.messages)?e.messages:null;if(!o||!o.length)return t===w.OpenAI&&typeof e.input=="string"&&(e.input+=`
|
|
3
3
|
|
|
4
4
|
${n.tagged(r)}`),e;let s=o.length-1;for(;s>=0&&o[s].role!==$.User;)s-=1;if(s<0)return e;let i=o[s],a=n.tagged(r);return typeof i.content=="string"?i.content+=`
|
|
5
5
|
|
|
6
6
|
${a}`:Array.isArray(i.content)&&i.content.push({type:y.Text,text:a}),e}static tagged(e){return`<dezycro-companion>
|
|
7
7
|
${e}
|
|
8
|
-
</dezycro-companion>`}};var Q={rules:[{nameIncludes:ie.UpdateTask,inputField:ae.Status,inputValues:[q.Done,q.Pushed],requireAll:[b.SpecPublished,b.VerifiedRecently],reason:"Cannot mark a task DONE/PUSHED yet."}]},
|
|
8
|
+
</dezycro-companion>`}};var Q={rules:[{nameIncludes:ie.UpdateTask,inputField:ae.Status,inputValues:[q.Done,q.Pushed],requireAll:[b.SpecPublished,b.VerifiedRecently],reason:"Cannot mark a task DONE/PUSHED yet."}]},A=class n{constructor(e,t){this.policy=e;this.state=t}policy;state;static STATE_PREDICATES={[b.SpecPublished]:e=>!!e&&e.needsSpecPublish!==!0,[b.VerifiedRecently]:e=>!e||!e.lastVerifyCompletionTs?!1:e.lastEditTs?Date.parse(e.lastVerifyCompletionTs)>=Date.parse(e.lastEditTs):!0};static FAILED_HINT={[b.SpecPublished]:"spec not published (controller/API changed) \u2014 run /dezycro:publish-spec",[b.VerifiedRecently]:"no passing verify since last edit \u2014 run /dezycro:verify"};decide(e,t){for(let r of this.policy?.rules??[]){if(!e||!e.includes(r.nameIncludes))continue;if(r.inputField){let a=t?.[r.inputField],l=(r.inputValues??[]).map(u=>String(u).toUpperCase());if(a==null||!l.includes(String(a).toUpperCase()))continue}let o=r.requireAll??[];if(o.length===0)return this.blocked(e,r.reason);let s=o.filter(a=>!n.STATE_PREDICATES[a]?.(this.state));if(s.length===0)continue;let i=s.map(a=>n.FAILED_HINT[a]||a).join("; ");return this.blocked(e,`${r.reason||"Blocked by Dezycro policy."} ${i}.`)}return null}blocked(e,t){return{toolName:e||"?",detail:t||"Blocked by Dezycro policy."}}};var Ae=new Set([d.ContentBlockStart,d.ContentBlockDelta,d.ContentBlockStop]),m=class n{constructor(e,t){this.name=e;this.data=t}name;data;static parse(e){let t=null,r=null;for(let s of e.split(`
|
|
9
9
|
`))s.startsWith("event:")?t=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());let o=null;try{o=r?JSON.parse(r):null}catch{o=null}return o?new n(t??String(o.type??""),o):null}static parseStream(e){return e.split(`
|
|
10
10
|
|
|
11
|
-
`).filter(t=>t.trim().length>0).map(t=>n.parse(t)).filter(t=>t!==null)}static of(e){return new n(e.type,e)}static toolUseOf(e){return e?.type===y.ToolUse?e:null}get type(){return String(this.data.type??"")}get index(){return Number(this.data.index)}is(e){return this.type===e}get isContentBlockEvent(){return
|
|
11
|
+
`).filter(t=>t.trim().length>0).map(t=>n.parse(t)).filter(t=>t!==null)}static of(e){return new n(e.type,e)}static toolUseOf(e){return e?.type===y.ToolUse?e:null}get type(){return String(this.data.type??"")}get index(){return Number(this.data.index)}is(e){return this.type===e}get isContentBlockEvent(){return Ae.has(this.type)}get toolUse(){return n.toolUseOf(this.data.content_block)}get inputJsonChunk(){let e=this.data.delta;return e?.type===H.InputJson?e.partial_json??"":""}get usage(){let e=this.data.message,t=this.data.usage??e?.usage;return t?{inputTokens:t.input_tokens,outputTokens:t.output_tokens,cacheReadTokens:t.cache_read_input_tokens,cacheCreationTokens:t.cache_creation_input_tokens}:null}get model(){return this.data.message?.model??null}withIndex(e){return new n(this.name,{...this.data,index:e})}withStopReasonEnded(){let e=JSON.parse(JSON.stringify(this.data));return e.delta?.stop_reason===x.ToolUse&&(e.delta.stop_reason=x.EndTurn),new n(this.name,e)}serialize(){return`event: ${this.name}
|
|
12
12
|
data: ${JSON.stringify(this.data)}
|
|
13
13
|
|
|
14
14
|
`}};var B=class{constructor(e){this.reasons=e}reasons;get isEmpty(){return this.reasons.length===0}text(){let e=this.reasons.map(t=>`\u2022 ${t.toolName}: ${t.detail}`).join(`
|
|
15
15
|
`);return`\u26D4 Dezycro blocked ${this.reasons.length} tool call(s):
|
|
16
16
|
${e}
|
|
17
|
-
Do the required step, then retry.`}sseEvents(e){return[m.of({type:d.ContentBlockStart,index:e,content_block:{type:y.Text,text:""}}),m.of({type:d.ContentBlockDelta,index:e,delta:{type:H.Text,text:this.text()}}),m.of({type:d.ContentBlockStop,index:e})].map(t=>t.serialize()).join("")}};var E=class{next=0;mapped=new Map;take(e){let t=this.next++;return this.mapped.set(e,t),t}of(e){return this.mapped.get(e)??e}reserve(){return this.next++}};var T=class{constructor(e){this.engine=e}engine;blockedReasons=[];sawAllowedToolUse=!1;judge(e,t){let r=this.engine.decide(e,t);return r?(this.blockedReasons.push(r),!0):(this.sawAllowedToolUse=!0,!1)}parseToolInput(e){try{return e?JSON.parse(e):{}}catch{return{}}}get denial(){return new B(this.blockedReasons)}get blockedCount(){return this.blockedReasons.length}};var
|
|
17
|
+
Do the required step, then retry.`}sseEvents(e){return[m.of({type:d.ContentBlockStart,index:e,content_block:{type:y.Text,text:""}}),m.of({type:d.ContentBlockDelta,index:e,delta:{type:H.Text,text:this.text()}}),m.of({type:d.ContentBlockStop,index:e})].map(t=>t.serialize()).join("")}};var E=class{next=0;mapped=new Map;take(e){let t=this.next++;return this.mapped.set(e,t),t}of(e){return this.mapped.get(e)??e}reserve(){return this.next++}};var T=class{constructor(e){this.engine=e}engine;blockedReasons=[];sawAllowedToolUse=!1;judge(e,t){let r=this.engine.decide(e,t);return r?(this.blockedReasons.push(r),!0):(this.sawAllowedToolUse=!0,!1)}parseToolInput(e){try{return e?JSON.parse(e):{}}catch{return{}}}get denial(){return new B(this.blockedReasons)}get blockedCount(){return this.blockedReasons.length}};var D=class extends T{rewrite(e){try{if(!e||!Array.isArray(e.content))return e;let t=e.content.filter(o=>{let s=m.toolUseOf(o);return s?!this.judge(s.name,s.input??{}):!0}),r=this.denial;return r.isEmpty||(t.push({type:y.Text,text:r.text()}),e.content=t,!this.sawAllowedToolUse&&e.stop_reason===x.ToolUse&&(e.stop_reason=x.EndTurn)),e}catch{return e}}};var I=class extends T{pending="";remapper=new E;openTool=null;denialEmitted=!1;push(e){this.pending+=e;let t="",r;for(;(r=this.pending.indexOf(`
|
|
18
18
|
|
|
19
19
|
`))!==-1;){let o=this.pending.slice(0,r);this.pending=this.pending.slice(r+2),o.trim()&&(t+=this.handle(o))}return t}flush(){let e="";return this.pending.trim()&&(e+=this.handle(this.pending),this.pending=""),e+this.emitDenialIfNeeded()}handle(e){let t=m.parse(e);if(!t)return`${e}
|
|
20
20
|
|
|
21
|
-
`;switch(t.type){case d.ContentBlockStart:return this.onBlockStart(t);case d.ContentBlockDelta:return this.onBlockDelta(t);case d.ContentBlockStop:return this.onBlockStop(t);case d.MessageDelta:return this.emitDenialIfNeeded()+(this.sawAllowedToolUse?t:t.withStopReasonEnded()).serialize();default:return t.serialize()}}onBlockStart(e){let t=e.toolUse;return t?(this.openTool={originalIndex:e.index,toolName:t.name,inputJson:"",bufferedEvents:[e]},""):e.withIndex(this.remapper.take(e.index)).serialize()}onBlockDelta(e){return this.openTool&&e.index===this.openTool.originalIndex?(this.openTool.inputJson+=e.inputJsonChunk,this.openTool.bufferedEvents.push(e),""):e.withIndex(this.remapper.of(e.index)).serialize()}onBlockStop(e){return this.openTool&&e.index===this.openTool.originalIndex?this.closeOpenTool(e):e.withIndex(this.remapper.of(e.index)).serialize()}closeOpenTool(e){let t=this.openTool;if(this.openTool=null,this.judge(t.toolName,this.parseToolInput(t.inputJson)))return"";let r=this.remapper.take(t.originalIndex);return t.bufferedEvents.map(s=>s.withIndex(r).serialize()).join("")+e.withIndex(r).serialize()}emitDenialIfNeeded(){let e=this.denial;return e.isEmpty||this.denialEmitted?"":(this.denialEmitted=!0,e.sseEvents(this.remapper.reserve()))}};var
|
|
22
|
-
`}static stringify(e){return typeof e=="string"?e:(0,
|
|
21
|
+
`;switch(t.type){case d.ContentBlockStart:return this.onBlockStart(t);case d.ContentBlockDelta:return this.onBlockDelta(t);case d.ContentBlockStop:return this.onBlockStop(t);case d.MessageDelta:return this.emitDenialIfNeeded()+(this.sawAllowedToolUse?t:t.withStopReasonEnded()).serialize();default:return t.serialize()}}onBlockStart(e){let t=e.toolUse;return t?(this.openTool={originalIndex:e.index,toolName:t.name,inputJson:"",bufferedEvents:[e]},""):e.withIndex(this.remapper.take(e.index)).serialize()}onBlockDelta(e){return this.openTool&&e.index===this.openTool.originalIndex?(this.openTool.inputJson+=e.inputJsonChunk,this.openTool.bufferedEvents.push(e),""):e.withIndex(this.remapper.of(e.index)).serialize()}onBlockStop(e){return this.openTool&&e.index===this.openTool.originalIndex?this.closeOpenTool(e):e.withIndex(this.remapper.of(e.index)).serialize()}closeOpenTool(e){let t=this.openTool;if(this.openTool=null,this.judge(t.toolName,this.parseToolInput(t.inputJson)))return"";let r=this.remapper.take(t.originalIndex);return t.bufferedEvents.map(s=>s.withIndex(r).serialize()).join("")+e.withIndex(r).serialize()}emitDenialIfNeeded(){let e=this.denial;return e.isEmpty||this.denialEmitted?"":(this.denialEmitted=!0,e.sseEvents(this.remapper.reserve()))}};var ce=require("node:util"),pe=require("tslog");var V=c(require("node:fs")),le=c(require("node:os")),S=c(require("node:path")),Be="DZ_LOG_DIR",U=class n{stream;constructor(e){this.stream=n.open(e)}static dir(){let e=process.env[Be];if(e)return e;let t=le.homedir();switch(process.platform){case"win32":return S.join(process.env.LOCALAPPDATA||S.join(t,"AppData","Local"),"Dezycro","logs");case"darwin":return S.join(t,"Library","Logs","Dezycro");default:return S.join(process.env.XDG_STATE_HOME||S.join(t,".local","state"),"dezycro","logs")}}write(e){(this.stream??process.stderr).write(e)}static open(e){try{let t=n.dir();return V.mkdirSync(t,{recursive:!0}),V.createWriteStream(S.join(t,`${e}.log`),{flags:"a"})}catch{return null}}};var ee={silly:0,trace:1,debug:2,info:3,warn:4,error:5,fatal:6},W=3,te="DZ_LOG_LEVEL";var De="{{dateIsoStr}} {{logLevelName}} [{{name}}] ",L=class n{constructor(e,t=new U(e),r=n.resolveMinLevel(process.env[te])){this.tag=e;this.impl=new pe.Logger({name:e,type:"pretty",minLevel:r,stylePrettyLogs:!1,prettyLogTimeZone:"UTC",prettyLogTemplate:De,hideLogPositionForProduction:!0,overwrite:{transportFormatted:(o,s,i)=>t.write(n.format(o,s,i))}})}tag;impl;silly(...e){this.impl.silly(...e)}trace(...e){this.impl.trace(...e)}debug(...e){this.impl.debug(...e)}info(...e){this.impl.info(...e)}warn(...e){this.impl.warn(...e)}error(...e){this.impl.error(...e)}fatal(...e){this.impl.fatal(...e)}static resolveMinLevel(e){return e?ee[e.trim().toLowerCase()]??W:W}static format(e,t,r){return`${[e.trimEnd(),...t.map(n.stringify),...r].join(" ")}
|
|
22
|
+
`}static stringify(e){return typeof e=="string"?e:(0,ce.inspect)(e,{depth:3,breakLength:1/0})}};var Y=c(require("node:fs")),de=c(require("node:path"));var ue=c(require("node:fs")),v=c(require("node:path")),Z=class n{static MAX_DEPTH=6;static dir(){let e=__dirname;for(let t=0;t<n.MAX_DEPTH;t+=1){if(ue.existsSync(v.join(e,"package.json")))return e;e=v.dirname(e)}return v.resolve(__dirname,"..","..")}static file(...e){return v.join(n.dir(),...e)}};var O=class n{constructor(e=n.defaultDir()){this.dir=e}dir;load(){return Promise.resolve(n.scan(this.dir))}static defaultDir(){return Z.file("skills")}static scan(e){let t={},r;try{r=Y.readdirSync(e,{withFileTypes:!0})}catch{return t}for(let o of r){if(!o.isDirectory())continue;let s=de.join(e,o.name,"SKILL.md"),i;try{i=Y.readFileSync(s,"utf8")}catch{continue}let{name:a,body:l}=n.parseSkill(i),u=a||o.name;t[`/dezycro:${u}`]=n.instructionFor(u,l)}return t}static parseSkill(e){if(e.startsWith("---")){let t=e.indexOf(`
|
|
23
23
|
---`,3);if(t!==-1){let r=e.slice(3,t),o=e.slice(t+4).trimStart();return{name:n.frontmatterName(r),body:o}}}return{name:null,body:e}}static frontmatterName(e){let t="name:";for(let r of e.split(`
|
|
24
24
|
`)){let o=r.trim();if(o.startsWith(t))return o.slice(t.length).trim()||null}return null}static instructionFor(e,t){return`The user invoked the Dezycro \`/dezycro:${e}\` command. Your harness may not support it natively \u2014 follow these instructions:
|
|
25
25
|
|
|
26
|
-
${t}`}};var
|
|
27
|
-
`)}catch{}}static prepare(e){if(!n.enabled())return null;try{let t=n.dir();return K.mkdirSync(t,{recursive:!0}),C.join(t,`${e}.jsonl`)}catch{return null}}};var
|
|
26
|
+
${t}`}};var P=class{constructor(e){this.sources=e}sources;async load(){return(await Promise.all(this.sources.map(t=>t.load()))).reduce((t,r)=>({...t,...r}),{})}};var K=c(require("node:fs")),me=c(require("node:os")),C=c(require("node:path")),Ie="DZ_METRICS_DIR",Ue="DZ_METRICS",h=class n{file;constructor(e="gateway"){this.file=n.prepare(e)}static enabled(){return process.env[Ue]!=="0"}static dir(){let e=process.env[Ie];if(e)return e;let t=me.homedir();switch(process.platform){case"win32":return C.join(process.env.LOCALAPPDATA||C.join(t,"AppData","Local"),"Dezycro","metrics");case"darwin":return C.join(t,"Library","Application Support","Dezycro","metrics");default:return C.join(process.env.XDG_STATE_HOME||C.join(t,".local","state"),"dezycro","metrics")}}record(e){if(this.file)try{K.appendFileSync(this.file,`${JSON.stringify({ts:new Date().toISOString(),...e})}
|
|
27
|
+
`)}catch{}}static prepare(e){if(!n.enabled())return null;try{let t=n.dir();return K.mkdirSync(t,{recursive:!0}),C.join(t,`${e}.jsonl`)}catch{return null}}};var N=class{pending="";modelId=null;totals={inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0};feed(e){this.pending+=e;let t=this.pending.indexOf(`
|
|
28
28
|
|
|
29
29
|
`);for(;t!==-1;)this.observe(this.pending.slice(0,t)),this.pending=this.pending.slice(t+2),t=this.pending.indexOf(`
|
|
30
30
|
|
|
31
|
-
`)}get model(){return this.modelId}get usage(){return{...this.totals}}observe(e){let t=m.parse(e);if(!t)return;this.modelId??=t.model;let r=t.usage;r&&(r.inputTokens!=null&&(this.totals.inputTokens=r.inputTokens),r.outputTokens!=null&&(this.totals.outputTokens=r.outputTokens),r.cacheReadTokens!=null&&(this.totals.cacheReadTokens=r.cacheReadTokens),r.cacheCreationTokens!=null&&(this.totals.cacheCreationTokens=r.cacheCreationTokens))}};var
|
|
32
|
-
`))}static aggregate(e){let t=n.empty();for(let r of e){let o=n.parse(r);o&&(o.type==="turn"?n.addTurn(t,o):o.type==="compaction"&&n.addCompaction(t,o),n.trackTime(t,o.ts))}return t}static addTurn(e,t){e.turns+=1,e.inputTokens+=n.num(t.inputTokens),e.outputTokens+=n.num(t.outputTokens),e.cacheReadTokens+=n.num(t.cacheReadTokens),e.cacheCreationTokens+=n.num(t.cacheCreationTokens),e.totalDurationMs+=n.num(t.durationMs),e.gateBlocks+=n.num(t.blockedToolCalls);let r=n.num(t.freshToolChars);if(e.maxFreshToolChars=Math.max(e.maxFreshToolChars,r),r>n.BIG_TOOL_CHARS&&(e.bigToolTurns+=1),e.maxToolDefChars=Math.max(e.maxToolDefChars,n.num(t.toolDefChars)),e.maxSystemChars=Math.max(e.maxSystemChars,n.num(t.systemChars)),e.tailResultChars+=n.num(t.tailResultChars),e.tailTextChars+=n.num(t.tailTextChars),e.maxCacheCreationTokens=Math.max(e.maxCacheCreationTokens,n.num(t.cacheCreationTokens)),typeof t.status=="number"&&t.status!==200&&(e.errorTurns+=1),n.bump(e.models,typeof t.model=="string"?t.model:"(unknown)"),Array.isArray(t.skillsTriggered))for(let o of t.skillsTriggered)n.bump(e.skillsTriggered,String(o))}static addCompaction(e,t){e.compactions+=1,e.charsSaved+=n.num(t.charsSaved),e.estTokensSaved+=n.num(t.estTokensSaved),e.linesElided+=n.num(t.elidedLines),n.bump(e.commands,typeof t.command=="string"?t.command:"(unknown)")}static trackTime(e,t){typeof t=="string"&&((!e.firstTs||t<e.firstTs)&&(e.firstTs=t),(!e.lastTs||t>e.lastTs)&&(e.lastTs=t))}static parse(e){if(!e.trim())return null;try{return JSON.parse(e)}catch{return null}}static bump(e,t){e[t]=(e[t]??0)+1}static num(e){return typeof e=="number"&&Number.isFinite(e)?e:0}static empty(){return{turns:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,totalDurationMs:0,errorTurns:0,gateBlocks:0,maxFreshToolChars:0,bigToolTurns:0,maxToolDefChars:0,maxSystemChars:0,tailResultChars:0,tailTextChars:0,maxCacheCreationTokens:0,models:{},skillsTriggered:{},compactions:0,charsSaved:0,estTokensSaved:0,linesElided:0,commands:{},firstTs:null,lastTs:null}}};var f=c(require("node:fs")),
|
|
31
|
+
`)}get model(){return this.modelId}get usage(){return{...this.totals}}observe(e){let t=m.parse(e);if(!t)return;this.modelId??=t.model;let r=t.usage;r&&(r.inputTokens!=null&&(this.totals.inputTokens=r.inputTokens),r.outputTokens!=null&&(this.totals.outputTokens=r.outputTokens),r.cacheReadTokens!=null&&(this.totals.cacheReadTokens=r.cacheReadTokens),r.cacheCreationTokens!=null&&(this.totals.cacheCreationTokens=r.cacheCreationTokens))}};var fe=c(require("node:fs")),he=c(require("node:path"));var M=class n{static BIG_TOOL_CHARS=4e3;static defaultFile(){return he.join(h.dir(),"gateway.jsonl")}static fromFile(e=n.defaultFile()){let t;try{t=fe.readFileSync(e,"utf8")}catch{return n.empty()}return n.aggregate(t.split(`
|
|
32
|
+
`))}static aggregate(e){let t=n.empty();for(let r of e){let o=n.parse(r);o&&(o.type==="turn"?n.addTurn(t,o):o.type==="compaction"&&n.addCompaction(t,o),n.trackTime(t,o.ts))}return t}static addTurn(e,t){e.turns+=1,e.inputTokens+=n.num(t.inputTokens),e.outputTokens+=n.num(t.outputTokens),e.cacheReadTokens+=n.num(t.cacheReadTokens),e.cacheCreationTokens+=n.num(t.cacheCreationTokens),e.totalDurationMs+=n.num(t.durationMs),e.gateBlocks+=n.num(t.blockedToolCalls);let r=n.num(t.freshToolChars);if(e.maxFreshToolChars=Math.max(e.maxFreshToolChars,r),r>n.BIG_TOOL_CHARS&&(e.bigToolTurns+=1),e.maxToolDefChars=Math.max(e.maxToolDefChars,n.num(t.toolDefChars)),e.maxSystemChars=Math.max(e.maxSystemChars,n.num(t.systemChars)),e.tailResultChars+=n.num(t.tailResultChars),e.tailTextChars+=n.num(t.tailTextChars),e.maxCacheCreationTokens=Math.max(e.maxCacheCreationTokens,n.num(t.cacheCreationTokens)),typeof t.status=="number"&&t.status!==200&&(e.errorTurns+=1),n.bump(e.models,typeof t.model=="string"?t.model:"(unknown)"),Array.isArray(t.skillsTriggered))for(let o of t.skillsTriggered)n.bump(e.skillsTriggered,String(o))}static addCompaction(e,t){e.compactions+=1,e.charsSaved+=n.num(t.charsSaved),e.estTokensSaved+=n.num(t.estTokensSaved),e.linesElided+=n.num(t.elidedLines),n.bump(e.commands,typeof t.command=="string"?t.command:"(unknown)")}static trackTime(e,t){typeof t=="string"&&((!e.firstTs||t<e.firstTs)&&(e.firstTs=t),(!e.lastTs||t>e.lastTs)&&(e.lastTs=t))}static parse(e){if(!e.trim())return null;try{return JSON.parse(e)}catch{return null}}static bump(e,t){e[t]=(e[t]??0)+1}static num(e){return typeof e=="number"&&Number.isFinite(e)?e:0}static empty(){return{turns:0,inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,totalDurationMs:0,errorTurns:0,gateBlocks:0,maxFreshToolChars:0,bigToolTurns:0,maxToolDefChars:0,maxSystemChars:0,tailResultChars:0,tailTextChars:0,maxCacheCreationTokens:0,models:{},skillsTriggered:{},compactions:0,charsSaved:0,estTokensSaved:0,linesElided:0,commands:{},firstTs:null,lastTs:null}}};var f=c(require("node:fs")),ge=c(require("node:path")),j=class n{apiUrl;workspaceId;token;metricsFile;cursorFile;batchSize;timeoutMs;fetchImpl;constructor(e){this.apiUrl=e.apiUrl,this.workspaceId=e.workspaceId,this.token=e.token,this.metricsFile=e.metricsFile,this.cursorFile=e.cursorFile,this.batchSize=e.batchSize??1e3,this.timeoutMs=e.timeoutMs??15e3,this.fetchImpl=e.fetchImpl??fetch}async upload({dryRun:e=!1}={}){let{lines:t,newOffset:r}=this.readNewLines(),o=n.toBatch(t),s=o.turns.length+o.compactions.length,i={turns:o.turns.length,compactions:o.compactions.length,newOffset:r,sent:!1,dryRun:e};return e?i:s===0?(r!==this.readCursor()&&this.writeCursor(r),i):(await this.postAll(o),this.writeCursor(r),{...i,sent:!0})}static toBatch(e){let t=[],r=[];for(let o of e){let s;try{s=JSON.parse(o)}catch{continue}typeof s.ts=="string"&&(s.type==="turn"?t.push(n.mapTurn(s)):s.type==="compaction"&&r.push(n.mapCompaction(s)))}return{turns:t,compactions:r}}static mapTurn(e){return{timestamp:e.ts,provider:e.provider??null,model:e.model??null,status:e.status??null,durationMs:e.durationMs??null,inputTokens:e.inputTokens??null,outputTokens:e.outputTokens??null,cacheReadTokens:e.cacheReadTokens??null,cacheCreationTokens:e.cacheCreationTokens??null,toolDefChars:e.toolDefChars??null,systemChars:e.systemChars??null,freshToolChars:e.freshToolChars??null,tailResultChars:e.tailResultChars??null,tailTextChars:e.tailTextChars??null,blockedToolCalls:e.blockedToolCalls??null,skillsFired:Array.isArray(e.skillsTriggered)?e.skillsTriggered:[]}}static mapCompaction(e){return{timestamp:e.ts,command:e.command??null,originalChars:e.originalChars??null,outputChars:e.outputChars??null,charsSaved:e.charsSaved??null,estTokensSaved:e.estTokensSaved??null,originalLines:e.originalLines??null,outputLines:e.outputLines??null,elidedLines:e.elidedLines??null}}readNewLines(){let e=this.readCursor(),t;try{t=f.statSync(this.metricsFile).size}catch{return{lines:[],newOffset:e}}if(e>t&&(e=0),e===t)return{lines:[],newOffset:e};let r=f.openSync(this.metricsFile,"r");try{let o=t-e,s=Buffer.alloc(o);f.readSync(r,s,0,o,e);let i=s.toString("utf8"),a=i.lastIndexOf(`
|
|
33
33
|
`);if(a<0)return{lines:[],newOffset:e};let l=i.slice(0,a+1),u=e+Buffer.byteLength(l,"utf8");return{lines:l.split(`
|
|
34
|
-
`).filter(
|
|
35
|
-
`).length} line(s))`),{bodyText:JSON.stringify(r),triggers:s,composition:i}):{bodyText:e,triggers:s,composition:i}}catch{return{bodyText:e,triggers:[],composition:k.emptyComposition()}}}streamResponse(e,t,r,o){t.writeHead(e.status,n.filterResponseHeaders(e.headers));let s=r?new
|
|
34
|
+
`).filter(_=>_.trim().length>0),newOffset:u}}finally{f.closeSync(r)}}readCursor(){try{let e=JSON.parse(f.readFileSync(this.cursorFile,"utf8"));return typeof e.offset=="number"&&e.offset>=0?e.offset:0}catch{return 0}}writeCursor(e){try{f.mkdirSync(ge.dirname(this.cursorFile),{recursive:!0}),f.writeFileSync(this.cursorFile,JSON.stringify({offset:e,uploadedAt:new Date().toISOString()}))}catch{}}async postAll(e){for(let t=0;t<e.turns.length;t+=this.batchSize)await this.postBatch({turns:e.turns.slice(t,t+this.batchSize),compactions:[]});for(let t=0;t<e.compactions.length;t+=this.batchSize)await this.postBatch({turns:[],compactions:e.compactions.slice(t,t+this.batchSize)})}async postBatch(e){let t=`${this.apiUrl}/api/v1/workspaces/${this.workspaceId}/usage-telemetry`,r=new AbortController,o=setTimeout(()=>r.abort(),this.timeoutMs);try{let s=await this.fetchImpl(t,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"content-type":"application/json",accept:"application/json"},body:JSON.stringify(e),signal:r.signal});if(!s.ok)throw new Error(`usage-telemetry upload returned ${s.status}`)}finally{clearTimeout(o)}}};var F=class n{constructor(e,t){this.config=e;this.deps=t;this.injector=new k(t.skills)}config;deps;static UPSTREAMS=[{match:e=>e.startsWith("/v1/messages"),base:"https://api.anthropic.com",provider:w.Anthropic},{match:e=>e.startsWith("/v1/chat/completions")||e.startsWith("/v1/responses")||e.startsWith("/v1/completions"),base:"https://api.openai.com",provider:w.OpenAI}];static HOP_BY_HOP_REQUEST=["host","content-length","connection","accept-encoding","transfer-encoding"];static HOP_BY_HOP_RESPONSE=["content-encoding","content-length","transfer-encoding","connection"];injector;logger=new L("gateway");metrics=new h("gateway");telemetryTimer=null;telemetryUploader=null;static async fromEnv(){let e={port:Number(process.env.PORT||13579),inject:process.env.INJECT==="1",gate:process.env.GATE==="1",capture:process.env.CAPTURE==="1",stateFile:process.env.DZ_STATE_FILE||null},t={skills:await n.loadSkills(),policy:n.loadJson(process.env.DZ_POLICY_FILE)||Q,loadState:()=>n.loadJson(e.stateFile)};return new n(e,t)}static loadSkills(){return new P(n.skillSources()).load()}static skillSources(){return[new O]}createServer(){return ye.createServer((e,t)=>this.handle(e,t))}listen(){let e=this.createServer();return e.on("error",t=>{t.code==="EADDRINUSE"&&(this.logger.warn(`port ${this.config.port} already in use \u2014 a gateway is probably running.`),process.exit(1)),this.logger.error(`server error: ${t.message}`),process.exit(1)}),e.listen(this.config.port,"127.0.0.1",()=>{this.logger.info(`listening on http://127.0.0.1:${this.config.port} (inject=${this.config.inject} gate=${this.config.gate}) skills=${Object.keys(this.deps.skills).length}`)}),this.startTelemetry(),e}startTelemetry(){if(!h.enabled()||process.env.DZ_TELEMETRY==="0")return;let e=J.at(process.cwd()).connection();if("error"in e){this.logger.debug(`telemetry: off (${e.error})`);return}this.telemetryUploader=new j({...e,metricsFile:M.defaultFile(),cursorFile:Te.join(h.dir(),"gateway.upload-cursor.json")});let t=Math.max(3e4,Number(process.env.DZ_TELEMETRY_INTERVAL_MS)||3e5),r=()=>{this.flushTelemetry()};this.telemetryTimer=setInterval(r,t),this.telemetryTimer.unref?.(),setTimeout(r,15e3).unref?.(),this.logger.info(`telemetry: background upload every ${Math.round(t/1e3)}s \u2192 ws ${e.workspaceId}`)}async flushTelemetry(){if(this.telemetryUploader)try{let e=await this.telemetryUploader.upload();e.sent&&this.logger.info(`telemetry: uploaded ${e.turns} turn + ${e.compactions} compaction event(s)`)}catch(e){this.logger.warn(`telemetry upload failed: ${e.message}`)}}handle(e,t){if(this.handleControlPlane(e,t))return;let r=n.pickUpstream(e.url||""),o=[];e.on("data",s=>o.push(s)),e.on("end",()=>this.forward(e,t,r,o))}handleControlPlane(e,t){return e.url===X.Health?(t.writeHead(200,{"content-type":R.Json}),t.end(JSON.stringify({ok:!0,dz:!0,pid:process.pid,port:this.config.port,inject:this.config.inject,gate:this.config.gate})),!0):e.url===X.Stop?(t.writeHead(200,{"content-type":R.Json}),t.end(JSON.stringify({ok:!0,stopping:!0})),this.telemetryTimer&&clearInterval(this.telemetryTimer),this.flushTelemetry().finally(()=>setTimeout(()=>process.exit(0),50)),setTimeout(()=>process.exit(0),3e3).unref?.(),!0):!1}async forward(e,t,r,o){let s=Date.now(),i=Buffer.concat(o),a=[],l=k.emptyComposition();if(this.config.inject&&r&&e.method==="POST"&&i.length){let p=this.injectBody(i.toString("utf8"),r.provider);i=Buffer.from(p.bodyText,"utf8"),a=p.triggers,l=p.composition}let u=process.env.FORCE_UPSTREAM||(r?r.base:"https://api.anthropic.com");try{let p=await fetch(u+e.url,{method:e.method,headers:n.buildForwardHeaders(e.headers),body:["GET","HEAD"].includes(e.method||"")?void 0:i,redirect:"manual"}),_=(p.headers.get("content-type")||"").toLowerCase();if(r?.provider===w.Anthropic&&p.ok&&p.body&&(this.config.gate||h.enabled())){let re=this.config.gate?new A(this.deps.policy,this.deps.loadState()):null,ne={startedAt:s,provider:r.provider,status:p.status,triggers:a,...l};if(_.includes(R.EventStream))return this.streamResponse(p,t,re,ne);if(_.includes(R.Json))return this.jsonResponse(p,t,re,ne)}t.writeHead(p.status,n.filterResponseHeaders(p.headers)),p.body?n.webToNode(p.body).pipe(t):t.end()}catch(p){this.logger.error(`upstream error: ${p.message}`),t.writeHead(502,{"content-type":R.Json}),t.end(JSON.stringify({error:"gateway upstream failed",detail:String(p)}))}}injectBody(e,t){try{let r=JSON.parse(e),{text:o,triggers:s}=this.injector.apply(r,t),i=h.enabled()?k.composition(r):k.emptyComposition();return o?(this.logger.debug(`-> ${t} injected(${o.split(`
|
|
35
|
+
`).length} line(s))`),{bodyText:JSON.stringify(r),triggers:s,composition:i}):{bodyText:e,triggers:s,composition:i}}catch{return{bodyText:e,triggers:[],composition:k.emptyComposition()}}}streamResponse(e,t,r,o){t.writeHead(e.status,n.filterResponseHeaders(e.headers));let s=r?new I(r):null,i=h.enabled()?new N:null,a=n.webToNode(e.body);a.setEncoding("utf8"),a.on("data",l=>{if(i&&i.feed(l),!s){t.write(l);return}try{let u=s.push(l);u&&t.write(u)}catch{t.write(l)}}),a.on("end",()=>{if(s)try{let l=s.flush();l&&t.write(l)}catch{}t.end(),this.recordTurn(o,i,s)}),a.on("error",()=>{try{t.end()}catch{}this.recordTurn(o,i,s)})}async jsonResponse(e,t,r,o){let s=await e.text(),i=s,a=null,l={model:null,usage:{}};try{let u=JSON.parse(s);l={model:u.model??null,usage:n.usageOf(u)},r&&(a=new D(r),i=JSON.stringify(a.rewrite(u)))}catch{i=s}a&&i!==s&&this.logger.info("\u26D4 gate rewrote response (blocked tool_use)"),t.writeHead(e.status,n.filterResponseHeaders(e.headers)),t.end(i),this.recordTurn(o,l,a)}recordTurn(e,t,r){let o=t?.usage??{};this.metrics.record({type:"turn",provider:e.provider,model:t?.model??null,durationMs:Date.now()-e.startedAt,status:e.status,inputTokens:o.inputTokens,outputTokens:o.outputTokens,cacheReadTokens:o.cacheReadTokens,cacheCreationTokens:o.cacheCreationTokens,skillsTriggered:e.triggers.length?e.triggers:void 0,blockedToolCalls:r?r.blockedCount:void 0,gated:r?r.blockedCount>0:void 0,freshToolChars:e.freshToolChars||void 0,toolDefChars:e.toolDefChars||void 0,systemChars:e.systemChars||void 0,tailResultChars:e.tailResultChars||void 0,tailTextChars:e.tailTextChars||void 0})}static usageOf(e){let t=e.usage;return t?{inputTokens:t.input_tokens,outputTokens:t.output_tokens,cacheReadTokens:t.cache_read_input_tokens,cacheCreationTokens:t.cache_creation_input_tokens}:{}}static pickUpstream(e){return n.UPSTREAMS.find(t=>t.match(e))??null}static buildForwardHeaders(e){let t={};for(let[r,o]of Object.entries(e))n.HOP_BY_HOP_REQUEST.includes(r.toLowerCase())||(typeof o=="string"?t[r]=o:Array.isArray(o)&&(t[r]=o.join(", ")));return t}static filterResponseHeaders(e){let t={};return e.forEach((r,o)=>{n.HOP_BY_HOP_RESPONSE.includes(o.toLowerCase())||(t[o]=r)}),t}static webToNode(e){return be.Readable.fromWeb(e)}static loadJson(e){try{return e?JSON.parse(ke.readFileSync(e,"utf8")):null}catch{return null}}};function Le(n,e){return new F(n,e).createServer()}require.main===module&&F.fromEnv().then(n=>n.listen());0&&(module.exports={Gateway,createGatewayServer});
|
package/dist/hooks/lib/router.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`;j.appendFileSync(
|
|
3
|
-
`)}function
|
|
4
|
-
`)}renderEvent(
|
|
5
|
-
`),!0}catch{return!1}}clear(){try{if(x.existsSync(this.file))return x.unlinkSync(this.file),!0}catch{}return!1}};var
|
|
1
|
+
"use strict";var lt=Object.create;var F=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var pt=Object.getOwnPropertyNames;var ft=Object.getPrototypeOf,gt=Object.prototype.hasOwnProperty;var mt=(t,e)=>{for(var n in e)F(t,n,{get:e[n],enumerable:!0})},ce=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of pt(e))!gt.call(t,r)&&r!==n&&F(t,r,{get:()=>e[r],enumerable:!(o=dt(e,r))||o.enumerable});return t};var S=(t,e,n)=>(n=t!=null?lt(ft(t)):{},ce(e||!t||!t.__esModule?F(n,"default",{value:t,enumerable:!0}):n,t)),ht=t=>ce(F({},"__esModule",{value:!0}),t);var xn={};mt(xn,{QUALITY_GATE_REASON_PREFIX:()=>Ze,TRIVIAL_TURN_CHAR_DEFAULT_EXPORT:()=>Pn,_extractEditedPaths:()=>yn,_handlePostEdit:()=>Sn,_handleSessionStart:()=>Cn,_handleStop:()=>bn,_handleUpdateTaskGate:()=>kn,_handleUserPromptSubmit:()=>Tn,_handleWorkbookMutation:()=>vn,_readActiveFeatureId:()=>wn,_transcriptCharsSinceLastStop:()=>In,dispatch:()=>sn,shouldSurfaceSpecReminder:()=>st});module.exports=ht(xn);var U=S(require("fs")),Qe=S(require("path"));var B=S(require("fs")),R=S(require("path")),ue=Object.freeze({conservative:{decision:.85,issue:.8,assumption:.9,taskStatus:.9},balanced:{decision:.75,issue:.7,assumption:.8,taskStatus:.85},aggressive:{decision:.6,issue:.55,assumption:.7,taskStatus:.75}}),D=Object.freeze({companion:{autoVerify:{preTaskDone:!0,prePush:!0,postEditPulse:{enabled:!0,threshold:5},autoPublishSpecOnControllerChange:!0,controllerPaths:["**/controllers/**/*.{kt,java,py,go,ts,tsx,js,rs,rb,cs}","**/api/**/*.{kt,java,py,go,ts,tsx,js,rs,rb,cs}"],verifyTimeoutSeconds:300,publishSpecTimeoutSeconds:300},autoWorkbookUpdates:{enabled:!0,preset:"conservative",maxAutoLogsPerTurn:2,maxAutoLogsPerSession:10,undoWindow:"next-turn",thresholds:{decision:null,issue:null,assumption:null,taskStatus:null},trivialTurnCharCutoff:600,hashRingBufferSize:32},coverageNudges:{enabled:!0,staleBaselineDays:14,fetchMode:"async"},authoring:{defaultDepth:"adaptive",existingWorkScan:!0,qualityGate:{enabled:!0},minViableContextGate:{enabled:!0}},safeMode:!1}});function Y(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function le(t,e){if(!Y(e))return e===void 0?t:e;let n=Array.isArray(t)?[...t]:{...t};for(let o of Object.keys(e)){let r=n[o],s=e[o];Y(r)&&Y(s)?n[o]=le(r,s):n[o]=s}return n}function de(t){let e=R.join(t,".dezycro","config.json"),n;try{n=B.readFileSync(e,"utf8")}catch(r){if(r.code==="ENOENT")return JSON.parse(JSON.stringify(D));throw r}let o;try{o=JSON.parse(n)}catch{return JSON.parse(JSON.stringify(D))}return le(JSON.parse(JSON.stringify(D)),o)}function pe(t){let e=t?.companion?.autoWorkbookUpdates||{},n=e.preset||"conservative",o=ue[n]||ue.conservative,r=e.thresholds||{};return{decision:typeof r.decision=="number"?r.decision:o.decision,issue:typeof r.issue=="number"?r.issue:o.issue,assumption:typeof r.assumption=="number"?r.assumption:o.assumption,taskStatus:typeof r.taskStatus=="number"?r.taskStatus:o.taskStatus}}function w(t){let e=R.resolve(t||process.cwd());for(let n=0;n<64;n+=1){if(B.existsSync(R.join(e,".dezycro")))return e;let o=R.dirname(e);if(o===e)return null;e=o}return null}var m=S(require("fs")),N=S(require("path")),St=500,kt=10,Q=32,fe=64,ge=Object.freeze({autoDecisionLogs:0,autoIssueLogs:0,autoAssumptionLogs:0,autoTaskStatusLogs:0,undoCount:0,verifyAutoRuns:0,verifyAutoFailures:0,qualityGateFailures:0,contextGateFailures:0,lockContention:0,forceApprovals:0}),bt=Object.freeze({schemaVersion:1,currentSessionId:null,authoringMode:!1,authoringDocId:null,authoringDocType:null,authoringTranscriptPath:null,authoringStartedTs:null,pulseCount:0,lastEditTs:null,needsSpecPublish:!1,controllerEditsSinceLastPublish:[],coverageSnapshot:null,coverageSnapshotTs:null,coverageFetchPending:!1,lastVerifyCompletionTs:null,recentDecisionHashes:[],recentIssueHashes:[],recentAssumptionHashes:[],lastAutoWorkbookMutation:null,sessionAutoLogCount:0,turnAutoLogCount:0,currentTurnId:0,suppressWorkbookUpdatesUntil:null,pendingWorkbookSweep:!1,pendingWorkbookSweepReason:null,lastSeenVerifyCompletionTs:null,commandBus:{cursor:null,lastPollTs:null,lastAttemptTs:null,consecutiveFailures:0,recentEventIds:[]},metrics:ge});function me(t){return N.join(t,".dezycro","companion-state.json")}function he(t){return N.join(t,".dezycro",".companion-state.lock")}function Tt(t){return N.join(t,".dezycro",".companion-state.json.tmp")}function vt(t){m.mkdirSync(N.join(t,".dezycro"),{recursive:!0})}function Z(){return JSON.parse(JSON.stringify(bt))}function k(t){let e=me(t);try{let n=m.readFileSync(e,"utf8"),o=JSON.parse(n);return{...Z(),...o,metrics:{...ge,...o.metrics||{}}}}catch(n){let o=n;return o&&o.code==="ENOENT",Z()}}function Ct(t){let e=he(t),n=Date.now();for(;Date.now()-n<St;){try{let r=m.openSync(e,"wx");return m.writeSync(r,String(process.pid)),m.closeSync(r),!0}catch(r){if(r.code!=="EEXIST")throw r}let o=Date.now()+kt;for(;Date.now()<o;);}return!1}function wt(t){try{m.unlinkSync(he(t))}catch{}}function It(t,e){return e?{...t,...e}:t}function ee(t,e,n){if(!e||t.includes(e))return t;let o=t.concat([e]);return o.length>n?o.slice(o.length-n):o}function l(t,e){if(vt(t),!Ct(t))return null;try{let n=k(t),o=e||{},r={...n};for(let a of Object.keys(o)){let c=o[a];if(a==="metrics")r.metrics=It(n.metrics,c);else if(a==="pushDecisionHash")r.recentDecisionHashes=ee(n.recentDecisionHashes,c,Q);else if(a==="pushIssueHash")r.recentIssueHashes=ee(n.recentIssueHashes,c,Q);else if(a==="pushAssumptionHash")r.recentAssumptionHashes=ee(n.recentAssumptionHashes,c,Q);else if(a==="pushControllerEdit"){let u=c,p=n.controllerEditsSinceLastPublish.filter(h=>h.path!==u.path).concat([u]);r.controllerEditsSinceLastPublish=p.length>fe?p.slice(p.length-fe):p}else r[a]=c}let s=Tt(t),i=m.openSync(s,"w");return m.writeSync(i,JSON.stringify(r,null,2)),m.fsyncSync(i),m.closeSync(i),m.renameSync(s,me(t)),r}finally{wt(t)}}function E(t,e,n=1){let o=k(t).metrics[e]||0;return l(t,{metrics:{[e]:o+n}})}var j=S(require("fs")),ne=S(require("path")),Pt="companion.log";function ye(t,e){try{let n=ne.join(t,".dezycro");if(!j.existsSync(n))return;let o=JSON.stringify({ts:new Date().toISOString(),...e})+`
|
|
2
|
+
`;j.appendFileSync(ne.join(n,Pt),o,{encoding:"utf8"})}catch{}}function g(t,e,n){ye(t,{level:"info",event:e,...n||{}})}function $(t,e,n){ye(t,{level:"warn",event:e,...n||{}})}var ke=S(require("fs")),be=S(require("path"));function Te(t){let e=t||{},n=e.repoRoot,o=typeof e.maxAgeMinutes=="number"?e.maxAgeMinutes:60;if(!n)return!1;let r=be.join(n,".dezycro","state.json"),s;try{let d=ke.readFileSync(r,"utf8");s=JSON.parse(d)}catch{return!1}if(!s||typeof s!="object")return!1;let i=s.lastVerifyTs,a=s.lastVerifyRunId;if(!i||!a)return!1;let c=Date.parse(i);if(!Number.isFinite(c))return!1;let u=Date.now()-c;return!(u<0||u>o*60*1e3)}function ve(t){let e=t||{},n=e.paths||[],o=e.status||"DONE",r=n.length>0?n.join(","):"<paths>";return{reason:"Cannot mark task "+o+" \u2014 no recent passing verifier run found for the linked paths. Run `/dezycro:verify --path "+r+"` first to attach passing verifier evidence, then retry."}}function Ce(t){if(!t)return{needed:!1,controllerPaths:[],lastEditTs:null};let e=k(t),n=Array.isArray(e.controllerEditsSinceLastPublish)?e.controllerEditsSinceLastPublish:[],o=n.map(i=>i&&i.path).filter(Boolean),r=n.length>0&&n[n.length-1].editedTs||null;return{needed:!!e.needsSpecPublish&&o.length>0,controllerPaths:o,lastEditTs:r}}function Rt(t){return String(t||"").replace(/\\/g,"/")}function Ie(t){let e=t.match(/\{([^{}]+)\}/);if(!e||e.index===void 0)return[t];let n=e[0],r=e[1].split(","),s=[];for(let i of r){let a=t.slice(0,e.index)+i+t.slice(e.index+n.length);s.push(...Ie(a))}return s}function _t(t){let e="^";for(let n=0;n<t.length;n+=1){let o=t[n];o==="*"?t[n+1]==="*"?(n+=1,t[n+1]==="/"?(n+=1,e+="(?:.*/)?"):e+=".*"):e+="[^/]*":o==="?"?e+="[^/]":".+^$()|[]\\".indexOf(o)!==-1?e+="\\"+o:e+=o}return e+="$",new RegExp(e)}var we=new Map;function Et(t){let e=we.get(t);if(e)return e;let n=Ie(t).map(_t);return we.set(t,n),n}function Ot(t,e){if(!t||!Array.isArray(e)||e.length===0)return!1;let n=Rt(t);for(let o of e){if(typeof o!="string"||o.length===0)continue;let r=Et(o);for(let s of r)if(s.test(n))return!0}return!1}function Pe(t,e){return Array.isArray(t)?t.filter(n=>Ot(n,e)):[]}var b=S(require("fs")),V=S(require("path"));var xe=Object.freeze({IDLE:"IDLE",DETECT_INTENT:"DETECT_INTENT",SCAN_EXISTING_WORK:"SCAN_EXISTING_WORK",CLARIFY:"CLARIFY",PROPOSE_PLACEMENT:"PROPOSE_PLACEMENT",CREATE_FEATURE:"CREATE_FEATURE",TRD_DISCOVERY:"TRD_DISCOVERY",MIN_CONTEXT_GATE:"MIN_CONTEXT_GATE",DRAFT:"DRAFT",ITERATE:"ITERATE",QUALITY_GATE:"QUALITY_GATE",FINALIZE:"FINALIZE"}),Ae=Object.freeze({PRD:"PRD",TRD:"TRD"}),Rn=Object.freeze(["skip","draft it","just write it","next"]),_n=Object.freeze([xe.MIN_CONTEXT_GATE,xe.QUALITY_GATE]),Nt="authoring-transcript.json",Lt="authoring-current-draft.json";function Re(t){return V.join(t,".dezycro",Nt)}function _e(t){return V.join(t,".dezycro",Lt)}function Mt(t){b.mkdirSync(V.join(t,".dezycro"),{recursive:!0})}function Ht(t,e){let n=`${t}.tmp`,o=b.openSync(n,"w");try{b.writeSync(o,JSON.stringify(e,null,2)),b.fsyncSync(o)}finally{b.closeSync(o)}b.renameSync(n,t)}function Ee(t){try{let e=b.readFileSync(t,"utf8");return JSON.parse(e)}catch{return null}}function Oe(t,e){if(!e||!e.docId||!e.docType)throw new Error("authoring.enter: docId and docType required");if(e.docType!==Ae.PRD&&e.docType!==Ae.TRD)throw new Error(`authoring.enter: invalid docType ${e.docType}`);Mt(t);let n=Re(t),o=new Date().toISOString(),r=Ee(n),s=r&&r.docId===e.docId?r:{docId:e.docId,docType:e.docType,featureId:e.featureId||null,seed:e.seed||null,startedTs:o,discoverySummary:null,qaTurns:[],draftHistory:[],qualityGateHistory:[]};return Ht(n,s),l(t,{authoringMode:!0,authoringDocId:e.docId,authoringDocType:e.docType,authoringTranscriptPath:n,authoringStartedTs:o}),s}function De(t){l(t,{authoringMode:!1,authoringDocId:null,authoringDocType:null,authoringTranscriptPath:null,authoringStartedTs:null});for(let e of[Re(t),_e(t)])try{b.unlinkSync(e)}catch{}}function Ne(t){let e=k(t);return{active:!!(e&&e.authoringMode),docId:e?e.authoringDocId:null,docType:e?e.authoringDocType:null,transcriptPath:e?e.authoringTranscriptPath:null,startedTs:e?e.authoringStartedTs:null}}function Le(t){return Ee(_e(t))}var En=Object.freeze(["architecture","data model","data-model","datamodel","api contract","api-contract","apicontract","migration","auth","queue","verifier-behavior","verifier behavior"]),Ft=Object.freeze([{id:"architecture",pattern:/^##\s+architecture\b/im},{id:"data_model",pattern:/^##\s+data\s+model\b/im},{id:"api_contracts",pattern:/^##\s+api\s+contracts?\b/im},{id:"failure_modes",pattern:/^##\s+failure\s+modes?/im},{id:"migration",pattern:/^##\s+migration\b/im},{id:"open_questions",pattern:/^##\s+open\s+questions?\b/im}]),Bt=/\b(TBD|TODO|FIXME|fill in later|to be determined)\b/i,Me=1e3,He=/^##\s+Pillar\s+\d+\s*:\s*(.+?)\s*$/gim,On=Object.freeze(["data_model","api_contracts","state_or_persistence","failure_modes","migration_or_rollout"]);function jt(t){if(!t||typeof t!="string")return[];let e=[];He.lastIndex=0;let n;for(;(n=He.exec(t))!==null;){let o=n[1].trim();o&&e.push(o)}return e}function Ue(t){let{trdContent:e,prdContent:n}=t,o=[],r=(e||"").toString(),s=r.trim().length;s<Me&&o.push({section:"document",issue:`TRD is too short (${s} chars; minimum ${Me}).`,required_fix:"Expand the draft with concrete technical detail."});for(let c of Ft)c.pattern.test(r)||o.push({section:c.id,issue:"Required H2 section is missing.",required_fix:`Add a "## ${c.id.replace(/_/g," ")}" section grounded in the PRD + discovery.`});let i=r.match(Bt);i&&o.push({section:"placeholders",issue:`Placeholder token "${i[0]}" present \u2014 TRDs must not ship with unresolved placeholders.`,required_fix:"Resolve or move the open item into the ## Open Questions section."});let a=jt(n);if(a.length>0){let c=[],u=r.toLowerCase();for(let d of a)u.includes(d.toLowerCase())||c.push(d);c.length>0&&o.push({section:"pillar_coverage",issue:`TRD does not mention PRD pillar(s): ${c.join(", ")}.`,required_fix:"Add a per-pillar technical-design section, or reference each pillar by name in the relevant TRD section."})}return{passed:o.length===0,blockingIssues:o,deterministic:!0}}var Fe=S(require("crypto"));function Be(t,e,n){let o=String(t||"").toLowerCase().trim(),r=String(e||"").toLowerCase().trim().replace(/\s+/g," "),s=String(n||"").toLowerCase().trim();return Fe.createHash("sha1").update(`${o}::${r}::${s}`).digest("hex").slice(0,16)}var G=Object.freeze({decision:"Logging decision: {{summary}} \u2014 reason: {{reason}}. Say 'undo that' if wrong.",issue:"Logging issue ({{severity}}): {{summary}}. Say 'undo that' if wrong.",assumption:"Logging assumption: {{summary}} \u2014 rationale: {{rationale}}. Say 'undo that' if wrong.",task_status:"Marking task {{task_id}} as {{proposed_status}} \u2014 rationale: {{rationale}}. Say 'undo that' if wrong."}),Gt="Auto-logging paused \u2014 {{count}} entries logged this session. Type /dezycro:sync to log manually.";function je(t){let e=t.thresholds||{},n=Math.max(0,Number(t.perTurnSlotsLeft)||0),o=Math.max(0,Number(t.perSessionSlotsLeft)||0);if(n<=0||o<=0)return Gt.replace("{{count}}",o<=0?"session-cap":"turn-cap");let r=Math.min(n,o),s=(t.recentHashes||[]).filter(Boolean),i=["[Dezycro Companion]",`Feature: ${Jt(t.activeFeatureName,t.activeFeatureId)}. Slots: ${r} (${n}/turn, ${o}/session).`,"","Scan since your last message for committed signals to log:",` - Decision (conf \u2265 ${e.decision??.85}) \u2014 committed technical/product choice`,` - Issue (conf \u2265 ${e.issue??.8}) \u2014 current blocker/bug`,` - Assumption (conf \u2265 ${e.assumption??.9}) \u2014 unverified belief affecting impl`,` - Task-status (conf \u2265 ${e.taskStatus??.9}) \u2014 task is now DONE/PUSHED`,"","Skip: hypotheticals, brainstorming, implementation-obvious details, ephemeral content, intent statements while authoring a PRD/TRD."];return s.length>0&&i.push(`Already-logged hashes (skip dupes): ${s.join(", ")}`),i.push("","For each surviving candidate (max "+r+"): print the announce line verbatim and call the matching MCP tool.",' decision: "'+G.decision+'" \u2192 mcp__dezycro(-dev)?__add_decision',' issue: "'+G.issue+'" \u2192 mcp__dezycro(-dev)?__add_issue',' assumption: "'+G.assumption+'" \u2192 mcp__dezycro(-dev)?__add_assumption',' task_status: "'+G.task_status+'" \u2192 mcp__dezycro(-dev)?__update_task',"","If nothing meets the bar, simply continue with whatever the user asked next \u2014 do NOT output any acknowledgment line. The hook will silence itself for trivial turns."),i.join(`
|
|
3
|
+
`)}function Jt(t,e){if(!e)return"(none \u2014 skip if no feature is active)";let n=String(e).slice(0,8);return t?`${t} (${n}\u2026)`:n+"\u2026"}function $e(t){return typeof t!="string"?null:/add_decision$/.test(t)?"decision":/add_issue$/.test(t)?"issue":/add_assumption$/.test(t)?"assumption":/update_task$/.test(t)?"task-status":null}var Ve=Object.freeze(["undo that","no, wrong","revert that","undo the last log","wrong, undo"]);function Ge(t){if(typeof t!="string")return!1;let e=t.toLowerCase().trim();if(!e)return!1;for(let n=0;n<Ve.length;n+=1)if(e.includes(Ve[n]))return!0;return!1}function Je(t){if(!t||!t.tool||!t.entityId)return null;let e=t.entityId;switch(t.tool){case"add_decision":return{tool:"update_decision",args:{id:e,status:"INVALIDATED",reason:"undo by user"},humanLine:`Reverting the last auto-logged decision (${e.slice(0,8)}\u2026) \u2014 marking INVALIDATED.`};case"add_issue":return{tool:"update_issue",args:{id:e,status:"CANCELLED",reason:"undo by user"},humanLine:`Reverting the last auto-logged issue (${e.slice(0,8)}\u2026) \u2014 marking CANCELLED.`};case"add_assumption":return{tool:"update_issue",args:{id:e,status:"INVALIDATED",kind:"ASSUMPTION",reason:"undo by user"},humanLine:`Reverting the last auto-logged assumption (${e.slice(0,8)}\u2026) \u2014 marking INVALIDATED.`};case"update_task":return t.priorStatus?{tool:"update_task",args:{id:e,status:t.priorStatus},humanLine:`Reverting the last auto-task-status change \u2014 restoring ${e.slice(0,8)}\u2026 to ${t.priorStatus}.`}:null;default:return null}}function ze(t,e){return!t||typeof t.createdInTurnId!="number"?!1:e===t.createdInTurnId+1}function oe(t,e){return`${t} ${e}${t===1?"":"s"}`}function re(t){return!t||typeof t!="object"?null:{uncoveredPaths:Number(t.uncoveredPaths??0)||0,endpointsNotInSpec:Number(t.endpointsNotInSpec??0)||0,staleBaselines:Number(t.staleBaselines??0)||0}}function J(t){let e=re(t);if(!e)return null;let n=[];return e.uncoveredPaths>0&&n.push(`${oe(e.uncoveredPaths,"path")} uncovered`),e.endpointsNotInSpec>0&&n.push(`${oe(e.endpointsNotInSpec,"endpoint")} not in spec`),e.staleBaselines>0&&n.push(`${oe(e.staleBaselines,"baseline")} stale`),n.length===0?null:`Coverage: ${n.join(", ")}`}function We(t,e){let n=re(t),o=re(e);if(!o)return null;if(!n)return J(e);let s=[["paths uncovered",o.uncoveredPaths-n.uncoveredPaths],["endpoints not in spec",o.endpointsNotInSpec-n.endpointsNotInSpec],["baselines stale",o.staleBaselines-n.staleBaselines]].filter(([,a])=>a!==0);return s.length===0?null:`Coverage delta since last verify: ${s.map(([a,c])=>`${c>0?"+":""}${c} ${a}`).join(", ")}`}var L={HaltAndReplan:"HALT_AND_REPLAN",AcknowledgeAndContinue:"ACKNOWLEDGE_AND_CONTINUE",SilentLog:"SILENT_LOG"};var W=S(require("fs")),qe=S(require("os")),I=S(require("path")),z=class t{constructor(e){this.repoRoot=e;this.config=t.readJson(I.join(e,".dezycro","config.json"))}repoRoot;config;static at(e=process.cwd()){return new t(t.findRepoRoot(e)??I.resolve(e))}get workspaceId(){return t.env("DZ_WORKSPACE_ID")??t.str(this.config?.workspaceId)}get tenantId(){return t.env("DZ_TENANT_ID")??t.str(this.config?.tenantId)}get projectId(){return t.str(this.config?.projectId)}get apiUrl(){let e=t.env("DZ_API_URL");if(e)return t.trimSlash(e);let n=Array.isArray(this.config?.environments)?this.config?.environments:[],o=n.find(s=>t.isObj(s)&&s.default===!0)??n[0],r=t.isObj(o)?t.str(o.apiUrl):null;return r?t.trimSlash(r):null}get token(){let e=t.env("DZ_TOKEN");if(e)return e;let n=[I.join(this.repoRoot,".dezycro","companion-token.local.json"),I.join(qe.homedir(),".dezycro","token.json")];for(let o of n){let r=t.str(t.readJson(o)?.token);if(r)return r}return null}activeFeature(){let e=t.readJson(I.join(this.repoRoot,".dezycro","active-feature.json")),n=t.str(e?.featureId);if(!n)return null;let o=t.str(e?.workspaceId)??this.workspaceId;return o?{workspaceId:o,featureId:n,active:e?.active===!0}:null}connection(){let e=this.apiUrl;if(!e)return{error:"no apiUrl (set DZ_API_URL or .dezycro/config.json environments[].apiUrl)"};let n=this.workspaceId;if(!n)return{error:"no workspaceId (set DZ_WORKSPACE_ID or .dezycro/config.json workspaceId)"};let o=this.token;return o?{apiUrl:e,workspaceId:n,token:o}:{error:"no token (run `dezycro setup` or set DZ_TOKEN)"}}static findRepoRoot(e){let n=I.resolve(e||process.cwd());for(let o=0;o<64;o+=1){if(W.existsSync(I.join(n,".dezycro")))return n;let r=I.dirname(n);if(r===n)return null;n=r}return null}static readJson(e){try{return JSON.parse(W.readFileSync(e,"utf8"))}catch{return null}}static isObj(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}static str(e){return typeof e=="string"&&e.length>0?e:null}static env(e){let n=process.env[e];return n&&n.length>0?n:null}static trimSlash(e){return e.replace(/\/$/,"")}};var Kt=["sessionStart","userPromptSubmit","stop","postToolUse"],Xt=60,Yt=L.HaltAndReplan,Ke=200,Qt=100,Zt=3,en=1800,se=class t{async pollIfDue(e,n,o,r){let s=this.resolveConfig(o),i=s.reactionMode,a={events:[],statePatch:null,reactionMode:i};if(!s.enabled||!s.hooks.has(n)&&n!=="sessionStart")return a;let c=r.commandBus,u=c.lastAttemptTs??c.lastPollTs;if(n!=="sessionStart"&&u){let f=Date.parse(u);if(!Number.isNaN(f)){let C=t.backoffSeconds(s.minPollIntervalSeconds,c.consecutiveFailures??0,s.circuitBreakerThreshold,s.maxBackoffSeconds);if((Date.now()-f)/1e3<C)return a}}let d=new z(e),p=d.activeFeature();if(!p||!p.active)return a;let h=d.apiUrl;if(!h)return a;let v=d.token;if(!v)return g(e,"command_bus_skip_no_token",{hookEvent:n}),a;let y=n==="sessionStart"?null:c.cursor,P=new Date().toISOString();try{let f=await this.fetchInbox(h,p,v,y),C=new Set(c.recentEventIds??[]),T=f.events.filter(O=>!C.has(O.eventId)),_=this.trimRecent([...c.recentEventIds??[],...T.map(O=>O.eventId)]),X={commandBus:{cursor:f.nextCursor||c.cursor,lastPollTs:f.serverTs,lastAttemptTs:P,consecutiveFailures:0,recentEventIds:_}};return T.length>0&&g(e,"command_bus_events_received",{hookEvent:n,count:T.length,types:T.map(O=>O.eventType)}),{events:T,statePatch:X,reactionMode:i}}catch(f){let C=(c.consecutiveFailures??0)+1,T={commandBus:{...c,lastAttemptTs:P,consecutiveFailures:C}},_=t.backoffSeconds(s.minPollIntervalSeconds,C,s.circuitBreakerThreshold,s.maxBackoffSeconds);return g(e,"command_bus_poll_failed",{hookEvent:n,error:f instanceof Error?f.message:String(f),consecutiveFailures:C,nextPollAfterSeconds:_,backoff:C>=s.circuitBreakerThreshold}),{events:[],statePatch:T,reactionMode:i}}}static backoffSeconds(e,n,o,r){if(n<o)return e;let s=n-o+1;return Math.min(e*Math.pow(2,s),r)}resolveConfig(e){let n=e?.enabled!==!1,o=new Set(e?.pollHooks??Kt);o.add("sessionStart");let r=Math.max(0,e?.minPollIntervalSeconds??Xt),s=e?.reactionMode??Yt,i=Math.max(1,e?.circuitBreakerThreshold??Zt),a=Math.max(r,e?.maxBackoffSeconds??en);return{enabled:n,hooks:o,minPollIntervalSeconds:r,reactionMode:s,circuitBreakerThreshold:i,maxBackoffSeconds:a}}async fetchInbox(e,n,o,r){let s=new URL(`${e}/api/v1/workspaces/${n.workspaceId}/features/${n.featureId}/inbox`);r&&s.searchParams.set("since",r),s.searchParams.set("limit",String(Qt));let i=new AbortController,a=setTimeout(()=>i.abort(),5e3);try{let c=await fetch(s.toString(),{method:"GET",headers:{Authorization:`Bearer ${o}`,Accept:"application/json"},signal:i.signal});if(!c.ok)throw new Error(`inbox poll returned ${c.status}`);let u=await c.json();if(!u||typeof u.serverTs!="string"||typeof u.nextCursor!="string")throw new Error("inbox poll response missing serverTs/nextCursor");return{serverTs:u.serverTs,nextCursor:u.nextCursor,events:Array.isArray(u.events)?u.events:[]}}finally{clearTimeout(a)}}trimRecent(e){return e.length<=Ke?e:e.slice(e.length-Ke)}},ie=class{renderForAgent(e,n){if(e.length===0)return"";let o=[`\u26A0\uFE0F Dezycro Command Bus: ${e.length} new event(s) on this feature.`,""];for(let r of e)o.push(this.renderEvent(r));return e.some(r=>r.urgency==="BLOCKING")&&o.push("",this.reactionGuidance(n)),o.join(`
|
|
4
|
+
`)}renderEvent(e){if(e.eventType==="INVALIDATION"){let r=this.stringField(e.payload,"artifactSummary")??"(no summary)",s=this.stringField(e.payload,"reason")??"(no reason)",i=this.stringField(e.payload,"previousStatus")??"?",a=`${e.sourceType.toLowerCase()} ${e.sourceId??"?"}`;return`- INVALIDATION (${e.urgency}): ${a} ("${this.truncate(r,120)}") \u2014 reason: "${this.truncate(s,200)}" \u2014 was ${i}.`}let n=this.summarizePayload(e.payload),o=`${e.sourceType.toLowerCase()}${e.sourceId?` ${e.sourceId}`:""}`;return`- [Dezycro] ${e.eventType} (${e.urgency}) from ${o}${n?`: ${n}`:""}.`}summarizePayload(e){let n=[];for(let[o,r]of Object.entries(e??{}))r!=null&&(Array.isArray(r)?n.push(`${o}=${r.join("|")}`):typeof r!="object"&&n.push(`${o}=${String(r)}`));return this.truncate(n.join(", "),240)}reactionGuidance(e){switch(e){case L.HaltAndReplan:return"Reaction mode: HALT_AND_REPLAN \u2014 pause your current line of work, acknowledge in chat, and re-plan around these invalidations before touching code again.";case L.AcknowledgeAndContinue:return"Reaction mode: ACKNOWLEDGE_AND_CONTINUE \u2014 surface this in your reply but continue current work; do not silently reuse invalidated artifacts.";case L.SilentLog:return"Reaction mode: SILENT_LOG \u2014 recorded for the session transcript; no chat interruption.";default:return""}}stringField(e,n){let o=e?.[n];return typeof o=="string"?o:null}truncate(e,n){return e.length<=n?e:e.slice(0,n-1)+"\u2026"}},M=new se,q=new ie;var x=S(require("fs")),Xe=S(require("path"));function Ye(t){switch(t){case"resume":return!0;case"compact":return null;case"startup":case"clear":return!1;default:return!1}}var H=class{file;constructor(e){this.file=Xe.join(e,".dezycro","active-feature.json")}read(){try{let e=JSON.parse(x.readFileSync(this.file,"utf8")),n=typeof e.featureId=="string"?e.featureId:null;return n?{featureId:n,featureName:typeof e.featureName=="string"?e.featureName:void 0,workspaceId:typeof e.workspaceId=="string"?e.workspaceId:void 0,selectedAt:typeof e.selectedAt=="string"?e.selectedAt:void 0,active:e.active===!0}:null}catch{return null}}setActive(e){let n=this.read();if(!n||(n.active??!1)===e)return!1;try{return x.writeFileSync(this.file,`${JSON.stringify({...n,active:e},null,2)}
|
|
5
|
+
`),!0}catch{return!1}}clear(){try{if(x.existsSync(this.file))return x.unlinkSync(this.file),!0}catch{}return!1}};var nn=new Set(["DONE","PUSHED"]),on=["/dezycro:sync","log what we did","log this","save progress","save what we did","wrap up","we're done","we are done","end of session","sweep the workbook"];function rn(t){if(typeof t!="string")return null;let e=t.toLowerCase().trim();if(!e)return null;for(let n of on)if(e.includes(n))return n;return null}var Ze="TRD quality gate (deterministic layer) blocked APPROVED transition: ";async function sn(t){let{event:e,route:n,payload:o,flags:r}=t;return e==="state"?un(r||{}):e==="authoring-state"?ln(r||{}):e==="pre-tool-use"&&n==="update_task"?et(o||{}):e==="pre-tool-use"&&n==="change_document_status"?cn(o||{}):e==="post-tool-use"&&n==="edit"?tt(o||{}):e==="post-tool-use"&&n==="workbook_mutation"?ut(o||{}):e==="session-start"?ot(o||{}):e==="session-end"?pn(o||{}):e==="user-prompt-submit"?rt(o||{}):e==="stop"?it(o||{}):0}function et(t){let e=w(process.cwd());if(!e)return process.stdout.write("{}"),0;let n=t&&t.tool_input||{},o=String(n.status||"").toUpperCase();if(!nn.has(o))return process.stdout.write("{}"),0;let r=n.pathRefs,s=Array.isArray(r)?r.filter(Boolean):[];if(s.length===0)return process.stdout.write("{}"),0;let i=A(e);if((i&&i.companion&&i.companion.autoVerify||{}).preTaskDone===!1)return process.stdout.write("{}"),0;if(Te({repoRoot:e,paths:s})){if(g(e,"pre_done_gate_pass",{status:o,pathRefs:s}),o==="PUSHED"){let p=an(e,i);if(p){g(e,"pre_push_coverage_nudge",{line:p});let h={systemMessage:p};return process.stdout.write(JSON.stringify(h)),0}}return process.stdout.write("{}"),0}E(e,"verifyAutoRuns"),E(e,"verifyAutoFailures"),$(e,"pre_done_gate_block",{status:o,pathRefs:s});let u=ve({paths:s,status:o}).reason,d={decision:"block",reason:u,hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:u}};return process.stdout.write(JSON.stringify(d)),0}function an(t,e){if((e&&e.companion&&e.companion.coverageNudges||{}).enabled===!1)return null;let o=k(t).coverageSnapshot,r=J(o);return r?`[Companion] ${r} \u2014 verify passed, but consider checking these before push.`:null}function cn(t){let n=t&&t.tool_input||{},o=n.status||n.newStatus||null,r=n.docId||n.documentId||n.id||null;if(o!=="APPROVED")return process.stdout.write("{}"),0;let s=w(process.cwd());if(!s)return process.stdout.write("{}"),0;let i=Le(s);if(!i||r&&i.docId&&i.docId!==r)return $(s,"quality_gate_degraded_permit",{reason:i?"docId_mismatch":"sidecar_missing",docId:r,sidecarDocId:i?i.docId:null}),process.stdout.write("{}"),0;if(i.docType!=="TRD")return process.stdout.write("{}"),0;let a=Ue({trdContent:i.content,prdContent:i.prdContent||""});if(a.passed)return g(s,"quality_gate_deterministic_pass",{docId:i.docId}),process.stdout.write("{}"),0;E(s,"qualityGateFailures");let c=a.blockingIssues.map(p=>`[${p.section}] ${p.issue}`).slice(0,5).join(" | "),u=`${Ze}${c||"unspecified failure"}. Fix and try again.`;$(s,"quality_gate_blocked",{docId:i.docId,issues:a.blockingIssues});let d={decision:"block",reason:u,hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:u}};return process.stdout.write(JSON.stringify(d)),0}async function tt(t){let e=w(process.cwd());if(!e)return 0;{let y=A(e),P=k(e),f=await M.pollIfDue(e,"postToolUse",y?.companion?.commandBus,P);f.statePatch&&l(e,f.statePatch);let C=q.renderForAgent(f.events,f.reactionMode);if(C){let T={hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:C}};return process.stdout.write(JSON.stringify(T)),0}}let n=t&&t.tool_input||{},o=nt(n);if(o.length===0)return 0;let r=A(e),s=r&&r.companion&&r.companion.autoVerify||{},i=Array.isArray(s.controllerPaths)?s.controllerPaths:[],a=s.postEditPulse&&s.postEditPulse.enabled!==!1,c=s.postEditPulse&&Number(s.postEditPulse.threshold)||5,u=Pe(o,i),d=new Date().toISOString(),h=(k(e).pulseCount||0)+1,v=a&&h>=c&&u.length>0;if(u.length===0)l(e,{pulseCount:h,lastEditTs:d});else for(let y=0;y<u.length;y+=1){let P=y===u.length-1,f={pushControllerEdit:{path:u[y],editedTs:d}};P&&(f.needsSpecPublish=!0,f.lastEditTs=d,f.pulseCount=v?0:h),l(e,f)}if(g(e,"post_edit",{edited:o.length,matchedControllers:u.length,pulseCount:v?0:h,nudged:v}),v){let y="[Companion] "+h+" edits since last verify and controller paths were touched ("+u.join(", ")+"). Consider running `/dezycro:verify` to catch regressions early.";process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:y}}))}return 0}function nt(t){if(!t||typeof t!="object")return[];let e=t.file_path;if(typeof e=="string")return[e];let n=t.path;if(typeof n=="string")return[n];let o=t.edits;if(Array.isArray(o)){let r=new Set;for(let s of o)s&&typeof s.file_path=="string"&&r.add(s.file_path);return Array.from(r)}return[]}function un(t){let e=w(process.cwd())||process.cwd();if(t.get){let n=k(e);return process.stdout.write(JSON.stringify(n,null,2)),0}if(typeof t.patch=="string"){let n;try{n=JSON.parse(t.patch)}catch(r){let s=r.message;return process.stdout.write(JSON.stringify({ok:!1,error:"invalid JSON for --patch: "+s})),1}return n===null||typeof n!="object"||Array.isArray(n)?(process.stdout.write(JSON.stringify({ok:!1,error:"--patch must be a JSON object"})),1):l(e,n)===null?(process.stdout.write(JSON.stringify({ok:!1,error:"lock contention \u2014 state not patched"})),1):(process.stdout.write(JSON.stringify({ok:!0})),0)}return process.stdout.write(JSON.stringify({ok:!1,error:"state requires one of --get or --patch=<json>"})),1}function ln(t){let e=w(process.cwd())||process.cwd(),n=t.set||(t.get?"get":null);if(n==="enter"){let o=t["doc-id"],r=t["doc-type"];if(!o||!r)return process.stdout.write(JSON.stringify({ok:!1,error:"--doc-id and --doc-type are required for --set=enter"})),1;try{let s=Oe(e,{docId:o,docType:r,featureId:t["feature-id"]||null,seed:t.seed||null});return process.stdout.write(JSON.stringify({ok:!0,transcript:s})),0}catch(s){return process.stdout.write(JSON.stringify({ok:!1,error:s.message})),1}}if(n==="exit")try{return De(e),process.stdout.write(JSON.stringify({ok:!0})),0}catch(o){return process.stdout.write(JSON.stringify({ok:!1,error:o.message})),1}if(n==="get"){let o=Ne(e);return process.stdout.write(JSON.stringify({ok:!0,...o})),0}return process.stdout.write(JSON.stringify({ok:!1,error:"authoring-state requires one of --set=enter, --set=exit, --get"})),1}var dn=600;async function ot(t){let e=w(process.cwd());if(!e)return 0;l(e,{sessionAutoLogCount:0,turnAutoLogCount:0,currentTurnId:0,lastAutoWorkbookMutation:null,coverageFetchPending:!1});let n=Ye(t.source);n!==null&&new H(e).setActive(n),g(e,"session_start",{source:t.source??null,active:n});let o=A(e),r=k(e),s=await M.pollIfDue(e,"sessionStart",o?.companion?.commandBus,r);return s.statePatch&&l(e,s.statePatch),0}async function pn(t){let e=w(process.cwd());if(!e)return 0;let n=new H(e).setActive(!1);return g(e,"session_end",{reason:t.reason??null,deactivated:n}),0}async function rt(t){let e=w(process.cwd());if(!e)return 0;let n=k(e),o=(n.currentTurnId||0)+1;l(e,{currentTurnId:o,turnAutoLogCount:0});{let i=A(e),a=await M.pollIfDue(e,"userPromptSubmit",i?.companion?.commandBus,n);a.statePatch&&l(e,a.statePatch);let c=q.renderForAgent(a.events,a.reactionMode);if(c){let u={hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:c}};return process.stdout.write(JSON.stringify(u)),0}}let r=String(t?.prompt??t?.user_message??t?.message??"").trim(),s=rn(r);if(s&&(l(e,{pendingWorkbookSweep:!0,pendingWorkbookSweepReason:"wrap_phrase:"+s}),g(e,"wrap_phrase_detected",{phrase:s})),r&&Ge(r)){let i=n.lastAutoWorkbookMutation;if(i&&ze(i,o)){let a=Je(i);if(a){E(e,"undoCount"),l(e,{lastAutoWorkbookMutation:null}),g(e,"undo_directive",{tool:a.tool,entityId:i.entityId});let u={hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:"[Dezycro Companion \u2014 undo] "+a.humanLine+`
|
|
6
6
|
|
|
7
7
|
Call `+a.tool+` with arguments:
|
|
8
8
|
`+JSON.stringify(a.args,null,2)+`
|
|
9
9
|
|
|
10
|
-
Then confirm the reversal in one short sentence.`}};return process.stdout.write(JSON.stringify(u)),0}}}{let i=
|
|
10
|
+
Then confirm the reversal in one short sentence.`}};return process.stdout.write(JSON.stringify(u)),0}}}{let i=fn(e);if(i){let a=n.specReminderSurfacedCount??0;if(st(i.count,a)){l(e,{specReminderSurfacedCount:i.count}),g(e,"publish_spec_nudge",{paths:i.count});let c={hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:i.text}};return process.stdout.write(JSON.stringify(c)),0}}else n.specReminderSurfacedCount&&l(e,{specReminderSurfacedCount:0})}return gn(e,n),process.stdout.write("{}"),0}function st(t,e){return t>e}function fn(t){let e=A(t);if((e&&e.companion&&e.companion.autoVerify||{}).autoPublishSpecOnControllerChange===!1)return null;let o=Ce(t);if(!o.needed||o.controllerPaths.length===0)return null;let r=8,s=o.controllerPaths,i=s.slice(0,r).map(c=>" - "+c);return s.length>r&&i.push(" - \u2026and "+(s.length-r)+" more"),{text:"[Dezycro Companion] "+s.length+` controller/API file(s) changed since the last published spec:
|
|
11
11
|
`+i.join(`
|
|
12
|
-
`)+"\n\nNew or changed endpoints are NOT yet reflected in the published OpenAPI spec, so verification cannot see them. Before continuing, run `/dezycro:publish-spec` to upload the updated spec (this regenerates the JEP), then `/dezycro:verify` to check the feature against it. This reminder
|
|
12
|
+
`)+"\n\nNew or changed endpoints are NOT yet reflected in the published OpenAPI spec, so verification cannot see them. Before continuing, run `/dezycro:publish-spec` to upload the updated spec (this regenerates the JEP), then `/dezycro:verify` to check the feature against it. This reminder shows once per change and again only if more controller/API files change; it clears after `/dezycro:publish-spec`.",count:s.length}}function gn(t,e){if(A(t)?.companion?.coverageNudges?.enabled===!1)return;let o=e.coverageSnapshot;if(!o||o.surfacedTs)return;let r=J(o);if(!r)return;l(t,{coverageSnapshot:{...o,surfacedTs:new Date().toISOString()}}),g(t,"coverage_one_liner",{line:r});let s={hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:"[Companion] "+r}};process.stdout.write(JSON.stringify(s))}async function it(t){let e=w(process.cwd());if(!e)return 0;let n=A(e);{let C=k(e),T=await M.pollIfDue(e,"stop",n?.companion?.commandBus,C);T.statePatch&&l(e,T.statePatch);let _=q.renderForAgent(T.events,T.reactionMode);if(_){let X={systemMessage:_};return process.stdout.write(JSON.stringify(X)),0}}let o=n?.companion?.autoWorkbookUpdates||{};if(n?.companion?.safeMode===!0||o.enabled===!1)return ae();let r=k(e),s=!!(r.lastVerifyCompletionTs&&r.lastVerifyCompletionTs!==r.lastSeenVerifyCompletionTs);if(!!!(r.pendingWorkbookSweep||s))return g(e,"stop_skip",{reason:"no_trigger"}),s&&l(e,{lastSeenVerifyCompletionTs:r.lastVerifyCompletionTs}),K(e,r);if(r.authoringMode)return g(e,"stop_skip",{reason:"authoring_mode"}),l(e,{pendingWorkbookSweep:!1,pendingWorkbookSweepReason:null,lastSeenVerifyCompletionTs:r.lastVerifyCompletionTs||r.lastSeenVerifyCompletionTs}),K(e,r);let a=Number(o.maxAutoLogsPerTurn??2),c=Number(o.maxAutoLogsPerSession??10),u=Math.max(0,a-(r.turnAutoLogCount||0)),d=Math.max(0,c-(r.sessionAutoLogCount||0));if(u===0||d===0)return g(e,"stop_skip",{reason:"caps_exhausted",perTurnSlotsLeft:u,perSessionSlotsLeft:d}),l(e,{pendingWorkbookSweep:!1,pendingWorkbookSweepReason:null,lastSeenVerifyCompletionTs:r.lastVerifyCompletionTs||r.lastSeenVerifyCompletionTs}),K(e,r);if(r.suppressWorkbookUpdatesUntil&&Date.now()<new Date(r.suppressWorkbookUpdatesUntil).getTime())return g(e,"stop_skip",{reason:"suppressed"}),l(e,{pendingWorkbookSweep:!1,pendingWorkbookSweepReason:null,lastSeenVerifyCompletionTs:r.lastVerifyCompletionTs||r.lastSeenVerifyCompletionTs}),K(e,r);l(e,{pendingWorkbookSweep:!1,pendingWorkbookSweepReason:null,lastSeenVerifyCompletionTs:r.lastVerifyCompletionTs||r.lastSeenVerifyCompletionTs});let p=pe(n),h=[...r.recentDecisionHashes||[],...r.recentIssueHashes||[],...r.recentAssumptionHashes||[]],v=ct(e),y=je({thresholds:p,perTurnSlotsLeft:u,perSessionSlotsLeft:d,recentHashes:h,activeFeatureId:v.featureId,activeFeatureName:v.featureName});g(e,"stop_sweep_directive",{perTurnSlotsLeft:u,perSessionSlotsLeft:d,recentHashCount:h.length});let P=at(e,r);P&&(y+=`
|
|
13
13
|
|
|
14
|
-
`+P);let f={decision:"block",reason:y};return process.stdout.write(JSON.stringify(f)),0}function K(e
|
|
15
|
-
`).filter(Boolean),r=0,s=!1;for(let i=o.length-1;i>=0;i-=1){let a;try{a=JSON.parse(o[i])}catch{continue}let c=a?.message?.role??a?.role;if(c==="assistant"){let u=JSON.stringify(a.message?.content??a.content??"");r+=u.length}else if(c==="user"){if(s)break;s=!0;let u=JSON.stringify(a.message?.content??a.content??"");r+=u.length}if(r>1e6)break}return r}catch{return null}}function
|
|
14
|
+
`+P);let f={decision:"block",reason:y};return process.stdout.write(JSON.stringify(f)),0}function K(t,e){let n=at(t,e);if(!n)return ae();g(t,"stop_coverage_delta",{delta:n});let o={systemMessage:n};return process.stdout.write(JSON.stringify(o)),0}function at(t,e){let n=e.lastVerifyCompletionTs,o=e.coverageSnapshot;if(!n||!o)return null;let r=o.surfacedTs?new Date(o.surfacedTs).getTime():0;if(new Date(n).getTime()<=r)return null;let i=We(o.previous||null,o);return i?(l(t,{coverageSnapshot:{...o,surfacedTs:new Date().toISOString()}}),"[Companion] "+i):null}function ae(){return process.stdout.write("{}"),0}function mn(t){try{let e=t?.transcript_path;if(!e||typeof e!="string"||!U.existsSync(e))return null;let o=U.readFileSync(e,"utf8").split(`
|
|
15
|
+
`).filter(Boolean),r=0,s=!1;for(let i=o.length-1;i>=0;i-=1){let a;try{a=JSON.parse(o[i])}catch{continue}let c=a?.message?.role??a?.role;if(c==="assistant"){let u=JSON.stringify(a.message?.content??a.content??"");r+=u.length}else if(c==="user"){if(s)break;s=!0;let u=JSON.stringify(a.message?.content??a.content??"");r+=u.length}if(r>1e6)break}return r}catch{return null}}function hn(t){return ct(t).featureId}function ct(t){try{let e=U.readFileSync(Qe.join(t,".dezycro","active-feature.json"),"utf8"),n=JSON.parse(e);return{featureId:n?.featureId||null,featureName:n?.featureName||null}}catch{return{featureId:null,featureName:null}}}function A(t){try{return de(t)}catch{return JSON.parse(JSON.stringify(D))}}function ut(t){let e=w(process.cwd());if(!e)return 0;let n=t?.tool_name||"",o=$e(n);if(!o)return 0;let r=t?.tool_input||{},s=t?.tool_response||t?.response||{},i=String(r.summary||r.title||r.description||r.statement||""),a=r.taskId||r.linkedTaskId||null,c=Be(o,i,a),u=s.data,d=s.id||(u?u.id:void 0)||r.taskId||null,p=k(e),h=(p.turnAutoLogCount||0)+1,v=(p.sessionAutoLogCount||0)+1,y={turnAutoLogCount:h,sessionAutoLogCount:v,lastAutoWorkbookMutation:{tool:n.split("__").pop()||"",entityId:d,createdInTurnId:p.currentTurnId||0,createdTs:new Date().toISOString(),priorStatus:r.priorStatus||null}};return o==="decision"&&(y.pushDecisionHash=c),o==="issue"&&(y.pushIssueHash=c),o==="assumption"&&(y.pushAssumptionHash=c),l(e,y),E(e,o==="decision"?"autoDecisionLogs":o==="issue"?"autoIssueLogs":o==="assumption"?"autoAssumptionLogs":"autoTaskStatusLogs"),g(e,"workbook_mutation",{kind:o,entityId:d,turnAutoLogCount:h,sessionAutoLogCount:v}),process.stdout.write("{}"),0}var yn=nt,Sn=tt,kn=et,bn=it,Tn=rt,vn=ut,Cn=ot,wn=hn,In=mn,Pn=dn;0&&(module.exports={QUALITY_GATE_REASON_PREFIX,TRIVIAL_TURN_CHAR_DEFAULT_EXPORT,_extractEditedPaths,_handlePostEdit,_handleSessionStart,_handleStop,_handleUpdateTaskGate,_handleUserPromptSubmit,_handleWorkbookMutation,_readActiveFeatureId,_transcriptCharsSinceLastStop,dispatch,shouldSurfaceSpecReminder});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dezycro-ai/agent-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Official Dezycro plugin for AI coding agents (Claude Code today, more to come) — reverse-engineer your codebase into features, PRDs, TRDs, and live verification.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dezycro": "./dist/cli/dezycro.js"
|