agentix-cli 0.47.1 → 0.49.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/apps/mac-helper/Sources/AgentXHelper/Buffer.swift +65 -0
- package/apps/mac-helper/Sources/AgentXHelper/Notify.swift +26 -0
- package/apps/mac-helper/Sources/AgentXHelper/Ring.swift +58 -0
- package/apps/mac-helper/Sources/AgentXHelper/Screens.swift +7 -0
- package/apps/mac-helper/Sources/AgentXHelper/Vision.swift +13 -8
- package/apps/mac-helper/Sources/AgentXHelper/Watch.swift +87 -0
- package/apps/mac-helper/Sources/AgentXHelper/main.swift +72 -18
- package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +17 -5
- package/apps/mac-voice/Sources/AgentXVoice/Config.swift +6 -1
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +5 -2
- package/dist/{App-RZDJH6MK.js → App-KE4SURSS.js} +2 -2
- package/dist/{ChatApp-6TXOFUDH.js → ChatApp-NNHIKXO2.js} +2 -2
- package/dist/{agent-I6RXAEXG.js → agent-J7SLJYQ6.js} +2 -2
- package/dist/{board-dashboard-4LAQOB74.js → board-dashboard-LG3ECH7C.js} +494 -132
- package/dist/board-dashboard-LG3ECH7C.js.map +1 -0
- package/dist/chunk-3L2FKVR6.js +19 -0
- package/dist/chunk-3L2FKVR6.js.map +1 -0
- package/dist/{chunk-BZLHS3VF.js → chunk-4NBWF4TL.js} +2 -2
- package/dist/{schedule-tool-6SNLG2NA.js → chunk-4TITGMPX.js} +3 -3
- package/dist/{schedule-tool-6SNLG2NA.js.map → chunk-4TITGMPX.js.map} +1 -1
- package/dist/{chunk-NXJBAKBR.js → chunk-5ALS7SVV.js} +2 -2
- package/dist/chunk-5XQCGPQJ.js +2 -0
- package/dist/chunk-5XQCGPQJ.js.map +1 -0
- package/dist/chunk-7DXE264B.js +2 -0
- package/dist/chunk-7DXE264B.js.map +1 -0
- package/dist/{chunk-FRHSQVFN.js → chunk-AQASR6KR.js} +3 -3
- package/dist/chunk-AQASR6KR.js.map +1 -0
- package/dist/{chunk-LYOXXD4T.js → chunk-B5XHX44Y.js} +2 -2
- package/dist/{chunk-7CVJ4JOE.js → chunk-DLKRPK5M.js} +2 -2
- package/dist/chunk-DTJKN5VT.js +28 -0
- package/dist/chunk-DTJKN5VT.js.map +1 -0
- package/dist/chunk-DVNIFP7S.js +23 -0
- package/dist/chunk-DVNIFP7S.js.map +1 -0
- package/dist/chunk-FM2GGPSD.js +626 -0
- package/dist/chunk-FM2GGPSD.js.map +1 -0
- package/dist/chunk-FULEQYM6.js +13 -0
- package/dist/chunk-FULEQYM6.js.map +1 -0
- package/dist/{chunk-3RHPZXCR.js → chunk-GCHUE3TN.js} +2 -2
- package/dist/{chunk-YIXQDOPN.js → chunk-HGT4AKOH.js} +185 -179
- package/dist/chunk-HGT4AKOH.js.map +1 -0
- package/dist/{chunk-XMRI32CY.js → chunk-HVQJIROJ.js} +64 -74
- package/dist/chunk-HVQJIROJ.js.map +1 -0
- package/dist/{chunk-BJWK7FPT.js → chunk-IXUEJBHD.js} +2 -2
- package/dist/{chunk-KTM7HSEB.js → chunk-JVNFRS26.js} +2 -2
- package/dist/{chunk-V7FYSZSV.js → chunk-LQRBGQIR.js} +2 -2
- package/dist/chunk-LQRBGQIR.js.map +1 -0
- package/dist/{chunk-XMWOV2D5.js → chunk-MWUJOAAW.js} +2 -2
- package/dist/{chunk-DJQA2CWD.js → chunk-N6EWZGIX.js} +6 -6
- package/dist/{chunk-DJQA2CWD.js.map → chunk-N6EWZGIX.js.map} +1 -1
- package/dist/{chunk-J63MRNXF.js → chunk-NLZD2QKF.js} +2 -2
- package/dist/chunk-OHA3J5ZV.js +243 -0
- package/dist/chunk-OHA3J5ZV.js.map +1 -0
- package/dist/chunk-OTW5MPFT.js +7 -0
- package/dist/chunk-OTW5MPFT.js.map +1 -0
- package/dist/chunk-OUZ7YVQZ.js +5 -0
- package/dist/{chunk-BHPIAG3E.js.map → chunk-OUZ7YVQZ.js.map} +1 -1
- package/dist/chunk-P2ZYT5D6.js +15 -0
- package/dist/chunk-P2ZYT5D6.js.map +1 -0
- package/dist/{chunk-FNLGY4UV.js → chunk-PZCTCCC5.js} +2 -2
- package/dist/chunk-Q7C3X3R6.js +61 -0
- package/dist/chunk-Q7C3X3R6.js.map +1 -0
- package/dist/{chunk-MDTKQZC6.js → chunk-QDE75R4U.js} +2 -2
- package/dist/{chunk-VHTFHGVW.js → chunk-RKAJR37K.js} +51 -51
- package/dist/chunk-RKAJR37K.js.map +1 -0
- package/dist/chunk-RKPAVWXF.js +2 -0
- package/dist/chunk-RKPAVWXF.js.map +1 -0
- package/dist/{chunk-SFLF64Q3.js → chunk-Z3IP66SL.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-JZTH46N2.js +2 -0
- package/dist/{compaction-QXU3A4LQ.js → compaction-U5SAYTX6.js} +2 -2
- package/dist/config-R47ITLIY.js +2 -0
- package/dist/config-mutator-T6JGXJ26.js +2 -0
- package/dist/context-planner-FJMU5WAT.js +17 -0
- package/dist/context-planner-FJMU5WAT.js.map +1 -0
- package/dist/doctor-2DMGAWMW.js +2 -0
- package/dist/failure-candidates-ARRMFXRY.js +8 -0
- package/dist/failure-candidates-ARRMFXRY.js.map +1 -0
- package/dist/index.d.ts +272 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-extract-YZI2QZVR.js +2 -0
- package/dist/processes-XWRGOLMT.js +2 -0
- package/dist/program-3CDFUJVE.js +2 -0
- package/dist/promote-57YNOVXV.js +2 -0
- package/dist/proposals-TX2HBBYV.js +2 -0
- package/dist/query-ZT7WXY2F.js +2 -0
- package/dist/registry-722GXALE.js +2 -0
- package/dist/{request-planner-5354IOYM.js → request-planner-PEAYYXAP.js} +2 -2
- package/dist/{review-candidates-UTWMO7UO.js → review-candidates-W7NIHNAI.js} +2 -2
- package/dist/{routing-JGNWB6VJ.js → routing-7LCO7UJ7.js} +2 -2
- package/dist/schedule-tool-ZD3VBUBW.js +2 -0
- package/dist/scheduler-GC3FQKXY.js +2 -0
- package/dist/{seat-STLDEYSO.js → seat-HR6QMAR2.js} +2 -2
- package/dist/{select-VP66P6XB.js → select-4XYRIZ5L.js} +2 -2
- package/dist/{surface-usage-FM2ZHGYE.js → surface-usage-V2BX4SBD.js} +2 -2
- package/dist/tool-PAQ47HV2.js +2 -0
- package/dist/tool-PAQ47HV2.js.map +1 -0
- package/dist/wiki-EREMPSAE.js +2 -0
- package/dist/wiki-EREMPSAE.js.map +1 -0
- package/package.json +1 -1
- package/dist/board-dashboard-4LAQOB74.js.map +0 -1
- package/dist/chunk-7L6M3P2N.js +0 -13
- package/dist/chunk-7L6M3P2N.js.map +0 -1
- package/dist/chunk-ANLKBCYH.js +0 -15
- package/dist/chunk-ANLKBCYH.js.map +0 -1
- package/dist/chunk-BHPIAG3E.js +0 -5
- package/dist/chunk-CQR6C5FU.js +0 -23
- package/dist/chunk-CQR6C5FU.js.map +0 -1
- package/dist/chunk-FQBPSL36.js +0 -25
- package/dist/chunk-FQBPSL36.js.map +0 -1
- package/dist/chunk-FRHSQVFN.js.map +0 -1
- package/dist/chunk-FXGSSZAP.js +0 -9
- package/dist/chunk-FXGSSZAP.js.map +0 -1
- package/dist/chunk-OSSI6R4K.js +0 -2
- package/dist/chunk-OSSI6R4K.js.map +0 -1
- package/dist/chunk-QURVHYBP.js +0 -616
- package/dist/chunk-QURVHYBP.js.map +0 -1
- package/dist/chunk-V7FYSZSV.js.map +0 -1
- package/dist/chunk-VHTFHGVW.js.map +0 -1
- package/dist/chunk-VZDKE2EZ.js +0 -241
- package/dist/chunk-VZDKE2EZ.js.map +0 -1
- package/dist/chunk-W544ZCCO.js +0 -7
- package/dist/chunk-W544ZCCO.js.map +0 -1
- package/dist/chunk-WZGABQ72.js +0 -59
- package/dist/chunk-WZGABQ72.js.map +0 -1
- package/dist/chunk-XMRI32CY.js.map +0 -1
- package/dist/chunk-YIXQDOPN.js.map +0 -1
- package/dist/client-LAIP23IP.js +0 -2
- package/dist/config-OZ2OOKFA.js +0 -2
- package/dist/config-mutator-EUF7QQ4V.js +0 -2
- package/dist/context-planner-AQHJMVY2.js +0 -17
- package/dist/context-planner-AQHJMVY2.js.map +0 -1
- package/dist/doctor-PEE3F5TX.js +0 -2
- package/dist/memory-extract-3TO7UC5B.js +0 -2
- package/dist/processes-I3XAPHG7.js +0 -2
- package/dist/program-PMHQRD5E.js +0 -2
- package/dist/promote-RNSGW4AJ.js +0 -2
- package/dist/proposals-MWMEXRDW.js +0 -2
- package/dist/query-BOUVRUU4.js +0 -2
- package/dist/registry-GGU43EOI.js +0 -2
- package/dist/scheduler-N25EAWF6.js +0 -2
- package/dist/wiki-SKIIAVCU.js +0 -2
- /package/dist/{App-RZDJH6MK.js.map → App-KE4SURSS.js.map} +0 -0
- /package/dist/{ChatApp-6TXOFUDH.js.map → ChatApp-NNHIKXO2.js.map} +0 -0
- /package/dist/{agent-I6RXAEXG.js.map → agent-J7SLJYQ6.js.map} +0 -0
- /package/dist/{chunk-BZLHS3VF.js.map → chunk-4NBWF4TL.js.map} +0 -0
- /package/dist/{chunk-NXJBAKBR.js.map → chunk-5ALS7SVV.js.map} +0 -0
- /package/dist/{chunk-LYOXXD4T.js.map → chunk-B5XHX44Y.js.map} +0 -0
- /package/dist/{chunk-7CVJ4JOE.js.map → chunk-DLKRPK5M.js.map} +0 -0
- /package/dist/{chunk-3RHPZXCR.js.map → chunk-GCHUE3TN.js.map} +0 -0
- /package/dist/{chunk-BJWK7FPT.js.map → chunk-IXUEJBHD.js.map} +0 -0
- /package/dist/{chunk-KTM7HSEB.js.map → chunk-JVNFRS26.js.map} +0 -0
- /package/dist/{chunk-XMWOV2D5.js.map → chunk-MWUJOAAW.js.map} +0 -0
- /package/dist/{chunk-J63MRNXF.js.map → chunk-NLZD2QKF.js.map} +0 -0
- /package/dist/{chunk-FNLGY4UV.js.map → chunk-PZCTCCC5.js.map} +0 -0
- /package/dist/{chunk-MDTKQZC6.js.map → chunk-QDE75R4U.js.map} +0 -0
- /package/dist/{chunk-SFLF64Q3.js.map → chunk-Z3IP66SL.js.map} +0 -0
- /package/dist/{client-LAIP23IP.js.map → client-JZTH46N2.js.map} +0 -0
- /package/dist/{compaction-QXU3A4LQ.js.map → compaction-U5SAYTX6.js.map} +0 -0
- /package/dist/{config-OZ2OOKFA.js.map → config-R47ITLIY.js.map} +0 -0
- /package/dist/{config-mutator-EUF7QQ4V.js.map → config-mutator-T6JGXJ26.js.map} +0 -0
- /package/dist/{doctor-PEE3F5TX.js.map → doctor-2DMGAWMW.js.map} +0 -0
- /package/dist/{memory-extract-3TO7UC5B.js.map → memory-extract-YZI2QZVR.js.map} +0 -0
- /package/dist/{processes-I3XAPHG7.js.map → processes-XWRGOLMT.js.map} +0 -0
- /package/dist/{program-PMHQRD5E.js.map → program-3CDFUJVE.js.map} +0 -0
- /package/dist/{promote-RNSGW4AJ.js.map → promote-57YNOVXV.js.map} +0 -0
- /package/dist/{proposals-MWMEXRDW.js.map → proposals-TX2HBBYV.js.map} +0 -0
- /package/dist/{query-BOUVRUU4.js.map → query-ZT7WXY2F.js.map} +0 -0
- /package/dist/{registry-GGU43EOI.js.map → registry-722GXALE.js.map} +0 -0
- /package/dist/{request-planner-5354IOYM.js.map → request-planner-PEAYYXAP.js.map} +0 -0
- /package/dist/{review-candidates-UTWMO7UO.js.map → review-candidates-W7NIHNAI.js.map} +0 -0
- /package/dist/{routing-JGNWB6VJ.js.map → routing-7LCO7UJ7.js.map} +0 -0
- /package/dist/{scheduler-N25EAWF6.js.map → schedule-tool-ZD3VBUBW.js.map} +0 -0
- /package/dist/{seat-STLDEYSO.js.map → scheduler-GC3FQKXY.js.map} +0 -0
- /package/dist/{surface-usage-FM2ZHGYE.js.map → seat-HR6QMAR2.js.map} +0 -0
- /package/dist/{select-VP66P6XB.js.map → select-4XYRIZ5L.js.map} +0 -0
- /package/dist/{wiki-SKIIAVCU.js.map → surface-usage-V2BX4SBD.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as et,b as tt,c as nt,d as S,e as A,f as N}from"./chunk-F4HZTZHW.js";import{a as Te,b as ft}from"./chunk-AJONZWLT.js";import{a as ne,b as He}from"./chunk-ZTEU5JVQ.js";import{o as we,p as Ke}from"./chunk-LCIREYTD.js";import{
|
|
1
|
+
import{a as et,b as tt,c as nt,d as S,e as A,f as N}from"./chunk-F4HZTZHW.js";import{a as Te,b as ft}from"./chunk-AJONZWLT.js";import{a as ne,b as He}from"./chunk-ZTEU5JVQ.js";import{o as we,p as Ke}from"./chunk-LCIREYTD.js";import{o as We,p as Ze}from"./chunk-P2ZYT5D6.js";import{a as rt,b as ot,c as st,d as it,e as at,f as ct,g as ut,h as lt,i as dt,j as pt,k as mt,l as bt}from"./chunk-BH3GTCZ6.js";import{b as E,c as Ye,d as he}from"./chunk-FIOB3MEX.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 gt(){$.clear(),X.clear()}var $,X,C=E(()=>{"use strict";$=new Map,X=new Map});import yt from"better-sqlite3";import{createHash as ht}from"crypto";import{mkdirSync as wt}from"fs";import{dirname as Tt,resolve as Et}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 kt(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 xt(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&&Rt(e),t<2&&At(e),t<3&&St(e)}function St(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 At(e){e.exec(`
|
|
@@ -111,4 +111,4 @@ import{a as et,b as tt,c as nt,d as S,e as A,f as N}from"./chunk-F4HZTZHW.js";im
|
|
|
111
111
|
`)}if(!m)throw new Error(`local decision backend could not get a valid answer after ${f+1} attempt(s): ${h}`);let M={},L=!1;for(let[k,q]of Object.entries(s.questions)){let x=_(q,m[k],{normalize:e.normalizeProbabilities??!0});M[k]=x.answer,x.repaired&&(L=!0)}return{model:a,answers:M,usage:g,meta:{backend:"local",structureMode:c,answerMode:"probabilities",repaired:L,retries:f,stateTruncated:l.truncated,latencyMs:Date.now()-i}}}finally{b()}}}}async function $t(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:B,description:"Report a probability distribution for every question.",input_schema:se(t)}],{...o,toolChoice:{type:"tool",name:B}}),a=i.content.find(c=>c.type==="tool_use"&&c.name===B),u=a&&a.type==="tool_use"?a.input:null;return{answers:Pe(u),usage:{inputTokens:i.usage.input_tokens,outputTokens:i.usage.output_tokens}}}async function Vt(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:Pe(Te(a.content??"")),usage:{inputTokens:0,outputTokens:a.tokensUsed??0}}}function Pe(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 zt(e,t){return e!=="auto"?e:t.generateRaw&&me[t.name]?.structuredOutput?"tool":"text"}function Jt(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 Bt,Pt,qt,Be,Xt,be=E(()=>{"use strict";Ke();Ue();ft();j();Y();N();z();Bt="claude-code",Pt="claude-haiku-4-5-20251001",qt=24e3,Be=2e3,Xt=3e4});import{readFileSync as Gt}from"fs";import{homedir as Yt}from"os";import{join as Kt}from"path";function v(e={}){let t=(e.baseUrl??Ht).replace(/\/+$/,""),r=e.path??"/classifier",n=e.name??"simple-jev",o=e.maxStateChars??Zt,s=e.maxChoiceOptions??en,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),on(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:y,dispose:d}=sn(a.abortSignal,a.timeoutMs??e.timeoutMs??Wt);try{let b={"Content-Type":"application/json"},g=rn(e.apiKeyEnv,e.apiKeyFile);g&&(b.Authorization=`Bearer ${g}`);let w=await p(`${t}${r}`,{method:"POST",headers:b,body:JSON.stringify({model:c,state:l.text,questions:nn(a.questions)}),signal:y});if(!w.ok){let k=await w.text().catch(()=>"");throw new Error(`${n} ${w.status}: ${k.slice(0,300)}`)}let f=await w.json(),m=F(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 h=m.data,M={},L=!1;for(let[k,q]of Object.entries(a.questions)){let x=_(q,h[k]);M[k]=x.answer,x.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 nn(e){let t={};for(let[r,n]of Object.entries(e))t[r]=n.instructions?n:{...n,instructions:tn[n.type]};return t}function rn(e,t){let r=e?process.env[e]:void 0;if(r)return r;if(!t)return;let n=t.startsWith("~/")?Kt(Yt(),t.slice(2)):t;if(!Z.has(n))try{let o=Gt(n,"utf-8").trim();Z.set(n,o.length>0?o:null)}catch{Z.set(n,null)}return Z.get(n)??void 0}function on(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 sn(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 Ht,Wt,Zt,en,tn,Z,fe=E(()=>{"use strict";j();N();z();Y();Ht="http://127.0.0.1:8000/v1",Wt=3e4,Zt=6e3,en=50;tn={choice:"Which option best fits?",score:"Which level best fits?",noul:"Is this true of the state?"};Z=new Map});var qe={};Ye(qe,{DecisionStore:()=>I,MAX_CHOICE_OPTIONS:()=>MAX_CHOICE_OPTIONS,SYSTEM_PROMPT:()=>J,TOOL_NAME:()=>B,UNCERTAINTY_HIGH:()=>Ce,UNCERTAINTY_LOW:()=>De,_resetDecisionBackendsForTesting:()=>gt,agreement:()=>rt,answerView:()=>Q,applyRecalibrator:()=>ue,applyTemperature:()=>lt,askSeat:()=>pn,band:()=>Ie,bootstrapInterval:()=>pt,brier:()=>at,buildDesign:()=>Ne,calibrationReport:()=>mt,choice:()=>tt,compareCalibrators:()=>Lt,confidenceFor:()=>re,configureDecisions:()=>cn,coverageCurve:()=>ut,createLocalDecisionBackend:()=>W,createMockDecisionBackend:()=>H,createSimpleJevBackend:()=>v,decisionsRuntime:()=>ln,describeIssues:()=>U,ece:()=>st,expectedScore:()=>Ae,finalizeAnswer:()=>_,fitLogistic:()=>ve,fitRecalibrator:()=>P,fitTemperature:()=>dt,getDecisionBackend:()=>D,getSeatMode:()=>Ve,labelsOf:()=>S,listDecisionBackends:()=>Ee,logLoss:()=>ct,logit:()=>le,mce:()=>it,measureConsistency:()=>Qt,normalizeDistribution:()=>xe,normalizedNegEntropy:()=>oe,noul:()=>et,pMax:()=>Se,parseSeatMode:()=>ge,rawAnswerSchema:()=>Re,rawAnswersSchema:()=>F,recordSeatOutcome:()=>dn,registerBuiltinDecisionBackends:()=>an,registerDecisionBackend:()=>R,reliabilityBins:()=>ot,renderQuestions:()=>_e,renderShapeInstructions:()=>ae,renderState:()=>G,renderUserPrompt:()=>ie,resetDecisionsRuntime:()=>un,score:()=>nt,seatEnvVar:()=>$e,sigmoid:()=>de,toolInputSchema:()=>se,validateQuestions:()=>A,withUid:()=>Qe});function an(e={},t={},r={},n={}){R("mock",()=>H()),R("local",()=>W(e)),R("simple-jev",()=>v(t)),R("jev",()=>v({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",()=>v({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 Xe=E(()=>{"use strict";ke();N();j();z();C();Y();V();bt();Me();je();ze();pe();be();fe();C();pe();be();fe()});function cn(e){T={...ye,...T,...e},ee=!0}function un(){T={...ye,seats:{}},ee=!1}function mn(){if(!ee){ee=!0;try{let{loadDaemonConfig:e}=(Ze(),he(We)),t=e()?.decisions;if(!t?.enabled)return;let{registerBuiltinDecisionBackends:r}=(Xe(),he(qe)),n=t.backends??{};r(n.local,n.simpleJev,n.jev,n.typesafe);let o=null;try{o=new I({path:t.dbPath})}catch{}T={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 ln(){return T}function ge(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return bn.includes(t)?t:null}function $e(e){return`AGENTX_DECISION_SEAT_${e.toUpperCase().replace(/[^A-Z0-9]+/g,"_")}`}function Ve(e,t=process.env){mn();let r=ge(t[$e(e)]);return r||(T.enabled?ge(T.seats[e]?.mode)??"off":"off")}function dn(e,t,r=!1){if(!(!e||!T.store))try{T.store.recordOutcome(e,t,r)}catch{}}async function pn(e,t,r,n={}){let o=Ve(e);if(o==="off")return null;let s=T.seats[e]??{mode:o},i=n.backend??s.backend??T.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}),l=fn(e,o,t,r,c,n,s);return{answers:c.answers,callId:l,mode:o}}catch(u){return gn(e,o,t,r,i,n,s,a,u),yn(e,i,u),null}}function fn(e,t,r,n,o,s,i){if(!T.store)return null;try{return T.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:Ge(s.incumbent),links:s.links,features:s.features,keepState:!i.redactState})}catch{return null}}function gn(e,t,r,n,o,s,i,a,u){if(T.store)try{T.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:Ge(s.incumbent),links:s.links,features:s.features,error:String(u?.message??u).slice(0,500),keepState:!i.redactState})}catch{}}function Ge(e){if(!e)return;let t={};for(let[r,n]of Object.entries(e))n!==void 0&&(t[r]={value:n});return t}function yn(e,t,r){let n=Date.now();n-Je<6e4||(Je=n,console.warn(`[decisions] seat "${e}" on backend "${t}" failed: ${r?.message??r}`))}var ye,T,ee,bn,Je,ze=E(()=>{C();V();ye={enabled:!1,defaultBackend:"local",seats:{},store:null},T={...ye},ee=!1;bn=["off","shadow","active"];Je=0});export{D as a,Ee as b,C as c,I as d,V as e,Lt as f,Me as g,Qt as h,je as i,me as j,Un as k,Ue as l,an as m,Xe as n,cn as o,un as p,ln as q,ge as r,$e as s,Ve as t,dn as u,pn as v,ze as w};
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-4NBWF4TL.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{a as D,b as _
|
|
1
|
+
import{a as D,b as _}from"./chunk-RKPAVWXF.js";import{a as q,b as O,c as R,d as B,f as b,g as S,h as E,i as w,j as y}from"./chunk-5XQCGPQJ.js";import{a as T,b as C,c as I,d as x,e as P}from"./chunk-NLZD2QKF.js";import{existsSync as X,readFileSync as F}from"fs";var J=new Set(["cron","heartbeat","api","a2a","mesh"]),M=160;function s(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function A(n,e=M){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function V(n){let e=T(n);if(!X(e))throw new Error(`config not found at ${e}`);return JSON.parse(F(e,"utf-8"))}function W(n,e){return n?.agents?.[e]?.admin===!0}function Y(n,e,t){return W(n,t.agentId)||e?.createdBy===t.agentId}function Z(n,e){let t=e?.createdBy?`agent "${e.createdBy}"`:"the operator";return`Not allowed: "${n}" was created by ${t}. Agents manage only schedules they created (unless configured admin).`}function K(n,e){let t=s(n.notify);if(t!=="none"){if(t&&t!=="here"){let r=t.split(":");return r.length<2||!r[0]||!r[1]?"invalid":{channel:r[0],chatId:r.slice(1).join(":")}}if(e.channel&&e.chatId&&!J.has(e.channel))return{channel:e.channel,chatId:e.chatId,...e.accountId?{accountId:e.accountId}:{}}}}function Q(n,e,t){let r=e.timezone||"UTC",u=e.enabled&&!y(e)?w(E(e.schedule,r,t),r):"\u2014",h=e.approval?`pending ${e.approval.action} approval`:e.enabled?"active":"paused",p=[`- ${n} [${h}] ${e.schedule} \u2014 ${S(e.schedule)} (${r})`,` agent: ${e.agent}; created by: ${e.createdBy||"operator"}; next: ${u}`];return e.notify&&p.push(` notify: ${e.notify.channel} ${e.notify.chatId}`),e.command?p.push(` command: ${A(String(e.command))}`):e.prompt&&p.push(` prompt: ${A(String(e.prompt))}`),p.join(`
|
|
2
2
|
`)}async function k(n,e,t){let r=n?.notifications?.destination;if(!r?.channel||!r?.chatId)return"No operator notification destination is configured (notifications.destination); the operator must check `agentx schedule list`.";if(!e.notifyOperator)return"Operator notification is unavailable in this context.";try{return await e.notifyOperator({channel:r.channel,chatId:r.chatId,accountId:r.accountId},t),"The operator has been notified."}catch(u){return`Could not notify the operator (${u?.message??u}); the request is still recorded.`}}async function re(n,e,t={}){let r=(s(n.action)||"list").toLowerCase(),u=t.now?t.now():new Date,h;try{h=V(t.configPath)}catch(a){return`Error: ${a.message}`}let p=h.crons||{};if(r==="list"){let a=n.mine===!0,l=Object.entries(p).filter(([,i])=>!a||e&&i?.createdBy===e.agentId);return l.length?l.map(([i,f])=>Q(i,f,u)).join(`
|
|
3
3
|
`):a?"You have no schedules.":"No schedules."}if(!e?.agentId)return"Error: caller agent is unknown (AGENTX_AGENT_ID not set). Pass callerAgentId.";if(!h.agents?.[e.agentId])return`Error: caller "${e.agentId}" is not an agent on this node.`;let o=s(n.id),m=a=>C(a,{configPath:t.configPath,reload:t.reload});if(r==="create"){let a=s(n.when),l=s(n.prompt);if(!a||!l)return"Error: create needs `when` (plain English) and `prompt`.";let i=D(a);if(!i)return`Error: couldn't parse "${a}". ${O}.`;let f=s(n.agent)||e.agentId;if(!h.agents?.[f])return`Error: agent "${f}" not found on this node.`;let g=s(n.timezone)||q;if(!B(g))return`Error: unknown timezone "${g}".`;let d=o||_(i.matched,f);if(!R(d))return`Error: invalid id "${d}" (letters, digits, "-" and "_" only).`;if(p[d])return`Error: a schedule "${d}" already exists. Pick another \`id\`.`;let $=K(n,e);if($==="invalid")return'Error: `notify` must be "here", "none", or "channel:chatId".';let z={action:"create",requestedBy:e.agentId,requestedAt:u.toISOString()},L=b({parsed:i,agent:f,prompt:l,timezone:g,notify:$,enabled:!1,createdBy:e.agentId,approval:z}),v=await m(U=>I(U,`crons.${d}`,L));if(!v.success)return`Error: ${v.error}`;let N=w(E(i.cron,g,u),g),G=[`Schedule approval requested by ${e.agentId}`,`Create: ${d}`,`When: ${i.human} \u2014 cron \`${i.cron}\` (${g})`,`Next fire: ${N}`,`Agent: ${f}`,$?`Notify: ${$.channel} ${$.chatId}`:"Notify: none",`Prompt: ${A(l,400)}`,"",`Approve: agentx schedule approve ${d}`,`Reject: agentx schedule reject ${d}`].join(`
|
|
4
4
|
`),H=await k(h,t,G);return[`Requested schedule "${d}": ${i.human} (cron ${i.cron}, ${g}); next fire would be ${N}.`,"It is saved DISABLED and will not run until the operator approves it.",H].join(`
|
|
5
5
|
`)}if(!o)return`Error: ${r} needs \`id\`.`;let c=p[o];if(!c)return`Error: schedule "${o}" not found.`;if(!Y(h,c,e))return Z(o,c);if(r==="pause"||r==="resume"){let a=r==="resume";if(a&&y(c))return`"${o}" is still awaiting operator approval; it can't be resumed until approved.`;if(c.enabled===a)return`"${o}" is already ${a?"active":"paused"}.`;let l=await m(i=>I(i,`crons.${o}.enabled`,a));return l.success?`"${o}" ${a?"resumed":"paused"}.`:`Error: ${l.error}`}if(r==="delete"){if(y(c)&&c.approval.requestedBy===e.agentId){let d=await m($=>P($,`crons.${o}`));return d.success?`Withdrew the pending request "${o}".`:`Error: ${d.error}`}if(y(c))return`"${o}" is a creation request still awaiting approval; only its requester or the operator (\`agentx schedule reject ${o}\`) can drop it.`;if(c.approval?.action==="delete")return`Deletion of "${o}" is already awaiting approval.`;let a={action:"delete",requestedBy:e.agentId,requestedAt:u.toISOString()},l=await m(d=>{if(!x(d,`crons.${o}`))throw new Error(`schedule "${o}" not found`);I(d,`crons.${o}.approval`,a)});if(!l.success)return`Error: ${l.error}`;let i=c.timezone||"UTC",f=[`Schedule approval requested by ${e.agentId}`,`Delete: ${o}`,`When: ${S(c.schedule)} \u2014 cron \`${c.schedule}\` (${i})`,`Next fire: ${c.enabled?w(E(c.schedule,i,u),i):"\u2014 (paused)"}`,`Agent: ${c.agent}`,"",`Approve: agentx schedule approve ${o}`,`Reject: agentx schedule reject ${o}`].join(`
|
|
6
6
|
`),g=await k(h,t,f);return[`Deletion of "${o}" requested. It keeps its current state until the operator approves.`,g].join(`
|
|
7
|
-
`)}return`Error: unknown action "${r}". Use list, create, pause, resume or delete.`}function oe(n,e=process.env){let t=s(e.AGENTX_AGENT_ID)||s(n.callerAgentId);if(!t)return null;let r=!!(s(e.AGENTX_CHANNEL)&&s(e.AGENTX_CHAT_ID)),u=s(r?e.AGENTX_CHANNEL:n.channel),h=s(r?e.AGENTX_CHAT_ID:n.chatId),p=s(n.accountId);return{agentId:t,channel:u,chatId:h,...p?{accountId:p}:{}}}export{
|
|
8
|
-
//# sourceMappingURL=
|
|
7
|
+
`)}return`Error: unknown action "${r}". Use list, create, pause, resume or delete.`}function oe(n,e=process.env){let t=s(e.AGENTX_AGENT_ID)||s(n.callerAgentId);if(!t)return null;let r=!!(s(e.AGENTX_CHANNEL)&&s(e.AGENTX_CHAT_ID)),u=s(r?e.AGENTX_CHANNEL:n.channel),h=s(r?e.AGENTX_CHAT_ID:n.chatId),p=s(n.accountId);return{agentId:t,channel:u,chatId:h,...p?{accountId:p}:{}}}export{re as a,oe as b};
|
|
8
|
+
//# sourceMappingURL=chunk-4TITGMPX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/crons/schedule-tool.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\"\nimport { applyConfigMutation, findConfigPath, getAtPath, setAtPath, unsetAtPath } from \"@/daemon/config-mutator\"\nimport { parseEnglishToCron, slugifyScheduleId } from \"@/utils/nl-cron\"\nimport {\n buildScheduleJob,\n DEFAULT_SCHEDULE_TIMEZONE,\n formatFireTime,\n humanizeCron,\n isPendingCreate,\n isValidScheduleId,\n isValidTimezone,\n nextFireTime,\n SUPPORTED_PHRASES_HINT,\n type NotifyTarget,\n type ScheduleApproval,\n} from \"./schedule-ops\"\n\n// --- Agent-facing `schedule` tool ---\n//\n// Lets an agent list / create / pause / resume / delete routines from any\n// chat. Writes go through the same builder and config mutator as the\n// `agentx schedule` CLI, with two differences that make it safe to hand to\n// a model:\n//\n// 1. create and delete are REQUESTS. Create writes the job disabled with an\n// `approval` marker (the scheduler refuses to run it while that marker\n// says \"create\"); delete only marks the job. The operator is notified\n// with the parsed cron and next fire time, and only\n// `agentx schedule approve|reject <id>` resolves the request. There is\n// no action here that approves anything.\n// 2. Ownership. Jobs record `createdBy`; an agent may touch only its own\n// unless its config says `admin: true`.\n\nexport type ScheduleAction = \"list\" | \"create\" | \"pause\" | \"resume\" | \"delete\"\n\nexport interface ScheduleCaller {\n agentId: string\n /** Chat the request came from — the default notify target. */\n channel?: string\n chatId?: string\n accountId?: string\n}\n\nexport interface ScheduleToolDeps {\n configPath?: string\n /** Hot-reload the daemon after a write. Default true. */\n reload?: boolean\n now?: () => Date\n /** Deliver the approval request to the operator. Throws on failure. */\n notifyOperator?: (dest: NotifyTarget, text: string) => Promise<void>\n}\n\n/** Channels that are not a conversation someone reads, so they never make a\n * sensible default delivery target for a routine's output. */\nconst NON_DELIVERABLE_CHANNELS = new Set([\"cron\", \"heartbeat\", \"api\", \"a2a\", \"mesh\"])\n\nconst PROMPT_PREVIEW = 160\n\nfunction str(v: unknown): string | undefined {\n return typeof v === \"string\" && v.trim() ? v.trim() : undefined\n}\n\nfunction preview(s: string, n = PROMPT_PREVIEW): string {\n const flat = s.replace(/\\s+/g, \" \").trim()\n return flat.length > n ? `${flat.slice(0, n - 1)}…` : flat\n}\n\nfunction readRawConfig(configPath?: string): any {\n const path = findConfigPath(configPath)\n if (!existsSync(path)) throw new Error(`config not found at ${path}`)\n return JSON.parse(readFileSync(path, \"utf-8\"))\n}\n\nfunction isAdmin(cfg: any, agentId: string): boolean {\n return cfg?.agents?.[agentId]?.admin === true\n}\n\nfunction canManage(cfg: any, job: any, caller: ScheduleCaller): boolean {\n return isAdmin(cfg, caller.agentId) || job?.createdBy === caller.agentId\n}\n\nfunction ownershipError(id: string, job: any): string {\n const owner = job?.createdBy ? `agent \"${job.createdBy}\"` : \"the operator\"\n return `Not allowed: \"${id}\" was created by ${owner}. Agents manage only schedules they created (unless configured admin).`\n}\n\nfunction resolveNotify(args: Record<string, unknown>, caller: ScheduleCaller): NotifyTarget | undefined | \"invalid\" {\n const raw = str(args.notify)\n if (raw === \"none\") return undefined\n if (raw && raw !== \"here\") {\n const parts = raw.split(\":\")\n if (parts.length < 2 || !parts[0] || !parts[1]) return \"invalid\"\n // chatIds can contain \":\" (gitlab \"org/repo:issue:1\"), so the channel\n // is the first segment and the rest is the chat id.\n return { channel: parts[0], chatId: parts.slice(1).join(\":\") }\n }\n if (caller.channel && caller.chatId && !NON_DELIVERABLE_CHANNELS.has(caller.channel)) {\n return { channel: caller.channel, chatId: caller.chatId, ...(caller.accountId ? { accountId: caller.accountId } : {}) }\n }\n return undefined\n}\n\nfunction describeJob(id: string, job: any, now: Date): string {\n const tz = job.timezone || \"UTC\"\n const next = job.enabled && !isPendingCreate(job) ? formatFireTime(nextFireTime(job.schedule, tz, now), tz) : \"—\"\n const state = job.approval\n ? `pending ${job.approval.action} approval`\n : job.enabled ? \"active\" : \"paused\"\n const lines = [\n `- ${id} [${state}] ${job.schedule} — ${humanizeCron(job.schedule)} (${tz})`,\n ` agent: ${job.agent}; created by: ${job.createdBy || \"operator\"}; next: ${next}`,\n ]\n if (job.notify) lines.push(` notify: ${job.notify.channel} ${job.notify.chatId}`)\n if (job.command) lines.push(` command: ${preview(String(job.command))}`)\n else if (job.prompt) lines.push(` prompt: ${preview(String(job.prompt))}`)\n return lines.join(\"\\n\")\n}\n\nasync function notifyApproval(\n cfg: any,\n deps: ScheduleToolDeps,\n text: string,\n): Promise<string> {\n const dest = cfg?.notifications?.destination\n if (!dest?.channel || !dest?.chatId) {\n return \"No operator notification destination is configured (notifications.destination); the operator must check `agentx schedule list`.\"\n }\n if (!deps.notifyOperator) return \"Operator notification is unavailable in this context.\"\n try {\n await deps.notifyOperator({ channel: dest.channel, chatId: dest.chatId, accountId: dest.accountId }, text)\n return \"The operator has been notified.\"\n } catch (e: any) {\n return `Could not notify the operator (${e?.message ?? e}); the request is still recorded.`\n }\n}\n\n/**\n * Run one tool action. Returns the text the agent sees. Throws only on\n * programming errors — every expected refusal is returned as text so the\n * model can relay it.\n */\nexport async function runScheduleTool(\n args: Record<string, unknown>,\n caller: ScheduleCaller | null,\n deps: ScheduleToolDeps = {},\n): Promise<string> {\n const action = (str(args.action) || \"list\").toLowerCase() as ScheduleAction\n const now = deps.now ? deps.now() : new Date()\n\n let cfg: any\n try {\n cfg = readRawConfig(deps.configPath)\n } catch (e: any) {\n return `Error: ${e.message}`\n }\n const crons: Record<string, any> = cfg.crons || {}\n\n if (action === \"list\") {\n const mineOnly = args.mine === true\n const entries = Object.entries(crons).filter(([, j]) => !mineOnly || (caller && j?.createdBy === caller.agentId))\n if (!entries.length) return mineOnly ? \"You have no schedules.\" : \"No schedules.\"\n return entries.map(([id, j]) => describeJob(id, j, now)).join(\"\\n\")\n }\n\n if (!caller?.agentId) {\n return \"Error: caller agent is unknown (AGENTX_AGENT_ID not set). Pass callerAgentId.\"\n }\n if (!cfg.agents?.[caller.agentId]) {\n return `Error: caller \"${caller.agentId}\" is not an agent on this node.`\n }\n\n const id = str(args.id)\n const mutate = (fn: (c: any) => void) =>\n applyConfigMutation(fn, { configPath: deps.configPath, reload: deps.reload })\n\n if (action === \"create\") {\n const when = str(args.when)\n const prompt = str(args.prompt)\n if (!when || !prompt) return \"Error: create needs `when` (plain English) and `prompt`.\"\n const parsed = parseEnglishToCron(when)\n if (!parsed) return `Error: couldn't parse \"${when}\". ${SUPPORTED_PHRASES_HINT}.`\n\n const agent = str(args.agent) || caller.agentId\n if (!cfg.agents?.[agent]) return `Error: agent \"${agent}\" not found on this node.`\n\n const timezone = str(args.timezone) || DEFAULT_SCHEDULE_TIMEZONE\n if (!isValidTimezone(timezone)) return `Error: unknown timezone \"${timezone}\".`\n\n const jobId = id || slugifyScheduleId(parsed.matched, agent)\n if (!isValidScheduleId(jobId)) return `Error: invalid id \"${jobId}\" (letters, digits, \"-\" and \"_\" only).`\n if (crons[jobId]) return `Error: a schedule \"${jobId}\" already exists. Pick another \\`id\\`.`\n\n const notify = resolveNotify(args, caller)\n if (notify === \"invalid\") return 'Error: `notify` must be \"here\", \"none\", or \"channel:chatId\".'\n\n const approval: ScheduleApproval = {\n action: \"create\",\n requestedBy: caller.agentId,\n requestedAt: now.toISOString(),\n }\n const job = buildScheduleJob({\n parsed,\n agent,\n prompt,\n timezone,\n notify,\n enabled: false,\n createdBy: caller.agentId,\n approval,\n })\n\n const result = await mutate((c) => setAtPath(c, `crons.${jobId}`, job))\n if (!result.success) return `Error: ${result.error}`\n\n const next = formatFireTime(nextFireTime(parsed.cron, timezone, now), timezone)\n const request = [\n `Schedule approval requested by ${caller.agentId}`,\n `Create: ${jobId}`,\n `When: ${parsed.human} — cron \\`${parsed.cron}\\` (${timezone})`,\n `Next fire: ${next}`,\n `Agent: ${agent}`,\n notify ? `Notify: ${notify.channel} ${notify.chatId}` : \"Notify: none\",\n `Prompt: ${preview(prompt, 400)}`,\n \"\",\n `Approve: agentx schedule approve ${jobId}`,\n `Reject: agentx schedule reject ${jobId}`,\n ].join(\"\\n\")\n const notified = await notifyApproval(cfg, deps, request)\n\n return [\n `Requested schedule \"${jobId}\": ${parsed.human} (cron ${parsed.cron}, ${timezone}); next fire would be ${next}.`,\n \"It is saved DISABLED and will not run until the operator approves it.\",\n notified,\n ].join(\"\\n\")\n }\n\n if (!id) return `Error: ${action} needs \\`id\\`.`\n const job = crons[id]\n if (!job) return `Error: schedule \"${id}\" not found.`\n if (!canManage(cfg, job, caller)) return ownershipError(id, job)\n\n if (action === \"pause\" || action === \"resume\") {\n const enable = action === \"resume\"\n if (enable && isPendingCreate(job)) {\n return `\"${id}\" is still awaiting operator approval; it can't be resumed until approved.`\n }\n if (job.enabled === enable) return `\"${id}\" is already ${enable ? \"active\" : \"paused\"}.`\n const result = await mutate((c) => setAtPath(c, `crons.${id}.enabled`, enable))\n if (!result.success) return `Error: ${result.error}`\n return `\"${id}\" ${enable ? \"resumed\" : \"paused\"}.`\n }\n\n if (action === \"delete\") {\n // Withdrawing your own never-approved request removes nothing that ever\n // ran, so it needs no approval.\n if (isPendingCreate(job) && job.approval.requestedBy === caller.agentId) {\n const result = await mutate((c) => unsetAtPath(c, `crons.${id}`))\n if (!result.success) return `Error: ${result.error}`\n return `Withdrew the pending request \"${id}\".`\n }\n // Never replace a pending create marker with a delete marker: rejecting\n // that delete would leave a disabled job with no marker, which its owner\n // could then resume without the create ever being approved.\n if (isPendingCreate(job)) {\n return `\"${id}\" is a creation request still awaiting approval; only its requester or the operator (\\`agentx schedule reject ${id}\\`) can drop it.`\n }\n if (job.approval?.action === \"delete\") return `Deletion of \"${id}\" is already awaiting approval.`\n\n const approval: ScheduleApproval = {\n action: \"delete\",\n requestedBy: caller.agentId,\n requestedAt: now.toISOString(),\n }\n const result = await mutate((c) => {\n if (!getAtPath(c, `crons.${id}`)) throw new Error(`schedule \"${id}\" not found`)\n setAtPath(c, `crons.${id}.approval`, approval)\n })\n if (!result.success) return `Error: ${result.error}`\n\n const tz = job.timezone || \"UTC\"\n const request = [\n `Schedule approval requested by ${caller.agentId}`,\n `Delete: ${id}`,\n `When: ${humanizeCron(job.schedule)} — cron \\`${job.schedule}\\` (${tz})`,\n `Next fire: ${job.enabled ? formatFireTime(nextFireTime(job.schedule, tz, now), tz) : \"— (paused)\"}`,\n `Agent: ${job.agent}`,\n \"\",\n `Approve: agentx schedule approve ${id}`,\n `Reject: agentx schedule reject ${id}`,\n ].join(\"\\n\")\n const notified = await notifyApproval(cfg, deps, request)\n return [\n `Deletion of \"${id}\" requested. It keeps its current state until the operator approves.`,\n notified,\n ].join(\"\\n\")\n }\n\n return `Error: unknown action \"${action}\". Use list, create, pause, resume or delete.`\n}\n\n/**\n * Who is calling. The runtime-exported environment wins over model-supplied\n * arguments: an agent launched by AgentX cannot claim another identity by\n * passing `callerAgentId`. The arguments are the fallback for runtimes that\n * don't export the variables (e.g. an operator-configured MCP entry).\n */\nexport function resolveScheduleCaller(\n args: Record<string, unknown>,\n env: NodeJS.ProcessEnv = process.env,\n): ScheduleCaller | null {\n const agentId = str(env.AGENTX_AGENT_ID) || str(args.callerAgentId)\n if (!agentId) return null\n const envChat = Boolean(str(env.AGENTX_CHANNEL) && str(env.AGENTX_CHAT_ID))\n const channel = envChat ? str(env.AGENTX_CHANNEL) : str(args.channel)\n const chatId = envChat ? str(env.AGENTX_CHAT_ID) : str(args.chatId)\n const accountId = str(args.accountId)\n return { agentId, channel, chatId, ...(accountId ? { accountId } : {}) }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","NON_DELIVERABLE_CHANNELS","PROMPT_PREVIEW","str","v","preview","s","n","flat","readRawConfig","configPath","path","findConfigPath","existsSync","readFileSync","isAdmin","cfg","agentId","canManage","job","caller","ownershipError","id","owner","resolveNotify","args","raw","parts","describeJob","now","tz","next","isPendingCreate","formatFireTime","nextFireTime","state","lines","humanizeCron","notifyApproval","deps","text","dest","e","runScheduleTool","action","crons","mineOnly","entries","j","mutate","fn","applyConfigMutation","when","prompt","parsed","parseEnglishToCron","SUPPORTED_PHRASES_HINT","agent","timezone","DEFAULT_SCHEDULE_TIMEZONE","isValidTimezone","jobId","slugifyScheduleId","isValidScheduleId","notify","approval","buildScheduleJob","result","c","setAtPath","request","notified","enable","unsetAtPath","getAtPath","resolveScheduleCaller","env","envChat","channel","chatId","accountId"]}
|
|
1
|
+
{"version":3,"sources":["../src/crons/schedule-tool.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\"\nimport { applyConfigMutation, findConfigPath, getAtPath, setAtPath, unsetAtPath } from \"@/daemon/config-mutator\"\nimport { parseEnglishToCron, slugifyScheduleId } from \"@/utils/nl-cron\"\nimport {\n buildScheduleJob,\n DEFAULT_SCHEDULE_TIMEZONE,\n formatFireTime,\n humanizeCron,\n isPendingCreate,\n isValidScheduleId,\n isValidTimezone,\n nextFireTime,\n SUPPORTED_PHRASES_HINT,\n type NotifyTarget,\n type ScheduleApproval,\n} from \"./schedule-ops\"\n\n// --- Agent-facing `schedule` tool ---\n//\n// Lets an agent list / create / pause / resume / delete routines from any\n// chat. Writes go through the same builder and config mutator as the\n// `agentx schedule` CLI, with two differences that make it safe to hand to\n// a model:\n//\n// 1. create and delete are REQUESTS. Create writes the job disabled with an\n// `approval` marker (the scheduler refuses to run it while that marker\n// says \"create\"); delete only marks the job. The operator is notified\n// with the parsed cron and next fire time, and only\n// `agentx schedule approve|reject <id>` resolves the request. There is\n// no action here that approves anything.\n// 2. Ownership. Jobs record `createdBy`; an agent may touch only its own\n// unless its config says `admin: true`.\n\nexport type ScheduleAction = \"list\" | \"create\" | \"pause\" | \"resume\" | \"delete\"\n\nexport interface ScheduleCaller {\n agentId: string\n /** Chat the request came from — the default notify target. */\n channel?: string\n chatId?: string\n accountId?: string\n}\n\nexport interface ScheduleToolDeps {\n configPath?: string\n /** Hot-reload the daemon after a write. Default true. */\n reload?: boolean\n now?: () => Date\n /** Deliver the approval request to the operator. Throws on failure. */\n notifyOperator?: (dest: NotifyTarget, text: string) => Promise<void>\n}\n\n/** Channels that are not a conversation someone reads, so they never make a\n * sensible default delivery target for a routine's output. */\nconst NON_DELIVERABLE_CHANNELS = new Set([\"cron\", \"heartbeat\", \"api\", \"a2a\", \"mesh\"])\n\nconst PROMPT_PREVIEW = 160\n\nfunction str(v: unknown): string | undefined {\n return typeof v === \"string\" && v.trim() ? v.trim() : undefined\n}\n\nfunction preview(s: string, n = PROMPT_PREVIEW): string {\n const flat = s.replace(/\\s+/g, \" \").trim()\n return flat.length > n ? `${flat.slice(0, n - 1)}…` : flat\n}\n\nfunction readRawConfig(configPath?: string): any {\n const path = findConfigPath(configPath)\n if (!existsSync(path)) throw new Error(`config not found at ${path}`)\n return JSON.parse(readFileSync(path, \"utf-8\"))\n}\n\nfunction isAdmin(cfg: any, agentId: string): boolean {\n return cfg?.agents?.[agentId]?.admin === true\n}\n\nfunction canManage(cfg: any, job: any, caller: ScheduleCaller): boolean {\n return isAdmin(cfg, caller.agentId) || job?.createdBy === caller.agentId\n}\n\nfunction ownershipError(id: string, job: any): string {\n const owner = job?.createdBy ? `agent \"${job.createdBy}\"` : \"the operator\"\n return `Not allowed: \"${id}\" was created by ${owner}. Agents manage only schedules they created (unless configured admin).`\n}\n\nfunction resolveNotify(args: Record<string, unknown>, caller: ScheduleCaller): NotifyTarget | undefined | \"invalid\" {\n const raw = str(args.notify)\n if (raw === \"none\") return undefined\n if (raw && raw !== \"here\") {\n const parts = raw.split(\":\")\n if (parts.length < 2 || !parts[0] || !parts[1]) return \"invalid\"\n // chatIds can contain \":\" (gitlab \"org/repo:issue:1\"), so the channel\n // is the first segment and the rest is the chat id.\n return { channel: parts[0], chatId: parts.slice(1).join(\":\") }\n }\n if (caller.channel && caller.chatId && !NON_DELIVERABLE_CHANNELS.has(caller.channel)) {\n return { channel: caller.channel, chatId: caller.chatId, ...(caller.accountId ? { accountId: caller.accountId } : {}) }\n }\n return undefined\n}\n\nfunction describeJob(id: string, job: any, now: Date): string {\n const tz = job.timezone || \"UTC\"\n const next = job.enabled && !isPendingCreate(job) ? formatFireTime(nextFireTime(job.schedule, tz, now), tz) : \"—\"\n const state = job.approval\n ? `pending ${job.approval.action} approval`\n : job.enabled ? \"active\" : \"paused\"\n const lines = [\n `- ${id} [${state}] ${job.schedule} — ${humanizeCron(job.schedule)} (${tz})`,\n ` agent: ${job.agent}; created by: ${job.createdBy || \"operator\"}; next: ${next}`,\n ]\n if (job.notify) lines.push(` notify: ${job.notify.channel} ${job.notify.chatId}`)\n if (job.command) lines.push(` command: ${preview(String(job.command))}`)\n else if (job.prompt) lines.push(` prompt: ${preview(String(job.prompt))}`)\n return lines.join(\"\\n\")\n}\n\nasync function notifyApproval(\n cfg: any,\n deps: ScheduleToolDeps,\n text: string,\n): Promise<string> {\n const dest = cfg?.notifications?.destination\n if (!dest?.channel || !dest?.chatId) {\n return \"No operator notification destination is configured (notifications.destination); the operator must check `agentx schedule list`.\"\n }\n if (!deps.notifyOperator) return \"Operator notification is unavailable in this context.\"\n try {\n await deps.notifyOperator({ channel: dest.channel, chatId: dest.chatId, accountId: dest.accountId }, text)\n return \"The operator has been notified.\"\n } catch (e: any) {\n return `Could not notify the operator (${e?.message ?? e}); the request is still recorded.`\n }\n}\n\n/**\n * Run one tool action. Returns the text the agent sees. Throws only on\n * programming errors — every expected refusal is returned as text so the\n * model can relay it.\n */\nexport async function runScheduleTool(\n args: Record<string, unknown>,\n caller: ScheduleCaller | null,\n deps: ScheduleToolDeps = {},\n): Promise<string> {\n const action = (str(args.action) || \"list\").toLowerCase() as ScheduleAction\n const now = deps.now ? deps.now() : new Date()\n\n let cfg: any\n try {\n cfg = readRawConfig(deps.configPath)\n } catch (e: any) {\n return `Error: ${e.message}`\n }\n const crons: Record<string, any> = cfg.crons || {}\n\n if (action === \"list\") {\n const mineOnly = args.mine === true\n const entries = Object.entries(crons).filter(([, j]) => !mineOnly || (caller && j?.createdBy === caller.agentId))\n if (!entries.length) return mineOnly ? \"You have no schedules.\" : \"No schedules.\"\n return entries.map(([id, j]) => describeJob(id, j, now)).join(\"\\n\")\n }\n\n if (!caller?.agentId) {\n return \"Error: caller agent is unknown (AGENTX_AGENT_ID not set). Pass callerAgentId.\"\n }\n if (!cfg.agents?.[caller.agentId]) {\n return `Error: caller \"${caller.agentId}\" is not an agent on this node.`\n }\n\n const id = str(args.id)\n const mutate = (fn: (c: any) => void) =>\n applyConfigMutation(fn, { configPath: deps.configPath, reload: deps.reload })\n\n if (action === \"create\") {\n const when = str(args.when)\n const prompt = str(args.prompt)\n if (!when || !prompt) return \"Error: create needs `when` (plain English) and `prompt`.\"\n const parsed = parseEnglishToCron(when)\n if (!parsed) return `Error: couldn't parse \"${when}\". ${SUPPORTED_PHRASES_HINT}.`\n\n const agent = str(args.agent) || caller.agentId\n if (!cfg.agents?.[agent]) return `Error: agent \"${agent}\" not found on this node.`\n\n const timezone = str(args.timezone) || DEFAULT_SCHEDULE_TIMEZONE\n if (!isValidTimezone(timezone)) return `Error: unknown timezone \"${timezone}\".`\n\n const jobId = id || slugifyScheduleId(parsed.matched, agent)\n if (!isValidScheduleId(jobId)) return `Error: invalid id \"${jobId}\" (letters, digits, \"-\" and \"_\" only).`\n if (crons[jobId]) return `Error: a schedule \"${jobId}\" already exists. Pick another \\`id\\`.`\n\n const notify = resolveNotify(args, caller)\n if (notify === \"invalid\") return 'Error: `notify` must be \"here\", \"none\", or \"channel:chatId\".'\n\n const approval: ScheduleApproval = {\n action: \"create\",\n requestedBy: caller.agentId,\n requestedAt: now.toISOString(),\n }\n const job = buildScheduleJob({\n parsed,\n agent,\n prompt,\n timezone,\n notify,\n enabled: false,\n createdBy: caller.agentId,\n approval,\n })\n\n const result = await mutate((c) => setAtPath(c, `crons.${jobId}`, job))\n if (!result.success) return `Error: ${result.error}`\n\n const next = formatFireTime(nextFireTime(parsed.cron, timezone, now), timezone)\n const request = [\n `Schedule approval requested by ${caller.agentId}`,\n `Create: ${jobId}`,\n `When: ${parsed.human} — cron \\`${parsed.cron}\\` (${timezone})`,\n `Next fire: ${next}`,\n `Agent: ${agent}`,\n notify ? `Notify: ${notify.channel} ${notify.chatId}` : \"Notify: none\",\n `Prompt: ${preview(prompt, 400)}`,\n \"\",\n `Approve: agentx schedule approve ${jobId}`,\n `Reject: agentx schedule reject ${jobId}`,\n ].join(\"\\n\")\n const notified = await notifyApproval(cfg, deps, request)\n\n return [\n `Requested schedule \"${jobId}\": ${parsed.human} (cron ${parsed.cron}, ${timezone}); next fire would be ${next}.`,\n \"It is saved DISABLED and will not run until the operator approves it.\",\n notified,\n ].join(\"\\n\")\n }\n\n if (!id) return `Error: ${action} needs \\`id\\`.`\n const job = crons[id]\n if (!job) return `Error: schedule \"${id}\" not found.`\n if (!canManage(cfg, job, caller)) return ownershipError(id, job)\n\n if (action === \"pause\" || action === \"resume\") {\n const enable = action === \"resume\"\n if (enable && isPendingCreate(job)) {\n return `\"${id}\" is still awaiting operator approval; it can't be resumed until approved.`\n }\n if (job.enabled === enable) return `\"${id}\" is already ${enable ? \"active\" : \"paused\"}.`\n const result = await mutate((c) => setAtPath(c, `crons.${id}.enabled`, enable))\n if (!result.success) return `Error: ${result.error}`\n return `\"${id}\" ${enable ? \"resumed\" : \"paused\"}.`\n }\n\n if (action === \"delete\") {\n // Withdrawing your own never-approved request removes nothing that ever\n // ran, so it needs no approval.\n if (isPendingCreate(job) && job.approval.requestedBy === caller.agentId) {\n const result = await mutate((c) => unsetAtPath(c, `crons.${id}`))\n if (!result.success) return `Error: ${result.error}`\n return `Withdrew the pending request \"${id}\".`\n }\n // Never replace a pending create marker with a delete marker: rejecting\n // that delete would leave a disabled job with no marker, which its owner\n // could then resume without the create ever being approved.\n if (isPendingCreate(job)) {\n return `\"${id}\" is a creation request still awaiting approval; only its requester or the operator (\\`agentx schedule reject ${id}\\`) can drop it.`\n }\n if (job.approval?.action === \"delete\") return `Deletion of \"${id}\" is already awaiting approval.`\n\n const approval: ScheduleApproval = {\n action: \"delete\",\n requestedBy: caller.agentId,\n requestedAt: now.toISOString(),\n }\n const result = await mutate((c) => {\n if (!getAtPath(c, `crons.${id}`)) throw new Error(`schedule \"${id}\" not found`)\n setAtPath(c, `crons.${id}.approval`, approval)\n })\n if (!result.success) return `Error: ${result.error}`\n\n const tz = job.timezone || \"UTC\"\n const request = [\n `Schedule approval requested by ${caller.agentId}`,\n `Delete: ${id}`,\n `When: ${humanizeCron(job.schedule)} — cron \\`${job.schedule}\\` (${tz})`,\n `Next fire: ${job.enabled ? formatFireTime(nextFireTime(job.schedule, tz, now), tz) : \"— (paused)\"}`,\n `Agent: ${job.agent}`,\n \"\",\n `Approve: agentx schedule approve ${id}`,\n `Reject: agentx schedule reject ${id}`,\n ].join(\"\\n\")\n const notified = await notifyApproval(cfg, deps, request)\n return [\n `Deletion of \"${id}\" requested. It keeps its current state until the operator approves.`,\n notified,\n ].join(\"\\n\")\n }\n\n return `Error: unknown action \"${action}\". Use list, create, pause, resume or delete.`\n}\n\n/**\n * Who is calling. The runtime-exported environment wins over model-supplied\n * arguments: an agent launched by AgentX cannot claim another identity by\n * passing `callerAgentId`. The arguments are the fallback for runtimes that\n * don't export the variables (e.g. an operator-configured MCP entry).\n */\nexport function resolveScheduleCaller(\n args: Record<string, unknown>,\n env: NodeJS.ProcessEnv = process.env,\n): ScheduleCaller | null {\n const agentId = str(env.AGENTX_AGENT_ID) || str(args.callerAgentId)\n if (!agentId) return null\n const envChat = Boolean(str(env.AGENTX_CHANNEL) && str(env.AGENTX_CHAT_ID))\n const channel = envChat ? str(env.AGENTX_CHANNEL) : str(args.channel)\n const chatId = envChat ? str(env.AGENTX_CHAT_ID) : str(args.chatId)\n const accountId = str(args.accountId)\n return { agentId, channel, chatId, ...(accountId ? { accountId } : {}) }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","NON_DELIVERABLE_CHANNELS","PROMPT_PREVIEW","str","v","preview","s","n","flat","readRawConfig","configPath","path","findConfigPath","existsSync","readFileSync","isAdmin","cfg","agentId","canManage","job","caller","ownershipError","id","owner","resolveNotify","args","raw","parts","describeJob","now","tz","next","isPendingCreate","formatFireTime","nextFireTime","state","lines","humanizeCron","notifyApproval","deps","text","dest","e","runScheduleTool","action","crons","mineOnly","entries","j","mutate","fn","applyConfigMutation","when","prompt","parsed","parseEnglishToCron","SUPPORTED_PHRASES_HINT","agent","timezone","DEFAULT_SCHEDULE_TIMEZONE","isValidTimezone","jobId","slugifyScheduleId","isValidScheduleId","notify","approval","buildScheduleJob","result","c","setAtPath","request","notified","enable","unsetAtPath","getAtPath","resolveScheduleCaller","env","envChat","channel","chatId","accountId"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{v as l,w}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import{v as l,w}from"./chunk-4NBWF4TL.js";import{a as i,f as p}from"./chunk-F4HZTZHW.js";w();p();var d="task-tier";function u(e){return{task:f(e.message,2e3),agent:e.agent,channel:e.channel??null,continuesExistingSession:e.isFollowUp??!1,...e.toolsAvailable?{toolsAvailable:e.toolsAvailable}:{}}}var c={needsFlagship:i("This task needs the strongest available model to be done correctly.",{true:"Doing it well takes real reasoning: writing or reviewing code, diagnosing a failure, planning work across several steps, weighing a judgement, handling money, touching production or anything irreversible, following a long or ambiguous instruction, or work where being subtly wrong would not be noticed. Anything where a weaker model would produce something that LOOKS right belongs here.",false:"It is mechanical and its result is obvious on sight: acknowledging or confirming a message, restating or formatting something already written, a greeting, a status echo, reading one file and reporting what it says, a lookup with one right answer, a scheduled heartbeat with nothing to decide."})};function g(e){return e.needsFlagship.noul}function f(e,n){return e.length>n?`${e.slice(0,n)}\u2026`:e}var h=.2,m=60*60*1e3;function F(e,n){if(e==="claude-code"){let t=n?.cheapModels?.[e]??n?.cheapModel;return t&&/^(claude-|haiku$|sonnet$|opus$)/.test(t)?t:void 0}if(e==="codex-cli"){let t=n?.cheapModels?.[e];return t&&/^(gpt-|o\d)/.test(t)?t:void 0}}async function M(e){let n=(o,r=null)=>({downgraded:!1,needsFlagship:r,reason:o});if(e.channel==="voice"||e.channel==="desktop"||e.channel==="opencode")return n(`${e.channel} requests retain the configured model`);if(!e.cheapModel)return n("no cheaper model configured");if(e.isFollowUp){let o=e.sessionIdleMs??0,r=e.cacheTtlMs??m;if(o<r)return n(`follow-up on a warm cache (idle ${Math.round(o/1e3)}s) \u2014 swapping would cost more than it saves`)}let t;try{t=await l(d,u(e),c,{incumbent:{needsFlagship:1},features:{agent:e.agent,channel:e.channel??"unknown"}})}catch{return n("routing seat threw \u2014 keeping the flagship")}if(!t)return n("routing seat unavailable \u2014 keeping the flagship");let s=g(t.answers);if(t.mode!=="active")return n(`shadow \u2014 would ${s<(e.threshold??h)?"downgrade":"keep"} (${s.toFixed(2)})`,s);let a=e.threshold??h;return s>=a?n(`needs the flagship (${s.toFixed(2)})`,s):{model:e.cheapModel,downgraded:!0,needsFlagship:s,reason:`mechanical task (${s.toFixed(2)} below ${a}) \u2192 ${e.cheapModel}`}}export{F as a,M as b};
|
|
2
|
+
//# sourceMappingURL=chunk-5ALS7SVV.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{k as p}from"./chunk-B5XHX44Y.js";import{b as i,c as u,d as l,e as c}from"./chunk-NLZD2QKF.js";import d from"cronstrue";var f=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||f,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.createdBy&&(t.createdBy=e.createdBy),e.approval&&(t.approval=e.approval),t}function P(e){try{return d.toString(e,{use24HourTimeFormat:!1})}catch{return e}}function T(e,r,t=new Date){try{return p(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{f 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-5XQCGPQJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/crons/schedule-ops.ts"],"sourcesContent":["import cronstrue from \"cronstrue\"\nimport { applyConfigMutation, getAtPath, setAtPath, unsetAtPath, type MutationResult } from \"@/daemon/config-mutator\"\nimport type { NlCronResult } from \"@/utils/nl-cron\"\nimport { getNextCronDate } from \"./scheduler\"\n\n// --- Shared schedule operations ---\n//\n// One code path for everything that writes a `crons.<id>` entry from a\n// natural-language schedule: the `agentx schedule` CLI and the agent-facing\n// `agentx_schedule` MCP tool both build jobs here, so the two can never\n// drift into writing different shapes.\n//\n// Also owns the operator side of the approval flow (approve / reject), which\n// only the CLI exposes. Agents can request; they cannot approve.\n\nexport type OnErrorValue = \"log\" | \"notify\" | \"disable\"\n\nexport interface NotifyTarget {\n channel: string\n chatId: string\n accountId?: string\n}\n\nexport interface ScheduleApproval {\n action: \"create\" | \"delete\"\n requestedBy: string\n requestedAt: string\n}\n\n/** Default timezone for schedules created without one: this machine's, the\n * same as the CLI's `--timezone` default. */\nexport const DEFAULT_SCHEDULE_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone\nexport const DEFAULT_SCHEDULE_TIMEOUT = 600\n\nexport const SUPPORTED_PHRASES_HINT =\n 'Try: \"every morning at 9\", \"weekdays at 6pm\", \"every 15 minutes\", \"every monday at 10am\", ' +\n '\"1st of every month at noon\", \"daily at 9:30am\", \"every hour\"'\n\n/** Cron ids become a dot-path segment (`crons.<id>`), so dots and other\n * separators are refused rather than silently nesting the config. */\nconst SCHEDULE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/\n\nexport function isValidScheduleId(id: string): boolean {\n return SCHEDULE_ID_RE.test(id)\n}\n\nexport function isValidTimezone(tz: string): boolean {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz })\n return true\n } catch {\n return false\n }\n}\n\nexport function parseOnError(flag: string | undefined): OnErrorValue[] {\n if (!flag) return [\"log\"]\n return flag\n .split(\",\")\n .map((s) => s.trim().toLowerCase())\n .filter((s): s is OnErrorValue => s === \"log\" || s === \"notify\" || s === \"disable\")\n}\n\nexport interface ScheduleJobInput {\n parsed: NlCronResult\n agent: string\n prompt: string\n timezone?: string\n timeout?: number\n model?: string\n notify?: NotifyTarget\n onError?: OnErrorValue[]\n enabled?: boolean\n createdBy?: string\n approval?: ScheduleApproval\n}\n\n/** Build the `crons.<id>` object. A notify target implies the \"notify\"\n * error mode, exactly as the CLI always did. */\nexport function buildScheduleJob(input: ScheduleJobInput): Record<string, unknown> {\n const onError = [...(input.onError ?? [\"log\"])]\n if (input.notify && !onError.includes(\"notify\")) onError.push(\"notify\")\n\n const job: Record<string, unknown> = {\n enabled: input.enabled ?? true,\n schedule: input.parsed.cron,\n timezone: input.timezone || DEFAULT_SCHEDULE_TIMEZONE,\n agent: input.agent,\n prompt: input.prompt,\n timeout: input.timeout ?? DEFAULT_SCHEDULE_TIMEOUT,\n onError,\n }\n if (input.model) job.model = input.model\n if (input.notify) job.notify = input.notify\n if (input.createdBy) job.createdBy = input.createdBy\n if (input.approval) job.approval = input.approval\n return job\n}\n\nexport function humanizeCron(cron: string): string {\n try {\n return cronstrue.toString(cron, { use24HourTimeFormat: false })\n } catch {\n return cron\n }\n}\n\nexport function nextFireTime(cron: string, timezone: string, now: Date = new Date()): Date | null {\n try {\n return getNextCronDate(cron, now, timezone)\n } catch {\n return null\n }\n}\n\n/** \"Mon, 28 Sep 2026, 10:00 (<tz>)\" — the wall-clock time where the job\n * runs, which is what an operator reading an approval request cares about. */\nexport function formatFireTime(d: Date | null, timezone: string): string {\n if (!d) return \"unknown (no match within a year)\"\n try {\n const local = new Intl.DateTimeFormat(\"en-GB\", {\n timeZone: timezone,\n weekday: \"short\",\n day: \"2-digit\",\n month: \"short\",\n year: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n }).format(d)\n return `${local} (${timezone})`\n } catch {\n return d.toISOString()\n }\n}\n\nexport function isPendingCreate(job: any): boolean {\n return job?.approval?.action === \"create\"\n}\n\n// ── Operator approval ────────────────────────────────────────────────\n\nexport interface ApprovalOutcome {\n success: boolean\n /** What happened, for the CLI to print. */\n message: string\n result?: MutationResult\n}\n\n/**\n * Apply a pending agent request. `create` → enable and clear the marker;\n * `delete` → remove the job. Hot-reloads the daemon through the same\n * mutator the CLI uses.\n */\nexport async function approveSchedule(\n id: string,\n opts: { configPath?: string; reload?: boolean } = {},\n): Promise<ApprovalOutcome> {\n let message = \"\"\n const result = await applyConfigMutation((cfg) => {\n const job: any = getAtPath(cfg, `crons.${id}`)\n if (!job) throw new Error(`cron \"${id}\" not found`)\n const approval = job.approval as ScheduleApproval | undefined\n if (!approval) throw new Error(`cron \"${id}\" has no pending request`)\n if (approval.action === \"create\") {\n delete job.approval\n job.enabled = true\n message = `${id} approved and enabled (requested by ${approval.requestedBy})`\n } else {\n unsetAtPath(cfg, `crons.${id}`)\n message = `${id} deletion approved; job removed (requested by ${approval.requestedBy})`\n }\n }, { configPath: opts.configPath, reload: opts.reload })\n if (!result.success) return { success: false, message: result.error || \"failed\", result }\n return { success: true, message, result }\n}\n\n/** Refuse a pending request. `create` → drop the never-run job; `delete` →\n * keep the job exactly as it was and clear the marker. */\nexport async function rejectSchedule(\n id: string,\n opts: { configPath?: string; reload?: boolean } = {},\n): Promise<ApprovalOutcome> {\n let message = \"\"\n const result = await applyConfigMutation((cfg) => {\n const job: any = getAtPath(cfg, `crons.${id}`)\n if (!job) throw new Error(`cron \"${id}\" not found`)\n const approval = job.approval as ScheduleApproval | undefined\n if (!approval) throw new Error(`cron \"${id}\" has no pending request`)\n if (approval.action === \"create\") {\n unsetAtPath(cfg, `crons.${id}`)\n message = `${id} rejected; pending job removed`\n } else {\n delete job.approval\n message = `${id} deletion rejected; job kept`\n }\n }, { configPath: opts.configPath, reload: opts.reload })\n if (!result.success) return { success: false, message: result.error || \"failed\", result }\n return { success: true, message, result }\n}\n\n/** Enable/disable, refusing to enable a job still awaiting approval. */\nexport async function setScheduleEnabled(\n id: string,\n enabled: boolean,\n opts: { configPath?: string; reload?: boolean } = {},\n): Promise<MutationResult> {\n return applyConfigMutation((cfg) => {\n const job: any = getAtPath(cfg, `crons.${id}`)\n if (!job) throw new Error(`cron \"${id}\" not found`)\n if (enabled && isPendingCreate(job)) {\n throw new Error(`cron \"${id}\" is awaiting approval; run \\`agentx schedule approve ${id}\\``)\n }\n setAtPath(cfg, `crons.${id}.enabled`, enabled)\n }, { configPath: opts.configPath, reload: opts.reload })\n}\n"],"mappings":"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","names":["cronstrue","DEFAULT_SCHEDULE_TIMEZONE","DEFAULT_SCHEDULE_TIMEOUT","SUPPORTED_PHRASES_HINT","SCHEDULE_ID_RE","isValidScheduleId","id","isValidTimezone","tz","parseOnError","flag","s","buildScheduleJob","input","onError","job","humanizeCron","cron","cronstrue","nextFireTime","timezone","now","getNextCronDate","formatFireTime","d","isPendingCreate","approveSchedule","opts","message","result","applyConfigMutation","cfg","getAtPath","approval","unsetAtPath","rejectSchedule","setScheduleEnabled","enabled","setAtPath"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r=new Set(["cli","chat-cli","exec","tui","dashboard","admin","test-drive","workflow-editor","voice","opencode","mcp","ntfy"]),a=new Set(["telegram","whatsapp","slack","discord","gitlab","github","api","a2a","mesh","subagent","compaction","cron","workflow","business","heartbeat","selftest"]);function n(e){let t=(e??"").toLowerCase().split("@")[0];return r.has(t)?"operator":a.has(t)?"internal":"external"}var s=[/\bglpat-[A-Za-z0-9_-]{16,}/,/\bgh[pousr]_[A-Za-z0-9]{30,}/,/\bgithub_pat_[A-Za-z0-9_]{20,}/,/\bsk-ant-[A-Za-z0-9_-]{16,}/,/\bsk-(proj-)?[A-Za-z0-9_-]{20,}/,/\bxox[abprs]-[A-Za-z0-9-]{10,}/,/\bAKIA[0-9A-Z]{16}\b/,/\bAIza[0-9A-Za-z_-]{35}\b/,/\b\d{8,10}:[A-Za-z0-9_-]{35}\b/,/-----BEGIN [A-Z ]*PRIVATE KEY-----/,/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/,/\b(password|passwd|pwd|secret|api[_-]?key|access[_-]?key|token)\s*[:=]\s*["']?[^\s"',;]{8,}/i,/\b[a-z][a-z0-9+.-]*:\/\/[^\s:/@]+:[^\s:/@]{6,}@/i];function o(e){return s.some(t=>t.test(e))}function i(e){return e.source.trust??n(e.source.channel)}function c(e){return e==="external"?"held":void 0}function u(e){return e.category==="secret"||o(e.content)||e.review==="rejected"||e.review==="held"?!1:i(e)==="external"?e.review==="approved":!0}export{n as a,o as b,i as c,c as d,u as e};
|
|
2
|
+
//# sourceMappingURL=chunk-7DXE264B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agents/memory-trust.ts"],"sourcesContent":["// --- What extracted memory may keep, and what it may inject ---\n//\n// Facts are extracted from conversations after every reply and injected\n// into later tasks of the same agent, in any chat. Three rules keep that\n// from becoming a leak or a persistent prompt injection:\n//\n// 1. Secrets are never stored or injected. A credential pasted into one\n// chat must not follow the agent into every other chat.\n// 2. Every fact records how far its source can be trusted, from the\n// channel it came through.\n// 3. Facts from external sources (webhooks, public widgets, anything\n// unknown) are held out of injection until someone approves them:\n// anybody can write to those channels.\n//\n// Pure functions, unit tested.\n\nexport type SourceTrust =\n /** Only the operator can reach it: CLI, dashboard, local voice and TUI. */\n | \"operator\"\n /** Authenticated people or peers: allow-listed chat senders, forge\n * project members, mesh callers. */\n | \"internal\"\n /** Anyone can write to it. */\n | \"external\"\n\nexport type FactReview = \"held\" | \"approved\" | \"rejected\"\n\nconst OPERATOR_CHANNELS = new Set([\n \"cli\", \"chat-cli\", \"exec\", \"tui\", \"dashboard\", \"admin\", \"test-drive\",\n \"workflow-editor\", \"voice\", \"opencode\", \"mcp\", \"ntfy\",\n])\n\n/** People behind an allow-list or project membership, mesh peers, and\n * this node's own automation. New extraction skips the machine channels\n * (cron, workflow, a2a) anyway; older facts from them keep working. */\nconst INTERNAL_CHANNELS = new Set([\n \"telegram\", \"whatsapp\", \"slack\", \"discord\", \"gitlab\", \"github\",\n \"api\", \"a2a\", \"mesh\", \"subagent\", \"compaction\",\n \"cron\", \"workflow\", \"business\", \"heartbeat\", \"selftest\",\n])\n\n/** Trust for a fact's source channel. Channels carry a node suffix\n * (\"telegram@peer-server\"). Anything else, including web-chat,\n * public-api, webhooks and channels added later, is external. */\nexport function trustForChannel(channel: string | undefined): SourceTrust {\n const base = (channel ?? \"\").toLowerCase().split(\"@\")[0]\n if (OPERATOR_CHANNELS.has(base)) return \"operator\"\n if (INTERNAL_CHANNELS.has(base)) return \"internal\"\n return \"external\"\n}\n\n// Shapes of credentials. Deliberately specific: each pattern is a known\n// token format or an explicit assignment, so ordinary prose about \"the\n// token\" or \"a password reset\" is not caught.\nconst SECRET_PATTERNS: RegExp[] = [\n /\\bglpat-[A-Za-z0-9_-]{16,}/, // GitLab PAT\n /\\bgh[pousr]_[A-Za-z0-9]{30,}/, // GitHub tokens\n /\\bgithub_pat_[A-Za-z0-9_]{20,}/,\n /\\bsk-ant-[A-Za-z0-9_-]{16,}/, // Anthropic\n /\\bsk-(proj-)?[A-Za-z0-9_-]{20,}/, // OpenAI-style\n /\\bxox[abprs]-[A-Za-z0-9-]{10,}/, // Slack\n /\\bAKIA[0-9A-Z]{16}\\b/, // AWS access key\n /\\bAIza[0-9A-Za-z_-]{35}\\b/, // Google API key\n /\\b\\d{8,10}:[A-Za-z0-9_-]{35}\\b/, // Telegram bot token\n /-----BEGIN [A-Z ]*PRIVATE KEY-----/,\n /\\beyJ[A-Za-z0-9_-]{10,}\\.eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/, // JWT\n /\\b(password|passwd|pwd|secret|api[_-]?key|access[_-]?key|token)\\s*[:=]\\s*[\"']?[^\\s\"',;]{8,}/i,\n /\\b[a-z][a-z0-9+.-]*:\\/\\/[^\\s:/@]+:[^\\s:/@]{6,}@/i, // URL with user:password@\n]\n\nexport function containsSecret(text: string): boolean {\n return SECRET_PATTERNS.some((p) => p.test(text))\n}\n\n/** The fields of a stored fact this module reads. Older facts have no\n * trust or review; trust then comes from their source channel. */\nexport interface FactTrustFields {\n category: string\n content: string\n source: { channel: string; trust?: SourceTrust }\n review?: FactReview\n}\n\nexport function factTrust(f: FactTrustFields): SourceTrust {\n return f.source.trust ?? trustForChannel(f.source.channel)\n}\n\n/** Whether a new fact from this source waits for review before use. */\nexport function initialReview(trust: SourceTrust): FactReview | undefined {\n return trust === \"external\" ? \"held\" : undefined\n}\n\n/** Whether a stored fact may be injected into a prompt. */\nexport function isInjectable(f: FactTrustFields): boolean {\n if (f.category === \"secret\" || containsSecret(f.content)) return false\n if (f.review === \"rejected\" || f.review === \"held\") return false\n if (factTrust(f) === \"external\") return f.review === \"approved\"\n return true\n}\n"],"mappings":"AA2BA,IAAMA,EAAoB,IAAI,IAAI,CAChC,MAAO,WAAY,OAAQ,MAAO,YAAa,QAAS,aACxD,kBAAmB,QAAS,WAAY,MAAO,MACjD,CAAC,EAKKC,EAAoB,IAAI,IAAI,CAChC,WAAY,WAAY,QAAS,UAAW,SAAU,SACtD,MAAO,MAAO,OAAQ,WAAY,aAClC,OAAQ,WAAY,WAAY,YAAa,UAC/C,CAAC,EAKM,SAASC,EAAgBC,EAA0C,CACxE,IAAMC,GAAQD,GAAW,IAAI,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,EACvD,OAAIH,EAAkB,IAAII,CAAI,EAAU,WACpCH,EAAkB,IAAIG,CAAI,EAAU,WACjC,UACT,CAKA,IAAMC,EAA4B,CAChC,6BACA,+BACA,iCACA,8BACA,kCACA,iCACA,uBACA,4BACA,iCACA,qCACA,qEACA,+FACA,kDACF,EAEO,SAASC,EAAeC,EAAuB,CACpD,OAAOF,EAAgB,KAAMG,GAAMA,EAAE,KAAKD,CAAI,CAAC,CACjD,CAWO,SAASE,EAAUC,EAAiC,CACzD,OAAOA,EAAE,OAAO,OAASR,EAAgBQ,EAAE,OAAO,OAAO,CAC3D,CAGO,SAASC,EAAcC,EAA4C,CACxE,OAAOA,IAAU,WAAa,OAAS,MACzC,CAGO,SAASC,EAAaH,EAA6B,CAExD,OADIA,EAAE,WAAa,UAAYJ,EAAeI,EAAE,OAAO,GACnDA,EAAE,SAAW,YAAcA,EAAE,SAAW,OAAe,GACvDD,EAAUC,CAAC,IAAM,WAAmBA,EAAE,SAAW,WAC9C,EACT","names":["OPERATOR_CHANNELS","INTERNAL_CHANNELS","trustForChannel","channel","base","SECRET_PATTERNS","containsSecret","text","p","factTrust","f","initialReview","trust","isInjectable"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{existsSync as c,mkdirSync as l,readdirSync as g,readFileSync as d,renameSync as u,writeFileSync as m}from"fs";import{resolve as i}from"path";function
|
|
2
|
-
`),u(e,o)}function P(r,t){try{return JSON.parse(d(a(r,t),"utf-8"))}catch{return null}}function v(r,t){let o=
|
|
3
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import{existsSync as c,mkdirSync as l,readdirSync as g,readFileSync as d,renameSync as u,writeFileSync as m}from"fs";import{resolve as i}from"path";function n(r){return i(r,"_proposals")}function a(r,t){if(!/^[a-z0-9-]+$/.test(t))throw new Error(`invalid proposal id: ${t}`);return i(n(r),`${t}.json`)}function y(r,t){let o=new Date(r).toISOString().slice(0,10),e=t.replace(/\.md$/,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48);return`${o}-${e||"article"}-${Math.random().toString(36).slice(2,6)}`}function x(r,t){l(n(r),{recursive:!0});let o=a(r,t.id),e=`${o}.${process.pid}.tmp`;m(e,JSON.stringify(t,null,2)+`
|
|
2
|
+
`),u(e,o)}function P(r,t){try{return JSON.parse(d(a(r,t),"utf-8"))}catch{return null}}function v(r,t){let o=n(r);if(!c(o))return[];let e=[];for(let p of g(o).filter(s=>s.endsWith(".json")).sort()){let s=P(r,p.slice(0,-5));s&&(!t||s.status===t)&&e.push(s)}return e}export{n as a,y as b,x as c,P as d,v as e};
|
|
3
|
+
//# sourceMappingURL=chunk-AQASR6KR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wiki/proposals.ts"],"sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Promotion proposals: lessons wait for a human before the wiki ---\n//\n// `wiki promote` used to write public, org-wide articles straight into the\n// shared wiki from a nightly job. A wrong lesson, or one planted through a\n// poisoned memory, reached every agent the next morning. Now the judge's\n// output becomes a proposal here, with the evidence that produced it, and\n// only an operator's approval writes the article (promote.ts).\n//\n// Storage only: one JSON file per proposal under `<wiki>/_proposals/`.\n// The wiki index skips `_`-prefixed folders, so pending proposals are\n// invisible to agents.\n\nexport type ProposalStatus = \"pending\" | \"approved\" | \"rejected\"\n\n/** The article the judge wants to write. Same shape as PromotedArticle. */\nexport interface ProposedArticle {\n path: string\n title: string\n type?: string\n related?: string[]\n tags: string[]\n content: string\n promotedFrom: string[]\n}\n\n/** One memory, review finding or recurring failure behind the proposal. */\nexport interface ProposalSource {\n stamp: string\n kind: \"memory\" | \"review\" | \"failure\"\n agentId: string\n type: string\n name: string\n description: string\n /** Distinct sessions a review finding or failure appeared in. */\n occurrences?: number\n /** Some of those sessions, for a reviewer to open. */\n sessions?: string[]\n /** Some of the failed runs (task ids), for `agentx trace show`. */\n tasks?: string[]\n /** A recurring failure's signature: the failing tool, the error class\n * and how many runs hit it. The agent is `agentId`. */\n failure?: { tool: string; errorClass: string; runs: number }\n /** Who wrote the memory, and in which task (agent-memory provenance). */\n author?: string\n taskId?: string\n updatedAt: string\n /** Start of the memory body. */\n excerpt: string\n}\n\nexport interface ProposalEvidence {\n /** Agents whose memories, reviews or failures back it. */\n agents: string[]\n /** Highest recurrence among its sources (1 for plain memories). */\n occurrences: number\n sources: ProposalSource[]\n}\n\nexport interface PromotionProposal {\n id: string\n createdAt: string\n status: ProposalStatus\n article: ProposedArticle\n evidence: ProposalEvidence\n /** Set when the article already existed: approval refuses if it has\n * changed since, so a proposal can't silently revert someone's edit. */\n replaces?: { lastUpdated: string; contentHash: string }\n decidedBy?: string\n decidedAt?: string\n reason?: string\n}\n\nexport function proposalsDir(wikiDir: string): string {\n return resolve(wikiDir, \"_proposals\")\n}\n\nfunction fileFor(wikiDir: string, id: string): string {\n if (!/^[a-z0-9-]+$/.test(id)) throw new Error(`invalid proposal id: ${id}`)\n return resolve(proposalsDir(wikiDir), `${id}.json`)\n}\n\nexport function newProposalId(now: number, path: string): string {\n const day = new Date(now).toISOString().slice(0, 10)\n const slug = path.replace(/\\.md$/, \"\").toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 48)\n return `${day}-${slug || \"article\"}-${Math.random().toString(36).slice(2, 6)}`\n}\n\nexport function saveProposal(wikiDir: string, p: PromotionProposal): void {\n mkdirSync(proposalsDir(wikiDir), { recursive: true })\n const path = fileFor(wikiDir, p.id)\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(p, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\nexport function readProposal(wikiDir: string, id: string): PromotionProposal | null {\n try {\n return JSON.parse(readFileSync(fileFor(wikiDir, id), \"utf-8\")) as PromotionProposal\n } catch {\n return null\n }\n}\n\n/** Proposals, oldest first; only `status` ones when given. */\nexport function listProposals(wikiDir: string, status?: ProposalStatus): PromotionProposal[] {\n const dir = proposalsDir(wikiDir)\n if (!existsSync(dir)) return []\n const out: PromotionProposal[] = []\n for (const f of readdirSync(dir).filter((f) => f.endsWith(\".json\")).sort()) {\n const p = readProposal(wikiDir, f.slice(0, -5))\n if (p && (!status || p.status === status)) out.push(p)\n }\n return out\n}\n"],"mappings":"AAAA,OAAS,cAAAA,EAAY,aAAAC,EAAW,eAAAC,EAAa,gBAAAC,EAAc,cAAAC,EAAY,iBAAAC,MAAqB,KAC5F,OAAS,WAAAC,MAAe,OA0EjB,SAASC,EAAaC,EAAyB,CACpD,OAAOF,EAAQE,EAAS,YAAY,CACtC,CAEA,SAASC,EAAQD,EAAiBE,EAAoB,CACpD,GAAI,CAAC,eAAe,KAAKA,CAAE,EAAG,MAAM,IAAI,MAAM,wBAAwBA,GAAI,EAC1E,OAAOJ,EAAQC,EAAaC,CAAO,EAAG,GAAGE,QAAS,CACpD,CAEO,SAASC,EAAcC,EAAaC,EAAsB,CAC/D,IAAMC,EAAM,IAAI,KAAKF,CAAG,EAAE,YAAY,EAAE,MAAM,EAAG,EAAE,EAC7CG,EAAOF,EAAK,QAAQ,QAAS,EAAE,EAAE,YAAY,EAAE,QAAQ,cAAe,GAAG,EAAE,QAAQ,WAAY,EAAE,EAAE,MAAM,EAAG,EAAE,EACpH,MAAO,GAAGC,KAAOC,GAAQ,aAAa,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,GAC7E,CAEO,SAASC,EAAaR,EAAiBS,EAA4B,CACxEhB,EAAUM,EAAaC,CAAO,EAAG,CAAE,UAAW,EAAK,CAAC,EACpD,IAAMK,EAAOJ,EAAQD,EAASS,EAAE,EAAE,EAC5BC,EAAM,GAAGL,KAAQ,QAAQ,UAC/BR,EAAca,EAAK,KAAK,UAAUD,EAAG,KAAM,CAAC,EAAI;AAAA,CAAI,EACpDb,EAAWc,EAAKL,CAAI,CACtB,CAEO,SAASM,EAAaX,EAAiBE,EAAsC,CAClF,GAAI,CACF,OAAO,KAAK,MAAMP,EAAaM,EAAQD,EAASE,CAAE,EAAG,OAAO,CAAC,CAC/D,MAAE,CACA,OAAO,IACT,CACF,CAGO,SAASU,EAAcZ,EAAiBa,EAA8C,CAC3F,IAAMC,EAAMf,EAAaC,CAAO,EAChC,GAAI,CAACR,EAAWsB,CAAG,EAAG,MAAO,CAAC,EAC9B,IAAMC,EAA2B,CAAC,EAClC,QAAWC,KAAKtB,EAAYoB,CAAG,EAAE,OAAQE,GAAMA,EAAE,SAAS,OAAO,CAAC,EAAE,KAAK,EAAG,CAC1E,IAAMP,EAAIE,EAAaX,EAASgB,EAAE,MAAM,EAAG,EAAE,CAAC,EAC1CP,IAAM,CAACI,GAAUJ,EAAE,SAAWI,IAASE,EAAI,KAAKN,CAAC,EAEvD,OAAOM,CACT","names":["existsSync","mkdirSync","readdirSync","readFileSync","renameSync","writeFileSync","resolve","proposalsDir","wikiDir","fileFor","id","newProposalId","now","path","day","slug","saveProposal","p","tmp","readProposal","listProposals","status","dir","out","f"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as S,c as O}from"./chunk-
|
|
1
|
+
import{b as S,c as O}from"./chunk-NLZD2QKF.js";import{a as T,b as M}from"./chunk-ZTEU5JVQ.js";import{a as C,b as ne}from"./chunk-L2WSPY6S.js";import{e as k}from"./chunk-FIOB3MEX.js";import{execFile as ye}from"child_process";import{writeFileSync as z,mkdirSync as $,existsSync as b,readFileSync as Te}from"fs";import{resolve as _}from"path";var re=["off","shadow","authoritative"],ie={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"},se="INTENT_LEDGER_MODE";function X(r,e=process.env){let t=F(e[ie[r]]);if(t)return t;let n=F(e[se]);return n||"off"}function F(r){if(typeof r!="string")return null;let e=r.trim().toLowerCase();return re.includes(e)?e:null}M();import oe from"better-sqlite3";import{existsSync as $e,mkdirSync as de}from"fs";import{dirname as ce,resolve as ae}from"path";var I=class{db;path;constructor(e={}){this.path=ae(process.cwd(),e.path??".agentx/intent/ledger.sqlite"),de(ce(this.path),{recursive:!0}),this.db=new oe(this.path),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),ge(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??T(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?P(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?P(t):null}recordDecision(e){this.db.prepare(`INSERT INTO intent_decisions (event_id, decided_at, decided_by, agent_id, outcome, reason)
|
|
@@ -120,4 +120,4 @@ ${i.prompt}`,i.maxOutputTokens),agentId:i.agent,autonomy:i.autonomy,timeoutMinut
|
|
|
120
120
|
`);return t.length<=e?t.join(`
|
|
121
121
|
`):t.slice(-e).join(`
|
|
122
122
|
`)}function Ne(r,e,t){return new Promise((n,i)=>{ye("/bin/sh",["-c",r],{timeout:e,maxBuffer:8*1024*1024,...t?{env:t}:{}},(s,d,o)=>{if(s&&s.killed){i(new Error(`command timed out after ${Math.round(e/1e3)}s`));return}n({stdout:String(d??""),stderr:String(o??""),code:s?typeof s.code=="number"?s.code:1:0})})})}export{I as a,U as b,X as c,Me as d,Y as e,H as f,Ve as g,Ie as h,Q as i,Z as j,ee as k,Re as l,x as m};
|
|
123
|
-
//# sourceMappingURL=chunk-
|
|
123
|
+
//# sourceMappingURL=chunk-B5XHX44Y.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as b,d as h,e as u,f as m}from"./chunk-
|
|
1
|
+
import{c as b,d as h,e as u,f as m}from"./chunk-LQRBGQIR.js";var p=`:root {
|
|
2
2
|
/* --- Brand (agentina) --------------------------------------------- */
|
|
3
3
|
--ax-blue: #2979FF;
|
|
4
4
|
--ax-blue-d: #1B5FD9;
|
|
@@ -2016,4 +2016,4 @@ ${a.noAssistant?"":`<script>${k({markdownToHtml:_})}${w}</script>`}
|
|
|
2016
2016
|
const card = btn.closest('.ax-row-card');
|
|
2017
2017
|
if (card) card.classList.toggle('is-open');
|
|
2018
2018
|
};`;export{k as a,_ as b,$ as c,t as d,S as e,T as f,C as g,A as h,H as i,O as j,j as k,I as l,L as m,B as n,F as o,P as p};
|
|
2019
|
-
//# sourceMappingURL=chunk-
|
|
2019
|
+
//# sourceMappingURL=chunk-DLKRPK5M.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import{t as Ie,u as ve}from"./chunk-OHA3J5ZV.js";import{d as Se,e as $e}from"./chunk-AQASR6KR.js";import{b as J}from"./chunk-3L2FKVR6.js";import{g as be,h as ye,i as ke,k as we,l as xe}from"./chunk-5XQCGPQJ.js";import{k as he}from"./chunk-B5XHX44Y.js";import{m as pe,p as rt}from"./chunk-P2ZYT5D6.js";import{existsSync as it,readdirSync as ot,readFileSync as at,statSync as lt}from"fs";import{resolve as ct}from"path";function Re(n,e,t=Date.now(),r=7){let s=r*864e5,o=new Map;for(let a of e){let i=o.get(a.workflowId);i?i.push(a):o.set(a.workflowId,[a])}return n.map(a=>{let i=o.get(a.id)??[],l=i.filter(m=>t-m.at<=s),c=i.filter(m=>t-m.at>s&&t-m.at<=s*2),u=l.filter(m=>m.status==="failed").length,g=i.filter(m=>m.status==="paused").length,d=i.length?Math.max(...i.map(m=>m.at)):null,f=i.length?c.length>0&&l.length===0?"dormant":l.length>0&&u*2>=l.length?"failing":l.length>0?"active":"quiet":"never";return{id:a.id,name:a.name||a.id,state:f,lastRunAt:d,recent:l.length,prior:c.length,failed:u,paused:g}}).sort((a,i)=>{let l={dormant:0,failing:1,active:2,quiet:3,never:4};return l[a.state]-l[i.state]||(i.lastRunAt??0)-(a.lastRunAt??0)})}var F=new Map;function xn(n,e=1e3){if(!it(n))return[];let t=ot(n).filter(o=>o.endsWith(".jsonl")).map(o=>{let a=ct(n,o);return{path:a,mtime:lt(a).mtimeMs}}).sort((o,a)=>a.mtime-o.mtime).slice(0,e),r=new Set(t.map(o=>o.path));for(let o of F.keys())r.has(o)||F.delete(o);let s=[];for(let{path:o,mtime:a}of t){let i=F.get(o);if(i&&i.mtime===a){i.summary&&s.push(i.summary);continue}let l=ut(o,a);F.set(o,{mtime:a,summary:l}),l&&s.push(l)}return s}function ut(n,e){try{let t=at(n,"utf-8").split(`
|
|
2
|
+
`).filter(Boolean);if(!t.length)return null;let r=JSON.parse(t[0]),s=r.run?.workflowId;if(!s)return null;let o=r.run?.status??"unknown";for(let a=t.length-1;a>=0;a--){let i=JSON.parse(t[a]),l=i.status??i.run?.status;if(l){o=l;break}}return{workflowId:s,status:o,at:e}}catch{return null}}var dt={failStreak:3,disabledDays:30,missedFires:2,graceMs:15*6e4},k={routines:200,summary:160,filters:6,filterValue:60,text:120},gt=(n,e,t)=>{try{return he(n,e,t)}catch{return null}},_e=864e5;function vn(n){let e=n.now??Date.now(),t={...dt,...n.thresholds},r=n.nextFire??gt,s=[];for(let i of n.crons){let l=n.cronRuns.get(i.id)??[],c=i.timezone||"UTC",u=l.map(f=>({at:Date.parse(f.startedAt),status:f.status})),g=l[0],d={id:`cron:${i.id}`,source:"cron",kind:"schedule",name:S(i.id,k.text),trigger:{schedule:S(i.schedule,k.text),timezone:c},agent:i.agent||null,enabled:i.enabled,state:i.enabled?"enabled":"disabled",nextRunAt:i.enabled?G(i.nextRun)??G(r(i.schedule,new Date(e),c)):null,lastRun:g?{at:g.startedAt,status:g.status,summary:yt(g.status==="success"?void 0:g.errorSummary,k.summary)}:null,lastSuccessAt:l.find(f=>f.status==="success")?.startedAt??null,consecutiveFailures:Ae(u),sampledRuns:l.length,flags:[],attention:null};d.flags=Ce(d,u,i.schedule,c,null,e,t,r),s.push(De(d))}let o=new Map(Re(n.workflows.map(i=>({id:i.id,name:i.title})),n.workflowRuns,e).map(i=>[i.id,i])),a=new Map;for(let i of n.workflowRuns){let l=a.get(i.workflowId);l?l.push(i):a.set(i.workflowId,[i])}for(let i of n.workflows){let l=i.nodes.find(v=>v.type.startsWith("trigger."));if(!l||l.type!=="trigger.cron"&&l.type!=="trigger.hook")continue;let c=l.config??{},u=i.state||"active",g=u==="active",d=(a.get(i.id)??[]).slice().sort((v,q)=>q.at-v.at),f=d.map(v=>({at:v.at,status:pt(v.status)})),m=f[0],h=l.type==="trigger.cron",b=typeof c.spec=="string"?c.spec:"",K=typeof c.timezone=="string"?c.timezone:"UTC",O={id:`workflow:${i.id}`,source:"workflow",kind:h?"schedule":"event",name:S(i.title||i.id,k.text),trigger:h?{schedule:S(b,k.text),timezone:K}:{event:S(typeof c.event=="string"?c.event:"",k.text),filters:bt(c.filter,i)},agent:ht(i),enabled:g,state:u,nextRunAt:h&&g&&b?G(r(b,new Date(e),K)):null,lastRun:m?{at:new Date(m.at).toISOString(),status:m.status}:null,lastSuccessAt:(()=>{let v=f.find(q=>q.status==="success");return v?new Date(v.at).toISOString():null})(),consecutiveFailures:Ae(f),sampledRuns:d.length,flags:[],attention:null},P=Date.parse(i.updated||i.created||"");O.flags=h?Ce(O,f,b,K,Number.isFinite(P)?P:null,e,t,r):ft(O,o.get(i.id)?.state==="dormant",Number.isFinite(P)?P:null,e,t),s.push(De(O))}return s.sort(mt).slice(0,k.routines)}function Ae(n){let e=0;for(let t of n)if(!(t.status==="running"||t.status==="paused"||t.status==="unknown"))if(t.status==="failed"||t.status==="timeout")e++;else break;return e}function Ce(n,e,t,r,s,o,a,i){let l=[],c=e.length?e[0].at:null;if(!n.enabled){let d=Te(c,s,o,a);return d&&l.push(d),l}if(n.consecutiveFailures>=a.failStreak&&l.push({reason:"failing",detail:`${n.consecutiveFailures} failed attempts in a row`}),c===null)return l.push({reason:"never-ran",detail:"No persisted attempt"}),l;let u=new Date(c),g=null;for(let d=0;d<a.missedFires&&(g=i(t,u,r),!!g);d++)u=g;return g&&o>g.getTime()+a.graceMs&&l.push({reason:"overdue",detail:`No attempt since ${new Date(c).toISOString()}; ${a.missedFires} scheduled fires missed`}),l}function ft(n,e,t,r,s){let o=[],a=n.lastRun?Date.parse(n.lastRun.at):null;if(!n.enabled){let i=Te(a,t,r,s);return i&&o.push(i),o}return n.consecutiveFailures>=s.failStreak&&o.push({reason:"failing",detail:`${n.consecutiveFailures} failed runs in a row`}),a===null?o.push({reason:"never-ran",detail:"No run recorded for this trigger"}):e&&o.push({reason:"dormant",detail:"Fired in the prior week, silent in the last one"}),o}function Te(n,e,t,r){let s=Math.max(n??0,e??0);return s&&t-s<r.disabledDays*_e?null:{reason:"disabled-long",detail:s?`Disabled; no activity for ${Math.floor((t-s)/_e)} days`:"Disabled and never ran"}}function De(n){let e=new Set(n.flags.map(t=>t.reason));return n.attention=e.has("failing")?"critical":e.has("overdue")||e.has("dormant")||e.has("never-ran")?"warning":e.has("disabled-long")?"info":null,n}var je={critical:0,warning:1,info:2};function mt(n,e){let t=n.attention?je[n.attention]:3,r=e.attention?je[e.attention]:3;return t-r||Number(e.enabled)-Number(n.enabled)||n.name.localeCompare(e.name)}function pt(n){switch(n){case"completed":case"ok":return"success";case"failed":return"failed";case"timeout":return"timeout";case"canceled":return"canceled";case"running":return"running";case"paused":return"paused";default:return"unknown"}}function ht(n){if(n.ownerAgent)return S(n.ownerAgent,k.text);let e=n.nodes.find(t=>t.type==="agent"&&typeof t.config?.agentId=="string"&&t.config.agentId);return e?S(String(e.config.agentId),k.text):null}function bt(n,e){let t=[],r=e?.project;if(r&&t.push(S(`project=${r}`,k.filterValue)),n&&typeof n=="object"&&!Array.isArray(n))for(let[s,o]of Object.entries(n)){let a=Array.isArray(o)?o.map(String):o==null?[]:[String(o)];a.length&&t.push(S(`${s}=${a.join(",")}`,k.filterValue))}return t.slice(0,k.filters)}function G(n){if(!n)return null;let e=n instanceof Date?n:new Date(n);return Number.isFinite(e.getTime())?e.toISOString():null}function S(n,e){return n.length<=e?n:n.slice(0,e-3)+"..."}function yt(n,e){return n===void 0?void 0:S(n,e)}function B(n){return(Array.isArray(n)?n[0]:n)?.trim()??""}function kt(n){try{return new URL(n).host.toLowerCase()}catch{return null}}function wt(n=process.env){return new Set((n.AGENTX_ALLOWED_ORIGINS||"").split(",").map(e=>e.trim().replace(/\/+$/,"").toLowerCase()).filter(Boolean))}function _n(n,e=wt()){let t=B(n.origin);if(t){if(e.has(t.replace(/\/+$/,"").toLowerCase()))return"same-origin";let s=kt(t),o=[B(n.host),B(n["x-forwarded-host"])].filter(Boolean).map(a=>a.toLowerCase());return s&&o.includes(s)?"same-origin":"foreign"}let r=B(n["sec-fetch-site"]).toLowerCase();return r==="cross-site"||r==="same-site"?"foreign":"none"}function An(n){let e=(n||"GET").toUpperCase();return e!=="GET"&&e!=="HEAD"}import{readFileSync as X,writeFileSync as Be,existsSync as Y,readdirSync as Ct,statSync as Dt}from"fs";import{resolve as Q,join as jt}from"path";import{existsSync as Ee,mkdirSync as xt,readFileSync as St,writeFileSync as Le}from"fs";import{dirname as $t,resolve as Oe}from"path";import{z as p}from"zod";var It=p.object({type:p.enum(["gitlab","github"]),host:p.string().optional(),project:p.string(),iid:p.number().int().positive(),url:p.string()}),vt=p.object({id:p.string(),title:p.string(),description:p.string().optional(),assignee:p.string().optional(),labels:p.array(p.string()).default([]),milestone:p.string().optional(),status:p.enum(["todo","doing","blocked","done"]).default("todo"),priority:p.number().int().optional(),estimatedSeconds:p.number().int().optional(),source:It.optional(),importedAt:p.string().optional(),createdAt:p.string(),updatedAt:p.string(),blocker:p.string().optional(),doneNote:p.string().optional()}),Rt=p.object({version:p.literal(1),items:p.array(vt).default([])}),U=class{constructor(e){this.path=e}jsonPath(){return Oe(process.cwd(),this.path).replace(/\.md$/i,".json")}mdPath(){return Oe(process.cwd(),this.path).replace(/\.json$/i,".md")}exists(){return Ee(this.jsonPath())}load(){let e=this.jsonPath();if(!Ee(e))return{version:1,items:[]};let t=St(e,"utf-8");try{return Rt.parse(JSON.parse(t))}catch(r){throw new Error(`Backlog file invalid (${e}): ${r.message}`)}}save(e){let t=this.jsonPath();xt($t(t),{recursive:!0}),Le(t,JSON.stringify(e,null,2)+`
|
|
3
|
+
`),Le(this.mdPath(),this.toMarkdown(e))}list(){return this.load().items}findById(e){return this.list().find(t=>t.id===e)}add(e){let t=this.load();if(t.items.some(o=>o.id===e.id))throw new Error(`backlog item ${e.id} already exists`);let r=new Date().toISOString(),s={...e,labels:e.labels??[],status:e.status??"todo",createdAt:e.createdAt??r,updatedAt:r};return t.items.push(s),this.save(t),s}addMany(e){let t=this.load(),r=new Set(t.items.map(a=>a.id)),s=new Date().toISOString(),o=[];for(let a of e){if(r.has(a.id))continue;let i={...a,labels:a.labels??[],status:a.status??"todo",createdAt:a.createdAt??s,updatedAt:s};t.items.push(i),o.push(i),r.add(i.id)}return o.length&&this.save(t),o}update(e,t){let r=this.load(),s=r.items.findIndex(a=>a.id===e);if(s<0)throw new Error(`backlog item ${e} not found`);let o={...r.items[s],...t,id:r.items[s].id,createdAt:r.items[s].createdAt,updatedAt:new Date().toISOString()};return r.items[s]=o,this.save(r),o}remove(e){let t=this.load(),r=t.items.length;return t.items=t.items.filter(s=>s.id!==e),t.items.length===r?!1:(this.save(t),!0)}toMarkdown(e){let t=["# Backlog","","_Generated from `backlog.json`. Do not edit by hand \u2014 use `agentx backlog` commands._",""],r={doing:[],blocked:[],todo:[],done:[]};for(let o of e.items)r[o.status].push(o);let s=[["doing","Doing"],["blocked","Blocked"],["todo","To Do"],["done","Done"]];for(let[o,a]of s)if(r[o].length){t.push(`## ${a}`,"");for(let i of r[o]){let l=o==="done"?"x":" ",c=i.assignee?`@${i.assignee} `:"",u=i.estimatedSeconds?` [time: ${Math.round(i.estimatedSeconds/60)}m]`:"",g=i.source?` (${i.source.type}: ${i.source.project}#${i.source.iid})`:"";t.push(`- [${l}] ${c}${i.title}${u}${g}`),i.source?.url&&t.push(` - <${i.source.url}>`),i.labels.length&&t.push(` - labels: ${i.labels.join(", ")}`),i.milestone&&t.push(` - milestone: ${i.milestone}`),i.blocker&&t.push(` - BLOCKED: ${i.blocker}`)}t.push("")}return t.join(`
|
|
4
|
+
`)}};function En(n){return`${n.type}:${n.project}:${n.iid}`}function Pe(n,e,t){let r=[];if(e.type==="gitlab"){let s=t.channels.gitlab?.agentMappings??[];for(let o of n){let a=s.find(i=>i.agentId===o);a?.gitlabUsernames?.length?r.push(a.gitlabUsernames[0]):r.push(o)}}else if(e.type==="github"){let s=t.channels.github?.agentMappings??[];for(let o of n){let a=s.find(i=>i.agentId===o);a?.githubUsernames?.length?r.push(a.githubUsernames[0]):r.push(o)}}return r}async function V(n,e,t,r=()=>{}){return n.source?n.source.type==="gitlab"?_t(n.source,e,t,r):n.source.type==="github"?At(n.source,e,t,r):{ok:!1,error:`unknown source.type ${n.source.type}`,attempts:[]}:{ok:!0,attempts:[]}}async function _t(n,e,t,r){let s=t.channels.gitlab,o=s?.token,a=s?.host||(n.host?`https://${n.host}`:void 0);if(!o||!a)return{ok:!1,error:"gitlab token/host not configured",attempts:[]};let i=[],l=async(f,m={})=>fetch(`${a}/api/v4${f}`,{...m,headers:{"PRIVATE-TOKEN":o,"Content-Type":"application/json",...m.headers||{}}}),c=encodeURIComponent(n.project),u;e.assigneeUsernames!==void 0&&(u=(await Promise.all(e.assigneeUsernames.map(async m=>{try{let h=await fetch(`${a}/api/v4/users?username=${encodeURIComponent(m)}`,{headers:{"PRIVATE-TOKEN":o}});if(!h.ok)return null;let b=await h.json();return Array.isArray(b)&&b[0]?.id?b[0].id:null}catch{return null}}))).filter(m=>typeof m=="number"));let g;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")g=0;else try{let f=await l(`/projects/${c}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);if(f.ok){let m=await f.json();Array.isArray(m)&&m[0]?.id&&(g=m[0].id)}}catch(f){r(`[backlog-sync] milestone lookup failed: ${f.message}`)}let d={};if(e.title!==void 0&&(d.title=e.title),e.description!==void 0&&(d.description=e.description),e.labels!==void 0&&(d.labels=e.labels.join(",")),e.addLabels?.length&&(d.add_labels=e.addLabels.join(",")),e.removeLabels?.length&&(d.remove_labels=e.removeLabels.join(",")),u!==void 0&&(d.assignee_ids=u),g!==void 0&&(d.milestone_id=g),e.state&&(d.state_event=e.state==="closed"?"close":"reopen"),Object.keys(d).length)try{let f=await l(`/projects/${c}/issues/${n.iid}`,{method:"PUT",body:JSON.stringify(d)});if(i.push({kind:"PUT issue",ok:f.ok,status:f.status}),!f.ok){let m=await f.text().catch(()=>"");return{ok:!1,attempts:i,error:`PUT issue ${f.status}: ${m.slice(0,200)}`,url:n.url}}}catch(f){return i.push({kind:"PUT issue",ok:!1,error:f.message}),{ok:!1,attempts:i,error:f.message,url:n.url}}if(e.note)try{let f=await l(`/projects/${c}/issues/${n.iid}/notes`,{method:"POST",body:JSON.stringify({body:e.note})});i.push({kind:"POST note",ok:f.ok,status:f.status})}catch(f){i.push({kind:"POST note",ok:!1,error:f.message})}return{ok:i.every(f=>f.ok),attempts:i,url:n.url}}async function At(n,e,t,r){let o=t.channels.github?.token;if(!o)return{ok:!1,error:"github token not configured",attempts:[]};let a=[],i=async(d,f={})=>fetch(`https://api.github.com${d}`,{...f,headers:{Authorization:`Bearer ${o}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28",...f.headers||{}}}),l=n.project,c;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")c=null;else try{let d=await i(`/repos/${l}/milestones?state=all&per_page=100`);if(d.ok){let f=await d.json(),m=Array.isArray(f)?f.find(h=>h.title===e.milestoneTitle):null;m?.number&&(c=m.number)}}catch(d){r(`[backlog-sync] github milestone lookup failed: ${d.message}`)}let u;if(e.labels!==void 0)u=e.labels;else if(e.addLabels?.length||e.removeLabels?.length)try{let d=await i(`/repos/${l}/issues/${n.iid}`);if(d.ok){let f=await d.json(),m=Array.isArray(f.labels)?f.labels.map(b=>typeof b=="string"?b:b.name):[],h=new Set([...m,...e.addLabels??[]]);for(let b of e.removeLabels??[])h.delete(b);u=[...h]}}catch(d){r(`[backlog-sync] github label fetch failed: ${d.message}`)}let g={};if(e.title!==void 0&&(g.title=e.title),e.description!==void 0&&(g.body=e.description),u!==void 0&&(g.labels=u),e.assigneeUsernames!==void 0&&(g.assignees=e.assigneeUsernames),c!==void 0&&(g.milestone=c),e.state&&(g.state=e.state),Object.keys(g).length)try{let d=await i(`/repos/${l}/issues/${n.iid}`,{method:"PATCH",body:JSON.stringify(g)});if(a.push({kind:"PATCH issue",ok:d.ok,status:d.status}),!d.ok){let f=await d.text().catch(()=>"");return{ok:!1,attempts:a,error:`PATCH issue ${d.status}: ${f.slice(0,200)}`,url:n.url}}}catch(d){return a.push({kind:"PATCH issue",ok:!1,error:d.message}),{ok:!1,attempts:a,error:d.message,url:n.url}}if(e.note)try{let d=await i(`/repos/${l}/issues/${n.iid}/comments`,{method:"POST",body:JSON.stringify({body:e.note})});a.push({kind:"POST comment",ok:d.ok,status:d.status})}catch(d){a.push({kind:"POST comment",ok:!1,error:d.message})}return{ok:a.every(d=>d.ok),attempts:a,url:n.url}}var Z=/^(\s*)-\s*\[( |x|X)\]\s*(.*)$/,N=/@([a-z0-9_-]+)/i,Fe=/\[time:\s*([0-9hm\s]+)\]/i;function Tt(n){let e=n.match(/(\d+)\s*h/i),t=n.match(/(\d+)\s*m/i);return(e?parseInt(e[1],10)*3600:0)+(t?parseInt(t[1],10)*60:0)}var ee=class{constructor(e,t,r=()=>{}){this.path=e;this.daemon=t;this.log=r;this.store=new U(this.path)}type="backlog";capabilities={listAll:!0,create:!1,transition:!1,labels:!0,search:!1};store;getStore(){return this.store}readMd(){let e=Q(process.cwd(),this.path);return Y(e)?X(e,"utf-8").split(`
|
|
5
|
+
`):[]}writeMd(e){let t=Q(process.cwd(),this.path);Be(t,e.join(`
|
|
6
|
+
`))}async listOpen(e){if(this.store.exists())return this.store.list().filter(o=>o.status!=="done"&&(!o.assignee||o.assignee.toLowerCase()===e.toLowerCase())).map(o=>this.toWorkItem(o));let t=this.readMd(),r=[];for(let s=0;s<t.length;s++){let o=t[s].match(Z);if(!o||o[2].toLowerCase()==="x")continue;let i=o[3],l=i.match(N);if(l&&l[1].toLowerCase()!==e.toLowerCase())continue;let c=i.match(Fe),u=i.replace(N,"").replace(Fe,"").trim();r.push({id:`backlog:${s}`,title:u||`Task at line ${s+1}`,assignee:l?l[1]:void 0,estimatedSeconds:c?Tt(c[1]):void 0,priority:s})}return r}async listAll(e={}){return this.store.exists()?this.store.list().map(t=>this.toWorkItem(t)):[]}async claim(e,t){if(!this.store.exists())return;let r=this.store.findById(t);if(!r)return;let s=this.store.update(t,{assignee:r.assignee||e,status:"doing"});if(s.source&&this.daemon){let o=Pe([s.assignee||e],s.source,this.daemon);V(s,{assigneeUsernames:o,addLabels:["Doing"],removeLabels:["To Do"]},this.daemon,this.log).catch(a=>this.log(`[backlog-sync] claim failed for ${t}: ${a?.message??a}`))}}async report(e,t){if(this.store.exists()&&this.store.findById(e)){let i={};t.status==="done"?i.status="done":t.status==="blocked"?(i.status="blocked",i.blocker=t.blocker||t.note||void 0):t.status==="in-progress"&&(i.status="doing"),t.timeSeconds&&(i.estimatedSeconds=t.timeSeconds);let l=this.store.update(e,i);if(l.source&&this.daemon){let c={};t.status==="done"?(c.addLabels=["Done"],c.removeLabels=["Doing"]):t.status==="blocked"&&(c.addLabels=["Blocked"]),t.note&&(c.note=t.note),Object.keys(c).length&&V(l,c,this.daemon,this.log).catch(u=>this.log(`[backlog-sync] report failed for ${e}: ${u?.message??u}`))}return}if(!e.startsWith("backlog:"))throw new Error(`not a backlog id: ${e}`);let r=parseInt(e.slice(8),10),s=this.readMd(),o=s[r];if(!o)throw new Error(`backlog line ${r} missing`);if(!o.match(Z))throw new Error(`backlog line ${r} not a checkbox`);if(t.status==="done"){s[r]=o.replace(/- \[ \]/,"- [x]");let i=t.timeSeconds?` <!-- done by agent, ${Math.round(t.timeSeconds/60)}m -->`:" <!-- done by agent -->";s.splice(r+1,0,i)}else t.status==="blocked"?s.splice(r+1,0,` <!-- BLOCKED: ${t.blocker||t.note||"?"} -->`):t.note&&s.splice(r+1,0,` <!-- ${t.note.replace(/-->/g,"\u2014 >")} -->`);this.writeMd(s)}toWorkItem(e){let t={todo:"todo",doing:"doing",blocked:"onhold",done:"done"}[e.status];return{id:e.id,title:e.title,description:e.description,assignee:e.assignee,estimatedSeconds:e.estimatedSeconds,priority:e.priority,labels:e.labels,stage:t,milestone:e.milestone,url:e.source?.url,updatedAt:e.updatedAt,state:e.status==="done"?"closed":"opened"}}},te=class{constructor(e,t){this.root=e;this.glob=t}type="wiki";capabilities={listAll:!1,create:!1,transition:!1,labels:!1,search:!1};walk(e,t){if(Y(e))for(let r of Ct(e)){let s=jt(e,r);Dt(s).isDirectory()?this.walk(s,t):r.endsWith(".md")&&t.push(s)}}async listOpen(e){let t=[];this.walk(Q(process.cwd(),this.root),t);let r=[];for(let s of t){let o=X(s,"utf-8").split(`
|
|
7
|
+
`);for(let a=0;a<o.length;a++){let i=o[a].match(Z);if(!i||i[2].toLowerCase()==="x")continue;let l=i[3].match(N);!l||l[1].toLowerCase()!==e.toLowerCase()||r.push({id:`wiki:${s}:${a}`,title:i[3].replace(N,"").trim(),assignee:l[1],priority:a})}}return r}async claim(){}async report(e,t){let r=e.split(":"),s=parseInt(r[r.length-1],10),o=r.slice(1,-1).join(":");if(!Y(o))return;let a=X(o,"utf-8").split(`
|
|
8
|
+
`);t.status==="done"&&a[s]&&(a[s]=a[s].replace(/- \[ \]/,"- [x]"),Be(o,a.join(`
|
|
9
|
+
`)))}},ne=class{constructor(e,t,r,s,o){this.host=e;this.token=t;this.projects=r;this.agentUsernames=s;this.log=o}type="gitlab";capabilities={listAll:!0,create:!0,transition:!0,labels:!0,search:!0};usernameToAgent(e){for(let[t,r]of Object.entries(this.agentUsernames))if(r.some(s=>s.toLowerCase()===e.toLowerCase()))return t}mapIssue(e,t){let r=e.references?.full?.split("#")[0]||t,s=[],o;Array.isArray(e.labels)&&(e.labels.length&&typeof e.labels[0]=="object"?(o=e.labels.map(c=>({name:c.name,color:c.color,text_color:c.text_color})),s=o.map(c=>c.name)):s=e.labels);let i=(Array.isArray(e.assignees)&&e.assignees.length?e.assignees:e.assignee?[e.assignee]:[]).map(c=>({username:c.username,name:c.name,avatarUrl:c.avatar_url})),l=i[0]?.username;return{id:`gitlab:${r}:issue:${e.iid}`,title:e.title,description:e.description||void 0,assignee:l?this.usernameToAgent(l)||l:void 0,assignees:i,url:e.web_url,priority:e.weight??99,estimatedSeconds:e.time_stats?.time_estimate||void 0,labels:s,labelDetails:o,updatedAt:e.updated_at,state:e.state==="closed"?"closed":"opened",milestone:e.milestone?.title||void 0}}async api(e,t={}){let r=await fetch(`${this.host}/api/v4${e}`,{...t,headers:{"PRIVATE-TOKEN":this.token,"Content-Type":"application/json",...t.headers||{}}});if(!r.ok)throw new Error(`GitLab ${r.status}: ${await r.text().catch(()=>"")}`);return r.json()}async listOpen(e){let t=this.agentUsernames[e]||[];if(!t.length)return[];let r=[],s=this.projects.length?this.projects:["__ALL__"];for(let o of t)for(let a of s)try{let i=`assignee_username=${encodeURIComponent(o)}&state=opened&scope=all&per_page=20`,l=a==="__ALL__"?`/issues?${i}`:`/projects/${encodeURIComponent(a)}/issues?${i}`,c=await this.api(l);for(let u of c){let g=this.mapIssue(u,a);g.assignee=e,r.push(g)}}catch(i){this.log(`[business] GitLab listOpen failed for ${o} on ${a}: ${i.message}`)}return r}async claim(e,t){let{project:r,iid:s,type:o}=this.parseId(t),a=`/projects/${encodeURIComponent(r)}/${o==="issue"?"issues":"merge_requests"}/${s}?add_labels=Doing&remove_labels=To Do`;try{await this.api(a,{method:"PUT"})}catch(i){this.log(`[business] claim label update failed: ${i.message}`)}}async report(e,t){let{project:r,iid:s,type:o}=this.parseId(e),a=o==="issue"?"issues":"merge_requests";if(t.timeSeconds&&t.timeSeconds>0){let i=Math.max(1,Math.round(t.timeSeconds/60)),l=i>=60?`${Math.floor(i/60)}h${i%60?` ${i%60}m`:""}`:`${i}m`;try{await this.api(`/projects/${encodeURIComponent(r)}/${a}/${s}/add_spent_time?duration=${encodeURIComponent(l)}`,{method:"POST"})}catch(c){this.log(`[business] add_spent_time failed: ${c.message}`)}}if(t.status==="done")try{await this.api(`/projects/${encodeURIComponent(r)}/${a}/${s}?add_labels=Done&remove_labels=Doing`,{method:"PUT"})}catch(i){this.log(`[business] done label update failed: ${i.message}`)}else if(t.status==="blocked")try{await this.api(`/projects/${encodeURIComponent(r)}/${a}/${s}?add_labels=Blocked`,{method:"PUT"})}catch(i){this.log(`[business] blocked label update failed: ${i.message}`)}if(t.note)try{await this.api(`/projects/${encodeURIComponent(r)}/${a}/${s}/notes`,{method:"POST",body:JSON.stringify({body:t.note})})}catch(i){this.log(`[business] report note failed: ${i.message}`)}}async listAll(e={}){let t=e.sinceDays??30,r=new Date(Date.now()-t*24*36e5).toISOString(),s=new URLSearchParams,o=e.state??"opened";s.set("state",o),s.set("updated_after",r),s.set("scope","all"),s.set("per_page","100"),s.set("with_labels_details","true"),s.set("order_by","updated_at"),s.set("sort","desc"),e.labels?.length&&s.set("labels",e.labels.join(",")),e.milestone&&s.set("milestone",e.milestone),e.search&&s.set("search",e.search);let a=this.projects.length?this.projects:["__ALL__"],i=[];for(let c of a)try{let u=c==="__ALL__"?`/issues?${s.toString()}`:`/projects/${encodeURIComponent(c)}/issues?${s.toString()}`,g=await this.api(u);for(let d of g)i.push(this.mapIssue(d,c))}catch(u){this.log(`[business] GitLab listAll failed on ${c}: ${u.message}`)}let l=i;if(e.notLabels?.length){let c=new Set(e.notLabels);l=l.filter(u=>!(u.labels||[]).some(g=>c.has(g)))}if(e.withoutScopedPrefix){let c=e.withoutScopedPrefix+"::";l=l.filter(u=>!(u.labels||[]).some(g=>g.startsWith(c)))}return l}async setState(e,t){let{project:r,iid:s,type:o}=this.parseId(e),a=o==="issue"?"issues":"merge_requests";await this.api(`/projects/${encodeURIComponent(r)}/${a}/${s}?state_event=${t}`,{method:"PUT"})}async getItem(e){let{project:t,iid:r}=this.parseId(e);try{let s=await this.api(`/projects/${encodeURIComponent(t)}/issues/${r}?with_labels_details=true`);return{...this.mapIssue(s,t),descriptionHtml:s.description_html||void 0,createdAt:s.created_at,author:s.author?{username:s.author.username,name:s.author.name,avatarUrl:s.author.avatar_url}:void 0,allLabels:Array.isArray(s.labels)?typeof s.labels[0]=="object"?s.labels.map(a=>a.name):s.labels:[]}}catch(s){return this.log(`[board] GitLab getItem failed for ${e}: ${s.message}`),null}}async updateItem(e,t){let{project:r,iid:s}=this.parseId(e),o;t.assigneeUsernames&&(o=(await Promise.all(t.assigneeUsernames.map(async u=>{try{let g=await this.api(`/users?username=${encodeURIComponent(u)}`);return Array.isArray(g)&&g[0]?.id?g[0].id:null}catch{return null}}))).filter(u=>typeof u=="number"));let a;if(t.milestoneTitle!==void 0)if(t.milestoneTitle===null||t.milestoneTitle==="")a=0;else try{let c=await this.api(`/projects/${encodeURIComponent(r)}/milestones?title=${encodeURIComponent(t.milestoneTitle)}`);Array.isArray(c)&&c[0]?.id&&(a=c[0].id)}catch(c){this.log(`[board] milestone lookup failed for "${t.milestoneTitle}": ${c.message}`)}let i={};t.title!==void 0&&(i.title=t.title),t.description!==void 0&&(i.description=t.description),t.labels!==void 0&&(i.labels=t.labels.join(",")),t.addLabels?.length&&(i.add_labels=t.addLabels.join(",")),t.removeLabels?.length&&(i.remove_labels=t.removeLabels.join(",")),o!==void 0&&(i.assignee_ids=o),a!==void 0&&(i.milestone_id=a);let l=await this.api(`/projects/${encodeURIComponent(r)}/issues/${s}`,{method:"PUT",body:JSON.stringify(i)});return this.mapIssue(l,r)}async listMembers(){let e=new Map;for(let t of this.projects)try{let r=await this.api(`/projects/${encodeURIComponent(t)}/members/all?per_page=100`);for(let s of r)s.username&&!e.has(s.username)&&e.set(s.username,{username:s.username,name:s.name,avatarUrl:s.avatar_url})}catch(r){this.log(`[board] listMembers failed for ${t}: ${r.message}`)}return[...e.values()].sort((t,r)=>t.username.localeCompare(r.username))}async listMilestones(){let e=new Map;for(let r of this.projects)try{let s=await this.api(`/projects/${encodeURIComponent(r)}/milestones?per_page=100`);for(let o of s)o.title&&!e.has(o.title)&&e.set(o.title,{id:o.id,title:o.title,state:o.state,dueDate:o.due_date})}catch(s){this.log(`[board] listMilestones failed for ${r}: ${s.message}`)}let t=[...e.values()];return t.sort((r,s)=>r.state!==s.state?r.state==="active"?-1:1:r.title.localeCompare(s.title)),t}async create(e){let t=e.projectHint||this.projects[0];if(!t)throw new Error("GitLabWorkSource.create requires projectHint or configured projects");let r,s=e.assigneeUsernames?.length?e.assigneeUsernames:e.assignee?(this.agentUsernames[e.assignee]||[]).slice(0,1):[];s.length&&(r=(await Promise.all(s.map(async c=>{try{let u=await this.api(`/users?username=${encodeURIComponent(c)}`);return Array.isArray(u)&&u[0]?.id?u[0].id:null}catch(u){return this.log(`[board] user lookup failed for ${c}: ${u.message}`),null}}))).filter(c=>typeof c=="number"));let o;if(e.milestoneTitle)try{let l=await this.api(`/projects/${encodeURIComponent(t)}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);Array.isArray(l)&&l[0]?.id&&(o=l[0].id)}catch(l){this.log(`[board] milestone lookup failed for "${e.milestoneTitle}": ${l.message}`)}let a={title:e.title,description:e.description,labels:(e.labels||[]).join(",")};r?.length&&(a.assignee_ids=r),o!==void 0&&(a.milestone_id=o);let i=await this.api(`/projects/${encodeURIComponent(t)}/issues`,{method:"POST",body:JSON.stringify(a)});return this.mapIssue(i,t)}async transition(e,t,r){await this.transitionMany(e,t?[t]:[],r?[r]:[])}async transitionMany(e,t,r){let{project:s,iid:o,type:a}=this.parseId(e),i=a==="issue"?"issues":"merge_requests",l=new URLSearchParams;t.length&&l.set("add_labels",t.join(",")),r.length&&l.set("remove_labels",r.join(",")),l.toString()&&await this.api(`/projects/${encodeURIComponent(s)}/${i}/${o}?${l.toString()}`,{method:"PUT"})}parseId(e){let r=e.replace(/^gitlab:/,"").split(":"),s=r.pop(),o=r.pop()==="mr"?"mr":"issue";return{project:r.join(":"),type:o,iid:s}}};function Nn(n,e,t){let r=n.workSource;switch(r.type){case"backlog":return new ee(r.path,e,t);case"wiki":return new te(r.path,r.glob);case"gitlab":{let s=e.channels.gitlab;if(!s?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let o={};for(let i of s.agentMappings)i.gitlabUsernames.length&&(o[i.agentId]=i.gitlabUsernames);let a=r.projects.length?r.projects:s.routes.map(i=>i.project);return new ne(s.host,s.token,a,o,t)}}}var se="unmapped";function re(n,e=[]){if(!n)return se;let t=e.find(s=>s.id===n);if(t?.client)return t.client;let r=n.indexOf("/");return r>0?n.slice(0,r):n}function Et(n){let e=new Map,t=n.projects??[],r=n.orgChart??{};for(let o of t)o.pm&&(e.has(o.pm)||e.set(o.pm,re(o.id,t)));let s=(o,a=new Set)=>{if(e.has(o))return e.get(o);if(a.has(o))return;a.add(o);let i=r[o]?.reportsTo;if(!i)return;let l=s(i,a);return l&&e.set(o,l),l};for(let o of Object.keys(r))s(o);return e}function Lt(n,e,t=[]){if(!t.length)return;let r=t.filter(s=>!s.channel||s.channel===n);return r.find(s=>s.chatId&&e.chatId&&s.chatId===e.chatId)??r.find(s=>s.username&&e.username&&s.username===e.username)??r.find(s=>s.senderId&&e.senderId&&s.senderId===e.senderId)??r.find(s=>s.channel&&!s.chatId&&!s.username&&!s.senderId)}function Wn(n,e){let t=Lt(n.channel,{chatId:n.chatId,username:n.username},e.contactMap);if(t)return t.client;if(n.project)return re(n.project,e.projects);if(n.agentId){let r=Et(e).get(n.agentId);if(r)return r}return se}function zn(n,e){let t=String(n||"").split(":");if(t.length<3)return{agentId:e};let[r,s,...o]=t,a=o.join(":"),i={agentId:e||r,channel:s};return s==="gitlab"||s==="github"?i.project=a.split(":")[0]:s==="cron"||s==="api"||(i.chatId=a.split("@")[0]),i}var Ot=n=>n===se?"internal":"client";function Pt(n,e){let t=e.clients?.[n];return{id:n,name:t?.name||n,kind:t?.kind??Ot(n),respondWithinMinutes:Ft(t?.respondWithin),standing:t?.standing??[],declared:!!t}}function Hn(n){let e=new Set;for(let t of n.projects??[])e.add(re(t.id,n.projects));for(let t of n.contactMap??[])e.add(t.client);for(let t of Object.keys(n.clients??{}))e.add(t);return[...e].sort().map(t=>Pt(t,n))}function Ft(n){let e=/^(\d+)\s*([mhd])$/.exec(String(n??"").trim());if(!e)return;let t=Number(e[1]);return e[2]==="m"?t:e[2]==="h"?t*60:t*1440}import{existsSync as Bt,mkdirSync as Ut,readdirSync as Nt,readFileSync as Mt,renameSync as Wt,writeFileSync as zt}from"fs";import{resolve as Ne}from"path";var Ue=["discard","keep","pause","approve"],$={title:120,ask:300,recommend:300,source:500,note:500,pendingPerAgent:25},Ht={defaultExpiryDays:3,maxExpiryDays:30};function A(n){return Ne(n,".agentx","approvals")}var Kt=/^[a-z0-9][a-z0-9-]{0,80}$/;function Me(n){return Kt.test(n)}function We(n,e){if(!Me(e))throw new Error(`invalid card id: ${e}`);return Ne(A(n),`${e}.json`)}function qt(n,e){let t=new Date(n).toISOString().slice(0,10),r=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40);return`${t}-${r||"card"}-${Math.random().toString(36).slice(2,6)}`}function M(n,e){Ut(A(n),{recursive:!0});let t=We(n,e.id),r=`${t}.${process.pid}.tmp`;zt(r,JSON.stringify(e,null,2)+`
|
|
10
|
+
`),Wt(r,t)}function j(n,e){if(!Me(e))return null;try{return JSON.parse(Mt(We(n,e),"utf-8"))}catch{return null}}function T(n,e){let t=A(n);if(!Bt(t))return[];let r=[];for(let s of Nt(t).filter(o=>o.endsWith(".json")&&!o.startsWith("_")).sort()){let o=j(n,s.slice(0,-5));o&&(!e||o.status===e)&&r.push(o)}return r}function y(n){return typeof n=="string"?n.replace(/\s+/g," ").trim():""}function Jt(n,e,t){let r=e+t.maxExpiryDays*864e5,s,o=y(n);if(!o)s=e+t.defaultExpiryDays*864e5;else{let a=/^(\d+)\s*([hd])$/i.exec(o);if(a)s=e+Number(a[1])*(a[2].toLowerCase()==="d"?864e5:36e5);else if(s=Date.parse(o),Number.isNaN(s))return{ok:!1,error:`expires must be an ISO date or time, or like "12h" / "3d" (got "${o}")`}}return s<=e?{ok:!1,error:"expires must be in the future"}:{ok:!0,at:new Date(Math.min(s,r)).toISOString()}}function Gt(n,e={}){let t=e.now??Date.now(),r=e.settings??Ht,s=y(n.title),o=y(n.ask),a=y(n.recommend),i=y(n.raised_by);if(!s)return{ok:!1,error:"title is required"};if(!o)return{ok:!1,error:"ask is required: the yes/no question"};if(!a)return{ok:!1,error:"recommend is required: your advice and why, in one line"};if(!i)return{ok:!1,error:"raised_by is required: the agent id"};if(s.length>$.title)return{ok:!1,error:`title is longer than ${$.title} characters`};if(o.length>$.ask)return{ok:!1,error:`ask is longer than ${$.ask} characters`};if(a.length>$.recommend)return{ok:!1,error:`recommend is longer than ${$.recommend} characters`};let l=y(n.if_silent).toLowerCase();if(!Ue.includes(l))return{ok:!1,error:`if_silent must be one of ${Ue.join(", ")}`};let c=Jt(n.expires,t,r);if(!c.ok)return c;let u=y(n.source);if(u.length>$.source)return{ok:!1,error:`source is longer than ${$.source} characters`};if(u&&/^[a-z][a-z0-9+.-]*:/i.test(u)&&!/^https?:\/\//i.test(u))return{ok:!1,error:"source must be an http(s) link or a plain reference"};let g,d=n.reply;return d&&typeof d=="object"&&y(d.channel)&&y(d.chatId)&&(g={channel:y(d.channel),chatId:y(d.chatId),...y(d.accountId)?{accountId:y(d.accountId)}:{}}),{ok:!0,card:{id:qt(t,s),title:s,ask:o,recommend:a,if_silent:l,expires:c.at,...u?{source:u}:{},raised_by:i,created_at:new Date(t).toISOString(),...g?{reply:g}:{},status:"pending"}}}function Gn(n,e,t={}){let r=Gt(e,t);if(!r.ok)return r;let s=T(n,"pending").filter(o=>o.raised_by===r.card.raised_by).length;return s>=$.pendingPerAgent?{ok:!1,error:`${r.card.raised_by} already has ${s} cards waiting; wait for decisions before raising more`}:(M(n,r.card),r)}function ze(n,e,t,r={}){let s=j(n,e);if(!s)return{ok:!1,error:`no card "${e}"`};if(s.status!=="pending")return{ok:!1,error:`card "${e}" is already ${s.status}`};let o=y(r.note).slice(0,$.note),a={...s,status:"decided",verdict:t,decided_by:r.by??"operator",decided_at:new Date(r.now??Date.now()).toISOString(),...o?{note:o}:{}};return M(n,a),{ok:!0,card:a}}function Vn(n,e=Date.now()){let t=[];for(let r of T(n,"pending")){if(Date.parse(r.expires)>e)continue;let s={...r,status:"expired",outcome:r.if_silent,decided_by:"expiry",decided_at:new Date(e).toISOString()};M(n,s),t.push(s)}return t}function Xn(n){return T(n).filter(e=>e.status!=="pending"&&!e.agent_notified_at)}function Yn(n,e,t=Date.now()){let r=j(n,e);!r||r.agent_notified_at||M(n,{...r,agent_notified_at:new Date(t).toISOString()})}function Qn(n){let e=n.status==="decided"?n.verdict==="yes"?"The operator said YES.":"The operator said NO.":`Nobody answered before it expired, so the default applied: ${n.outcome??n.if_silent}.`,t=[`[Approval result] Your decision card "${n.title}" (${n.id}) is closed.`,`Question: ${n.ask}`,e];return n.note&&t.push(`Operator note: ${n.note}`),n.source&&t.push(`Source: ${n.source}`),n.reply&&t.push(`You raised it from ${n.reply.channel} chat ${n.reply.chatId}; reply there if the requester should know.`),t.push("Act on this result now. Do not raise the same card again."),t.join(`
|
|
11
|
+
`)}import{existsSync as ie,readdirSync as en,readFileSync as tn}from"fs";import{resolve as C}from"path";import{mkdirSync as Vt,readFileSync as Xt,renameSync as Yt,writeFileSync as Qt}from"fs";import{resolve as Zt}from"path";function He(n){return Zt(A(n),"_state.json")}function W(n){try{let e=JSON.parse(Xt(He(n),"utf-8"));return{snoozed:e&&typeof e.snoozed=="object"&&e.snoozed?e.snoozed:{},...typeof e?.lastDigest=="string"?{lastDigest:e.lastDigest}:{}}}catch{return{snoozed:{}}}}function Ke(n,e){Vt(A(n),{recursive:!0});let t=He(n),r=`${t}.${process.pid}.tmp`;Qt(r,JSON.stringify(e,null,2)+`
|
|
12
|
+
`),Yt(r,t)}function qe(n,e,t,r=Date.now()){let s=W(n),o={};for(let[a,i]of Object.entries(s.snoozed))Date.parse(i)>r&&(o[a]=i);o[e]=t.toISOString(),Ke(n,{...s,snoozed:o})}function ss(n,e){Ke(n,{...W(n),lastDigest:e})}var Je=["card","schedule","memory","wiki"],nn=280;function oe(n,e=nn){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function Ge(n){if(n.configPath)return C(n.configPath);let e=[C(n.root,"agentx.json"),C(n.root,".agentx","config.json")];return e.find(t=>ie(t))??e[0]}function ae(n){return n.wikiDir?C(n.wikiDir):C(n.root,".agentx","wiki")}function sn(n){return T(n.root,"pending").map(rn)}function rn(n){return{key:`card:${n.id}`,kind:"card",title:n.title,ask:n.ask,yes:`tell ${n.raised_by} yes`,no:`tell ${n.raised_by} no`,recommend:n.recommend,if_silent:n.if_silent,expires:n.expires,...n.source?{source:n.source}:{},raised_by:n.raised_by,created_at:n.created_at}}function on(n){let e=Ge(n);if(!ie(e))return[];let t;try{t=JSON.parse(tn(e,"utf-8"))}catch{return[]}let r=new Date(n.now??Date.now()),s=[];for(let[o,a]of Object.entries(t?.crons??{})){let i=a?.approval;if(!i||i.action!=="create"&&i.action!=="delete")continue;let l=a.timezone||"UTC",c=a.schedule?be(a.schedule):"",u=a.schedule?`${c.charAt(0).toLowerCase()}${c.slice(1)} (${a.schedule})`:"no schedule",g=String(a.prompt??a.command??""),d=i.action==="create";s.push({key:`schedule:${o}`,kind:"schedule",title:d?`New schedule "${o}" for ${a.agent??"an agent"}`:`Delete schedule "${o}"`,ask:d?`Let ${a.agent??"the agent"} run this ${u}?`:`Remove the schedule "${o}" (${u})?`,yes:d?"enable it":"remove it",no:d?"drop the request":"keep the schedule",raised_by:String(i.requestedBy??"unknown"),created_at:String(i.requestedAt??""),detail:oe(`${g}${d&&a.schedule?` \xB7 first run ${ke(ye(a.schedule,l,r),l)}`:""}`),more:"agentx schedule list"})}return s}function Ve(n){let e=C(n,".agentx","memory");return ie(e)?en(e).filter(t=>t.endsWith(".jsonl")).map(t=>t.slice(0,-6)).sort():[]}function an(n){let e=Ve(n.root);if(e.length===0)return[];let t=new J(n.root),r=[];for(let s of e)for(let o of t.held(s))r.push({key:`memory:${s}/${o.id}`,kind:"memory",title:`Fact ${s} learned from ${o.source.channel}`,ask:`Let ${s} use this fact in its prompts?`,yes:"use it",no:"keep it out for good",raised_by:s,created_at:o.createdAt,detail:oe(o.content),more:`agentx memory facts held --agent ${s}`});return r}function ln(n){let e=n.sources.filter(t=>t.failure);return e.length?e.map(t=>`Recurring failure: ${t.agentId}'s ${t.failure.tool} fails with "${t.failure.errorClass}" in ${t.occurrences??1} sessions (${t.failure.runs} runs).`).join(" "):`${n.sources.length} source(s)${n.occurrences>1?`, seen in ${n.occurrences} sessions`:""}.`}function cn(n){return $e(ae(n),"pending").map(e=>{let t=e.evidence;return{key:`wiki:${e.id}`,kind:"wiki",title:e.article.title,ask:e.replaces?`Update "${e.article.path}" in the shared wiki?`:`Add "${e.article.path}" to the shared wiki?`,yes:"write the article",no:"decline it",raised_by:t.agents.join(", ")||"wiki promote",created_at:e.createdAt,detail:oe(`${ln(t)} ${e.article.content}`),more:`agentx wiki proposals show ${e.id}`}})}var Xe={card:sn,schedule:on,memory:an,wiki:cn};function un(n,e){let t=n.expires?Date.parse(n.expires):1/0,r=e.expires?Date.parse(e.expires):1/0;return t!==r?t-r:(Date.parse(n.created_at)||0)-(Date.parse(e.created_at)||0)}function fs(n,e={}){let t=n.now??Date.now(),{snoozed:r}=W(n.root),s=[],o=[],a=0;for(let i of e.kinds??Je){let l;try{l=Xe[i](n)}catch(c){o.push({kind:i,error:String(c?.message??c).slice(0,200)});continue}for(let c of l){let u=r[c.key];if(u&&Date.parse(u)>t){if(!e.includeSnoozed){a++;continue}c.snoozed_until=u}s.push(c)}}return s.sort(un),{items:s,snoozed:a,errors:o}}function dn(n){let e=n.indexOf(":");if(e<=0)return null;let t=n.slice(0,e),r=n.slice(e+1);return!Je.includes(t)||!r?null:{kind:t,ref:r}}function gn(n,e,t){switch(e){case"card":return j(n.root,t)?.status==="pending";case"wiki":return Se(ae(n),t)?.status==="pending";default:return Xe[e](n).some(r=>r.key===`${e}:${t}`)}}async function ms(n,e,t,r={}){let s=dn(e);if(!s)return{ok:!1,error:`unknown item "${e}": use a key from \`agentx approvals list\``};let{kind:o,ref:a}=s,i=n.now??Date.now(),l=r.by??"operator";if(t==="later"){if(!gn(n,o,a))return{ok:!1,error:`nothing waiting for "${e}"`};let u=r.laterHours&&r.laterHours>0?r.laterHours:24,g=new Date(i+u*36e5);return qe(n.root,e,g,i),{ok:!0,message:`${e} put off until ${g.toISOString()}`}}let c=t==="yes";switch(o){case"card":{let u=ze(n.root,a,c?"yes":"no",{by:l,note:r.note,now:i});return u.ok?{ok:!0,message:`${e}: ${u.card.raised_by} will be told ${c?"yes":"no"}`}:u}case"schedule":{let u=await(c?we:xe)(a,{configPath:Ge(n),reload:n.reload});return u.success?{ok:!0,message:u.message}:{ok:!1,error:u.message}}case"memory":{let u=a.indexOf("/");if(u<=0)return{ok:!1,error:"memory keys look like memory:<agent>/<fact-id>"};let g=a.slice(0,u),d=a.slice(u+1);if(!Ve(n.root).includes(g))return{ok:!1,error:`no memory for agent "${g}"`};let f=new J(n.root);return f.held(g).some(m=>m.id===d)?(f.review(g,d,c?"approved":"rejected",l),{ok:!0,message:`${e} ${c?"approved: the agent may use it":"rejected: it stays out of prompts"}`}):{ok:!1,error:`fact "${d}" isn't waiting for review`}}case"wiki":{let u=ae(n),g=c?Ie(u,a,{by:l,force:r.force,now:i}):ve(u,a,{by:l,reason:r.note,now:i});return g.ok?{ok:!0,message:c?`${g.proposal.article.path} written to the shared wiki`:`${e} rejected`}:g}}}import{existsSync as x,readFileSync as de,writeFileSync as ge,mkdirSync as z,readdirSync as ue,rmSync as fn,statSync as I}from"fs";import{resolve as Ye,relative as mn,dirname as fe,join as _,extname as E,basename as me}from"path";var w=200*1024,Qe=new Set([".md",".markdown",".txt"]),D=new Set([".md",".markdown",".txt",".json",".jsonc",".yaml",".yml",".toml",".sh",".bash",".zsh",".py",".js",".mjs",".ts",".tsx",".jsx",".css",".html",".lock",".cfg",".ini",".env",".gitignore"]),pn=6,hn=new Set(["CLAUDE.md","SOUL.md","IDENTITY.md","PERSONA.md","AGENT.md","BOOTSTRAP.md"]);function R(n,e){if(!n)throw new Error("Agent workspace is not configured.");let t=Ye(n);if(x(t)||z(t,{recursive:!0}),!e||e.startsWith("/")||e.match(/^[a-zA-Z]:/))throw new Error(`Path must be relative to the workspace: ${e}`);let r=Ye(t,e);if(mn(t,r).startsWith(".."))throw new Error(`Path escapes the workspace: ${e}`);return r}function Ze(n){let e=E(n).toLowerCase();if(!Qe.has(e))throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${e}).`)}function le(n,e){let t=n.split(/\r?\n/).find(r=>r.trim().startsWith("#"));return t&&t.replace(/^#+\s*/,"").trim().slice(0,120)||e}function ys(n){let e=R(n,"."),t=[],r=new Set,s=[];try{s=ue(e)}catch{}for(let i of hn){let l=_(e,i);if(x(l)&&I(l).isFile()){let c=I(l).size,u=c>0&&c<w?ce(l):"";t.push({path:i,title:le(u,i),size:c,exists:!0}),r.add(i)}else t.push({path:i,title:i,size:0,exists:!1}),r.add(i)}for(let i of s){if(r.has(i))continue;let l=_(e,i);try{let c=I(l);if(!c.isFile()||!Qe.has(E(i).toLowerCase()))continue;let u=c.size>0&&c.size<w?ce(l):"";t.push({path:i,title:le(u,i),size:c.size,exists:!0})}catch{}}let o=[],a=_(e,".claude","skills");if(x(a))try{for(let i of ue(a)){let l=_(a,i),c;try{c=I(l)}catch{continue}if(!c.isDirectory())continue;let u=_(l,"SKILL.md");if(!x(u))continue;let g=I(u),d=g.size<w?ce(u):"";o.push({slug:i,title:le(d,i),size:g.size,path:`.claude/skills/${i}/SKILL.md`})}}catch{}return o.sort((i,l)=>i.slug.localeCompare(l.slug)),{identity:t,skills:o,workspace:e}}function ce(n){try{return de(n,"utf-8")}catch{return""}}function ks(n,e){let t=R(n,e);if(Ze(t),!x(t))return{path:e,content:""};if(I(t).size>w)throw new Error(`File is too large to edit in the admin panel (> ${w/1024} KB).`);return{path:e,content:de(t,"utf-8")}}function ws(n,e,t){let r=R(n,e);Ze(r);let s=Buffer.from(t,"utf-8");if(s.length>w)throw new Error(`File too large (${s.length} > ${w} bytes).`);return z(fe(r),{recursive:!0}),ge(r,s),{path:e,bytes:s.length}}function xs(n,e,t={}){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Skill slug must be lowercase (letters, digits, -, _) and start with a letter or digit.");let r=`.claude/skills/${e}/SKILL.md`,s=R(n,r);if(x(s))throw new Error(`Skill "${e}" already exists.`);z(fe(s),{recursive:!0});let o=t.content?.trim()?t.content:bn(e,t.title);return ge(s,o),{slug:e,path:r}}function Ss(n,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let t=R(n,`.claude/skills/${e}`);if(!x(t))throw new Error(`Skill "${e}" not found.`);if(!I(t).isDirectory())throw new Error(`Skill path is not a directory: ${e}`);return fn(t,{recursive:!0,force:!0}),{slug:e}}function $s(n,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let t=R(n,`.claude/skills/${e}`);if(!x(t))throw new Error(`Skill "${e}" not found.`);let r=[];return s(t,"",0,r),r.sort((o,a)=>o.kind!==a.kind?o.kind==="dir"?-1:1:o.path.localeCompare(a.path)),r;function s(o,a,i,l){if(i>pn)return;let c=[];try{c=ue(o)}catch{return}for(let u of c){if(u==="node_modules"||u===".git")continue;let g=_(o,u),d=a?`${a}/${u}`:u,f;try{f=I(g)}catch{continue}if(f.isDirectory())l.push({path:`${d}/`,kind:"dir",size:0,editable:!1}),s(g,d,i+1,l);else if(f.isFile()){let m=E(u).toLowerCase(),h=D.has(m)||D.has(u.toLowerCase());l.push({path:d,kind:"file",size:f.size,editable:h&&f.size<w})}}}}function Is(n,e,t){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!t||t.includes(".."))throw new Error(`Invalid file path: ${t}`);let r=R(n,`.claude/skills/${e}/${t}`);if(!x(r)||!I(r).isFile())throw new Error(`File not found: ${t}`);let s=E(r).toLowerCase(),o=me(r).toLowerCase();if(!D.has(s)&&!D.has(o))throw new Error(`File type not editable: ${t}`);if(I(r).size>w)throw new Error(`File too large to edit (> ${w/1024} KB): ${t}`);return{path:t,content:de(r,"utf-8")}}function vs(n,e,t,r){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!t||t.includes(".."))throw new Error(`Invalid file path: ${t}`);let s=R(n,`.claude/skills/${e}/${t}`),o=E(s).toLowerCase(),a=me(s).toLowerCase();if(!D.has(o)&&!D.has(a))throw new Error(`File type not editable: ${t}`);let i=Buffer.from(r,"utf-8");if(i.length>w)throw new Error(`File too large (${i.length} > ${w} bytes).`);return z(fe(s),{recursive:!0}),ge(s,i),{path:t,bytes:i.length}}function Rs(n,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let t=R(n,`.claude/skills/${e}`);if(!x(t))throw new Error(`Skill "${e}" not found.`);let r=s=>x(_(t,s));return r("pnpm-lock.yaml")?{manager:"pnpm",file:"pnpm-lock.yaml",command:"pnpm install"}:r("yarn.lock")?{manager:"yarn",file:"yarn.lock",command:"yarn install"}:r("package.json")?{manager:"npm",file:"package.json",command:"npm install"}:r("requirements.txt")?{manager:"pip",file:"requirements.txt",command:"pip install -r requirements.txt"}:r("Gemfile")?{manager:"bundle",file:"Gemfile",command:"bundle install"}:{manager:null,file:null,command:null}}function bn(n,e){return`# ${e?.trim()||n}
|
|
13
|
+
|
|
14
|
+
Describe what this skill does and when the agent should use it. Keep it under ~5 lines \u2014 the agent reads this to decide whether to invoke the skill.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
- Trigger condition 1
|
|
18
|
+
- Trigger condition 2
|
|
19
|
+
|
|
20
|
+
## How to use
|
|
21
|
+
Document the arguments, commands, or files the skill expects. Example:
|
|
22
|
+
|
|
23
|
+
\`\`\`bash
|
|
24
|
+
# Example invocation
|
|
25
|
+
claude-code ${me(n)} --arg value
|
|
26
|
+
\`\`\`
|
|
27
|
+
`}rt();var et={maxPixels:12e5,timeoutMs:5e3,intervalMs:100,changeThreshold:.015,stableMs:400,regions:{},buffer:{enabled:!1,seconds:10,fps:2,region:"screen",maxPixels:3e5}};function tt(n){return{...et,...n??{},regions:{...n?.regions??{}},buffer:{...et.buffer,...n?.buffer??{}}}}function Cs(n){try{return tt(pe(n).screen)}catch{return tt(void 0)}}var yn=/^[a-z][\w-]*$/,nt=["window","screen","menubar","notifications"];function L(n,e,t,r){let s=Number(n);if(n===""||n===null||!Number.isFinite(s)||!t(s))throw new Error(`${e} must be ${r}`);return s}var H=(n,e)=>L(n,e,t=>Number.isInteger(t)&&t>0,"a whole number above 0");function st(n){let e=typeof n=="string"?n.split(",").map(Number):[n?.x,n?.y,n?.width,n?.height].map(Number);if(e.length!==4||!e.every(Number.isFinite)||e[2]<=0||e[3]<=0)throw new Error("a region is x,y,width,height in screen points, with width and height above 0");return{x:e[0],y:e[1],width:e[2],height:e[3]}}function Ds(n,e){let t={...n??{}};if("maxPixels"in e&&(t.maxPixels=H(e.maxPixels,"maxPixels")),"timeoutMs"in e&&(t.timeoutMs=H(e.timeoutMs,"timeoutMs")),"intervalMs"in e&&(t.intervalMs=H(e.intervalMs,"intervalMs")),"stableMs"in e&&(t.stableMs=L(e.stableMs,"stableMs",s=>Number.isInteger(s)&&s>=0,"a whole number, 0 or more")),"changeThreshold"in e&&(t.changeThreshold=L(e.changeThreshold,"changeThreshold",s=>s>=0&&s<=1,"between 0 and 1")),e.regions&&typeof e.regions=="object"){let s={...t.regions??{}};for(let[o,a]of Object.entries(e.regions)){if(!yn.test(o))throw new Error(`region name "${o}" must be lowercase letters, digits, - or _`);a===null?delete s[o]:s[o]=st(a)}t.regions=s}if(e.buffer&&typeof e.buffer=="object"){let s=e.buffer,o={...t.buffer??{}};"enabled"in s&&(o.enabled=!!s.enabled),"seconds"in s&&(o.seconds=L(s.seconds,"buffer.seconds",a=>a>0&&a<=120,"above 0 and at most 120")),"fps"in s&&(o.fps=L(s.fps,"buffer.fps",a=>a>0&&a<=10,"above 0 and at most 10")),"maxPixels"in s&&(o.maxPixels=H(s.maxPixels,"buffer.maxPixels")),"region"in s&&(o.region=String(s.region).trim()),t.buffer=o}let r=t.buffer?.region;if(r!==void 0&&!nt.includes(r)&&!t.regions?.[r])try{st(r)}catch{throw new Error(`buffer.region "${r}" is not a region \u2014 use ${[...nt,...Object.keys(t.regions??{})].join(", ")}, or x,y,w,h`)}return t}export{Re as a,xn as b,re as c,Et as d,Lt as e,Wn as f,zn as g,Hn as h,k as i,vn as j,Ue as k,Me as l,j as m,Gn as n,Vn as o,Xn as p,Yn as q,Qn as r,W as s,ss as t,fs as u,ms as v,_n as w,An as x,U as y,En as z,Pe as A,V as B,ne as C,Nn as D,ys as E,ks as F,ws as G,xs as H,Ss as I,$s as J,Is as K,vs as L,Rs as M,et as N,tt as O,Cs as P,nt as Q,Ds as R};
|
|
28
|
+
//# sourceMappingURL=chunk-DTJKN5VT.js.map
|