agentix-cli 0.154.2 → 0.155.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/{App-6T6NVB7O.js → App-P4MLXD46.js} +2 -2
- package/dist/{ChatApp-QZBJ4NHC.js → ChatApp-DILDQOJL.js} +2 -2
- package/dist/{absorb-eval-EVX7LDXR.js → absorb-eval-DBC7EKU5.js} +2 -2
- package/dist/{agent-F2NT6B25.js → agent-OZ3KPI6Y.js} +2 -2
- package/dist/{board-dashboard-642BO7GV.js → board-dashboard-MWUCBHDN.js} +239 -233
- package/dist/board-dashboard-MWUCBHDN.js.map +1 -0
- package/dist/{chunk-KA2NV7H4.js → chunk-3ZAAUY2N.js} +2 -2
- package/dist/{chunk-743RAKLP.js → chunk-4RHM4XTI.js} +2 -2
- package/dist/{chunk-U4YTTWR6.js → chunk-6CXJAZZD.js} +2 -2
- package/dist/{chunk-AKCEMKQM.js → chunk-ACB6GRSP.js} +2 -2
- package/dist/{chunk-W2RB5XG7.js → chunk-AHZBWCXI.js} +2 -2
- package/dist/chunk-AVAR5KNN.js +36 -0
- package/dist/chunk-AVAR5KNN.js.map +1 -0
- package/dist/{chunk-E76HREC7.js → chunk-CTXHMJLZ.js} +3 -3
- package/dist/{chunk-IA4J3YLB.js → chunk-D65HXPIB.js} +2 -2
- package/dist/{chunk-S3EX64LR.js → chunk-EE3ZYIIB.js} +2 -2
- package/dist/{chunk-VRF4YW46.js → chunk-FTIJQLBX.js} +2 -2
- package/dist/{chunk-YL26FRKJ.js → chunk-GIFUJ3LL.js} +2 -2
- package/dist/chunk-H7DLFJBV.js +575 -0
- package/dist/chunk-H7DLFJBV.js.map +1 -0
- package/dist/{chunk-4CWACHEH.js → chunk-HGF73KFH.js} +2 -2
- package/dist/{chunk-JAML6222.js → chunk-HOVJVXEP.js} +2 -2
- package/dist/{chunk-GRVTLUQ6.js → chunk-IW4AZVJR.js} +2 -2
- package/dist/{chunk-IWWEUXZQ.js → chunk-J3IP3UZX.js} +2 -2
- package/dist/{chunk-67DWBJEO.js → chunk-J432IZXG.js} +333 -336
- package/dist/chunk-J432IZXG.js.map +1 -0
- package/dist/{chunk-37I654UJ.js → chunk-KYRF2FPT.js} +2 -2
- package/dist/{chunk-SD3CC4EX.js → chunk-NJEJU5XN.js} +2 -2
- package/dist/{chunk-CUAS4ITR.js → chunk-PI6CKUUH.js} +2 -2
- package/dist/{chunk-HUN6COOF.js → chunk-Q7LUTCNO.js} +2 -2
- package/dist/chunk-QHRQ3PUX.js +3 -0
- package/dist/chunk-QHRQ3PUX.js.map +1 -0
- package/dist/chunk-SQTL2CLY.js +76 -0
- package/dist/chunk-SQTL2CLY.js.map +1 -0
- package/dist/{chunk-EGTANAFI.js → chunk-SSFQWEPJ.js} +2 -2
- package/dist/{chunk-MLC5INGD.js → chunk-UK6MICKK.js} +5 -5
- package/dist/{chunk-MLC5INGD.js.map → chunk-UK6MICKK.js.map} +1 -1
- package/dist/{chunk-YJNUVAM4.js → chunk-WHMX2D2Q.js} +2 -2
- package/dist/{chunk-ABCQ6QMJ.js → chunk-YDAFHXDE.js} +2 -2
- package/dist/{chunk-GFRAHUAQ.js → chunk-YLAJOO5X.js} +2 -2
- package/dist/{chunk-B75BLZ2M.js → chunk-YXBQSLFV.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-OCLSGJYQ.js → client-7JINGNNU.js} +2 -2
- package/dist/{config-FZTWI3VG.js → config-S4ZZHOUZ.js} +2 -2
- package/dist/{config-mutate-X5IKMROK.js → config-mutate-U3KKAXVD.js} +2 -2
- package/dist/config-mutator-KKRVNVVV.js +2 -0
- package/dist/{contributions-KHGGVSR6.js → contributions-6F3MYSRR.js} +2 -2
- package/dist/{doctor-KNCRQ3YO.js → doctor-UDZI2OMU.js} +2 -2
- package/dist/{follow-up-tool-TGKEPA5C.js → follow-up-tool-MP6FOIQE.js} +2 -2
- package/dist/{hub-HQUAH5H6.js → hub-TSUVK7PH.js} +2 -2
- package/dist/index.d.ts +362 -61
- package/dist/index.js +1 -1
- package/dist/{program-CYOAZ43O.js → program-CMWF3BQS.js} +234 -232
- package/dist/program-CMWF3BQS.js.map +1 -0
- package/dist/{promote-VD4OVQGL.js → promote-YVOYLTXI.js} +2 -2
- package/dist/{push-bridge-P7HH25VN.js → push-bridge-CFPGPPO7.js} +2 -2
- package/dist/{query-5CPK6G2H.js → query-ZGXXMJ4M.js} +2 -2
- package/dist/{query-settings-35GDM3HU.js → query-settings-TNOGVKBX.js} +2 -2
- package/dist/{registry-JCHKHCRE.js → registry-R2X4YGUK.js} +2 -2
- package/dist/{request-planner-ZIG4YVXC.js → request-planner-QBNGJMF5.js} +2 -2
- package/dist/{review-candidates-LPZWOR2K.js → review-candidates-WCDKCFXR.js} +2 -2
- package/dist/{routing-BLOYDLU4.js → routing-RRRO2GDA.js} +2 -2
- package/dist/schedule-tool-2XZ3I5IL.js +2 -0
- package/dist/{scheduler-BEJRDQR3.js → scheduler-7O73TDCG.js} +2 -2
- package/dist/{seat-NU3UJC6C.js → seat-CCDGNARC.js} +2 -2
- package/dist/{select-IWAFX4XJ.js → select-VPZ4QDHV.js} +2 -2
- package/dist/{set-enabled-JF75TSFU.js → set-enabled-VYSPZXPC.js} +2 -2
- package/dist/{tool-PQBQJWM5.js → tool-K3PZOFC2.js} +2 -2
- package/dist/{tool-WTOOPTGC.js → tool-VPDXU3IZ.js} +2 -2
- package/dist/{wiki-DXG655NP.js → wiki-QA7BDTOR.js} +2 -2
- package/dist/wiki-enrich-ZIZ5QHQ3.js +2 -0
- package/package.json +1 -1
- package/dist/board-dashboard-642BO7GV.js.map +0 -1
- package/dist/chunk-67DWBJEO.js.map +0 -1
- package/dist/chunk-HSCZSNOX.js +0 -533
- package/dist/chunk-HSCZSNOX.js.map +0 -1
- package/dist/chunk-VKEH4IBA.js +0 -76
- package/dist/chunk-VKEH4IBA.js.map +0 -1
- package/dist/chunk-XOUK5ZIQ.js +0 -36
- package/dist/chunk-XOUK5ZIQ.js.map +0 -1
- package/dist/chunk-YMX3QCV7.js +0 -3
- package/dist/chunk-YMX3QCV7.js.map +0 -1
- package/dist/config-mutator-C5BMIBZO.js +0 -2
- package/dist/program-CYOAZ43O.js.map +0 -1
- package/dist/schedule-tool-7KFO3NPD.js +0 -2
- package/dist/wiki-enrich-5VQCT6BT.js +0 -2
- /package/dist/{App-6T6NVB7O.js.map → App-P4MLXD46.js.map} +0 -0
- /package/dist/{ChatApp-QZBJ4NHC.js.map → ChatApp-DILDQOJL.js.map} +0 -0
- /package/dist/{absorb-eval-EVX7LDXR.js.map → absorb-eval-DBC7EKU5.js.map} +0 -0
- /package/dist/{agent-F2NT6B25.js.map → agent-OZ3KPI6Y.js.map} +0 -0
- /package/dist/{chunk-KA2NV7H4.js.map → chunk-3ZAAUY2N.js.map} +0 -0
- /package/dist/{chunk-743RAKLP.js.map → chunk-4RHM4XTI.js.map} +0 -0
- /package/dist/{chunk-U4YTTWR6.js.map → chunk-6CXJAZZD.js.map} +0 -0
- /package/dist/{chunk-AKCEMKQM.js.map → chunk-ACB6GRSP.js.map} +0 -0
- /package/dist/{chunk-W2RB5XG7.js.map → chunk-AHZBWCXI.js.map} +0 -0
- /package/dist/{chunk-E76HREC7.js.map → chunk-CTXHMJLZ.js.map} +0 -0
- /package/dist/{chunk-IA4J3YLB.js.map → chunk-D65HXPIB.js.map} +0 -0
- /package/dist/{chunk-S3EX64LR.js.map → chunk-EE3ZYIIB.js.map} +0 -0
- /package/dist/{chunk-VRF4YW46.js.map → chunk-FTIJQLBX.js.map} +0 -0
- /package/dist/{chunk-YL26FRKJ.js.map → chunk-GIFUJ3LL.js.map} +0 -0
- /package/dist/{chunk-4CWACHEH.js.map → chunk-HGF73KFH.js.map} +0 -0
- /package/dist/{chunk-JAML6222.js.map → chunk-HOVJVXEP.js.map} +0 -0
- /package/dist/{chunk-GRVTLUQ6.js.map → chunk-IW4AZVJR.js.map} +0 -0
- /package/dist/{chunk-IWWEUXZQ.js.map → chunk-J3IP3UZX.js.map} +0 -0
- /package/dist/{chunk-37I654UJ.js.map → chunk-KYRF2FPT.js.map} +0 -0
- /package/dist/{chunk-SD3CC4EX.js.map → chunk-NJEJU5XN.js.map} +0 -0
- /package/dist/{chunk-CUAS4ITR.js.map → chunk-PI6CKUUH.js.map} +0 -0
- /package/dist/{chunk-HUN6COOF.js.map → chunk-Q7LUTCNO.js.map} +0 -0
- /package/dist/{chunk-EGTANAFI.js.map → chunk-SSFQWEPJ.js.map} +0 -0
- /package/dist/{chunk-YJNUVAM4.js.map → chunk-WHMX2D2Q.js.map} +0 -0
- /package/dist/{chunk-ABCQ6QMJ.js.map → chunk-YDAFHXDE.js.map} +0 -0
- /package/dist/{chunk-GFRAHUAQ.js.map → chunk-YLAJOO5X.js.map} +0 -0
- /package/dist/{chunk-B75BLZ2M.js.map → chunk-YXBQSLFV.js.map} +0 -0
- /package/dist/{client-OCLSGJYQ.js.map → client-7JINGNNU.js.map} +0 -0
- /package/dist/{config-FZTWI3VG.js.map → config-S4ZZHOUZ.js.map} +0 -0
- /package/dist/{config-mutate-X5IKMROK.js.map → config-mutate-U3KKAXVD.js.map} +0 -0
- /package/dist/{config-mutator-C5BMIBZO.js.map → config-mutator-KKRVNVVV.js.map} +0 -0
- /package/dist/{contributions-KHGGVSR6.js.map → contributions-6F3MYSRR.js.map} +0 -0
- /package/dist/{doctor-KNCRQ3YO.js.map → doctor-UDZI2OMU.js.map} +0 -0
- /package/dist/{follow-up-tool-TGKEPA5C.js.map → follow-up-tool-MP6FOIQE.js.map} +0 -0
- /package/dist/{hub-HQUAH5H6.js.map → hub-TSUVK7PH.js.map} +0 -0
- /package/dist/{promote-VD4OVQGL.js.map → promote-YVOYLTXI.js.map} +0 -0
- /package/dist/{push-bridge-P7HH25VN.js.map → push-bridge-CFPGPPO7.js.map} +0 -0
- /package/dist/{query-5CPK6G2H.js.map → query-ZGXXMJ4M.js.map} +0 -0
- /package/dist/{query-settings-35GDM3HU.js.map → query-settings-TNOGVKBX.js.map} +0 -0
- /package/dist/{registry-JCHKHCRE.js.map → registry-R2X4YGUK.js.map} +0 -0
- /package/dist/{request-planner-ZIG4YVXC.js.map → request-planner-QBNGJMF5.js.map} +0 -0
- /package/dist/{review-candidates-LPZWOR2K.js.map → review-candidates-WCDKCFXR.js.map} +0 -0
- /package/dist/{routing-BLOYDLU4.js.map → routing-RRRO2GDA.js.map} +0 -0
- /package/dist/{schedule-tool-7KFO3NPD.js.map → schedule-tool-2XZ3I5IL.js.map} +0 -0
- /package/dist/{scheduler-BEJRDQR3.js.map → scheduler-7O73TDCG.js.map} +0 -0
- /package/dist/{seat-NU3UJC6C.js.map → seat-CCDGNARC.js.map} +0 -0
- /package/dist/{select-IWAFX4XJ.js.map → select-VPZ4QDHV.js.map} +0 -0
- /package/dist/{set-enabled-JF75TSFU.js.map → set-enabled-VYSPZXPC.js.map} +0 -0
- /package/dist/{tool-PQBQJWM5.js.map → tool-K3PZOFC2.js.map} +0 -0
- /package/dist/{tool-WTOOPTGC.js.map → tool-VPDXU3IZ.js.map} +0 -0
- /package/dist/{wiki-DXG655NP.js.map → wiki-QA7BDTOR.js.map} +0 -0
- /package/dist/{wiki-enrich-5VQCT6BT.js.map → wiki-enrich-ZIZ5QHQ3.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{a as T,b as E,c as Y,d as j,e as G}from"./chunk-WPNRDEHW.js";import{v as R,y as O,z as U}from"./chunk-743RAKLP.js";import{a as V,b as C,f as B}from"./chunk-72SZI2UW.js";import{a as W,b as se}from"./chunk-MCI3DIWW.js";import{o as z,p as re}from"./chunk-JNG3P5V2.js";B();var xe="wiki-rerank",Se=30,ne=900;function Ne(a){let e=a.excerptChars??ne;return{query:a.query,candidates:a.candidates.map(t=>({id:t.id,title:t.title,tags:t.tags?.length?t.tags.join(", "):null,excerpt:ie(t.excerpt,e)}))}}function ke(a){let e={};for(let t of a)e[t.id]=t.title;return{best:C(e,"Which candidate answers the query?"),answerable:V("Do any of the candidates answer the query?")}}function Ie(a,e){let t=a.best,r={};for(let i of e)r[i.id]=t.probabilities[i.id]??0;let n=new Map(e.map((i,s)=>[i.id,s]));return{ranked:[...e.map(i=>i.id)].sort((i,s)=>{let c=r[s]-r[i];return c!==0?c:(n.get(i)??0)-(n.get(s)??0)}),scores:r,answerable:a.answerable.noul,confidence:t.confidence}}function ie(a,e){let t=String(a??"").replace(/\s+/g," ").trim();return t.length>e?t.slice(0,e):t}var x={version:2,levels:[{id:"category",description:"Top-level kind of work. Closed set \u2014 pick the closest fit.",axes:[{name:"kind",type:"enum",values:["code","ops","support","admin","knowledge","social","system"],description:"Which category this work belongs in."}]},{id:"verb",description:"Specific intent \u2014 verb-level only, NOT client/project-bound.",axes:[{name:"name",type:"free",description:"Lower-kebab dot-namespaced verb. Examples: review.merge-request, fix.bug, investigate.error, deploy.staging, deploy.production, rollback.release, spec.feature, triage.issue, document.feature, chat.greeting, chat.support-request, schedule.add, config.change, ingest.contact, transcribe.audio, brief.daily, summarize.thread, plan.work."}]}],leafInput:{name:"input",type:"enum",values:["telegram","whatsapp","slack","discord","gitlab-mr","gitlab-issue","github-issue","github-pr","cron","webhook","mesh","http"],description:"Where the message entered the system."},leafOutput:{name:"output",type:"free",description:"One short sentence describing what the agent is expected to produce. Generic \u2014 refers to the verb's outcome, not the specific client/project (those are on the event metadata already)."}},$={code:"Work on source code: review a PR or MR, fix a bug, build a feature, refactor, write a spec, or answer a question about code. Includes changes to AgentX's own code.",ops:"Running systems: deploy, roll back, monitor, scale, restart a service, or handle a production incident.",support:"A person talking to an agent: a greeting, casual chat, thanks, a question to answer, a request for help, a follow-up or complaint about an earlier request, or routing a request to someone else. The default for conversation that is not itself one of the other kinds of work.",admin:"Changing how the agents are set up: configuration, schedules, tokens, roles, adding an agent or a channel. Not a question about the setup or a complaint that something did not run.",knowledge:"Writing or gathering knowledge to keep: documentation, wiki articles, research, summarising a thread.",social:"Content made for an audience other than the agent: posts, announcements, daily briefs, weekly reports. Not a conversation with the agent.",system:"Internal sub-calls made by the platform itself, such as the intent classifier. A message from a person is almost never this."},M=[{category:"code",verb:"review.merge-request",description:"Review a GitLab MR or GitHub PR"},{category:"code",verb:"review.code-change",description:"General code review (snippet, diff)"},{category:"code",verb:"fix.bug",description:"Fix a reported bug"},{category:"code",verb:"implement.feature",description:"Build a new feature"},{category:"code",verb:"investigate.error",description:"Investigate a failing test, exception, pipeline"},{category:"code",verb:"refactor.code",description:"Restructure existing code without behaviour change"},{category:"code",verb:"spec.feature",description:"Write or update a feature spec / RFC"},{category:"code",verb:"triage.issue",description:"Classify, label, or assign an issue"},{category:"code",verb:"answer.code-question",description:"Answer a code-related question"},{category:"ops",verb:"deploy.staging",description:"Deploy to a staging/preview environment"},{category:"ops",verb:"deploy.production",description:"Deploy to production"},{category:"ops",verb:"rollback.release",description:"Roll back a release"},{category:"ops",verb:"investigate.incident",description:"Investigate a production incident"},{category:"ops",verb:"monitor.system",description:"Check system status / metrics"},{category:"ops",verb:"rotate.credential",description:"Rotate a token, key, certificate"},{category:"ops",verb:"audit.security",description:"Review for security issues"},{category:"support",verb:"chat.greeting",description:"A casual hello, no actionable request"},{category:"support",verb:"chat.support-request",description:"End-user / customer asking for help"},{category:"support",verb:"chat.casual",description:"Informal back-and-forth chat"},{category:"support",verb:"answer.question",description:"Answer an open-ended question"},{category:"support",verb:"route.request",description:"Forward a request to the right agent"},{category:"admin",verb:"config.change",description:"Change agentx.json / environment / config"},{category:"admin",verb:"schedule.add",description:"Add a new cron / scheduled task"},{category:"admin",verb:"schedule.remove",description:"Remove or disable a schedule"},{category:"admin",verb:"token.create",description:"Mint a scoped API token"},{category:"admin",verb:"agent.add",description:"Configure a new agent"},{category:"admin",verb:"channel.add",description:"Wire up a new channel"},{category:"knowledge",verb:"document.feature",description:"Write or update documentation"},{category:"knowledge",verb:"summarize.thread",description:"Summarize a long conversation/thread"},{category:"knowledge",verb:"research.topic",description:"Investigate / gather info on a topic"},{category:"knowledge",verb:"wiki.absorb",description:"Roll raw entries into typed wiki articles"},{category:"social",verb:"brief.daily",description:"Compose a daily brief / digest"},{category:"social",verb:"draft.post",description:"Draft a marketing post / announcement"},{category:"social",verb:"report.weekly",description:"Compose a weekly status report"},{category:"system",verb:"classify.intent",description:"Internal: graph-classifier sub-call"}];import{readFileSync as I,writeFileSync as _,appendFileSync as oe,existsSync as S,mkdirSync as D,renameSync as ae,statSync as Q}from"fs";import{resolve as A,dirname as Z}from"path";import{createHash as ce}from"crypto";var F=class{baseDir;log;parsed=new Map;constructor(e={}){this.baseDir=e.baseDir??A(process.cwd(),".agentx/graph"),this.log=e.log??console.error.bind(console,"[graph]"),D(this.baseDir,{recursive:!0})}schemaPath(){return A(this.baseDir,"schema.json")}nodesPath(){return A(this.baseDir,"nodes.json")}indexPath(){return A(this.baseDir,"index.json")}classificationsPath(){return A(this.baseDir,"classifications.jsonl")}loadSchema(){let e=this.schemaPath();if(!S(e))return this.saveSchema(x),this.log("seeded starter schema at",e),x;let t=I(e,"utf-8"),r=T.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);if((r.data.version??1)<(x.version??2)){let n=e.replace(/\.json$/,`.v${r.data.version??1}.bak.json`);try{_(n,t),this.log(`migrated graph schema v${r.data.version??1} -> v${x.version}; old saved at ${n}`)}catch(i){this.log(`could not back up old schema: ${i?.message??i}`)}this.saveSchema(x);let o=this.nodesPath();if(S(o)){let i=o.replace(/\.json$/,".v1.bak.json");try{_(i,I(o,"utf-8")),this.log(`archived v1 nodes.json -> ${i}`)}catch(s){this.log(`could not back up old nodes: ${s?.message??s}`)}try{let s=K();this.saveNodes(s)}catch(s){this.log(`could not seed v2 nodes: ${s?.message??s}`)}}return x}return r.data}saveSchema(e){let t=T.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid schema: ${t.error.issues.map(r=>r.message).join("; ")}`);X(this.schemaPath(),t.data)}loadNodes(){let e=this.nodesPath();if(!S(e)){let t=K();return this.saveNodes(t),t}return structuredClone(this.readParsed(e,t=>{let r=j.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}))}saveNodes(e){let t=j.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid nodes file: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.nodesPath(),t.data)}readParsed(e,t){let{mtimeMs:r,size:n}=Q(e),o=this.parsed.get(e);if(o&&o.mtimeMs===r&&o.size===n)return o.data;let i=t(I(e,"utf-8"));return this.parsed.set(e,{mtimeMs:r,size:n,data:i}),i}writeParsed(e,t){this.parsed.delete(e),X(e,t);let{mtimeMs:r,size:n}=Q(e);this.parsed.set(e,{mtimeMs:r,size:n,data:t})}validateNode(e,t,r){let n=t.levels.find(s=>s.id===e.level);if(!n)throw new Error(`Unknown level: "${e.level}"`);let o=n.axes.filter(s=>!s.optional).filter(s=>!(s.name in e.axes));if(o.length)throw new Error(`Node ${e.id} (${e.level}) missing required axes: ${o.map(s=>s.name).join(", ")}`);for(let s of n.axes){let c=e.axes[s.name];if(c!=null){if(s.type==="enum"&&s.values&&!s.values.includes(c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" not in enum ${JSON.stringify(s.values)}`);if(s.type==="ref"){if(!r.some(l=>l.id===c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" refers to unknown node`);if(s.refLevel){let l=r.find(h=>h.id===c);if(l.level!==s.refLevel)throw new Error(`Node ${e.id}: axis ${s.name} expected level "${s.refLevel}" but got "${l.level}"`)}}}}let i=t.levels.findIndex(s=>s.id===e.level);if(i===0){if(e.parentId!==null)throw new Error(`Root-level node ${e.id} must have parentId: null`)}else{if(!e.parentId)throw new Error(`Non-root node ${e.id} must have a parentId`);let s=r.find(l=>l.id===e.parentId);if(!s)throw new Error(`Node ${e.id}: parent "${e.parentId}" not found`);let c=t.levels.findIndex(l=>l.id===s.level);if(c<0||c>=i)throw new Error(`Node ${e.id} at level "${e.level}" has parent at level "${s.level}" \u2014 parent must be at a higher level`)}}commitNodesAlongPath(e,t,r,n){let o=[],i=[],s=new Date().toISOString();for(let c=0;c<e.length;c++){let l=e[c],h=this.loadNodes().nodes;if(h.find(p=>p.id===l)){i.push(l);continue}let u=0;for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(w=>w.id===y)||o.find(w=>w.id===y);if(N){u=r.levels.findIndex(w=>w.id===N.level)+1;break}}let m=t[l]??{},d=null;for(let p=u;p<r.levels.length;p++){let y=r.levels[p];if(y.axes.filter(w=>!w.optional).filter(w=>!(w.name in m)).length===0){d=y.id,u=p+1;break}}if(!d&&u<r.levels.length&&(d=r.levels[u].id,u++),!d)throw new Error(`Can't place node ${l} \u2014 no schema level left (cursor=${u}, levels=${r.levels.length})`);let f=null,v=r.levels.findIndex(p=>p.id===d);for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(k=>k.id===y)||o.find(k=>k.id===y);if(!N)continue;let w=r.levels.findIndex(k=>k.id===N.level);if(w>=0&&w<v){f=y;break}}let g={id:l,level:d,parentId:f,axes:m,createdAt:s,createdBy:n};this.addNode(g),o.push(g)}return{added:o,skipped:i}}addNode(e){let t=this.loadSchema(),r=this.loadNodes();if(r.nodes.some(n=>n.id===e.id))throw new Error(`Node id already exists: ${e.id}`);return this.validateNode(e,t,[...r.nodes,e]),r.nodes.push(e),this.saveNodes(r),e}appendClassification(e){let t=E.safeParse(e);if(!t.success){let o=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join(" \xB7 ");return this.log(`skipped invalid classification \u2014 ${o} \xB7`,`path=${JSON.stringify(e.path)}`,`axes-keys=${JSON.stringify(Object.keys(e.proposedAxes||{}))}`),!1}let r=JSON.stringify(t.data)+`
|
|
1
|
+
import{a as T,b as E,c as Y,d as j,e as G}from"./chunk-WPNRDEHW.js";import{v as R,y as O,z as U}from"./chunk-4RHM4XTI.js";import{a as V,b as C,f as B}from"./chunk-72SZI2UW.js";import{a as W,b as se}from"./chunk-MCI3DIWW.js";import{o as z,p as re}from"./chunk-JNG3P5V2.js";B();var xe="wiki-rerank",Se=30,ne=900;function Ne(a){let e=a.excerptChars??ne;return{query:a.query,candidates:a.candidates.map(t=>({id:t.id,title:t.title,tags:t.tags?.length?t.tags.join(", "):null,excerpt:ie(t.excerpt,e)}))}}function ke(a){let e={};for(let t of a)e[t.id]=t.title;return{best:C(e,"Which candidate answers the query?"),answerable:V("Do any of the candidates answer the query?")}}function Ie(a,e){let t=a.best,r={};for(let i of e)r[i.id]=t.probabilities[i.id]??0;let n=new Map(e.map((i,s)=>[i.id,s]));return{ranked:[...e.map(i=>i.id)].sort((i,s)=>{let c=r[s]-r[i];return c!==0?c:(n.get(i)??0)-(n.get(s)??0)}),scores:r,answerable:a.answerable.noul,confidence:t.confidence}}function ie(a,e){let t=String(a??"").replace(/\s+/g," ").trim();return t.length>e?t.slice(0,e):t}var x={version:2,levels:[{id:"category",description:"Top-level kind of work. Closed set \u2014 pick the closest fit.",axes:[{name:"kind",type:"enum",values:["code","ops","support","admin","knowledge","social","system"],description:"Which category this work belongs in."}]},{id:"verb",description:"Specific intent \u2014 verb-level only, NOT client/project-bound.",axes:[{name:"name",type:"free",description:"Lower-kebab dot-namespaced verb. Examples: review.merge-request, fix.bug, investigate.error, deploy.staging, deploy.production, rollback.release, spec.feature, triage.issue, document.feature, chat.greeting, chat.support-request, schedule.add, config.change, ingest.contact, transcribe.audio, brief.daily, summarize.thread, plan.work."}]}],leafInput:{name:"input",type:"enum",values:["telegram","whatsapp","slack","discord","gitlab-mr","gitlab-issue","github-issue","github-pr","cron","webhook","mesh","http"],description:"Where the message entered the system."},leafOutput:{name:"output",type:"free",description:"One short sentence describing what the agent is expected to produce. Generic \u2014 refers to the verb's outcome, not the specific client/project (those are on the event metadata already)."}},$={code:"Work on source code: review a PR or MR, fix a bug, build a feature, refactor, write a spec, or answer a question about code. Includes changes to AgentX's own code.",ops:"Running systems: deploy, roll back, monitor, scale, restart a service, or handle a production incident.",support:"A person talking to an agent: a greeting, casual chat, thanks, a question to answer, a request for help, a follow-up or complaint about an earlier request, or routing a request to someone else. The default for conversation that is not itself one of the other kinds of work.",admin:"Changing how the agents are set up: configuration, schedules, tokens, roles, adding an agent or a channel. Not a question about the setup or a complaint that something did not run.",knowledge:"Writing or gathering knowledge to keep: documentation, wiki articles, research, summarising a thread.",social:"Content made for an audience other than the agent: posts, announcements, daily briefs, weekly reports. Not a conversation with the agent.",system:"Internal sub-calls made by the platform itself, such as the intent classifier. A message from a person is almost never this."},M=[{category:"code",verb:"review.merge-request",description:"Review a GitLab MR or GitHub PR"},{category:"code",verb:"review.code-change",description:"General code review (snippet, diff)"},{category:"code",verb:"fix.bug",description:"Fix a reported bug"},{category:"code",verb:"implement.feature",description:"Build a new feature"},{category:"code",verb:"investigate.error",description:"Investigate a failing test, exception, pipeline"},{category:"code",verb:"refactor.code",description:"Restructure existing code without behaviour change"},{category:"code",verb:"spec.feature",description:"Write or update a feature spec / RFC"},{category:"code",verb:"triage.issue",description:"Classify, label, or assign an issue"},{category:"code",verb:"answer.code-question",description:"Answer a code-related question"},{category:"ops",verb:"deploy.staging",description:"Deploy to a staging/preview environment"},{category:"ops",verb:"deploy.production",description:"Deploy to production"},{category:"ops",verb:"rollback.release",description:"Roll back a release"},{category:"ops",verb:"investigate.incident",description:"Investigate a production incident"},{category:"ops",verb:"monitor.system",description:"Check system status / metrics"},{category:"ops",verb:"rotate.credential",description:"Rotate a token, key, certificate"},{category:"ops",verb:"audit.security",description:"Review for security issues"},{category:"support",verb:"chat.greeting",description:"A casual hello, no actionable request"},{category:"support",verb:"chat.support-request",description:"End-user / customer asking for help"},{category:"support",verb:"chat.casual",description:"Informal back-and-forth chat"},{category:"support",verb:"answer.question",description:"Answer an open-ended question"},{category:"support",verb:"route.request",description:"Forward a request to the right agent"},{category:"admin",verb:"config.change",description:"Change agentx.json / environment / config"},{category:"admin",verb:"schedule.add",description:"Add a new cron / scheduled task"},{category:"admin",verb:"schedule.remove",description:"Remove or disable a schedule"},{category:"admin",verb:"token.create",description:"Mint a scoped API token"},{category:"admin",verb:"agent.add",description:"Configure a new agent"},{category:"admin",verb:"channel.add",description:"Wire up a new channel"},{category:"knowledge",verb:"document.feature",description:"Write or update documentation"},{category:"knowledge",verb:"summarize.thread",description:"Summarize a long conversation/thread"},{category:"knowledge",verb:"research.topic",description:"Investigate / gather info on a topic"},{category:"knowledge",verb:"wiki.absorb",description:"Roll raw entries into typed wiki articles"},{category:"social",verb:"brief.daily",description:"Compose a daily brief / digest"},{category:"social",verb:"draft.post",description:"Draft a marketing post / announcement"},{category:"social",verb:"report.weekly",description:"Compose a weekly status report"},{category:"system",verb:"classify.intent",description:"Internal: graph-classifier sub-call"}];import{readFileSync as I,writeFileSync as _,appendFileSync as oe,existsSync as S,mkdirSync as D,renameSync as ae,statSync as Q}from"fs";import{resolve as A,dirname as Z}from"path";import{createHash as ce}from"crypto";var F=class{baseDir;log;parsed=new Map;constructor(e={}){this.baseDir=e.baseDir??A(process.cwd(),".agentx/graph"),this.log=e.log??console.error.bind(console,"[graph]"),D(this.baseDir,{recursive:!0})}schemaPath(){return A(this.baseDir,"schema.json")}nodesPath(){return A(this.baseDir,"nodes.json")}indexPath(){return A(this.baseDir,"index.json")}classificationsPath(){return A(this.baseDir,"classifications.jsonl")}loadSchema(){let e=this.schemaPath();if(!S(e))return this.saveSchema(x),this.log("seeded starter schema at",e),x;let t=I(e,"utf-8"),r=T.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);if((r.data.version??1)<(x.version??2)){let n=e.replace(/\.json$/,`.v${r.data.version??1}.bak.json`);try{_(n,t),this.log(`migrated graph schema v${r.data.version??1} -> v${x.version}; old saved at ${n}`)}catch(i){this.log(`could not back up old schema: ${i?.message??i}`)}this.saveSchema(x);let o=this.nodesPath();if(S(o)){let i=o.replace(/\.json$/,".v1.bak.json");try{_(i,I(o,"utf-8")),this.log(`archived v1 nodes.json -> ${i}`)}catch(s){this.log(`could not back up old nodes: ${s?.message??s}`)}try{let s=K();this.saveNodes(s)}catch(s){this.log(`could not seed v2 nodes: ${s?.message??s}`)}}return x}return r.data}saveSchema(e){let t=T.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid schema: ${t.error.issues.map(r=>r.message).join("; ")}`);X(this.schemaPath(),t.data)}loadNodes(){let e=this.nodesPath();if(!S(e)){let t=K();return this.saveNodes(t),t}return structuredClone(this.readParsed(e,t=>{let r=j.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}))}saveNodes(e){let t=j.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid nodes file: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.nodesPath(),t.data)}readParsed(e,t){let{mtimeMs:r,size:n}=Q(e),o=this.parsed.get(e);if(o&&o.mtimeMs===r&&o.size===n)return o.data;let i=t(I(e,"utf-8"));return this.parsed.set(e,{mtimeMs:r,size:n,data:i}),i}writeParsed(e,t){this.parsed.delete(e),X(e,t);let{mtimeMs:r,size:n}=Q(e);this.parsed.set(e,{mtimeMs:r,size:n,data:t})}validateNode(e,t,r){let n=t.levels.find(s=>s.id===e.level);if(!n)throw new Error(`Unknown level: "${e.level}"`);let o=n.axes.filter(s=>!s.optional).filter(s=>!(s.name in e.axes));if(o.length)throw new Error(`Node ${e.id} (${e.level}) missing required axes: ${o.map(s=>s.name).join(", ")}`);for(let s of n.axes){let c=e.axes[s.name];if(c!=null){if(s.type==="enum"&&s.values&&!s.values.includes(c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" not in enum ${JSON.stringify(s.values)}`);if(s.type==="ref"){if(!r.some(l=>l.id===c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" refers to unknown node`);if(s.refLevel){let l=r.find(h=>h.id===c);if(l.level!==s.refLevel)throw new Error(`Node ${e.id}: axis ${s.name} expected level "${s.refLevel}" but got "${l.level}"`)}}}}let i=t.levels.findIndex(s=>s.id===e.level);if(i===0){if(e.parentId!==null)throw new Error(`Root-level node ${e.id} must have parentId: null`)}else{if(!e.parentId)throw new Error(`Non-root node ${e.id} must have a parentId`);let s=r.find(l=>l.id===e.parentId);if(!s)throw new Error(`Node ${e.id}: parent "${e.parentId}" not found`);let c=t.levels.findIndex(l=>l.id===s.level);if(c<0||c>=i)throw new Error(`Node ${e.id} at level "${e.level}" has parent at level "${s.level}" \u2014 parent must be at a higher level`)}}commitNodesAlongPath(e,t,r,n){let o=[],i=[],s=new Date().toISOString();for(let c=0;c<e.length;c++){let l=e[c],h=this.loadNodes().nodes;if(h.find(p=>p.id===l)){i.push(l);continue}let u=0;for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(w=>w.id===y)||o.find(w=>w.id===y);if(N){u=r.levels.findIndex(w=>w.id===N.level)+1;break}}let m=t[l]??{},d=null;for(let p=u;p<r.levels.length;p++){let y=r.levels[p];if(y.axes.filter(w=>!w.optional).filter(w=>!(w.name in m)).length===0){d=y.id,u=p+1;break}}if(!d&&u<r.levels.length&&(d=r.levels[u].id,u++),!d)throw new Error(`Can't place node ${l} \u2014 no schema level left (cursor=${u}, levels=${r.levels.length})`);let f=null,v=r.levels.findIndex(p=>p.id===d);for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(k=>k.id===y)||o.find(k=>k.id===y);if(!N)continue;let w=r.levels.findIndex(k=>k.id===N.level);if(w>=0&&w<v){f=y;break}}let g={id:l,level:d,parentId:f,axes:m,createdAt:s,createdBy:n};this.addNode(g),o.push(g)}return{added:o,skipped:i}}addNode(e){let t=this.loadSchema(),r=this.loadNodes();if(r.nodes.some(n=>n.id===e.id))throw new Error(`Node id already exists: ${e.id}`);return this.validateNode(e,t,[...r.nodes,e]),r.nodes.push(e),this.saveNodes(r),e}appendClassification(e){let t=E.safeParse(e);if(!t.success){let o=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join(" \xB7 ");return this.log(`skipped invalid classification \u2014 ${o} \xB7`,`path=${JSON.stringify(e.path)}`,`axes-keys=${JSON.stringify(Object.keys(e.proposedAxes||{}))}`),!1}let r=JSON.stringify(t.data)+`
|
|
2
2
|
`,n=this.classificationsPath();return S(n)||D(Z(n),{recursive:!0}),oe(n,r),!0}listPendingClassifications(e=200){return this.listByStatus("pending",e)}listAllClassifications(){return this.readAllCollapsed()}listByStatus(e,t=200){return this.readAllCollapsed().filter(n=>n.status===e).slice(0,t)}readAllCollapsed(){let e=this.classificationsPath();if(!S(e))return[];let r=I(e,"utf-8").split(`
|
|
3
3
|
`).filter(Boolean),n=new Map;for(let o of r)try{let i=E.safeParse(JSON.parse(o));if(!i.success)continue;n.set(i.data.msgHash,i.data)}catch{}return Array.from(n.values()).sort((o,i)=>o.ts<i.ts?1:-1)}updateClassificationStatus(e,t){let n=this.readAllCollapsed().find(i=>i.msgHash===e);if(!n)return null;let o={...n,status:t.status,ts:new Date().toISOString()};if(t.reviewer||t.reviewReason){let i=` \xB7 ${t.reviewer?`reviewer=${t.reviewer}`:""}${t.reviewReason?` \xB7 ${t.reviewReason}`:""}`;o.preview=((n.preview||"")+i).slice(0,500)}return this.appendClassification(o),o}readRecentClassifications(e=50){let t=this.classificationsPath();if(!S(t))return[];let n=I(t,"utf-8").split(`
|
|
4
4
|
`).filter(Boolean),o=[];for(let i=n.length-1;i>=0&&o.length<e;i--)try{let s=E.safeParse(JSON.parse(n[i]));s.success&&o.push(s.data)}catch{}return o}fingerprint(e){let r=[de(e.text),e.channel??""].join("");return ce("sha256").update(r).digest("hex").slice(0,32)}loadIndex(){return structuredClone(this.index())}saveIndex(e){let t=G.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid index: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.indexPath(),t.data)}index(){let e=this.indexPath();return S(e)?this.readParsed(e,t=>{let r=G.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}):{version:1,entries:{}}}getFingerprint(e){let t=this.index().entries[e];return t&&structuredClone(t)}setFingerprint(e,t){let r=Y.safeParse({...t,fingerprint:e,updatedAt:new Date().toISOString()});if(!r.success)throw new Error(`Refusing to save invalid index entry: ${r.error.issues.map(o=>o.message).join("; ")}`);let n=this.index();this.writeParsed(this.indexPath(),{...n,entries:{...n.entries,[e]:r.data}})}updateNodeAxes(e,t){let r=this.loadSchema(),n=this.loadNodes(),o=n.nodes.find(s=>s.id===e);if(!o)throw new Error(`Node not found: ${e}`);let i={...o,axes:t};return this.validateNode(i,r,n.nodes.map(s=>s.id===e?i:s)),n.nodes=n.nodes.map(s=>s.id===e?i:s),this.saveNodes(n),i}deleteNode(e){let t=this.loadNodes(),r=t.nodes.find(o=>o.parentId===e);if(r)throw new Error(`Cannot delete "${e}" \u2014 child node "${r.id}" still points to it`);let n=t.nodes.find(o=>Object.values(o.axes).some(i=>i===e));if(n)throw new Error(`Cannot delete "${e}" \u2014 node "${n.id}" references it via an axis`);t.nodes=t.nodes.filter(o=>o.id!==e),this.saveNodes(t)}approveClassification(e){if(this.getFingerprint(e.msgHash))return;let t=this.loadSchema(),r=new Set(this.loadNodes().nodes.map(n=>n.id));for(let n=0;n<e.path.length;n++){let o=e.path[n];if(r.has(o))continue;let i=t.levels[n]?.id;if(!i)break;let s=e.proposedAxes?.[o]??{},c=n===0?null:e.path[n-1];this.addNode({id:o,level:i,parentId:c,axes:s,createdAt:new Date().toISOString(),createdBy:e.agentId}),r.add(o)}this.setFingerprint(e.msgHash,{path:e.path,leaf:e.leaf}),this.appendClassification({...e,status:"approved",ts:new Date().toISOString()})}rejectClassification(e){this.appendClassification({...e,status:"rejected",ts:new Date().toISOString()})}};function X(a,e){D(Z(a),{recursive:!0});let t=`${a}.tmp-${process.pid}`;_(t,JSON.stringify(e,null,2)),ae(t,a)}function K(){let a=new Date().toISOString(),e=[],t=new Set;for(let r of M)t.has(r.category)||(e.push({id:r.category,level:"category",parentId:null,axes:{kind:r.category,description:$[r.category]},createdAt:a,createdBy:"starter"}),t.add(r.category));for(let r of M)e.push({id:r.verb,level:"verb",parentId:r.category,axes:{name:r.verb,...r.description?{description:r.description}:{}},createdAt:a,createdBy:"starter"});return{version:1,nodes:e}}function de(a){return a.toLowerCase().replace(/https?:\/\/\S+/g," url ").replace(/[@#][\w.\/-]+/g," ref ").replace(/\b[0-9a-f]{7,}\b/g," id ").replace(/\d+/g," num ").replace(/[^\p{L}\p{N}\s]+/gu," ").replace(/\s+/g," ").trim().slice(0,400)}se();re();U();import{createHash as ye}from"crypto";B();U();var P="intent-path",le=.5,pe=.3,ue=.45;function ge(a){return{message:ve(a.message,2e3),channel:a.channel??null,sender:a.sender??null,agent:a.agent??null}}function ee(a,e){let t={};for(let r of a)t[r.id]=me(r);return C(t,e)}function he(a){let e=a.map(t=>{let r=$[t.id];return t.axes?.description?.trim()||!r?t:{...t,axes:{...t.axes,description:r}}});return{category:ee(e,"Which category of work does this message ask for or report on? Pick the one a reviewer would file it under.")}}function fe(a){return{verb:ee(a,"Within that category, which specific action does the message ask for or report on? Prefer the most specific verb that fits; a casual or ambiguous message belongs to the most general one.")}}async function q(a,e,t={}){if(R(P)==="off")return null;let r=e.filter(m=>m.parentId===null);if(r.length<2)return null;let n=ge(a),o={agent:a.agent??"unknown",channel:a.channel??"unknown"},i=a.agent?[{kind:"agent",id:a.agent}]:void 0,s=await O(P,n,he(r),{incumbent:t.incumbent?.[0]?{category:t.incumbent[0]}:void 0,features:{...o,stage:"category"},links:i});if(!s)return null;let c=s.answers.category,l=c.pMax,h=c.pMax>=le,b=[c.choice],u=e.filter(m=>m.parentId===c.choice);if(u.length>=2){let m=t.incumbent?.[0]===c.choice,d=await O(P,{...n,category:c.choice},fe(u),{incumbent:m&&t.incumbent?.[1]?{verb:t.incumbent[1]}:void 0,features:{...o,stage:"verb",category:c.choice},links:i});if(!d)return null;let f=d.answers.verb;h=h&&f.pMax>=pe,(f.pMax>=ue||!h)&&(l=Math.min(l,f.pMax),b.push(f.choice))}else u.length===1&&b.push(u[0].id);return{path:b,confidence:l,confident:h,mode:s.mode}}function me(a){let e=a.axes?.description?.trim()||void 0,t=a.axes?.name?.trim(),r=t&&t!==a.id?t:void 0;return e&&r?`${r}: ${e}`:e??r??null}function ve(a,e){return a.length>e?`${a.slice(0,e)}\u2026`:a}var L=class{store;daemonUrl;token;draftAgent;autoApprove;autoApproveStructure;classifierModel;classifierProviderName;providerInstance;log;constructor(e){this.store=e.store,this.daemonUrl=e.daemonUrl.replace(/\/+$/,""),this.token=e.token,this.draftAgent=e.draftAgent,this.autoApprove=e.autoApproveConfidence??1,this.autoApproveStructure=e.autoApproveStructure??"extend-leaves",this.classifierModel=e.classifierModel??"claude-haiku-4-5-20251001",this.classifierProviderName=e.classifierProvider??"claude-code",this.log=e.log??console.error.bind(console,"[classifier]")}getProvider(){return this.providerInstance||(this.providerInstance=z(this.classifierProviderName)),this.providerInstance}async classify(e){let t=this.store.fingerprint({text:e.text,channel:e.channel,sender:e.sender}),r=this.store.getFingerprint(t);if(r)return this.store.appendClassification({ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,chatId:e.chatId,path:r.path,proposedAxes:{},leaf:r.leaf,source:"cache",status:"approved",preview:e.text.slice(0,200)}),{path:r.path,pathId:H(r.path),pathLabel:J(r.path,this.store.loadNodes().nodes),axes:{},leaf:r.leaf,source:"cache",status:"approved"};let n=this.store.loadSchema(),o=this.store.loadNodes().nodes,i=await this.propose(e,n,o);if(!i)return null;let{path:s,proposedAxes:c,confidence:l,leaf:h}=i;if(s.length===0)return null;let b={ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,chatId:e.chatId,path:s,proposedAxes:c,leaf:h,source:i.source,status:"pending",confidence:l,preview:e.text.slice(0,200)},u=new Set(o.map(g=>g.id)),m=s.map((g,p)=>u.has(g)?-1:p).filter(g=>g>=0),d=!1;if(this.autoApproveStructure==="any")d=!0;else if(this.autoApproveStructure==="extend-leaves"){let g=m.length===0,p=m.length===1&&m[0]===s.length-1;d=g||p}let f=l!==void 0&&l>=this.autoApprove,v="pending";if(d||f)try{this.commitNewNodes(s,c,n,o,e.sender),this.store.setFingerprint(t,{path:s,leaf:h}),v="approved"}catch(g){this.log("auto-approve failed \u2014 staying pending \xB7",`path=${JSON.stringify(s)}`,`reason=${(g?.message||g).toString().slice(0,200)}`)}return b.status=v,this.store.appendClassification(b),{path:s,pathId:H(s),pathLabel:J(s,this.store.loadNodes().nodes),axes:c,leaf:h,source:i.source,status:v,confidence:l}}async propose(e,t,r){let n=R(P),o={message:e.text,channel:e.channel,sender:e.sender,agent:e.agentId};if(n==="active"){let s=await q(o,r).catch(c=>(this.log("intent-path seat failed:",c?.message||c),null));if(s?.confident)return{path:s.path,proposedAxes:{},leaf:{},confidence:s.confidence,source:"seat"}}let i=await this.proposePath(e,t,r).catch(s=>(this.log("LLM proposal failed:",s?.message||s),null));return n==="shadow"&&i&&q(o,r,{incumbent:i.path}).catch(()=>{}),i?{...i,source:"llm"}:null}async proposePath(e,t,r){let n=r.map(d=>({id:d.id,level:d.level,parentId:d.parentId,axes:d.axes})),o=["You are the intent classifier for AgentX. You answer ONE question:",'"what kind of work does this message describe?" \u2014 verb-level only.',"","IMPORTANT \u2014 what NOT to encode in the path:","- Client / company / project / team names. Those are already on the event"," metadata (project, channel, agentId). Embedding them in the path causes"," duplicate nodes (one per client) for the same verb.","- The specific subject (issue number, file name, person name). Same reason.","- The agent's name or role. Pick the verb the *requester* intended.","","SCHEMA (fixed levels \u2014 pick one node per level):","```json",JSON.stringify(t,null,2),"```","","EXISTING NODES (prefer reusing these; only invent a new node when no","existing one fits):","```json",JSON.stringify(n,null,2),"```","","MESSAGE:","```",e.text.slice(0,2e3),"```",`channel: ${e.channel??"?"}`,`sender: ${e.sender??"?"}`,"","TASK:","1. Classify into 'category' (closed enum): code, ops, support, admin,"," knowledge, social, system. Pick the closest fit.","2. Pick or propose a 'verb' node. Verb ids are dot-namespaced lower-kebab,",' e.g. "review.merge-request", "deploy.staging", "investigate.error",',' "chat.greeting", "fix.bug". Reuse an existing verb when the message is'," the same kind of work as something already classified, even when the"," client / project / subject differs.","","Examples (right vs wrong):",'- "Please review MR #957 on globex/system" \u2192 ["code", "review.merge-request"]',' NOT ["business", "acme", "globex-v2", "review-mr-957-system"]','- "Deploy initech-v2 to staging please" \u2192 ["ops", "deploy.staging"]',' NOT ["business", "acme", "initech-v2", "deploy-initech-v2-to-staging"]','- "Hello Atlas" \u2192 ["support", "chat.greeting"]',"","NODE ID RULES (strict \u2014 invalid ids get dropped):","- lowercase-kebab + dots only: [a-z0-9][a-z0-9._-]*","- no spaces, no uppercase, no Arabic/other non-Latin",'- verb ids should use a "category.specific" or "verb.modifier" shape',"","Return ONE JSON object on one line, no prose, no fences:",' { "path": string[], "proposedAxes": { [nodeId]: { [axisName]: string } }, "leaf": { "input"?: string, "output"?: string }, "confidence": number }',"confidence in [0,1]. Prefer low confidence over guessing."].join(`
|
|
5
5
|
`),i=await this.callProvider(o),s=W(i);if(!s||!Array.isArray(s.path))return null;let c=/^[a-z0-9][a-z0-9._-]*$/,l=new Map,h=s.path.filter(d=>typeof d=="string"&&d.length>0).map(d=>{let f=d.trim(),v=te(f);return f!==v&&l.set(f,v),v}).filter(d=>c.test(d));if(h.length===0)return null;let b={};if(s.proposedAxes&&typeof s.proposedAxes=="object")for(let[d,f]of Object.entries(s.proposedAxes)){if(!f||typeof f!="object")continue;let v=l.get(d)??te(d);if(!v)continue;let g={};for(let[p,y]of Object.entries(f))typeof y=="string"&&(g[p]=y);!g.name&&d!==v&&(g.name=d.trim()),b[v]=g}let u={};s.leaf&&typeof s.leaf=="object"&&(typeof s.leaf.input=="string"&&(u.input=s.leaf.input),typeof s.leaf.output=="string"&&(u.output=s.leaf.output));let m=typeof s.confidence=="number"?Math.max(0,Math.min(1,s.confidence)):void 0;return{path:h,proposedAxes:b,confidence:m,leaf:u}}commitNewNodes(e,t,r,n,o){this.store.commitNodesAlongPath(e,t,r,o)}async callProvider(e){let t=this.getProvider(),r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{return(await t.generate([{role:"system",content:"You are a taxonomy classifier. Respond with a single JSON object on one line. No prose, no code fences."},{role:"user",content:e}],{model:this.classifierModel,maxTokens:800,abortSignal:r.signal,bare:!0})).content||""}finally{clearTimeout(n)}}};function te(a){let e=a.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"").replace(/-{2,}/g,"-");return e?/^[a-z0-9]/.test(e)?e:`n-${e}`.replace(/[-_]+$/,""):""}function H(a){return ye("sha1").update(a.join("")).digest("hex").slice(0,16)}function J(a,e){return a.map(t=>{let r=e.find(o=>o.id===t);return r&&(r.axes?.name||r.axes?.what)||t}).join(" \u203A ")}function we(a,e){if(a.length===0||e.length===0)return 0;let t=0;for(let n=0;n<Math.min(a.length,e.length)&&a[n]===e[n];n++)t++;if(t===0)return 0;let r=Math.max(a.length,e.length);return t/r}export{xe as a,Se as b,Ne as c,ke as d,Ie as e,x as f,F as g,L as h,J as i,we as j};
|
|
6
|
-
//# sourceMappingURL=chunk-
|
|
6
|
+
//# sourceMappingURL=chunk-3ZAAUY2N.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";import{a as ne,b as et}from"./chunk-FCPTN6NF.js";import{a as Te,b as ht}from"./chunk-MCI3DIWW.js";import{o as we,p as Ze}from"./chunk-JNG3P5V2.js";import{
|
|
1
|
+
import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";import{a as ne,b as et}from"./chunk-FCPTN6NF.js";import{a as Te,b as ht}from"./chunk-MCI3DIWW.js";import{o as we,p as Ze}from"./chunk-JNG3P5V2.js";import{Xa as tt,Ya as nt}from"./chunk-SQTL2CLY.js";import{a as it,b as at,c as ct,d as ut,e as lt,f as dt,g as pt,h as mt,i as bt,j as ft,k as gt,l as yt}from"./chunk-RGDKHYY2.js";import{a as E,b as We,c as he}from"./chunk-QIJLFPWE.js";function R(e,t){$.set(e,t),X.delete(e)}function D(e){let t=X.get(e);if(t)return t;let r=$.get(e);if(!r){let o=Ee();throw new Error(`unknown decision backend "${e}"`+(o.length>0?` \u2014 registered: ${o.join(", ")}`:" \u2014 none registered"))}let n=r();return X.set(e,n),n}function Ee(){return[...$.keys()].sort()}function wt(){$.clear(),X.clear()}var $,X,C=E(()=>{"use strict";$=new Map,X=new Map});import Tt from"better-sqlite3";import{createHash as Et}from"crypto";import{mkdirSync as kt}from"fs";import{dirname as St,resolve as xt}from"path";function Q(e){if(e.type==="noul"){let r=e.noul,n={yes:r,no:1-r},o=r>=.5?"yes":"no",s=Math.abs(r-.5)*2;return{predicted:o,confidence:s,probabilities:n,topLabel:o,topProb:Math.max(r,1-r),expectedScore:null,pMax:Math.max(r,1-r),negEntropy:s}}if(e.type==="choice")return{predicted:e.choice,confidence:e.confidence,probabilities:{...e.probabilities},topLabel:e.choice,topProb:e.probabilities[e.choice]??0,expectedScore:null,pMax:e.pMax,negEntropy:e.negEntropy};let t=String(Math.round(e.score));return{predicted:t,confidence:e.confidence,probabilities:{...e.probabilities},topLabel:t,topProb:e.probabilities[t]??0,expectedScore:e.score,pMax:e.pMax,negEntropy:e.negEntropy}}function At(e){if(typeof e!="string"||e.length===0)return{};try{let t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch{return{}}}function Rt(e){e.exec("CREATE TABLE IF NOT EXISTS schema_version (v INTEGER PRIMARY KEY);");let t=e.prepare("SELECT MAX(v) AS v FROM schema_version").get().v??0;t<1&&vt(e),t<2&&Ot(e),t<3&&_t(e)}function _t(e){e.exec(`
|
|
2
2
|
ALTER TABLE decision_calls ADD COLUMN features_json TEXT;
|
|
3
3
|
INSERT INTO schema_version (v) VALUES (3);
|
|
4
4
|
`)}function Ot(e){e.exec(`
|
|
@@ -111,4 +111,4 @@ import{a as rt,b as ot,c as st,d as x,e as A,f as v}from"./chunk-72SZI2UW.js";im
|
|
|
111
111
|
`)}if(!m)throw new Error(`local decision backend could not get a valid answer after ${f+1} attempt(s): ${w}`);let M={},L=!1;for(let[k,q]of Object.entries(s.questions)){let S=_(q,m[k],{normalize:e.normalizeProbabilities??!0});M[k]=S.answer,S.repaired&&(L=!0)}return{model:a,answers:M,usage:h,meta:{backend:"local",structureMode:c,answerMode:"probabilities",repaired:L,retries:f,stateTruncated:l.truncated,latencyMs:Date.now()-i}}}finally{b()}}}}async function Jt(e,t,r,n,o){if(!e.generateRaw)throw new Error(`provider "${e.name}" has no generateRaw(); use structureMode "text"`);let s=[{role:"user",content:r},...n?[{role:"user",content:n}]:[]],i=await e.generateRaw(s,J,[{name:F,description:"Report a probability distribution for every question.",input_schema:se(t)}],{...o,toolChoice:{type:"tool",name:F}}),a=i.content.find(c=>c.type==="tool_use"&&c.name===F),u=a&&a.type==="tool_use"?a.input:null;return{answers:Be(u),usage:{inputTokens:i.usage.input_tokens,outputTokens:i.usage.output_tokens}}}async function Gt(e,t,r,n,o){let s=[r,ae(t)].join(`
|
|
112
112
|
`),i=[{role:"system",content:J},{role:"user",content:s},...n?[{role:"user",content:n}]:[]],a=await e.generate(i,o);return{answers:Be(Te(a.content??"")),usage:{inputTokens:0,outputTokens:a.tokensUsed??0}}}function Be(e){if(e&&typeof e=="object"&&!Array.isArray(e)){let t=e;if(t.answers&&typeof t.answers=="object")return t.answers}return e}function Yt(e,t){return e!=="auto"?e:t.generateRaw&&me[t.name]?.structuredOutput?"tool":"text"}function Kt(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(new Error(`decision timed out after ${t}ms`)),t),o=()=>r.abort(e?.reason);return e&&(e.aborted?o():e.addEventListener("abort",o,{once:!0})),{signal:r.signal,dispose:()=>{clearTimeout(n),e?.removeEventListener("abort",o)}}}var Xt,$t,Vt,Fe,zt,be=E(()=>{"use strict";Ze();Ue();ht();j();Y();v();z();Xt="claude-code",$t="claude-haiku-4-5-20251001",Vt=24e3,Fe=2e3,zt=3e4});import{readFileSync as Ht}from"fs";import{homedir as Wt}from"os";import{join as Zt}from"path";function N(e={}){let t=(e.baseUrl??en).replace(/\/+$/,""),r=e.path??"/classifier",n=e.name??"simple-jev",o=e.maxStateChars??nn,s=e.maxChoiceOptions??rn,i={probabilitySource:e.probabilitySource??"logits",calibratedProbabilities:!1,maxChoiceOptions:s,maxStateChars:o,parallelQuestions:!0,images:!1};return{name:n,capabilities:i,async decide(a){A(a.questions),cn(a.questions,s);let u=Date.now(),c=a.model??e.model;if(!c)throw new Error("simple-jev backend needs a model id");let l=G(a.state,o),p=e.fetchImpl??fetch,{signal:g,dispose:d}=un(a.abortSignal,a.timeoutMs??e.timeoutMs??tn);try{let b={"Content-Type":"application/json"},h=an(e.apiKeyEnv,e.apiKeyFile);h&&(b.Authorization=`Bearer ${h}`);let T=await qe(p(`${t}${r}`,{method:"POST",headers:b,body:JSON.stringify({model:c,state:l.text,questions:sn(a.questions)}),signal:g}),g);if(!T.ok){let k=await T.text().catch(()=>"");throw new Error(`${n} ${T.status}: ${k.slice(0,300)}`)}let f=await qe(T.json(),g),m=P(a.questions).safeParse(f.answers);if(!m.success)throw new Error(`${n} returned a response that does not match the requested questions (contract drift, not a model slip \u2014 retrying will not help):
|
|
113
113
|
${U(m.error)}`);let w=m.data,M={},L=!1;for(let[k,q]of Object.entries(a.questions)){let S=_(q,w[k]);M[k]=S.answer,S.repaired&&(L=!0)}return{model:f.model??c,answers:M,usage:{inputTokens:f.usage?.input_tokens??0,outputTokens:f.usage?.output_tokens??0},meta:{backend:n,structureMode:i.probabilitySource==="native"?"native":"logprobs",answerMode:"probabilities",repaired:L,retries:0,stateTruncated:l.truncated,latencyMs:Date.now()-u}}}finally{d()}}}}function sn(e){let t={};for(let[r,n]of Object.entries(e))t[r]=n.instructions?n:{...n,instructions:on[n.type]};return t}function an(e,t){let r=e?process.env[e]:void 0;if(r)return r;if(!t)return;let n=t.startsWith("~/")?Zt(Wt(),t.slice(2)):t;if(!Z.has(n))try{let o=Ht(n,"utf-8").trim();Z.set(n,o.length>0?o:null)}catch{Z.set(n,null)}return Z.get(n)??void 0}function cn(e,t){for(let[r,n]of Object.entries(e))if(n.type==="choice"){let o=Object.keys(n.criteria).length;if(o>t)throw new Error(`question "${r}": accepts at most ${t} choice options, got ${o}`)}else if(n.type==="score"&&n.criteria.length>t)throw new Error(`question "${r}": accepts at most ${t} score levels, got ${n.criteria.length}`)}function qe(e,t){return t.aborted?Promise.reject(t.reason??new Error("aborted")):new Promise((r,n)=>{let o=()=>n(t.reason??new Error("aborted"));t.addEventListener("abort",o,{once:!0}),e.then(s=>{t.removeEventListener("abort",o),r(s)},s=>{t.removeEventListener("abort",o),n(s)})})}function un(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(new Error(`decision timed out after ${t}ms`)),t),o=()=>r.abort(e?.reason);return e&&(e.aborted?o():e.addEventListener("abort",o,{once:!0})),{signal:r.signal,dispose:()=>{clearTimeout(n),e?.removeEventListener("abort",o)}}}var en,tn,nn,rn,on,Z,fe=E(()=>{"use strict";j();v();z();Y();en="http://127.0.0.1:8000/v1",tn=3e4,nn=6e3,rn=50;on={choice:"Which option best fits?",score:"Which level best fits?",noul:"Is this true of the state?"};Z=new Map});var Xe={};We(Xe,{DEFAULT_SEAT_TIMEOUT_MS:()=>Ve,DecisionStore:()=>I,MAX_CHOICE_OPTIONS:()=>MAX_CHOICE_OPTIONS,SYSTEM_PROMPT:()=>J,TOOL_NAME:()=>F,UNCERTAINTY_HIGH:()=>Ce,UNCERTAINTY_LOW:()=>De,_resetDecisionBackendsForTesting:()=>wt,agreement:()=>it,answerView:()=>Q,applyRecalibrator:()=>ue,applyTemperature:()=>mt,askSeat:()=>yn,band:()=>Ie,bootstrapInterval:()=>ft,brier:()=>lt,buildDesign:()=>ve,calibrationReport:()=>gt,choice:()=>ot,compareCalibrators:()=>It,confidenceFor:()=>re,configureDecisions:()=>pn,configuredSeatTimeout:()=>dn,coverageCurve:()=>pt,createLocalDecisionBackend:()=>W,createMockDecisionBackend:()=>H,createSimpleJevBackend:()=>N,decisionsRuntime:()=>bn,describeIssues:()=>U,ece:()=>ct,expectedScore:()=>Ae,finalizeAnswer:()=>_,fitLogistic:()=>Ne,fitRecalibrator:()=>B,fitTemperature:()=>bt,getDecisionBackend:()=>D,getSeatMode:()=>Je,labelSeatCall:()=>fn,labelsOf:()=>x,listDecisionBackends:()=>Ee,logLoss:()=>dt,logit:()=>le,mce:()=>ut,measureConsistency:()=>Ut,normalizeDistribution:()=>Se,normalizedNegEntropy:()=>oe,noul:()=>rt,pMax:()=>xe,parseSeatMode:()=>ge,rawAnswerSchema:()=>Re,rawAnswersSchema:()=>P,recordSeatOutcome:()=>gn,registerBuiltinDecisionBackends:()=>ln,registerDecisionBackend:()=>R,reliabilityBins:()=>at,renderQuestions:()=>_e,renderShapeInstructions:()=>ae,renderState:()=>G,renderUserPrompt:()=>ie,resetDecisionsRuntime:()=>mn,score:()=>st,seatEnvVar:()=>ze,sigmoid:()=>de,toolInputSchema:()=>se,validateQuestions:()=>A,withUid:()=>Qe});function ln(e={},t={},r={},n={}){R("mock",()=>H()),R("local",()=>W(e)),R("simple-jev",()=>N(t)),R("jev",()=>N({name:"jev",baseUrl:"https://openrouter.ai/api/alpha",path:"/decisions",model:"jev-latest",apiKeyEnv:"OPENROUTER_API_KEY",apiKeyFile:"~/.agentx/openrouter-key.txt",probabilitySource:"native",maxChoiceOptions:255,maxStateChars:9e4,...r})),R("typesafe",()=>N({name:"typesafe",baseUrl:"https://api.typesafe.ai/v1",path:"/systemone",model:"jev-latest",apiKeyEnv:"TYPESAFE_API_KEY",apiKeyFile:"~/.agentx/typesafe-key.txt",probabilitySource:"native",maxChoiceOptions:255,maxStateChars:9e4,...n}))}var $e=E(()=>{"use strict";ke();v();j();z();C();Y();V();yt();Me();je();Ge();pe();be();fe();C();pe();be();fe()});function dn(e){return Ke(),y.seats[e]?.timeoutMs}function pn(e){y={...ye,...y,...e},ee=!0}function mn(){y={...ye,seats:{}},ee=!1}function Ke(){if(!ee){ee=!0;try{let{loadDaemonConfig:e}=(nt(),he(tt)),t=e()?.decisions;if(!t?.enabled)return;let{registerBuiltinDecisionBackends:r}=($e(),he(Xe)),n=t.backends??{};r(n.local,n.simpleJev,n.jev,n.typesafe);let o=null;try{o=new I({path:t.dbPath})}catch{}y={enabled:!0,defaultBackend:t.defaultBackend,store:o,seats:Object.fromEntries(Object.entries(t.seats??{}).map(([s,i])=>[s,{...i,redactState:t.redactState,keepStateRows:t.keepStateRows}]))}}catch{}}}function bn(){return y}function ge(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return hn.includes(t)?t:null}function ze(e){return`AGENTX_DECISION_SEAT_${e.toUpperCase().replace(/[^A-Z0-9]+/g,"_")}`}function Je(e,t=process.env){Ke();let r=ge(t[ze(e)]);return r||(y.enabled?ge(y.seats[e]?.mode)??"off":"off")}function fn(e,t,r,n={}){if(!(!e||!y.store))try{y.store.label(e,t,r,n)}catch{}}function gn(e,t,r=!1){if(!(!e||!y.store))try{y.store.recordOutcome(e,t,r)}catch{}}async function yn(e,t,r,n={}){let o=Je(e);if(o==="off")return null;let s=y.seats[e]??{mode:o},i=n.backend??s.backend??y.defaultBackend,a=Date.now();try{let c=await D(i).decide({state:t,questions:r,model:n.model??s.model,abortSignal:n.signal,timeoutMs:n.timeoutMs??s.timeoutMs??(y.seats[e]?Ve:void 0)}),l=wn(e,o,t,r,c,n,s);return{answers:c.answers,callId:l,mode:o}}catch(u){return Tn(e,o,t,r,i,n,s,a,u),En(e,i,u),null}}function wn(e,t,r,n,o,s,i){if(!y.store)return null;try{return y.store.recordCall({seat:e,mode:t,backend:o.meta.backend,model:o.model,meta:o.meta,state:r,questions:n,answers:o.answers,usage:o.usage,incumbent:He(s.incumbent),links:s.links,features:s.features,keepState:!i.redactState})}catch{return null}}function Tn(e,t,r,n,o,s,i,a,u){if(y.store)try{y.store.recordCall({seat:e,mode:t,backend:o,model:s.model??i.model??"unknown",meta:{structureMode:"text",answerMode:"probabilities",retries:0,stateTruncated:!1,latencyMs:Date.now()-a},state:r,questions:n,answers:{},incumbent:He(s.incumbent),links:s.links,features:s.features,error:String(u?.message??u).slice(0,500),keepState:!i.redactState})}catch{}}function He(e){if(!e)return;let t={};for(let[r,n]of Object.entries(e))n!==void 0&&(t[r]={value:n});return t}function En(e,t,r){let n=Date.now();n-Ye<6e4||(Ye=n,console.warn(`[decisions] seat "${e}" on backend "${t}" failed: ${r?.message??r}`))}var Ve,ye,y,ee,hn,Ye,Ge=E(()=>{C();V();Ve=1e4;ye={enabled:!1,defaultBackend:"local",seats:{},store:null},y={...ye},ee=!1;hn=["off","shadow","active"];Ye=0});export{D as a,Ee as b,C as c,I as d,V as e,It as f,Me as g,Ut as h,je as i,me as j,Xn as k,Ue as l,ln as m,$e as n,Ve as o,dn as p,pn as q,mn as r,bn as s,ge as t,ze as u,Je as v,fn as w,gn as x,yn as y,Ge as z};
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-4RHM4XTI.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as h}from"./chunk-
|
|
1
|
+
import{a as h}from"./chunk-D65HXPIB.js";import{resolve as n}from"path";import{existsSync as c,readdirSync as u,mkdirSync as l,readFileSync as p,writeFileSync as f,renameSync as S}from"fs";var m=class{baseDir;agentsDir;mode;sharedStore;agentStores=new Map;log;constructor(e=n(process.cwd(),".agentx/wiki"),r=console.error.bind(console,"[wiki-hub]"),t="graph"){this.baseDir=e,this.agentsDir=n(e,"agents"),this.mode=t,this.log=r,l(this.agentsDir,{recursive:!0}),this.sharedStore=new h(e,r)}getMode(){return this.mode}getAgentWiki(e){let r=`${e}:${this.mode}`;if(this.agentStores.has(r))return this.agentStores.get(r);let t=n(this.agentsDir,e,this.mode),s=new h(t,this.log);return this.agentStores.set(r,s),s}getBaseDir(){return this.baseDir}getSharedStore(){return this.sharedStore}sharedScope(e){return[...this.listAgentDirs().filter(t=>t!==e).map(t=>({id:t,store:this.getAgentWiki(t)})),{id:"shared",store:this.sharedStore,skip:t=>t.startsWith("agents/")}]}listAgentDirs(){return c(this.agentsDir)?u(this.agentsDir).filter(e=>!e.startsWith("_")&&!e.startsWith(".")&&c(n(this.agentsDir,e,this.mode))).sort():[]}listAgents(e=this.sharedStore.listEntries()){let r=new Set;for(let t of e)r.add(t.agentId);if(c(this.agentsDir))for(let t of u(this.agentsDir))!t.startsWith("_")&&!t.startsWith(".")&&r.add(t);return[...r].sort()}getAgentEntries(e){return this.sharedStore.listEntries({agentId:e})}getUnabsorbedEntries(e){return this.classifyEntries(e).pending}markProcessed(e,r,t){let s=new Set(t),g=this.readLedger(e),d=new Date().toISOString();for(let i of r)g.entries[i]={at:d,cited:s.has(i)};let o=this.ledgerPath(e);l(n(o,".."),{recursive:!0});let a=`${o}.tmp`;f(a,`${JSON.stringify(g,null,2)}
|
|
2
2
|
`),S(a,o)}summary(){let e=this.sharedStore.listEntries(),r=new Map;for(let t of e){let s=r.get(t.agentId);s?s.push(t):r.set(t.agentId,[t])}return this.listAgents(e).map(t=>{let{all:s,cited:g,read:d,pending:o,articles:a}=this.classifyEntries(t,r.get(t)??[]);return{agentId:t,totalEntries:s.length,totalArticles:a.length,cited:g.length,readNotCited:d.length,unabsorbed:o.length,articles:a}})}classifyEntries(e,r=this.getAgentEntries(e)){let t=this.getAgentWiki(e).rebuildIndex().articles,s=new Set;for(let i of t)if(i.sources)for(let y of i.sources)s.add(y);let g=this.readLedger(e).entries,d=[],o=[],a=[];for(let i of r)s.has(i.id)?d.push(i):g[i.id]?o.push(i):a.push(i);return{all:r,cited:d,read:o,pending:a,articles:t}}syncedFrom(e){let r=n(this.agentsDir,e,"_synced.json");if(!c(r))return null;try{return JSON.parse(p(r,"utf-8"))}catch(t){return this.log(`synced marker ${r} is not valid JSON: ${t.message}`),{node:"unknown",peerUrl:"",at:""}}}markSynced(e,r){let t=n(this.agentsDir,e,"_synced.json");l(n(t,".."),{recursive:!0});let s=`${t}.tmp`;f(s,`${JSON.stringify(r,null,2)}
|
|
3
3
|
`),S(s,t)}ledgerPath(e){return n(this.agentsDir,e,"_absorbed.json")}readLedger(e){let r=this.ledgerPath(e);if(!c(r))return{entries:{}};try{return{entries:JSON.parse(p(r,"utf-8")).entries??{}}}catch(t){throw new Error(`absorb ledger ${r} is not valid JSON: ${t.message}`)}}};export{m as a};
|
|
4
|
-
//# sourceMappingURL=chunk-
|
|
4
|
+
//# sourceMappingURL=chunk-6CXJAZZD.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{q as d}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import{q as d}from"./chunk-AHZBWCXI.js";import{b as i,c as u,d as l,e as c}from"./chunk-IW4AZVJR.js";import f from"cronstrue";var p=Intl.DateTimeFormat().resolvedOptions().timeZone,m=600,E='Try: "every morning at 9", "weekdays at 6pm", "every 15 minutes", "every monday at 10am", "1st of every month at noon", "daily at 9:30am", "every hour"',g=/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;function w(e){return g.test(e)}function x(e){try{return new Intl.DateTimeFormat("en-US",{timeZone:e}),!0}catch{return!1}}function $(e){return e?e.split(",").map(r=>r.trim().toLowerCase()).filter(r=>r==="log"||r==="notify"||r==="disable"):["log"]}function S(e){let r=[...e.onError??["log"]];e.notify&&!r.includes("notify")&&r.push("notify");let t={enabled:e.enabled??!0,schedule:e.parsed.cron,timezone:e.timezone||p,agent:e.agent,prompt:e.prompt,timeout:e.timeout??m,onError:r};return e.model&&(t.model=e.model),e.notify&&(t.notify=e.notify),e.notify&&e.deliverResult===!1&&(t.deliverResult=!1),e.createdBy&&(t.createdBy=e.createdBy),e.approval&&(t.approval=e.approval),t}function P(e){try{return f.toString(e,{use24HourTimeFormat:!1})}catch{return e}}function T(e,r,t=new Date){try{return d(e,t,r)}catch{return null}}function A(e,r){if(!e)return"unknown (no match within a year)";try{return`${new Intl.DateTimeFormat("en-GB",{timeZone:r,weekday:"short",day:"2-digit",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}).format(e)} (${r})`}catch{return e.toISOString()}}function h(e){return e?.approval?.action==="create"}async function D(e,r={}){let t="",o=await i(n=>{let a=l(n,`crons.${e}`);if(!a)throw new Error(`cron "${e}" not found`);let s=a.approval;if(!s)throw new Error(`cron "${e}" has no pending request`);s.action==="create"?(delete a.approval,a.enabled=!0,t=`${e} approved and enabled (requested by ${s.requestedBy})`):(c(n,`crons.${e}`),t=`${e} deletion approved; job removed (requested by ${s.requestedBy})`)},{configPath:r.configPath,reload:r.reload});return o.success?{success:!0,message:t,result:o}:{success:!1,message:o.error||"failed",result:o}}async function I(e,r={}){let t="",o=await i(n=>{let a=l(n,`crons.${e}`);if(!a)throw new Error(`cron "${e}" not found`);let s=a.approval;if(!s)throw new Error(`cron "${e}" has no pending request`);s.action==="create"?(c(n,`crons.${e}`),t=`${e} rejected; pending job removed`):(delete a.approval,t=`${e} deletion rejected; job kept`)},{configPath:r.configPath,reload:r.reload});return o.success?{success:!0,message:t,result:o}:{success:!1,message:o.error||"failed",result:o}}async function O(e,r,t={}){return i(o=>{let n=l(o,`crons.${e}`);if(!n)throw new Error(`cron "${e}" not found`);if(r&&h(n))throw new Error(`cron "${e}" is awaiting approval; run \`agentx schedule approve ${e}\``);u(o,`crons.${e}.enabled`,r)},{configPath:t.configPath,reload:t.reload})}export{p as a,E as b,w as c,x as d,$ as e,S as f,P as g,T as h,A as i,h as j,D as k,I as l,O as m};
|
|
2
|
+
//# sourceMappingURL=chunk-ACB6GRSP.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as S,c as O}from"./chunk-
|
|
1
|
+
import{b as S,c as O}from"./chunk-IW4AZVJR.js";import{h as B,j as J}from"./chunk-3UOTLMXD.js";import{a as I,b as P}from"./chunk-FCPTN6NF.js";import{a as X,b as le}from"./chunk-7I7IEX4S.js";import{d as F}from"./chunk-QIJLFPWE.js";import{execFile as ke}from"child_process";import{writeFileSync as ie,mkdirSync as x,existsSync as b,readFileSync as Ce}from"fs";import{resolve as v}from"path";var ge=["off","shadow","authoritative"],me={telegram:"INTENT_LEDGER_MODE_TELEGRAM",slack:"INTENT_LEDGER_MODE_SLACK",whatsapp:"INTENT_LEDGER_MODE_WHATSAPP",discord:"INTENT_LEDGER_MODE_DISCORD",gitlab:"INTENT_LEDGER_MODE_GITLAB",github:"INTENT_LEDGER_MODE_GITHUB",workflow:"INTENT_LEDGER_MODE_WORKFLOW",cron:"INTENT_LEDGER_MODE_CRON",mesh:"INTENT_LEDGER_MODE_MESH"},he="INTENT_LEDGER_MODE";function G(i,e=process.env){let t=U(e[me[i]]);if(t)return t;let n=U(e[he]);return n||"off"}function U(i){if(typeof i!="string")return null;let e=i.trim().toLowerCase();return ge.includes(e)?e:null}P();import fe from"better-sqlite3";import{existsSync as Ge,mkdirSync as pe}from"fs";import{dirname as Ee,resolve as ve}from"path";var T=class{db;path;constructor(e={}){this.path=ve(process.cwd(),e.path??".agentx/intent/ledger.sqlite"),pe(Ee(this.path),{recursive:!0}),this.db=new fe(this.path),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),Ie(this.db)}close(){this.db.close()}schemaVersion(){return this.db.prepare("SELECT MAX(v) AS v FROM schema_version").get().v??0}recordEvent(e){if(e.sourceEventId!==null){let n=this.findEventBySourceId(e.source,e.sourceEventId);if(n)return n}let t={id:e.id??I(e.ts),ts:e.ts,source:e.source,sourceEventId:e.sourceEventId,project:e.project,subject:e.subject,intent:e.intent,rawJson:e.rawJson};return this.db.prepare(`INSERT INTO intent_events (id, ts, source, source_event_id, project, subject, intent, raw_json)
|
|
2
2
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(t.id,t.ts,t.source,t.sourceEventId,t.project,t.subject,t.intent,t.rawJson),t}findEventBySourceId(e,t){let n=this.db.prepare(`SELECT id, ts, source, source_event_id, project, subject, intent, raw_json
|
|
3
3
|
FROM intent_events WHERE source = ? AND source_event_id = ?`).get(e,t);return n?Y(n):null}getEventById(e){let t=this.db.prepare(`SELECT id, ts, source, source_event_id, project, subject, intent, raw_json
|
|
4
4
|
FROM intent_events WHERE id = ?`).get(e);return t?Y(t):null}recordDecision(e){this.db.prepare(`INSERT INTO intent_decisions (event_id, decided_at, decided_by, agent_id, outcome, reason)
|
|
@@ -125,4 +125,4 @@ ${oe(a.block,r.prompt)}`,r.maxOutputTokens),agentId:r.agent,autonomy:r.autonomy,
|
|
|
125
125
|
`);return t.length<=e?t.join(`
|
|
126
126
|
`):t.slice(-e).join(`
|
|
127
127
|
`)}function Pe(i,e,t){return new Promise((n,r)=>{ke("/bin/sh",["-c",i],{timeout:e,maxBuffer:8*1024*1024,...t?{env:t}:{}},(s,o,a)=>{if(s&&s.killed){r(new Error(`command timed out after ${Math.round(e/1e3)}s`));return}n({stdout:String(o??""),stderr:String(a??""),code:s?typeof s.code=="number"?s.code:1:0})})})}export{T as a,V as b,at as c,Le as d,ct as e,dt as f,L as g,ee as h,G as i,ze as j,z as k,Q as l,gt as m,Me as n,ae as o,ce as p,de as q,C as r,M as s};
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
128
|
+
//# sourceMappingURL=chunk-AHZBWCXI.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import{a as k}from"./chunk-IMLAPB7G.js";import{k as y}from"./chunk-LQS27HSV.js";import{b as V}from"./chunk-KP7KDLZ2.js";import{L as B,M as J,N as X,O as K,S as b,W as $e}from"./chunk-SQTL2CLY.js";import{existsSync as z,readFileSync as Oe}from"node:fs";import{dirname as A,join as h}from"node:path";import{fileURLToPath as Ie}from"node:url";import{homedir as Ee}from"node:os";var M="tn.acme.agentx.voice",ft="AgentX Desktop.app",Y="AgentX Helper.app";function gt(e,t,n){return e!=="darwin"||t!=="arm64"||Number(n.split(".")[0])<23?"AgentX Desktop currently requires Apple Silicon and macOS 14 or newer.":null}function yt(e,t){if(t&&!Object.hasOwn(e,t))throw new Error(`Unknown agent: ${t}. Run agentx agent list.`);let n=t||Object.keys(e)[0];if(!n)throw new Error("No agents configured. Run agentx setup first.");return n}function T(e){return`'${e.replace(/'/g,"'\\''")}'`}var Z="/usr/bin:/bin:/usr/sbin:/sbin";function ht(e,t){return t||[...new Set([...e?[A(e)]:[],...Z.split(":")])].join(":")}function R(e){let t={amp:"&",lt:"<",gt:">",quot:'"',apos:"'"};return e.replace(/&(amp|lt|gt|quot|apos);/g,(n,r)=>t[r])}function wt(e){let t=e.match(/<key>PATH<\/key>\s*<string>([^<]*)<\/string>/);return t?R(t[1]):Z}var St=e=>/agentx\.voice.*\.plist$/.test(e);function xt(e,t){let n=null,r=[];for(let{file:o,plist:i}of[...t].sort((s,u)=>s.file<u.file?-1:1)){let s=i.match(/<key>Label<\/key>\s*<string>([^<]*)<\/string>/)?.[1],u=i.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/)?.[1];!s||!u||!R(u).endsWith("/Contents/MacOS/AgentXVoice")||(n?r.push({file:o,label:R(s)}):n={file:o,label:R(s)})}return{keep:n??{file:h(e,`${M}.plist`),label:M},remove:r}}function Q(e,t,n){for(let r of t.split(":"))if(r&&n(h(r,e)))return h(r,e);return null}function vt(e){let t=r=>r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),n={PATH:e.path,...e.agent?{AGENTX_VOICE_AGENT:e.agent}:{},AGENTX_DAEMON_URL:e.url,AGENTX_MAC_HELPER:e.helper,AGENTX_PASTE_COMMAND:`cd ${T(e.cwd)} && ${T(e.node)} ${T(e.cli)} paste`};return`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0"><dict>
|
|
4
|
+
<key>Label</key><string>${t(e.label??M)}</string>
|
|
5
|
+
<key>ProgramArguments</key><array><string>${t(e.executable)}</string></array>
|
|
6
|
+
<key>WorkingDirectory</key><string>${t(e.cwd)}</string>
|
|
7
|
+
<key>EnvironmentVariables</key><dict>${Object.entries(n).map(([r,o])=>`<key>${r}</key><string>${t(o)}</string>`).join("")}</dict>
|
|
8
|
+
<key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
|
|
9
|
+
<key>ProcessType</key><string>Interactive</string>
|
|
10
|
+
<key>StandardErrorPath</key><string>${t(e.log)}</string>
|
|
11
|
+
</dict></plist>
|
|
12
|
+
`}function Nt(e){return e?["--icon",e]:[]}function Ce(e){return h(e,"Applications",Y,"Contents/MacOS/agentx-mac-helper")}function Te(e=A(Ie(import.meta.url))){for(let t=e;;t=A(t)){try{if(JSON.parse(Oe(h(t,"package.json"),"utf8")).name==="agentix-cli")return t}catch{}if(A(t)===t)return null}}function Me(e,t,n){if(n)return n;let r=Ce(t);return z(r)||!e?r:h(e,"apps/mac-helper/build",Y,"Contents/MacOS/agentx-mac-helper")}function _(){let e=Me(Te(),Ee(),process.env.AGENTX_MAC_HELPER);return z(e)?e:null}import{accessSync as We,constants as je}from"fs";import{execFile as L}from"child_process";var ee=5e3,P=(e,t)=>new Promise(n=>{try{L(e,t,{timeout:ee},r=>n(!r))}catch{n(!1)}}),w=(e,t)=>new Promise(n=>{try{L(e,t,{timeout:ee},(r,o)=>n(r?null:String(o)))}catch{n(null)}}),$=(e,t)=>new Promise((n,r)=>{L(e,t,{timeout:3e4,maxBuffer:8*1024*1024},(o,i,s)=>{o?r(new Error(`${e} ${t[0]}: ${(s||o.message).trim()}`)):n(i)})});var te=e=>e.helper===void 0?_():e.helper;async function _e(e,t=w){if(!e)return"missing";let n=await t(e,["notify-status"]),r=null;try{r=n?JSON.parse(n):null}catch{r=null}return r?r.authorization==="notDetermined"?"not-asked":r.authorization==="denied"?"not-allowed":r.alertStyle==="none"?"hidden":"ready":"outdated"}function ne(e={}){let t=e.run??P;return{async post({title:n,message:r}){let o=te(e);return o&&await t(o,["notify","--title",n,"--message",r])||await t("/usr/bin/osascript",["-e","on run argv","-e","display notification (item 2 of argv) with title (item 1 of argv)","-e","end run",n,r])?"posted":"failed"},status:()=>_e(te(e),e.capture)}}function Le(e){let t=e.match(/"HIDIdleTime"\s*=\s*(\d+)/);return t?Math.floor(Number(t[1])/1e9):null}function re(e={}){let t=e.capture??w;return{async seconds(){let n=await t("/usr/sbin/ioreg",["-c","IOHIDSystem","-d","4"]);return n?Le(n):null}}}var De=`
|
|
13
|
+
function run(argv) {
|
|
14
|
+
var folderName = argv[0], title = argv[1], body = argv[2]
|
|
15
|
+
var Notes = Application("Notes")
|
|
16
|
+
var esc = function (s) { return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") }
|
|
17
|
+
var folder = Notes.folders.whose({ name: folderName })()[0]
|
|
18
|
+
if (!folder) {
|
|
19
|
+
folder = Notes.Folder({ name: folderName })
|
|
20
|
+
Notes.folders.push(folder)
|
|
21
|
+
folder = Notes.folders.whose({ name: folderName })()[0]
|
|
22
|
+
}
|
|
23
|
+
var lines = body.split("\\n").map(function (l) { return "<div>" + (l ? esc(l) : "<br>") + "</div>" })
|
|
24
|
+
// Notes takes the title from the first line: a name as well would show it twice.
|
|
25
|
+
var note = Notes.Note({ body: "<div><h1>" + esc(title) + "</h1></div>" + lines.join("") })
|
|
26
|
+
folder.notes.push(note)
|
|
27
|
+
return note.id()
|
|
28
|
+
}
|
|
29
|
+
`;function ie(e=$){return{async add({folder:t,title:n,body:r}){let i=(await e("/usr/bin/osascript",["-l","JavaScript","-e",De,t,n,r])).trim();if(!i)throw new Error("Notes did not return the new note's id");return{id:i}}}}import{existsSync as qe,readdirSync as He}from"fs";var se="/System/Library/Sounds";function oe(e){if(!/^[\w -]+$/.test(e))return null;let t=`${se}/${e}.aiff`;return qe(t)?t:null}function ae(e={}){let t=e.run??P;return{async play(n,r){let o=oe(n);o&&await t("/usr/bin/afplay",["-v",String(Math.min(1,Math.max(0,r))),o])},has:n=>oe(n)!==null,async names(){try{return He(se).filter(n=>n.endsWith(".aiff")).map(n=>n.slice(0,-5)).sort()}catch{return[]}}}}var ue={say:"a spoken line (say)",afplay:"a sound playing (afplay)"};function Fe(e,t,n=process.pid){for(let r of e.split(`
|
|
30
|
+
`)){let o=r.trim().match(/^(\d+)\s+(\d+)\s+(\S+)/);if(!o)continue;let[i,s,u]=[Number(o[1]),Number(o[2]),o[3]],l=u.slice(u.lastIndexOf("/")+1);if(!(!(l in ue)||i===n||t.includes(s)))return ue[l]}return null}function le(e={}){let t=e.capture??w;return{async othersSpeaking(n={}){let r=await t("/bin/ps",["-axo","pid=,ppid=,comm="]);return r?Fe(r,n.exceptParents??[]):null}}}var de="\u200B";function O(e){return e.startsWith("-")?de+e:e}var ce=e=>e?.startsWith(de+"-")?e.slice(1):e;function D(e){if(!e.trim()||e.startsWith("-"))throw new Error(`Reminders list name "${e}" is not usable: it must not be empty or start with "-"`);return e}var pe=e=>new Date(Math.floor(e.getTime()/6e4)*6e4).toISOString().replace(/\.\d{3}Z$/,"Z");function me(e="remindctl",t=$){return{async ensureList(n){let r=await t(e,["list","--json","--no-input"]),o=JSON.parse(r.trim()||"[]");if(!Array.isArray(o))throw new Error(`${e} list: expected a JSON array`);o.some(i=>i?.title===n)||await t(e,["list",D(n),"--create","--json","--no-input"])},async listOpen(n){let r=await t(e,["show","all","--list",D(n),"--json","--no-input"]),o=JSON.parse(r.trim()||"[]");if(!Array.isArray(o))throw new Error(`${e} show: expected a JSON array`);return o.filter(i=>i&&typeof i.id=="string"&&!i.isCompleted).map(i=>({...i,title:ce(i.title)??"",...i.notes!==void 0?{notes:ce(i.notes)}:{}}))},async add({list:n,title:r,notes:o,due:i,priority:s}){let u=["add","--title",O(r),"--list",D(n),"--notes",O(o)];i&&u.push("--due",pe(i)),s&&s!=="none"&&u.push("--priority",s);let l=await t(e,[...u,"--json","--no-input"]),p;try{p=JSON.parse(l.trim())?.id}catch{p=void 0}if(typeof p!="string"||!p)throw new Error(`${e} add: no reminder id in its answer`);return{id:p}},async update(n,r){let o=["edit",n];r.title!==void 0&&o.push("--title",O(r.title)),r.notes!==void 0&&o.push("--notes",O(r.notes)),r.due===null?o.push("--clear-due"):r.due&&o.push("--due",pe(r.due)),o.length!==2&&await t(e,[...o,"--json","--no-input"])},async complete(n){await t(e,["complete",n,"--json","--no-input"])},async remove(n){await t(e,["delete",n,"--force","--json","--no-input"])}}}var Ue=e=>{try{return We(e,je.X_OK),!0}catch{return!1}},Ge={async active(){let e=V();return e.active?!0:e.reason==="no active Focus assertion"?!1:null}};function fe(e={},t={}){let n=e.reminders?.command||"remindctl";return{os:"macos",tasks:me(n,t.output),notes:ie(t.output),banner:ne(t),sound:ae(t),focus:Ge,speech:le(t),idle:re(t),async describe(){let r=[],o=t.isExecutable??Ue;return(n.includes("/")?o(n):!!Q(n,process.env.PATH||"",o))||r.push(`Reminders: ${n} not found (brew install steipete/tap/remindctl, or set reminders.command).`),{os:"macos",tasks:!0,notes:!0,banner:!0,sound:!0,focus:!0,problems:r}}}}function I(e){return{os:"none",async describe(){return{os:"none",tasks:!1,notes:!1,banner:!1,sound:!1,focus:!1,problems:[e]}}}}var Be={darwin:fe};function q(e={},t={}){if(e.native?.adapter==="none")return I('Turned off: native.adapter is "none".');let n=t.platform??process.platform,r=(t.factories??Be)[n];return r?r(e,t.io??{}):I(`AgentX has no native adapter for ${n} yet.`)}import{existsSync as Je}from"fs";import{homedir as Xe}from"os";import{isAbsolute as Ke}from"path";var ge={banner:!0,sound:!0,soundName:"Glass",volume:.4,quietWaitSeconds:15};function an(e){return{...ge,...e??{}}}function un(e,t={}){let n=q({native:t.native},{platform:t.platform,io:{run:t.run,capture:t.capture,helper:t.helper}});return async(r,o)=>{let i=[];if(e.banner&&n.banner&&i.push(n.banner.post({title:r,message:o})),e.sound&&n.sound){let s=n.sound;i.push(Ve(n.speech,(e.quietWaitSeconds??ge.quietWaitSeconds)*1e3,t.pollMs??500).then(u=>u?s.play(e.soundName,e.volume):void 0))}await Promise.all(i)}}async function Ve(e,t,n){if(!e||t<=0)return!0;let r=Date.now()+t;for(;;){if(!await e.othersSpeaking())return!0;if(Date.now()>=r)return!1;await new Promise(o=>setTimeout(o,n))}}function ln(e,t,n=process.platform){let r={...e??{}},o=q({},{platform:n});if("banner"in t&&(r.banner=!!t.banner),"sound"in t&&(r.sound=!!t.sound),"soundName"in t){let i=String(t.soundName).trim();if(!(o.sound?o.sound.has(i):/^[\w -]+$/.test(i)))throw new Error(`no system sound named "${i}" on this machine`);r.soundName=i}if("icon"in t){let i=String(t.icon??"").trim().replace(/^~(?=\/)/,Xe());if(!i)delete r.icon;else{if(!Ke(i)||!/\.(png|jpe?g|icns)$/i.test(i))throw new Error("icon must be the full path to a .png, .jpg or .icns file");if(o.banner&&!Je(i))throw new Error(`no icon file at ${i}`);r.icon=i}}if("volume"in t){let i=Number(t.volume);if(!Number.isFinite(i)||i<0||i>1)throw new Error("volume must be between 0 and 1");r.volume=i}return r}import{existsSync as et,mkdirSync as tt,readFileSync as nt,renameSync as rt,writeFileSync as it}from"fs";import{dirname as ve,resolve as ot}from"path";X();$e();X();var fn=["owner","agent","person"],ze=36e5,Ye=e=>K.includes(e.state);function ye(e){return t=>!e||e.get(t)?.state!=="active"?null:e.steps(t).find(n=>n.state==="active")?.agentId??null}function H(e,t){return e.state==="waiting_owner"?{group:"owner",who:b}:e.promise&&e.owedTo&&e.owedTo!==b&&!t.isAgent(e.owedTo)?{group:"person",who:e.owedTo}:e.state==="needs_attention"?{group:"owner",who:b}:{group:"agent",who:t.activeStepAgent?.(e.id)??e.agentId}}function F(e,t,n){return Ye(e)?e.state==="needs_attention"?e.attentionReason??"needs attention":e.dueAt!==null?n>e.dueAt?`past its due time (${Ze(e.dueAt)})`:null:n-e.updatedAt>t*ze?`no activity for ${t} h or more`:null:null}function gn(e,t,n,r){let o={owner:[],agent:[],person:[]};for(let i of e){let s=F(i,t,n);if(!s)continue;let{group:u,who:l}=H(i,r);o[u].push({request:i,group:u,who:l,why:s})}return o}function yn(e,t){return e==="owner"?"you":e==="agent"?`agent ${t}`:`${t} (outside person)`}var Ze=e=>new Date(e).toISOString().slice(0,16).replace("T"," ")+" UTC";function hn(e){if(e==null||e==="")return;let t=typeof e=="number"?e:typeof e=="string"?Date.parse(e.trim()):NaN;return!Number.isFinite(t)||t<=0?"due must be an ISO date (2030-01-31T17:00:00Z) or epoch milliseconds":t}function wn(e){return t=>B(t,e())}var Qe=10;async function Sn(e,t,n){let r=e.dueForCheck(n.now-n.everyMinutes*6e4,Qe),o=0;return await Promise.all(r.map(async i=>{e.markChecked(i.id,i.verifyState,i.verifyDetail??"",n.now);let s=await t(i.closeWhen,i).catch(u=>({verdict:"unverifiable",detail:String(u?.message??u)}));if(s.verdict==="met"){e.closeVerified(i.id,s.detail,n.now)&&(o++,n.log(`[requests] ${i.id} closed by its check: ${s.detail}`));return}e.markChecked(i.id,s.verdict==="unverifiable"?"unverified":i.verifyState==="failed"?"failed":null,s.detail,n.now)})),{checked:r.length,closed:o}}var Se=200,he=4e3,we="Nothing, just so you know.";function W(e,t=Se){let n=e.headline?e.headline.length>t?`${e.headline.slice(0,t-1)}\u2026`:e.headline:f(e.text,t),r=e.state==="needs_attention"?`Hand it back to ${e.agentId}, or drop it.`:e.state==="waiting_owner"?e.need??(e.question?`Answer: ${f(e.question,150)}`:"Your answer."):e.state==="candidate"||e.state==="in_progress"||e.state==="waiting_other"?e.need??we:we;return{headline:n,need:r,said:xe(e.text)}}function xe(e){return e.replace(/```[\s\S]*?```/g," ").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^\s{0,3}(#{1,6}|>|[-*+]|\d+[.)])\s+/gm,"").replace(/[*_~`]+/g,"").replace(/\s+/g," ").trim()}function f(e,t=Se){let n=xe(e);if(n.length<=t)return n;let r=n.slice(0,t),o=Math.max(r.lastIndexOf(". "),r.lastIndexOf("? "),r.lastIndexOf("! "));return o>t/2?r.slice(0,o+1):`${r.slice(0,t-1).trimEnd()}\u2026`}function kn(e,t,n,r){let o=n?.get(e.id),i=r?F(e,r.staleAfterHours,r.now):null,s=t.lastAnswer(e.id),u=s&&s.text.length>he?`${s.text.slice(0,he)}
|
|
31
|
+
|
|
32
|
+
\u2026`:s?.text,l=W(e);return{...e,summary:l.headline,needed:l.need,textHtml:k(e.text),why:e.state==="waiting_owner"?e.question:e.state==="needs_attention"?e.attentionReason:null,ownerNoteHtml:e.ownerNote?k(e.ownerNote):null,lastAnswer:s?{agentId:s.agentId,at:s.at,html:k(u)}:null,loop:e.promise||e.dueAt!==null||e.closeWhen?{owedTo:e.owedTo,promise:e.promise,dueAt:e.dueAt,check:e.closeWhen?J(e.closeWhen):null,verifyState:e.verifyState,verifyDetail:e.verifyDetail}:null,stall:r&&i?{...H(e,{isAgent:r.isAgent,activeStepAgent:ye(n)}),why:i}:null,plan:o?{state:o.state,steps:n.steps(e.id).map(p=>({idx:p.idx,name:p.name,kind:p.kind,agentId:p.agentId,state:p.state,approval:p.needsApproval?p.approval:null,evidence:p.evidence,note:p.note,nudges:p.nudges}))}:null}}var j=3,st=30*24*36e5;function be(e){return ot(e,".agentx","native-mirror.json")}function ke(e){try{let t=JSON.parse(nt(be(e),"utf-8"));return{...t,items:t?.items&&typeof t.items=="object"?t.items:{}}}catch{return{items:{}}}}function Ne(e,t){let n=be(e);et(ve(n))||tt(ve(n),{recursive:!0});let r=`${n}.${process.pid}.tmp`;it(r,JSON.stringify(t,null,2)+`
|
|
33
|
+
`),rt(r,n)}var at=5*6e4;function In(e,t,n=Date.now()){let r=ke(e),o=r.checkedAt?Date.parse(r.checkedAt):NaN;return!r.cards||!(n-o<=at)?!1:r.items[`card:${t}`]?.state!=="failed"}var U=24*36e5;function Ae(e,t,n){let r=e+t.dueAfterMinutes*6e4;return new Date(n!==void 0&&Number.isFinite(n)?Math.max(e,Math.min(r,n)):r)}function ut(e,t,n,r){let o=Date.parse(e.expires),i=[f(e.ask,y.ask)];return e.choices?.length&&i.push(...e.choices.map((s,u)=>`${u+1}. ${s}`)),e.recommend&&i.push(`Recommended: ${f(e.recommend,y.recommend)}`),i.push(`Answer: ${n}`,`agentx: card=${e.id}`),{key:`card:${e.id}`,title:f(e.title,y.title),notes:i.join(`
|
|
34
|
+
`),due:Ae(r,t,o),priority:Number.isFinite(o)&&o-r<=U?"high":"none"}}function lt(e,t,n,r){let o=[f(e.question||e.text,y.ask),`Asked of ${e.agentId}.`,`Answer: ${n}`,`agentx: request=${e.id}`],i=e.dueAt??void 0;return{key:`request:${e.id}`,title:W(e,y.title).headline,notes:o.join(`
|
|
35
|
+
`),due:Ae(r,t,i),priority:i!==void 0&&i-r<=U?"high":"none"}}async function En(e){let{root:t,settings:n,tasks:r,log:o}=e,i=e.now??Date.now(),s=new Date(i).toISOString(),u={created:0,completed:0,dismissed:0,failed:0},l=ke(t);delete l.lastError;let p=a=>{l.lastError={at:s,message:a}},S=new Map;try{if(n.include.includes("card"))for(let a of e.cards())a.status==="pending"&&Date.parse(a.expires)>i&&S.set(`card:${a.id}`,ut(a,n,e.answerUrl,i));if(n.include.includes("request"))for(let a of e.requests())a.state==="waiting_owner"&&S.set(`request:${a.id}`,lt(a,n,e.answerUrl,i))}catch(a){return o(`[mirror] could not read what is waiting: ${a?.message??a}`),p(String(a?.message??a)),Ne(t,l),u}let G=!0,v=new Map,Re=async a=>{if(!v.has(a))try{v.set(a,new Set((await r.listOpen(a)).map(c=>c.id)))}catch(c){o(`[mirror] could not read list "${a}": ${c?.message??c}`),p(String(c?.message??c)),v.set(a,null),G=!1}return v.get(a)};for(let[a,c]of Object.entries(l.items)){if(c.state!=="open"||!c.id)continue;let d=await Re(c.list);if(d)if(S.has(a))d.has(c.id)||(l.items[a]={...c,state:"dismissed",at:s},u.dismissed++,o(`[mirror] ${a}: its task was ticked off or deleted; it stays on the Desk and is not mirrored again`));else{if(d.has(c.id))try{await r.complete(c.id)}catch(g){o(`[mirror] ${a}: could not complete its task: ${g?.message??g}`),p(String(g?.message??g));continue}l.items[a]={...c,state:"completed",at:s},u.completed++}}let E=null,x=[];for(let[a,c]of S){let d=l.items[a];if(d&&(d.state==="open"||d.state==="dismissed")||d?.state==="failed"&&d.failures>=j)continue;if(E===null)try{await r.ensureList(n.list),E=!0}catch(m){o(`[mirror] could not make list "${n.list}": ${m?.message??m}`),p(String(m?.message??m)),E=!1}let g=d?.state==="failed"?d.failures:0;try{let{id:m}=await r.add({list:n.list,title:c.title,notes:c.notes,due:c.due,priority:c.priority});l.items[a]={id:m,list:n.list,state:"open",at:s,failures:0},u.created++}catch(m){let N=String(m?.message??m),C=g+1;l.items[a]={list:n.list,state:"failed",at:s,failures:C,lastError:N},p(N),u.failed++,o(`[mirror] ${a}: could not add to Reminders (${C}/${j}): ${N}`),C===j&&x.push({title:c.title,message:N})}}let Pe=l.failureToldAt?Date.parse(l.failureToldAt):NaN;if(x.length&&!(i-Pe<U)){let a=x[0],c=x.length>1?` (and ${x.length-1} more)`:"";try{await e.notify("Could not add to Reminders",`${a.title}${c}: ${f(a.message,200)}. Still on the Desk.`),l.failureToldAt=s}catch(d){o(`[mirror] could not tell the owner: ${d?.message??d}`)}}G&&(l.checkedAt=s,l.cards=n.include.includes("card"));for(let[a,c]of Object.entries(l.items))c.state!=="open"&&!S.has(a)&&i-Date.parse(c.at)>st&&delete l.items[a];return Ne(t,l),u}export{fn as a,ye as b,H as c,gn as d,yn as e,Ze as f,hn as g,wn as h,Sn as i,W as j,kn as k,ft as l,Y as m,gt as n,yt as o,ht as p,wt as q,St as r,xt as s,Q as t,vt as u,Nt as v,Ce as w,Te as x,Me as y,_ as z,oe as A,q as B,ge as C,an as D,un as E,ln as F,ke as G,In as H,En as I};
|
|
36
|
+
//# sourceMappingURL=chunk-AVAR5KNN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/desktop/install.ts","../src/native/macos/index.ts","../src/native/macos/run.ts","../src/native/macos/banner.ts","../src/native/macos/idle.ts","../src/native/macos/notes.ts","../src/native/macos/sound.ts","../src/native/macos/speech.ts","../src/native/macos/tasks.ts","../src/native/none.ts","../src/native/index.ts","../src/notify/local.ts","../src/approvals/mirror.ts","../src/requests/card-view.ts","../src/requests/loops.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { homedir } from 'node:os'\n\nexport const DESKTOP_LABEL = 'tn.acme.agentx.voice'\nexport const DESKTOP_APP = 'AgentX Desktop.app'\nexport const HELPER_APP = 'AgentX Helper.app'\nexport function desktopPlatformError(platform: string, arch: string, release: string): string | null {\n if (platform !== 'darwin' || arch !== 'arm64' || Number(release.split('.')[0]) < 23)\n return 'AgentX Desktop currently requires Apple Silicon and macOS 14 or newer.'\n return null\n}\nexport function selectDesktopAgent(agents: Record<string, unknown>, requested?: string): string {\n if (requested && !Object.hasOwn(agents, requested)) throw new Error(`Unknown agent: ${requested}. Run agentx agent list.`)\n const id = requested || Object.keys(agents)[0]\n if (!id) throw new Error('No agents configured. Run agentx setup first.')\n return id\n}\nexport function shellQuote(value: string): string { return `'${value.replace(/'/g, \"'\\\\''\")}'` }\n/** launchd's default PATH, which is all a login item gets unless the plist sets one. */\nexport const LAUNCHD_PATH = '/usr/bin:/bin:/usr/sbin:/sbin'\n/** PATH for the login item: AGENTX_VOICE_PATH when set, else the folder of\n * the ffmpeg found at install time (mlx_whisper needs it) ahead of launchd's default. */\nexport function desktopPath(ffmpeg: string | null, override?: string): string {\n if (override) return override\n return [...new Set([...(ffmpeg ? [dirname(ffmpeg)] : []), ...LAUNCHD_PATH.split(':')])].join(':')\n}\nfunction unxml(s: string): string {\n const ents: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\" }\n return s.replace(/&(amp|lt|gt|quot|apos);/g, (_, e) => ents[e])\n}\n/** The PATH a login item plist sets, or launchd's default when it sets none. */\nexport function plistPathEnv(plist: string): string {\n const m = plist.match(/<key>PATH<\\/key>\\s*<string>([^<]*)<\\/string>/)\n return m ? unxml(m[1]) : LAUNCHD_PATH\n}\n/** Login item files the voice app may have been installed under. */\nexport const isVoiceLoginItemFile = (name: string) => /agentx\\.voice.*\\.plist$/.test(name)\nexport type LoginItem = { file: string; label: string }\n/** One login item per Mac. The label was renamed once and\n * apps/mac-voice/install.sh writes its own, so adopt the first existing\n * `*agentx.voice*` item that runs the voice app (any bundle name) and\n * retire the others; with none, use DESKTOP_LABEL. Plists are XML text. */\nexport function adoptLoginItem(dir: string, items: { file: string; plist: string }[]): { keep: LoginItem; remove: LoginItem[] } {\n let keep: LoginItem | null = null\n const remove: LoginItem[] = []\n for (const { file, plist } of [...items].sort((a, b) => (a.file < b.file ? -1 : 1))) {\n const label = plist.match(/<key>Label<\\/key>\\s*<string>([^<]*)<\\/string>/)?.[1]\n const program = plist.match(/<key>ProgramArguments<\\/key>\\s*<array>\\s*<string>([^<]*)<\\/string>/)?.[1]\n if (!label || !program || !unxml(program).endsWith('/Contents/MacOS/AgentXVoice')) continue\n if (keep) remove.push({ file, label: unxml(label) })\n else keep = { file, label: unxml(label) }\n }\n return { keep: keep ?? { file: join(dir, `${DESKTOP_LABEL}.plist`), label: DESKTOP_LABEL }, remove }\n}\n/** The file that a process with this PATH would run, or null. */\nexport function findOnPath(bin: string, path: string, isExecutable: (file: string) => boolean): string | null {\n for (const dir of path.split(':')) if (dir && isExecutable(join(dir, bin))) return join(dir, bin)\n return null\n}\n/** Without `agent` the app talks to the agent picked in its menu-bar\n * icon; with it, that agent is pinned and the menu cannot switch. */\nexport function desktopPlist(opts: { label?: string; executable: string; cwd: string; agent?: string; url: string; helper: string; cli: string; node: string; log: string; path: string }): string {\n const xml = (s: string) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"').replace(/'/g, ''')\n const env = {\n PATH: opts.path,\n ...(opts.agent ? { AGENTX_VOICE_AGENT: opts.agent } : {}),\n AGENTX_DAEMON_URL: opts.url,\n AGENTX_MAC_HELPER: opts.helper,\n AGENTX_PASTE_COMMAND: `cd ${shellQuote(opts.cwd)} && ${shellQuote(opts.node)} ${shellQuote(opts.cli)} paste`,\n }\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\"><dict>\n<key>Label</key><string>${xml(opts.label ?? DESKTOP_LABEL)}</string>\n<key>ProgramArguments</key><array><string>${xml(opts.executable)}</string></array>\n<key>WorkingDirectory</key><string>${xml(opts.cwd)}</string>\n<key>EnvironmentVariables</key><dict>${Object.entries(env).map(([k,v]) => `<key>${k}</key><string>${xml(v)}</string>`).join('')}</dict>\n<key>RunAtLoad</key><true/><key>KeepAlive</key><true/>\n<key>ProcessType</key><string>Interactive</string>\n<key>StandardErrorPath</key><string>${xml(opts.log)}</string>\n</dict></plist>\\n`\n}\n/** build.sh arguments for the helper: the banner icon from\n * notifications.local.icon, or none for the bundled AgentX logo. */\nexport function helperBuildArgs(icon?: string): string[] {\n return icon ? ['--icon', icon] : []\n}\nexport function installedHelper(home: string): string {\n return join(home, 'Applications', HELPER_APP, 'Contents/MacOS/agentx-mac-helper')\n}\n/** The AgentX package folder, found by walking up from this file (dist/\n * when installed, src/ in a checkout) — never from the caller's cwd, so\n * `agentx notify` finds a repo-built helper from any folder. */\nexport function packageRoot(from = dirname(fileURLToPath(import.meta.url))): string | null {\n for (let dir = from; ; dir = dirname(dir)) {\n try {\n if (JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).name === 'agentix-cli') return dir\n } catch { /* no package.json here — keep walking up */ }\n if (dirname(dir) === dir) return null\n }\n}\n/** The helper to run: an explicit path, else the one `agentx desktop\n * install` put in ~/Applications, else one built in the package. */\nexport function resolveHelper(root: string | null, home: string, override?: string): string {\n if (override) return override\n const installed = installedHelper(home)\n if (existsSync(installed) || !root) return installed\n return join(root, 'apps/mac-helper/build', HELPER_APP, 'Contents/MacOS/agentx-mac-helper')\n}\n/** The AgentX Helper binary when one is built or installed, else null.\n * AGENTX_MAC_HELPER points at a helper somewhere else. */\nexport function findHelper(): string | null {\n const path = resolveHelper(packageRoot(), homedir(), process.env.AGENTX_MAC_HELPER)\n return existsSync(path) ? path : null\n}\n","import { accessSync, constants } from \"fs\"\nimport { findOnPath } from \"@/desktop/install\"\nimport { readSystemFocus } from \"@/notify/focus\"\nimport type { NativeAdapter, NativeFocus } from \"../types\"\nimport { macosBanner } from \"./banner\"\nimport { macosIdle } from \"./idle\"\nimport { macosNotes } from \"./notes\"\nimport type { Capture, Output, Run } from \"./run\"\nimport { macosSound } from \"./sound\"\nimport { macosSpeech } from \"./speech\"\nimport { macosTasks } from \"./tasks\"\n\n/** Programs the adapter runs, so tests can stand in for them. */\nexport interface MacosIo {\n run?: Run\n capture?: Capture\n output?: Output\n /** The AgentX Helper binary; null means none. Unset: looked up on use. */\n helper?: string | null\n /** Is this file an executable? Used to find remindctl. */\n isExecutable?: (file: string) => boolean\n}\n\nconst executable = (file: string): boolean => {\n try { accessSync(file, constants.X_OK); return true } catch { return false }\n}\n\n/** System Focus from the private Focus database (notify/focus.ts). That\n * reader answers \"not in Focus\" when it can't read the file, so here\n * anything but a clean answer is null: the OS could not tell. */\nconst focus: NativeFocus = {\n async active() {\n const s = readSystemFocus()\n if (s.active) return true\n return s.reason === \"no active Focus assertion\" ? false : null\n },\n}\n\nexport function macosAdapter(cfg: { reminders?: { command?: string } } = {}, io: MacosIo = {}): NativeAdapter {\n const command = cfg.reminders?.command || \"remindctl\"\n return {\n os: \"macos\",\n tasks: macosTasks(command, io.output),\n notes: macosNotes(io.output),\n banner: macosBanner(io),\n sound: macosSound(io),\n focus,\n speech: macosSpeech(io),\n idle: macosIdle(io),\n async describe() {\n const problems: string[] = []\n const isExec = io.isExecutable ?? executable\n const found = command.includes(\"/\") ? isExec(command) : !!findOnPath(command, process.env.PATH || \"\", isExec)\n if (!found) problems.push(`Reminders: ${command} not found (brew install steipete/tap/remindctl, or set reminders.command).`)\n return { os: \"macos\", tasks: true, notes: true, banner: true, sound: true, focus: true, problems }\n },\n }\n}\n","import { execFile } from \"child_process\"\n\n/** Runs a program; resolves true when it exited 0. Never rejects. */\nexport type Run = (file: string, args: string[]) => Promise<boolean>\n\n/** Runs a program; resolves its stdout, or rejects with its stderr. */\nexport type Output = (file: string, args: string[]) => Promise<string>\n\n/** Runs a program; resolves its stdout, or null when it failed. */\nexport type Capture = (file: string, args: string[]) => Promise<string | null>\n\n/** A banner or a sound may not hold a caller hostage: afplay on a long\n * custom sound, or osascript stuck on a permission prompt, is cut off. */\nconst STEP_TIMEOUT_MS = 5_000\n\nexport const run: Run = (file, args) =>\n new Promise((done) => {\n try {\n execFile(file, args, { timeout: STEP_TIMEOUT_MS }, (err) => done(!err))\n } catch {\n done(false) // the program is not on this machine: not worth reporting\n }\n })\n\nexport const capture: Capture = (file, args) =>\n new Promise((done) => {\n try {\n execFile(file, args, { timeout: STEP_TIMEOUT_MS }, (err, stdout) => done(err ? null : String(stdout)))\n } catch {\n done(null)\n }\n })\n\nexport const output: Output = (file, args) =>\n new Promise((resolve, reject) => {\n execFile(file, args, { timeout: 30_000, maxBuffer: 8 * 1024 * 1024 }, (err, stdout, stderr) => {\n if (err) reject(new Error(`${file} ${args[0]}: ${(stderr || err.message).trim()}`))\n else resolve(stdout)\n })\n })\n","import { findHelper } from \"@/desktop/install\"\nimport type { BannerStatus, NativeBanner } from \"../types\"\nimport { capture as defaultCapture, run as defaultRun, type Capture, type Run } from \"./run\"\n\n// The banner is posted by the AgentX Helper app when it is installed, so it\n// carries the helper's icon (the AgentX logo by default). Without the\n// helper, or before macOS has allowed it to notify, osascript posts it, and\n// macOS shows it as coming from Script Editor.\n\nexport interface BannerIo {\n run?: Run\n capture?: Capture\n /** The helper binary; null means none. Unset: looked up on each use. */\n helper?: string | null\n}\n\nconst helperOf = (io: BannerIo): string | null => (io.helper === undefined ? findHelper() : io.helper)\n\n/** What the helper reports about its notification permission. Never shows\n * the macOS \"allow notifications\" prompt and never posts a banner. */\nexport async function helperBannerStatus(path: string | null, capture: Capture = defaultCapture): Promise<BannerStatus> {\n if (!path) return \"missing\"\n const out = await capture(path, [\"notify-status\"])\n let status: { authorization?: string; alertStyle?: string } | null = null\n try { status = out ? JSON.parse(out) : null } catch { status = null }\n if (!status) return \"outdated\"\n if (status.authorization === \"notDetermined\") return \"not-asked\"\n if (status.authorization === \"denied\") return \"not-allowed\"\n if (status.alertStyle === \"none\") return \"hidden\"\n return \"ready\"\n}\n\nexport function macosBanner(io: BannerIo = {}): NativeBanner {\n const exec = io.run ?? defaultRun\n return {\n async post({ title, message }) {\n const helper = helperOf(io)\n // A non-zero exit is usually \"not allowed to notify yet\" (the first\n // banner asks), so this one goes through osascript instead.\n if (helper && await exec(helper, [\"notify\", \"--title\", title, \"--message\", message])) return \"posted\"\n // Title and message travel as argv, never spliced into the script,\n // so a quote in either cannot turn into AppleScript.\n const ok = await exec(\"/usr/bin/osascript\", [\n \"-e\", \"on run argv\",\n \"-e\", \"display notification (item 2 of argv) with title (item 1 of argv)\",\n \"-e\", \"end run\",\n title, message,\n ])\n return ok ? \"posted\" : \"failed\"\n },\n status: () => helperBannerStatus(helperOf(io), io.capture),\n }\n}\n","import type { NativeIdle } from \"../types\"\nimport { capture as defaultCapture, type Capture } from \"./run\"\n\n// --- How long since the person touched this Mac (#1138 step B) ---\n//\n// The HID system keeps the time since the last keyboard, mouse or trackpad\n// input, in nanoseconds. ioreg prints it without any permission prompt.\n\n/** Seconds idle from `ioreg -c IOHIDSystem -d 4` output, or null. */\nexport function idleSecondsIn(ioreg: string): number | null {\n const m = ioreg.match(/\"HIDIdleTime\"\\s*=\\s*(\\d+)/)\n return m ? Math.floor(Number(m[1]) / 1e9) : null\n}\n\nexport function macosIdle(io: { capture?: Capture } = {}): NativeIdle {\n const capture = io.capture ?? defaultCapture\n return {\n async seconds() {\n const out = await capture(\"/usr/sbin/ioreg\", [\"-c\", \"IOHIDSystem\", \"-d\", \"4\"])\n return out ? idleSecondsIn(out) : null\n },\n }\n}\n","import type { NativeNotes } from \"../types\"\nimport { output as defaultOutput, type Output } from \"./run\"\n\n// Apple Notes through JXA (osascript -l JavaScript). The folder, title\n// and body travel as argv and are read by the script, never spliced into\n// it, so nothing in them can run as code. Notes stores a body as HTML:\n// the script escapes the text and keeps its line breaks. The first call\n// from the daemon's process asks for the macOS Automation permission\n// (System Settings › Privacy & Security › Automation › Notes).\n\nexport const NOTES_SCRIPT = `\nfunction run(argv) {\n var folderName = argv[0], title = argv[1], body = argv[2]\n var Notes = Application(\"Notes\")\n var esc = function (s) { return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\") }\n var folder = Notes.folders.whose({ name: folderName })()[0]\n if (!folder) {\n folder = Notes.Folder({ name: folderName })\n Notes.folders.push(folder)\n folder = Notes.folders.whose({ name: folderName })()[0]\n }\n var lines = body.split(\"\\\\n\").map(function (l) { return \"<div>\" + (l ? esc(l) : \"<br>\") + \"</div>\" })\n // Notes takes the title from the first line: a name as well would show it twice.\n var note = Notes.Note({ body: \"<div><h1>\" + esc(title) + \"</h1></div>\" + lines.join(\"\") })\n folder.notes.push(note)\n return note.id()\n}\n`\n\nexport function macosNotes(exec: Output = defaultOutput): NativeNotes {\n return {\n async add({ folder, title, body }) {\n const raw = await exec(\"/usr/bin/osascript\", [\"-l\", \"JavaScript\", \"-e\", NOTES_SCRIPT, folder, title, body])\n const id = raw.trim()\n if (!id) throw new Error(\"Notes did not return the new note's id\")\n return { id }\n },\n }\n}\n","import { existsSync, readdirSync } from \"fs\"\nimport type { NativeSound } from \"../types\"\nimport { run as defaultRun, type Run } from \"./run\"\n\nconst SOUNDS = \"/System/Library/Sounds\"\n\n/** The system sound file for a name, or null when there is none. Names\n * only: a path in the config must not reach afplay. */\nexport function soundPath(name: string): string | null {\n if (!/^[\\w -]+$/.test(name)) return null\n const path = `${SOUNDS}/${name}.aiff`\n return existsSync(path) ? path : null\n}\n\nexport function macosSound(io: { run?: Run } = {}): NativeSound {\n const exec = io.run ?? defaultRun\n return {\n async play(name, volume) {\n const path = soundPath(name)\n if (!path) return\n await exec(\"/usr/bin/afplay\", [\"-v\", String(Math.min(1, Math.max(0, volume))), path])\n },\n has: (name) => soundPath(name) !== null,\n async names() {\n try {\n return readdirSync(SOUNDS).filter((f) => f.endsWith(\".aiff\")).map((f) => f.slice(0, -5)).sort()\n } catch {\n return []\n }\n },\n }\n}\n","import type { NativeSpeech } from \"../types\"\nimport { capture as defaultCapture, type Capture } from \"./run\"\n\n// --- Is something else speaking on this Mac? (#1126) ---\n//\n// A script that narrates with `say`, or plays a recording with `afplay`,\n// talks to the person at this Mac without going through AgentX's speaking\n// queue. Before AgentX speaks or chimes, it looks at the process list:\n// one such program running, not started by AgentX itself, means wait.\n\n/** Programs that speak or play sound, and how the owner would say it. */\nconst SPEAKERS: Record<string, string> = { say: \"a spoken line (say)\", afplay: \"a sound playing (afplay)\" }\n\n/** \"pid ppid command\" lines from ps, the speakers among them. */\nexport function speakersIn(ps: string, exceptParents: number[], self = process.pid): string | null {\n for (const line of ps.split(\"\\n\")) {\n const m = line.trim().match(/^(\\d+)\\s+(\\d+)\\s+(\\S+)/)\n if (!m) continue\n const [pid, ppid, comm] = [Number(m[1]), Number(m[2]), m[3]]\n const name = comm.slice(comm.lastIndexOf(\"/\") + 1)\n if (!(name in SPEAKERS) || pid === self || exceptParents.includes(ppid)) continue\n return SPEAKERS[name]\n }\n return null\n}\n\nexport function macosSpeech(io: { capture?: Capture } = {}): NativeSpeech {\n const capture = io.capture ?? defaultCapture\n return {\n async othersSpeaking(opts = {}) {\n const ps = await capture(\"/bin/ps\", [\"-axo\", \"pid=,ppid=,comm=\"])\n return ps ? speakersIn(ps, opts.exceptParents ?? []) : null\n },\n }\n}\n","import type { NativeTask, NativeTasks } from \"../types\"\nimport { output as defaultOutput, type Output } from \"./run\"\n\n// Apple Reminders through remindctl (Homebrew). It is the same tool the\n// mac-pim skill uses, so the daemon and the skill see the same lists. The\n// first call from the daemon's process triggers the macOS Reminders\n// permission prompt.\n//\n// Every value travels as its own argv entry, never through a shell, so\n// quotes and newlines arrive as typed. remindctl 0.1.1 reads any value\n// that starts with \"-\" as an option (and a value equal to --help or\n// --version runs that), and has no \"--opt=value\" form, so such a value\n// gets an invisible zero-width space in front. Reminders keeps that\n// character; listOpen takes it off again. A list name is a lookup key and\n// cannot carry it, so a list name that starts with \"-\" is refused.\n//\n// Reminders keeps a due time to the minute, in this Mac's time zone:\n// seconds are dropped.\n\nconst ZWSP = \"\\u200b\"\n\n/** A value remindctl takes literally. */\nexport function argValue(v: string): string {\n return v.startsWith(\"-\") ? ZWSP + v : v\n}\n\nconst unArg = (v: string | undefined): string | undefined => (v?.startsWith(ZWSP + \"-\") ? v.slice(1) : v)\n\nfunction listName(list: string): string {\n if (!list.trim() || list.startsWith(\"-\")) throw new Error(`Reminders list name \"${list}\" is not usable: it must not be empty or start with \"-\"`)\n return list\n}\n\n/** ISO to the minute, which is all Reminders keeps. */\nconst isoDue = (d: Date): string => new Date(Math.floor(d.getTime() / 60_000) * 60_000).toISOString().replace(/\\.\\d{3}Z$/, \"Z\")\n\nexport function macosTasks(command = \"remindctl\", exec: Output = defaultOutput): NativeTasks {\n return {\n async ensureList(list) {\n const raw = await exec(command, [\"list\", \"--json\", \"--no-input\"])\n const lists = JSON.parse(raw.trim() || \"[]\")\n if (!Array.isArray(lists)) throw new Error(`${command} list: expected a JSON array`)\n if (lists.some((l: { title?: string }) => l?.title === list)) return\n await exec(command, [\"list\", listName(list), \"--create\", \"--json\", \"--no-input\"])\n },\n async listOpen(list) {\n const raw = await exec(command, [\"show\", \"all\", \"--list\", listName(list), \"--json\", \"--no-input\"])\n const items = JSON.parse(raw.trim() || \"[]\")\n if (!Array.isArray(items)) throw new Error(`${command} show: expected a JSON array`)\n return items\n .filter((r: NativeTask) => r && typeof r.id === \"string\" && !r.isCompleted)\n .map((r: NativeTask) => ({ ...r, title: unArg(r.title) ?? \"\", ...(r.notes !== undefined ? { notes: unArg(r.notes) } : {}) }))\n },\n async add({ list, title, notes, due, priority }) {\n const args = [\"add\", \"--title\", argValue(title), \"--list\", listName(list), \"--notes\", argValue(notes)]\n if (due) args.push(\"--due\", isoDue(due))\n if (priority && priority !== \"none\") args.push(\"--priority\", priority)\n const raw = await exec(command, [...args, \"--json\", \"--no-input\"])\n let id: unknown\n try { id = JSON.parse(raw.trim())?.id } catch { id = undefined }\n if (typeof id !== \"string\" || !id) throw new Error(`${command} add: no reminder id in its answer`)\n return { id }\n },\n async update(id, patch) {\n const args = [\"edit\", id]\n if (patch.title !== undefined) args.push(\"--title\", argValue(patch.title))\n if (patch.notes !== undefined) args.push(\"--notes\", argValue(patch.notes))\n if (patch.due === null) args.push(\"--clear-due\")\n else if (patch.due) args.push(\"--due\", isoDue(patch.due))\n // remindctl refuses an edit that changes nothing; so does this.\n if (args.length === 2) return\n await exec(command, [...args, \"--json\", \"--no-input\"])\n },\n async complete(id) {\n await exec(command, [\"complete\", id, \"--json\", \"--no-input\"])\n },\n async remove(id) {\n await exec(command, [\"delete\", id, \"--force\", \"--json\", \"--no-input\"])\n },\n }\n}\n","import type { NativeAdapter } from \"./types\"\n\n/** The adapter for a machine AgentX has no OS layer for, or where the owner\n * turned it off. Every capability is absent; describe() says why. */\nexport function noneAdapter(reason: string): NativeAdapter {\n return {\n os: \"none\",\n async describe() {\n return { os: \"none\", tasks: false, notes: false, banner: false, sound: false, focus: false, problems: [reason] }\n },\n }\n}\n","import { macosAdapter, type MacosIo } from \"./macos\"\nimport { noneAdapter } from \"./none\"\nimport type { NativeAdapter } from \"./types\"\n\nexport * from \"./types\"\nexport { noneAdapter } from \"./none\"\n\nexport type NativeAdapterChoice = \"auto\" | \"none\"\n\nexport type NativeConfig = { native?: { adapter?: NativeAdapterChoice }; reminders?: { command?: string } }\n\n/** Programs an adapter runs, so tests can stand in for them. */\nexport type NativeIo = MacosIo\n\n/** Builds the adapter for one OS. Each OS adapter registers here. */\nexport type NativeAdapterFactory = (cfg: NativeConfig, io: NativeIo) => NativeAdapter\n\nconst FACTORIES: Partial<Record<NodeJS.Platform, NativeAdapterFactory>> = {\n darwin: macosAdapter,\n}\n\n/** The adapter for this machine. `native.adapter: \"none\"` forces none on\n * any OS; \"auto\" (the default) picks by platform. */\nexport function loadNativeAdapter(\n cfg: NativeConfig = {},\n opts: { platform?: NodeJS.Platform; factories?: Partial<Record<NodeJS.Platform, NativeAdapterFactory>>; io?: NativeIo } = {},\n): NativeAdapter {\n if (cfg.native?.adapter === \"none\") return noneAdapter(\"Turned off: native.adapter is \\\"none\\\".\")\n const platform = opts.platform ?? process.platform\n const make = (opts.factories ?? FACTORIES)[platform]\n return make ? make(cfg, opts.io ?? {}) : noneAdapter(`AgentX has no native adapter for ${platform} yet.`)\n}\n","import { existsSync } from \"fs\"\nimport { homedir } from \"os\"\nimport { isAbsolute } from \"path\"\nimport { loadNativeAdapter, type NativeConfig, type NativeIo, type NativeSpeech } from \"@/native\"\n\nexport { findHelper } from \"@/desktop/install\"\n\n// What happens on THIS machine when a notification is delivered: a banner\n// on screen and a short sound. The push goes to the phone; these are for\n// the person sitting at the computer that raised the event. Both go\n// through the native adapter (src/native); a machine without one skips\n// them.\n//\n// Both are awaited rather than fired and forgotten. A caller that exits\n// straight after notifying — a `launchctl submit` job that removes itself,\n// a cron one-liner — used to take the sound down with it before it\n// played. Waiting costs about a second and makes the step reliable.\n//\n// Never fatal: a notification whose banner failed still arrived, and no\n// caller should have to handle an audio error to say a build finished.\n\nexport interface LocalSettings {\n /** Show a desktop banner (macOS only; other platforms skip it). */\n banner: boolean\n /** Play a sound (macOS only). */\n sound: boolean\n /** A system sound, by name (on a Mac, one of the sounds in System Settings › Sound). */\n soundName: string\n /** 0 (silent) … 1 (full). */\n volume: number\n /** Seconds the sound waits while something else speaks on this machine\n * (#1126). Still speaking after that: no sound, the banner is enough.\n * 0: never wait. */\n quietWaitSeconds?: number\n /** Image for the helper's app icon, which macOS puts on its banners.\n * Unset: the AgentX logo. Applied when `agentx desktop install` builds\n * the helper, since macOS reads the icon from the app, not the banner. */\n icon?: string\n}\n\n/** Glass is the gentlest system sound that is still audible over a\n * keyboard — Basso and Sosumi are alerts, Funk and Frog are jokes, and\n * Ping is the one every other app already uses. */\nexport const DEFAULT_LOCAL: LocalSettings = { banner: true, sound: true, soundName: \"Glass\", volume: 0.4, quietWaitSeconds: 15 }\n\n/** Shows the banner and plays the sound for one delivered notification. */\nexport type LocalAlert = (title: string, message: string) => Promise<void>\n\n/** Fill gaps in a partial `notifications.local` block with the defaults. */\nexport function localSettings(cfg: Partial<LocalSettings> | undefined): LocalSettings {\n return { ...DEFAULT_LOCAL, ...(cfg ?? {}) }\n}\n\nexport function localAlert(\n settings: LocalSettings,\n deps: {\n run?: NativeIo[\"run\"]; capture?: NativeIo[\"capture\"]; platform?: NodeJS.Platform; helper?: string | null; native?: NativeConfig[\"native\"]\n /** For tests: the poll between two looks at who is speaking. */\n pollMs?: number\n } = {},\n): LocalAlert {\n const native = loadNativeAdapter({ native: deps.native }, { platform: deps.platform, io: { run: deps.run, capture: deps.capture, helper: deps.helper } })\n return async (title, message) => {\n const steps: Promise<unknown>[] = []\n if (settings.banner && native.banner) steps.push(native.banner.post({ title, message }))\n if (settings.sound && native.sound) {\n const sound = native.sound\n // A chime over someone speaking is the collision #1126 is about:\n // the banner goes up at once, the sound waits for quiet.\n steps.push(quiet(native.speech, (settings.quietWaitSeconds ?? DEFAULT_LOCAL.quietWaitSeconds!) * 1000, deps.pollMs ?? 500)\n .then((ok) => (ok ? sound.play(settings.soundName, settings.volume) : undefined)))\n }\n await Promise.all(steps)\n }\n}\n\n/** True once nothing else speaks on this machine, false when something\n * still does after `waitMs`. Without a way to tell, true at once. The\n * daemon's own speech counts too (no `exceptParents` here, unlike the\n * speaking queue): a chime over a spoken reply is the same interruption,\n * so it waits, and past the wait the banner shows without the sound. */\nasync function quiet(speech: NativeSpeech | undefined, waitMs: number, pollMs: number): Promise<boolean> {\n if (!speech || waitMs <= 0) return true\n const until = Date.now() + waitMs\n for (;;) {\n if (!(await speech.othersSpeaking())) return true\n if (Date.now() >= until) return false\n await new Promise((r) => setTimeout(r, pollMs))\n }\n}\n\n/**\n * Apply a change to a stored `notifications.local` block, the one rule\n * both the CLI and the dashboard write through. Returns the new block;\n * throws on a value that would not load. Only a machine with a native\n * adapter has sounds to check a name against; elsewhere the setting is\n * inert, so it need only be well-formed.\n */\nexport function patchLocal(\n current: Partial<LocalSettings> | undefined,\n patch: Record<string, unknown>,\n platform: NodeJS.Platform = process.platform,\n): Partial<LocalSettings> {\n const next = { ...(current ?? {}) }\n const native = loadNativeAdapter({}, { platform })\n if (\"banner\" in patch) next.banner = Boolean(patch.banner)\n if (\"sound\" in patch) next.sound = Boolean(patch.sound)\n if (\"soundName\" in patch) {\n const name = String(patch.soundName).trim()\n const ok = native.sound ? native.sound.has(name) : /^[\\w -]+$/.test(name)\n if (!ok) throw new Error(`no system sound named \"${name}\" on this machine`)\n next.soundName = name\n }\n if (\"icon\" in patch) {\n const icon = String(patch.icon ?? \"\").trim().replace(/^~(?=\\/)/, homedir())\n if (!icon) delete next.icon\n else {\n if (!isAbsolute(icon) || !/\\.(png|jpe?g|icns)$/i.test(icon)) throw new Error(\"icon must be the full path to a .png, .jpg or .icns file\")\n if (native.banner && !existsSync(icon)) throw new Error(`no icon file at ${icon}`)\n next.icon = icon\n }\n }\n if (\"volume\" in patch) {\n const v = Number(patch.volume)\n if (!Number.isFinite(v) || v < 0 || v > 1) throw new Error(\"volume must be between 0 and 1\")\n next.volume = v\n }\n return next\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport type { NativePriority, NativeTasks } from \"@/native\"\nimport { cardWords, summarize } from \"@/requests/card-view\"\nimport type { RequestRecord } from \"@/requests/store\"\nimport { CARD_LIMITS, type DecisionCard } from \"./cards\"\n\n// --- The Reminders mirror (#1062 step 5) ---\n//\n// Each pending decision card, and each request waiting on the owner,\n// becomes one task in the OS task app (Apple Reminders on a Mac) with a due\n// time. Calendar shows it, and the system alert comes back when it falls\n// due. Answering stays on the Desk, the Approvals page or the CLI: a task\n// cannot carry choices or a draft.\n//\n// Runs once a minute beside the approvals sweep, on the node that holds the\n// cards (forwarded cards live on the owner's node, so that is where they\n// are mirrored). Off by default.\n//\n// Rules:\n// - one task per card or request, created once;\n// - the card is answered, expires or is closed, or the request stops\n// waiting on the owner: the task is completed;\n// - the owner ticks the task off or deletes it while the item still\n// waits: the item stays on the Desk and is never mirrored again.\n// Ticking a task is not an answer;\n// - three failed adds for one item: the owner is told once and that\n// item is not tried again;\n// - every task ends with `agentx: card=<id>` or `agentx: request=<id>`,\n// which check-ins and the reminders hand-back skip, so a mirrored\n// task never turns back into a card or an agent's job.\n//\n// State lives in its own file, written only by the daemon, not in the card\n// files that the CLI and the dashboard also write.\n\nexport interface MirrorSettings {\n enabled: boolean\n list: string\n dueAfterMinutes: number\n include: (\"card\" | \"request\")[]\n /** Where the owner answers. Unset: the local dashboard's Approvals page. */\n answerUrl?: string\n}\n\nexport type MirrorState = \"open\" | \"completed\" | \"dismissed\" | \"failed\"\n\nexport interface MirrorEntry {\n /** The task's id in the OS task app, once added. */\n id?: string\n list: string\n state: MirrorState\n /** ISO time of the last change. */\n at: string\n failures: number\n lastError?: string\n}\n\nexport interface MirrorFile {\n /** Keyed `card:<id>` or `request:<id>`, the inbox's keys. */\n items: Record<string, MirrorEntry>\n /** ISO time of the last pass that read every list it needed. Stale\n * (the mirror was turned off, or the list can't be read) means the\n * mirror no longer covers anything, and the Mac popup is back. */\n checkedAt?: string\n /** That pass mirrored cards (include has \"card\"). */\n cards?: boolean\n /** ISO time the owner was last told adds are failing: once a day. */\n failureToldAt?: string\n /** The latest pass's last error, for doctor. */\n lastError?: { at: string; message: string }\n}\n\nexport const MAX_ADD_FAILURES = 3\n/** Closed entries are kept this long, then forgotten. */\nconst KEEP_CLOSED_MS = 30 * 24 * 3_600_000\n\nexport function mirrorPath(root: string): string {\n return resolve(root, \".agentx\", \"native-mirror.json\")\n}\n\nexport function readMirror(root: string): MirrorFile {\n try {\n const parsed = JSON.parse(readFileSync(mirrorPath(root), \"utf-8\"))\n return { ...parsed, items: parsed?.items && typeof parsed.items === \"object\" ? parsed.items : {} }\n } catch {\n return { items: {} }\n }\n}\n\nfunction writeMirror(root: string, file: MirrorFile): void {\n const path = mirrorPath(root)\n if (!existsSync(dirname(path))) mkdirSync(dirname(path), { recursive: true })\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(file, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\n/** A pass older than this means the mirror is not running. */\nexport const MIRROR_FRESH_MS = 5 * 60_000\n\n/** True when the mirror is running and covers this card: it has a task,\n * or gets one on the next pass, or the owner ticked its task off. The Mac\n * popup then leaves it alone, so the owner is not alerted twice. A card\n * whose task could not be added is not covered. */\nexport function mirrorCovers(root: string, cardId: string, now = Date.now()): boolean {\n const file = readMirror(root)\n const checked = file.checkedAt ? Date.parse(file.checkedAt) : NaN\n if (!file.cards || !(now - checked <= MIRROR_FRESH_MS)) return false\n return file.items[`card:${cardId}`]?.state !== \"failed\"\n}\n\n/** What one task says. */\nexport interface MirrorItem {\n key: string\n title: string\n notes: string\n due: Date\n priority: NativePriority\n}\n\nconst DAY_MS = 24 * 3_600_000\n\nfunction dueFor(now: number, settings: MirrorSettings, limit?: number): Date {\n const due = now + settings.dueAfterMinutes * 60_000\n return new Date(limit !== undefined && Number.isFinite(limit) ? Math.max(now, Math.min(due, limit)) : due)\n}\n\nexport function cardItem(card: DecisionCard, settings: MirrorSettings, answerUrl: string, now: number): MirrorItem {\n const expires = Date.parse(card.expires)\n const lines = [summarize(card.ask, CARD_LIMITS.ask)]\n if (card.choices?.length) lines.push(...card.choices.map((c, i) => `${i + 1}. ${c}`))\n if (card.recommend) lines.push(`Recommended: ${summarize(card.recommend, CARD_LIMITS.recommend)}`)\n lines.push(`Answer: ${answerUrl}`, `agentx: card=${card.id}`)\n return {\n key: `card:${card.id}`,\n title: summarize(card.title, CARD_LIMITS.title),\n notes: lines.join(\"\\n\"),\n due: dueFor(now, settings, expires),\n priority: Number.isFinite(expires) && expires - now <= DAY_MS ? \"high\" : \"none\",\n }\n}\n\nexport function requestItem(r: RequestRecord, settings: MirrorSettings, answerUrl: string, now: number): MirrorItem {\n const lines = [summarize(r.question || r.text, CARD_LIMITS.ask), `Asked of ${r.agentId}.`, `Answer: ${answerUrl}`, `agentx: request=${r.id}`]\n const dueAt = r.dueAt ?? undefined\n return {\n key: `request:${r.id}`,\n title: cardWords(r, CARD_LIMITS.title).headline,\n notes: lines.join(\"\\n\"),\n due: dueFor(now, settings, dueAt),\n priority: dueAt !== undefined && dueAt - now <= DAY_MS ? \"high\" : \"none\",\n }\n}\n\nexport interface MirrorDeps {\n root: string\n settings: MirrorSettings\n tasks: NativeTasks\n /** Pending cards on this node. */\n cards: () => DecisionCard[]\n /** Requests in waiting_owner. */\n requests: () => RequestRecord[]\n answerUrl: string\n /** Tell the owner, through the usual notification. */\n notify: (title: string, message: string) => Promise<void>\n log: (msg: string) => void\n now?: number\n}\n\nexport interface MirrorResult {\n created: number\n completed: number\n dismissed: number\n failed: number\n}\n\n/** One pass of the mirror. Never throws. */\nexport async function runMirror(deps: MirrorDeps): Promise<MirrorResult> {\n const { root, settings, tasks, log } = deps\n const now = deps.now ?? Date.now()\n const at = new Date(now).toISOString()\n const result: MirrorResult = { created: 0, completed: 0, dismissed: 0, failed: 0 }\n const file = readMirror(root)\n // lastError says how the latest pass went: a clean pass clears it.\n delete file.lastError\n const fail = (message: string) => { file.lastError = { at, message } }\n\n const waiting = new Map<string, MirrorItem>()\n try {\n if (settings.include.includes(\"card\")) {\n for (const c of deps.cards()) if (c.status === \"pending\" && Date.parse(c.expires) > now) waiting.set(`card:${c.id}`, cardItem(c, settings, deps.answerUrl, now))\n }\n if (settings.include.includes(\"request\")) {\n for (const r of deps.requests()) if (r.state === \"waiting_owner\") waiting.set(`request:${r.id}`, requestItem(r, settings, deps.answerUrl, now))\n }\n } catch (e: any) {\n log(`[mirror] could not read what is waiting: ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n writeMirror(root, file)\n return result\n }\n\n // Close or notice dismissal for what is already mirrored. The open list\n // is read once per list; when it can't be read, nothing is closed or\n // dismissed this pass, so a hiccup never loses a task.\n let allRead = true\n const openIds = new Map<string, Set<string> | null>()\n const openIn = async (list: string): Promise<Set<string> | null> => {\n if (!openIds.has(list)) {\n try {\n openIds.set(list, new Set((await tasks.listOpen(list)).map((t) => t.id)))\n } catch (e: any) {\n log(`[mirror] could not read list \"${list}\": ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n openIds.set(list, null)\n allRead = false\n }\n }\n return openIds.get(list)!\n }\n\n for (const [key, entry] of Object.entries(file.items)) {\n if (entry.state !== \"open\" || !entry.id) continue\n const open = await openIn(entry.list)\n if (!open) continue\n if (!waiting.has(key)) {\n if (open.has(entry.id)) {\n try {\n await tasks.complete(entry.id)\n } catch (e: any) {\n log(`[mirror] ${key}: could not complete its task: ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n continue\n }\n }\n file.items[key] = { ...entry, state: \"completed\", at }\n result.completed++\n } else if (!open.has(entry.id)) {\n file.items[key] = { ...entry, state: \"dismissed\", at }\n result.dismissed++\n log(`[mirror] ${key}: its task was ticked off or deleted; it stays on the Desk and is not mirrored again`)\n }\n }\n\n let listReady: boolean | null = null\n const gaveUp: { title: string; message: string }[] = []\n for (const [key, item] of waiting) {\n const entry = file.items[key]\n if (entry && (entry.state === \"open\" || entry.state === \"dismissed\")) continue\n if (entry?.state === \"failed\" && entry.failures >= MAX_ADD_FAILURES) continue\n // The list is made on the first add of a pass, when it is missing.\n if (listReady === null) {\n try {\n await tasks.ensureList(settings.list)\n listReady = true\n } catch (e: any) {\n log(`[mirror] could not make list \"${settings.list}\": ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n listReady = false\n }\n }\n const failures = entry?.state === \"failed\" ? entry.failures : 0\n try {\n const { id } = await tasks.add({ list: settings.list, title: item.title, notes: item.notes, due: item.due, priority: item.priority })\n file.items[key] = { id, list: settings.list, state: \"open\", at, failures: 0 }\n result.created++\n } catch (e: any) {\n const message = String(e?.message ?? e)\n const n = failures + 1\n file.items[key] = { list: settings.list, state: \"failed\", at, failures: n, lastError: message }\n fail(message)\n result.failed++\n log(`[mirror] ${key}: could not add to Reminders (${n}/${MAX_ADD_FAILURES}): ${message}`)\n if (n === MAX_ADD_FAILURES) gaveUp.push({ title: item.title, message })\n }\n }\n\n // One notification a day at most, however many items gave up: a missing\n // permission fails every card the same way.\n const told = file.failureToldAt ? Date.parse(file.failureToldAt) : NaN\n if (gaveUp.length && !(now - told < DAY_MS)) {\n const first = gaveUp[0]\n const more = gaveUp.length > 1 ? ` (and ${gaveUp.length - 1} more)` : \"\"\n try {\n await deps.notify(\"Could not add to Reminders\", `${first.title}${more}: ${summarize(first.message, 200)}. Still on the Desk.`)\n file.failureToldAt = at\n } catch (err: any) {\n log(`[mirror] could not tell the owner: ${err?.message ?? err}`)\n }\n }\n\n if (allRead) {\n file.checkedAt = at\n file.cards = settings.include.includes(\"card\")\n }\n\n for (const [key, entry] of Object.entries(file.items)) {\n if (entry.state !== \"open\" && !waiting.has(key) && now - Date.parse(entry.at) > KEEP_CLOSED_MS) delete file.items[key]\n }\n writeMirror(root, file)\n return result\n}\n","import { markdownToHtml } from \"@/utils/markdown-html\"\nimport type { RequestRecord, RequestStore } from \"./store\"\nimport type { PlanState, PlanStore, StepState } from \"./plan-store\"\nimport { describeCloseWhen } from \"./checkers\"\nimport { activeStepAgentOf, stalledWhy, waitsOn, type StallGroup } from \"./loops\"\n\n// --- One open request as a card the owner can read in seconds (#459) ---\n//\n// The Approvals page shows each open request as a card: a short plain\n// summary, where it stands and why it is not finished, then the words the\n// owner used and the agent's last answer, both rendered. markdownToHtml\n// escapes before it marks up, so nothing an agent or a channel wrote\n// reaches the page as HTML. The summary is the request's headline (#1126);\n// a request without one yet falls back to the start of its own words,\n// without the markdown marks.\n\nexport const SUMMARY_MAX = 200\n/** An answer of pages is cut: the card is for reading quickly. */\nexport const ANSWER_MAX = 4000\n\n/** What a request needs from the owner when nothing does. */\nexport const NOTHING_NEEDED = \"Nothing, just so you know.\"\n\n/** A request as every surface titles it (#1126): what it is, the one\n * thing needed from the owner, and the owner's own words. The need\n * follows where it stands: a request that needs attention or waits on\n * the owner's answer says so, whatever the agent wrote earlier. */\nexport function cardWords(\n r: Pick<RequestRecord, \"text\" | \"headline\" | \"need\" | \"state\" | \"question\" | \"agentId\">,\n max = SUMMARY_MAX,\n): { headline: string; need: string; said: string } {\n const headline = r.headline ? (r.headline.length > max ? `${r.headline.slice(0, max - 1)}…` : r.headline) : summarize(r.text, max)\n const need = r.state === \"needs_attention\" ? `Hand it back to ${r.agentId}, or drop it.`\n : r.state === \"waiting_owner\" ? (r.need ?? (r.question ? `Answer: ${summarize(r.question, 150)}` : \"Your answer.\"))\n : r.state === \"candidate\" || r.state === \"in_progress\" || r.state === \"waiting_other\" ? (r.need ?? NOTHING_NEEDED)\n : NOTHING_NEEDED\n return { headline, need, said: plain(r.text) }\n}\n\nexport interface RequestCard extends RequestRecord {\n summary: string\n /** The one thing needed from the owner, in words: the agent's `need`\n * or what follows from where the request stands (cardWords). */\n needed: string\n /** The request in the owner's words (the transcript, when spoken). */\n textHtml: string\n /** Why it is not finished, or what is being asked. Null: work is under way. */\n why: string | null\n ownerNoteHtml: string | null\n lastAnswer: { agentId: string; at: number; html: string } | null\n /** The open loop (#1039): who it is owed to, when it is due, what\n * closes it. Null on a request with none of it. */\n loop: {\n owedTo: string | null\n promise: boolean\n dueAt: number | null\n /** What its check waits for, in words. */\n check: string | null\n verifyState: string | null\n verifyDetail: string | null\n } | null\n /** Stalled, and what it waits on. Null: not stalled, or not asked. */\n stall: { group: StallGroup; who: string; why: string } | null\n /** Its tracked plan (#788), step by step. Null: no plan. */\n plan: {\n state: PlanState\n steps: Array<{ idx: number; name: string; kind: string; agentId: string; state: StepState; approval: string | null; evidence: string | null; note: string | null; nudges: number }>\n } | null\n}\n\n/** Markdown to the words alone, on one line. */\nexport function plain(md: string): string {\n return md\n .replace(/```[\\s\\S]*?```/g, \" \")\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/^\\s{0,3}(#{1,6}|>|[-*+]|\\d+[.)])\\s+/gm, \"\")\n .replace(/[*_~`]+/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n}\n\n/** The start of the request, cut at a sentence when one ends in reach. */\nexport function summarize(md: string, max = SUMMARY_MAX): string {\n const text = plain(md)\n if (text.length <= max) return text\n const cut = text.slice(0, max)\n const end = Math.max(cut.lastIndexOf(\". \"), cut.lastIndexOf(\"? \"), cut.lastIndexOf(\"! \"))\n return end > max / 2 ? cut.slice(0, end + 1) : `${cut.slice(0, max - 1).trimEnd()}…`\n}\n\n/** What the stall view needs: the quiet time, the clock, and which ids are agents. */\nexport interface StallLookup { staleAfterHours: number; now: number; isAgent: (id: string) => boolean }\n\nexport function requestCard(\n r: RequestRecord,\n store: Pick<RequestStore, \"lastAnswer\">,\n plans?: Pick<PlanStore, \"get\" | \"steps\"> | null,\n stall?: StallLookup,\n): RequestCard {\n const plan = plans?.get(r.id)\n const why = stall ? stalledWhy(r, stall.staleAfterHours, stall.now) : null\n const answer = store.lastAnswer(r.id)\n const cutAnswer = answer && answer.text.length > ANSWER_MAX ? `${answer.text.slice(0, ANSWER_MAX)}\\n\\n…` : answer?.text\n const words = cardWords(r)\n return {\n ...r,\n summary: words.headline,\n needed: words.need,\n textHtml: markdownToHtml(r.text),\n why: r.state === \"waiting_owner\" ? r.question : r.state === \"needs_attention\" ? r.attentionReason : null,\n ownerNoteHtml: r.ownerNote ? markdownToHtml(r.ownerNote) : null,\n lastAnswer: answer ? { agentId: answer.agentId, at: answer.at, html: markdownToHtml(cutAnswer!) } : null,\n loop: r.promise || r.dueAt !== null || r.closeWhen ? {\n owedTo: r.owedTo, promise: r.promise, dueAt: r.dueAt, check: r.closeWhen ? describeCloseWhen(r.closeWhen) : null,\n verifyState: r.verifyState, verifyDetail: r.verifyDetail,\n } : null,\n stall: stall && why ? { ...waitsOn(r, { isAgent: stall.isAgent, activeStepAgent: activeStepAgentOf(plans) }), why } : null,\n plan: plan ? {\n state: plan.state,\n steps: plans!.steps(r.id).map((s) => ({\n idx: s.idx, name: s.name, kind: s.kind, agentId: s.agentId, state: s.state,\n approval: s.needsApproval ? s.approval : null, evidence: s.evidence, note: s.note, nudges: s.nudges,\n })),\n } : null,\n }\n}\n","import { OPEN_STATES, OWED_TO_OWNER, type RequestRecord, type RequestStore } from \"./store\"\nimport { runCheck, type CheckContext, type CheckResult, type CloseWhen } from \"./checkers\"\n\n// --- Open loops: who each one waits on, and when it is stalled (#1039) ---\n//\n// A loop is an open request: one the owner asked for, or one an agent\n// promised (action promise). It is stalled when it is past its due time,\n// or, without one, when nothing has happened for staleAfterHours. A loop\n// that needs attention is stalled too: nothing is retrying it.\n//\n// Stalled loops are grouped by what they wait on:\n// owner the owner's answer (waiting_owner), or the owner's decision\n// on one that needs attention\n// agent an agent: the one that has it, a plan step's agent, or the\n// agent it is owed to\n// person an outside person: a promise owed to a known person\n// The requests panel, `agentx requests --stalled` and the sweep's notice\n// all use this one grouping.\n\nexport const STALL_GROUPS = [\"owner\", \"agent\", \"person\"] as const\nexport type StallGroup = (typeof STALL_GROUPS)[number]\n\nexport interface StalledLoop {\n request: RequestRecord\n group: StallGroup\n /** Who it waits on: \"owner\", an agent id or a person id. */\n who: string\n /** Why it counts as stalled, in words. */\n why: string\n}\n\nexport interface LoopLookups {\n isAgent: (id: string) => boolean\n /** The agent of the active step of the request's plan, if it has one. */\n activeStepAgent?: (requestId: string) => string | null\n}\n\nconst HOUR = 3_600_000\nconst isOpen = (r: RequestRecord) => (OPEN_STATES as readonly string[]).includes(r.state)\n\n/** The agent of each request's active plan step, from the plan store. */\nexport function activeStepAgentOf(plans: { get(id: string): { state: string } | null; steps(id: string): Array<{ state: string; agentId: string }> } | null | undefined) {\n return (requestId: string): string | null => {\n if (!plans || plans.get(requestId)?.state !== \"active\") return null\n return plans.steps(requestId).find((s) => s.state === \"active\")?.agentId ?? null\n }\n}\n\n/** What an open loop waits on. */\nexport function waitsOn(r: RequestRecord, look: LoopLookups): { group: StallGroup; who: string } {\n if (r.state === \"waiting_owner\") return { group: \"owner\", who: OWED_TO_OWNER }\n if (r.promise && r.owedTo && r.owedTo !== OWED_TO_OWNER && !look.isAgent(r.owedTo)) return { group: \"person\", who: r.owedTo }\n if (r.state === \"needs_attention\") return { group: \"owner\", who: OWED_TO_OWNER }\n const step = look.activeStepAgent?.(r.id)\n return { group: \"agent\", who: step ?? r.agentId }\n}\n\n/** Why an open loop is stalled, or null when it is not. */\nexport function stalledWhy(r: RequestRecord, staleAfterHours: number, now: number): string | null {\n if (!isOpen(r)) return null\n if (r.state === \"needs_attention\") return r.attentionReason ?? \"needs attention\"\n if (r.dueAt !== null) return now > r.dueAt ? `past its due time (${when(r.dueAt)})` : null\n return now - r.updatedAt > staleAfterHours * HOUR ? `no activity for ${staleAfterHours} h or more` : null\n}\n\n/** Stalled loops among `items`, oldest first, grouped. */\nexport function stalledLoops(items: RequestRecord[], staleAfterHours: number, now: number, look: LoopLookups): Record<StallGroup, StalledLoop[]> {\n const out: Record<StallGroup, StalledLoop[]> = { owner: [], agent: [], person: [] }\n for (const r of items) {\n const why = stalledWhy(r, staleAfterHours, now)\n if (!why) continue\n const { group, who } = waitsOn(r, look)\n out[group].push({ request: r, group, who, why })\n }\n return out\n}\n\n/** The group, in words, for people. */\nexport function waitsOnWords(group: StallGroup, who: string): string {\n return group === \"owner\" ? \"you\" : group === \"agent\" ? `agent ${who}` : `${who} (outside person)`\n}\n\nexport const when = (ms: number) => new Date(ms).toISOString().slice(0, 16).replace(\"T\", \" \") + \" UTC\"\n\n/** A due time an agent or the owner gave: epoch ms, or an ISO date.\n * Undefined when absent, a string when it is not a time. */\nexport function parseDue(v: unknown): number | undefined | string {\n if (v === undefined || v === null || v === \"\") return undefined\n const at = typeof v === \"number\" ? v : typeof v === \"string\" ? Date.parse(v.trim()) : NaN\n if (!Number.isFinite(at) || at <= 0) return \"due must be an ISO date (2030-01-31T17:00:00Z) or epoch milliseconds\"\n return at\n}\n\n// ── Running the checkers from the requests check ─────────────────────────\n\n/** Runs a loop's checker. The daemon's own; tests give their own. */\nexport type LoopChecker = (spec: CloseWhen, request: RequestRecord) => Promise<CheckResult>\n\nexport function loopChecker(ctx: () => CheckContext): LoopChecker {\n return (spec) => runCheck(spec, ctx())\n}\n\n/** How many checkers run at once, and how many loops one check takes on. */\nconst CHECK_BATCH = 10\n\n/** Run the checker of every open loop whose last check is older than\n * `everyMinutes`. Met closes it as done with the checker's evidence;\n * unverifiable marks it unverified; not met leaves it as it is. */\nexport async function checkLoops(\n store: RequestStore,\n check: LoopChecker,\n opts: { everyMinutes: number; now: number; log: (msg: string) => void },\n): Promise<{ checked: number; closed: number }> {\n const due = store.dueForCheck(opts.now - opts.everyMinutes * 60_000, CHECK_BATCH)\n let closed = 0\n await Promise.all(due.map(async (r) => {\n // Marked before the call: a check that hangs is not started again\n // at the next minute.\n store.markChecked(r.id, r.verifyState, r.verifyDetail ?? \"\", opts.now)\n const res = await check(r.closeWhen!, r).catch((e: any): CheckResult => ({ verdict: \"unverifiable\", detail: String(e?.message ?? e) }))\n if (res.verdict === \"met\") {\n if (store.closeVerified(r.id, res.detail, opts.now)) {\n closed++\n opts.log(`[requests] ${r.id} closed by its check: ${res.detail}`)\n }\n return\n }\n // A refused done stays \"failed\" until the check says otherwise.\n store.markChecked(r.id, res.verdict === \"unverifiable\" ? \"unverified\" : r.verifyState === \"failed\" ? \"failed\" : null, res.detail, opts.now)\n }))\n return { checked: due.length, closed }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","dirname","join","fileURLToPath","homedir","DESKTOP_LABEL","DESKTOP_APP","HELPER_APP","desktopPlatformError","platform","arch","release","selectDesktopAgent","agents","requested","id","shellQuote","value","LAUNCHD_PATH","desktopPath","ffmpeg","override","unxml","s","ents","_","e","plistPathEnv","plist","m","isVoiceLoginItemFile","name","adoptLoginItem","dir","items","keep","remove","file","a","b","label","program","findOnPath","bin","path","isExecutable","desktopPlist","opts","xml","env","k","v","helperBuildArgs","icon","installedHelper","home","packageRoot","from","resolveHelper","root","installed","findHelper","accessSync","constants","execFile","STEP_TIMEOUT_MS","run","file","args","done","err","capture","stdout","output","resolve","reject","stderr","helperOf","io","findHelper","helperBannerStatus","path","capture","out","status","macosBanner","exec","run","title","message","helper","idleSecondsIn","ioreg","m","macosIdle","io","capture","out","NOTES_SCRIPT","macosNotes","exec","output","folder","title","body","id","existsSync","readdirSync","SOUNDS","soundPath","name","path","existsSync","macosSound","io","exec","run","volume","readdirSync","f","SPEAKERS","speakersIn","ps","exceptParents","self","line","m","pid","ppid","comm","name","macosSpeech","io","capture","opts","ZWSP","argValue","v","unArg","listName","list","isoDue","d","macosTasks","command","exec","output","raw","lists","l","items","r","title","notes","due","priority","args","id","patch","executable","file","accessSync","constants","focus","s","readSystemFocus","macosAdapter","cfg","io","command","macosTasks","macosNotes","macosBanner","macosSound","macosSpeech","macosIdle","problems","isExec","findOnPath","noneAdapter","reason","FACTORIES","macosAdapter","loadNativeAdapter","cfg","opts","noneAdapter","platform","make","existsSync","homedir","isAbsolute","DEFAULT_LOCAL","localSettings","cfg","localAlert","settings","deps","native","loadNativeAdapter","title","message","steps","sound","quiet","ok","speech","waitMs","pollMs","until","r","patchLocal","current","patch","platform","next","name","icon","homedir","isAbsolute","existsSync","v","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","init_checkers","init_store","init_checkers","STALL_GROUPS","HOUR","isOpen","r","OPEN_STATES","activeStepAgentOf","plans","requestId","s","waitsOn","look","OWED_TO_OWNER","stalledWhy","staleAfterHours","now","when","stalledLoops","items","out","why","group","who","waitsOnWords","ms","parseDue","v","at","loopChecker","ctx","spec","runCheck","CHECK_BATCH","checkLoops","store","check","opts","due","closed","res","e","SUMMARY_MAX","ANSWER_MAX","NOTHING_NEEDED","cardWords","r","max","headline","summarize","need","plain","md","text","cut","end","requestCard","store","plans","stall","plan","why","stalledWhy","answer","cutAnswer","words","markdownToHtml","describeCloseWhen","waitsOn","activeStepAgentOf","s","MAX_ADD_FAILURES","KEEP_CLOSED_MS","mirrorPath","root","resolve","readMirror","parsed","readFileSync","writeMirror","file","path","existsSync","dirname","mkdirSync","tmp","writeFileSync","renameSync","MIRROR_FRESH_MS","mirrorCovers","cardId","now","checked","DAY_MS","dueFor","settings","limit","due","cardItem","card","answerUrl","expires","lines","summarize","CARD_LIMITS","c","i","requestItem","r","dueAt","cardWords","runMirror","deps","tasks","log","at","result","fail","message","waiting","e","allRead","openIds","openIn","list","t","key","entry","open","listReady","gaveUp","item","failures","id","n","told","first","more","err"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as _,b as F,c as K,d as z,e as J}from"./chunk-SKSYII3K.js";import{a as j,b as I,c as Y,d as V,e as B,j as G}from"./chunk-
|
|
1
|
+
import{a as _,b as F,c as K,d as z,e as J}from"./chunk-SKSYII3K.js";import{a as j,b as I,c as Y,d as V,e as B,j as G}from"./chunk-3ZAAUY2N.js";import{a as H}from"./chunk-MWNCS57L.js";import{y as N,z as ot}from"./chunk-4RHM4XTI.js";import{g as Q}from"./chunk-6TURWSMN.js";import{b as E,c as L}from"./chunk-QOYAX2FT.js";import{readFileSync as lt,existsSync as X}from"fs";ot();import{resolve as R}from"path";import{execSync as ct}from"child_process";var ht="haiku",dt="sonnet",pt=.8;function mt(e,r,o,t){if(t.size===0)return 0;let c=e.listArticles(r||"").map(l=>l.path).filter(l=>!l.includes("/_versions/"));return c.length===0&&(c=o.sharedPool.map(l=>l.path)),c.length===0?0:c.filter(l=>t.has(l)).length/c.length}async function _t(e,r,o,t={}){let c=t.selectorModel??ht,l=t.synthModel??dt,m=t.maxCandidates??3,g=t.maxHops??2,d=t.maxArticles??8,i=t.timeoutMs??6e4,s=t.log??console.error.bind(console,"[wiki-query]"),h=t.messagePath?.length?t.messagePath:void 0,n=t.graphWeight??W,a=R(r.baseDir,"_index.md"),p=tt(r,o,t.shared),b=t.method??"catalog";if(b!=="catalog"){let u=z(r,t.shared);if(b==="summaries"||mt(r,o,p,u)>=pt){let f=t.summaries??K,P=t.notes&&o&&t.notes.owner===o?F(t.notes):void 0,y=await J(e,P?gt(p,P):p,P?new Map([...u,...P.summaries]):u,{...f,navigatorModel:t.selectorModel??f.navigatorModel,answerModel:t.synthModel??f.answerModel},{call:t.call??H,fetch:t.fetch,timeoutMs:i,log:s}),$=y.picked.map(w=>({title:w.meta.title,path:w.path,type:_(w.path)?"note":w.meta.type,hop:w.hop}));return{answer:y.answer,citations:y.status==="ok"?$.map(({hop:w,...v})=>v):[],candidates:$.filter(w=>w.hop===0).map(({title:w,path:v})=>({title:w,path:v})),walked:$,status:y.status,method:"summaries",basis:y.basis,live:y.live,liveAsked:y.liveAsked,trace:y.trace,...y.error?{error:y.error}:{}}}}if(!X(a)&&p.sharedPool.length===0)return M("no-catalog",e,"No _index.md found \u2014 run `agentx wiki status` to rebuild.");let it=(X(a)?lt(a,"utf-8"):"")+yt(e,p.sharedPool,h,n),T=Date.now(),A=[],S="";try{let u=await nt(e,p.pool,o,m,h,n);u?(A=u,S=`[wiki-rerank seat] ${u.map(f=>f.title).join(" | ")}`):(S=await Z(wt(e,it,m,h),c,i),A=bt(S))}catch(u){return s("selector failed:",u?.message),{...M("error",e,`Selector: ${u?.message||"unknown"}`),trace:{selectorMs:Date.now()-T,synthesisMs:0,selectorOutput:S}}}let x=Date.now()-T;if(A.length===0)return{...M("no-candidates",e,"Selector returned no candidates."),trace:{selectorMs:x,synthesisMs:0,selectorOutput:S}};let C=rt(A,p,g,d);if(C.length===0)return{...M("no-candidates",e,"Candidates did not resolve to readable articles."),candidates:A,trace:{selectorMs:x,synthesisMs:0,selectorOutput:S}};let D=Date.now(),U="";try{U=await Z(kt(e,C),l,i*2)}catch(u){return s("synthesis failed:",u?.message),{...M("error",e,`Synthesis: ${u?.message||"unknown"}`),candidates:A,walked:C.map(f=>({title:f.meta.title,path:f.path,type:f.meta.type,hop:f.hop??0})),trace:{selectorMs:x,synthesisMs:Date.now()-D,selectorOutput:S}}}let st=Date.now()-D;return{answer:U.trim(),citations:C.map(u=>({title:u.meta.title,path:u.path,type:u.meta.type})),candidates:A,walked:C.map(u=>({title:u.meta.title,path:u.path,type:u.meta.type,hop:u.hop??0})),status:"ok",trace:{selectorMs:x,synthesisMs:st,selectorOutput:S}}}async function Rt(e,r,o,t={}){let c=t.maxCandidates??3,l=t.graphWeight??W,m=t.messagePath?.length?t.messagePath:void 0,g=t.pool??q(r);if(g.length===0||!e.trim())return[];let d=await nt(e,g,o,c,m,l,t.stage??"retrieve");if(!d){let i=new Set(L(e,E(g.map(at))).map(s=>s.docIndex));d=O(e,g,m,l).filter(s=>i.has(s)).slice(0,c).map(s=>({title:g[s].title,path:g[s].path}))}return d.length===0?[]:rt(d,tt(r,o),t.maxHops??1,t.maxArticles??6)}function q(e){try{return(e.rebuildIndex().articles??[]).filter(r=>r.path&&!r.path.includes("/_versions/"))}catch{return[]}}function M(e,r,o){return{answer:"",citations:[],candidates:[],walked:[],status:e,error:o}}function tt(e,r,o=[]){let t=new Map,c=[];for(let i of e.listArticles(r||""))t.set(i.meta.title.toLowerCase(),i.path),c.push({path:i.path,related:i.meta.related??[],lastUpdated:i.meta.lastUpdated??""});let l=[],m=new Map;for(let i of o)if(i.store.baseDir!==e.baseDir){m.set(i.id,i);for(let s of i.store.listArticles(r||"")){if(s.path.includes("/_versions/")||i.skip?.(s.path))continue;let h=`@${i.id}/${s.path}`;l.push(ut(s,h)),c.push({path:h,related:s.meta.related??[],lastUpdated:s.meta.lastUpdated??""});let n=s.meta.title.toLowerCase();t.has(n)||t.set(n,h)}}let g=new Map;if(m.size>0)for(let i of[...c].sort((s,h)=>h.lastUpdated.localeCompare(s.lastUpdated)))for(let s of i.related){let h=s.toLowerCase(),n=g.get(h)??[];n.includes(i.path)||n.push(i.path),g.set(h,n)}let d;return{backlinks:g,readable:new Set(c.map(i=>i.path)),get pool(){return d??=[...q(e),...l]},sharedPool:l,titleIndex:t,read(i){let s=i.match(/^@([^/]+)\/(.+)$/),h=s?m.get(s[1]):void 0;if(s&&!h)return null;let n=h?.store??e,a=s?s[2]:i,p=r?n.readArticleAs(a,r):n.readArticle(a);return p?{...p,path:i}:null},links(i){let s=(i.meta.related??[]).map(a=>t.get(a.toLowerCase())).filter(a=>!!a),h=[i.meta.title,...i.meta.aliases??[]].map(a=>a.toLowerCase()),n=[...new Set(h.flatMap(a=>g.get(a)??[]))].filter(a=>a!==i.path).slice(0,et);return[...new Set([...s,...n])].filter(a=>a!==i.path)}}}function gt(e,r){return{...e,pool:[...e.pool,...r.pool],readable:new Set([...e.readable,...r.pool.map(o=>o.path)]),read:o=>_(o)?r.read(o):e.read(o)}}function ut(e,r){return{path:r,title:e.meta.title,type:e.meta.type,related:e.meta.related,tags:e.meta.tags||[],owner:e.meta.owner,access:e.meta.access,sharedWith:e.meta.sharedWith,aliases:[e.meta.title.toLowerCase(),...(e.meta.aliases??[]).map(o=>o.toLowerCase())],backlinks:0,sources:e.meta.sources,lastUpdated:e.meta.lastUpdated,graphPath:e.meta.graphPath}}var ft=150;function yt(e,r,o,t){return r.length===0?"":`
|
|
2
2
|
|
|
3
3
|
## Shared wiki (other agents' articles)
|
|
4
4
|
|
|
@@ -51,5 +51,5 @@ ${o}
|
|
|
51
51
|
|
|
52
52
|
Answer the question in 2\u20136 sentences. Cite articles by their title in square brackets like [Article Title]. When two articles disagree, prefer the one updated more recently, and say which agent's page and date the answer comes from. If the articles do not answer the question, say so plainly (do not invent). Prefer concrete facts over hedging.
|
|
53
53
|
|
|
54
|
-
Output ONLY the answer \u2014 no preamble, no "here is my answer:", no markdown fencing.`}function bt(e){let r=e.match(/\[[\s\S]*?\]/);if(!r)return[];try{let o=JSON.parse(r[0]);return Array.isArray(o)?o.filter(t=>t&&typeof t.title=="string"&&typeof t.path=="string").map(t=>({title:t.title,path:t.path})):[]}catch{return[]}}async function Z(e,r,o){let{writeFileSync:t,mkdirSync:c,rmSync:l}=await import("fs"),{tmpdir:m}=await import("os"),g=R(m(),`agentx-wiki-query-${process.pid}`);c(g,{recursive:!0});let d=R(g,`prompt-${Date.now()}.txt`);t(d,e);try{let i=`cat '${d}' | claude -p - --output-format json --max-turns 1 --model ${r} --disallowedTools "Bash Read Write Edit Glob Grep Agent WebSearch WebFetch NotebookEdit"`,s=ct(i,{env:Q(),encoding:"utf-8",timeout:o,maxBuffer:4*1024*1024});try{let h=JSON.parse(s);return String(h.result||h.content||"")}catch{return s}}finally{try{l(d,{force:!0})}catch{}}}async function Ot(e){try{let{loadDaemonConfig:r}=await import("./config-
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
54
|
+
Output ONLY the answer \u2014 no preamble, no "here is my answer:", no markdown fencing.`}function bt(e){let r=e.match(/\[[\s\S]*?\]/);if(!r)return[];try{let o=JSON.parse(r[0]);return Array.isArray(o)?o.filter(t=>t&&typeof t.title=="string"&&typeof t.path=="string").map(t=>({title:t.title,path:t.path})):[]}catch{return[]}}async function Z(e,r,o){let{writeFileSync:t,mkdirSync:c,rmSync:l}=await import("fs"),{tmpdir:m}=await import("os"),g=R(m(),`agentx-wiki-query-${process.pid}`);c(g,{recursive:!0});let d=R(g,`prompt-${Date.now()}.txt`);t(d,e);try{let i=`cat '${d}' | claude -p - --output-format json --max-turns 1 --model ${r} --disallowedTools "Bash Read Write Edit Glob Grep Agent WebSearch WebFetch NotebookEdit"`,s=ct(i,{env:Q(),encoding:"utf-8",timeout:o,maxBuffer:4*1024*1024});try{let h=JSON.parse(s);return String(h.result||h.content||"")}catch{return s}}finally{try{l(d,{force:!0})}catch{}}}async function Ot(e){try{let{loadDaemonConfig:r}=await import("./config-S4ZZHOUZ.js");return r(e).wiki.query.shared}catch{return!0}}export{ht as a,dt as b,pt as c,_t as d,Rt as e,q as f,ft as g,W as h,O as i,Ot as j};
|
|
55
|
+
//# sourceMappingURL=chunk-CTXHMJLZ.js.map
|