@aria-cli/cli 1.0.14 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.aria-build-stamp.json +1 -1
- package/dist/attached-local-control-client-2jz8vmjb.js +1 -0
- package/dist/cli-context.js +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/config.js +1 -0
- package/dist/daemon-service-esj85cr7.js +1 -0
- package/dist/ensure-daemon.js +1 -0
- package/dist/history/index.js +1 -0
- package/dist/index-00jaxgt2.js +2 -0
- package/dist/index-5v7br509.js +2 -0
- package/dist/index-718zvjhe.js +12 -0
- package/dist/index-76vaj0sr.js +321 -0
- package/dist/index-92syx5hd.js +149 -0
- package/dist/index-9j6r3gr8.js +2 -0
- package/dist/index-g5devafm.js +0 -0
- package/dist/index-j035n0mr.js +2 -0
- package/dist/index-nnqfqvqh.js +2 -0
- package/dist/index-sx36201d.js +5 -0
- package/dist/index-sxga6d5s.js +2 -0
- package/dist/index-wbm34jf5.js +24 -0
- package/dist/index-xjwfqz7t.js +2 -0
- package/dist/index-y2vy5jks.js +4 -0
- package/dist/index.js +1 -505
- package/dist/ink-repl.js +1 -0
- package/dist/kernel-0tytvcv0.js +1 -0
- package/dist/local-control-client.js +1 -0
- package/dist/repl-cleanup.js +1 -0
- package/dist/runtime-cutover-reset-0nywfrh6.js +1 -0
- package/dist/session-ybzq2j2n.js +1 -0
- package/dist/session.js +1 -0
- package/dist/ui/components/Banner.d.ts +1 -1
- package/package.json +10 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{oa as a,pa as b,qa as c,ra as d,sa as e,ta as f}from"./index-sx36201d.js";import"./index-nnqfqvqh.js";import"./index-9j6r3gr8.js";export{e as resolveLocalControlClientSync,d as resolveLocalControlClient,a as requestRuntimeSocketLease,f as createResilientAttachedClient,c as attachLocalControlClient,b as attachExistingLocalControlClient};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{na as a}from"./index-sxga6d5s.js";import"./index-nnqfqvqh.js";import"./index-9j6r3gr8.js";export{a as createCliContext};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b,c,d,e,f as g,g as h,h as i}from"../index-718zvjhe.js";import{j as f}from"../index-y2vy5jks.js";import"../index-j035n0mr.js";import"../index-00jaxgt2.js";import"../index-wbm34jf5.js";import"../index-76vaj0sr.js";import"../index-5v7br509.js";import"../index-xjwfqz7t.js";import"../index-sxga6d5s.js";import"../index-g5devafm.js";import"../index-sx36201d.js";import"../index-nnqfqvqh.js";import"../index-9j6r3gr8.js";export{h as startHeadlessStdioServer,f as runtimeCutoverResetCommand,c as runDaemonFromCli,i as program,g as createRuntimeCutoverResetCommand,e as createPairingCommand,d as createHeadlessCallCommand,b as createAuthCommand,a as createArionsCommand};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ua as a,va as b,wa as c,xa as d,ya as e}from"./index-nnqfqvqh.js";import"./index-9j6r3gr8.js";export{e as saveConfig,d as loadConfig,c as loadAndMigrateConfig,b as getConfigPath,a as getAriaDir};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{aa as a}from"./index-5v7br509.js";import"./index-g5devafm.js";import"./index-sx36201d.js";import"./index-nnqfqvqh.js";import"./index-9j6r3gr8.js";export{a as createDaemonService};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{k as a}from"./index-j035n0mr.js";import"./index-9j6r3gr8.js";export{a as ensureDaemon};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{$ as u,H as a,I as b,J as c,K as d,L as e,M as f,N as g,O as h,P as i,Q as j,R as k,S as l,T as m,U as n,V as o,W as p,X as q,Y as r,Z as s,_ as t}from"../index-76vaj0sr.js";import"../index-9j6r3gr8.js";export{h as toModelMessages,s as replaySessionFromJsonl,q as repairToolCallPairing,t as mergeWithJsonlRecovery,j as fromV1Columns,i as fromModelMessages,u as findJsonlForSession,m as extractToolCalls,o as extractToolCallId,n as extractThinking,l as extractTextContent,d as createUserMessage,e as createSystemMessage,f as createIncomingMessagePair,g as createErrorMessage,k as conversationMessageToHistoryMessages,r as TurnAccumulator,p as SessionHistory,c as ConversationMessageSchema,a as ContentBlockSchema,b as ArionRefSchema};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createRequire as e}from"node:module";var t=e(import.meta.url),i=t("../package.json"),s=i.version,r=["⚡ Search millions of lines instantly with native Rust-powered code search","\uD83E\uDDE0 Jump to definitions & find references with real LSP intelligence","✏️ Press Esc×2 to edit and fork any previous message in-place","\uD83D\uDD0A Get audio cues when tasks finish — try /sound to configure","\uD83C\uDFA8 All 87 tools now render rich, beautiful output in the terminal"];
|
|
2
|
+
export{s as n,r as o};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ra as x}from"./index-sx36201d.js";import{spawn as H}from"node:child_process";import{existsSync as j,mkdirSync as Y,openSync as k,closeSync as F}from"node:fs";import I from"node:path";import{fileURLToPath as Z}from"node:url";var b=15000,q=250;function U(z){return new Promise((G)=>setTimeout(G,Math.max(z,0)))}function M(){let z=Z(new URL("../../../server/dist/daemon-launcher.js",import.meta.url));if(j(z))return{command:process.execPath,args:[z]};try{let B=Z(import.meta.resolve("@aria-cli/server/daemon-launcher"));if(j(B))return{command:process.execPath,args:[B]}}catch{}let G=Z(new URL("../../../server/src/daemon-launcher.ts",import.meta.url));return{command:process.execPath,args:["--import","tsx",G]}}function N(z,G,B){return(typeof B.arion==="string"?B.arion.trim():"")||G||z.config.activeArion?.trim()||"ARIA"}function P(z){return{...typeof z.intervalMs==="number"?{intervalMs:z.intervalMs}:{},...z.allowedToolCategories||z.allowedShellCommands||typeof z.maxWriteOpsPerMinute==="number"||typeof z.maxGitPushesPerHour==="number"?{safetyPolicy:{...Array.isArray(z.allowedToolCategories)?{allowedToolCategories:z.allowedToolCategories}:{},...Array.isArray(z.allowedShellCommands)?{allowedShellCommands:z.allowedShellCommands}:{},...typeof z.maxWriteOpsPerMinute==="number"?{maxWriteOpsPerMinute:z.maxWriteOpsPerMinute}:{},...typeof z.maxGitPushesPerHour==="number"?{maxGitPushesPerHour:z.maxGitPushesPerHour}:{}}}:{}}}async function R(z){let G=Date.now()+b,B=null;while(Date.now()<G){try{let K=await x({ariaHome:z.ariaHome});if(K){let V=await K.getRuntimeStatus();if(!z.requireRunning||V.autonomousLoop.status==="running")return V}}catch(K){B=K instanceof Error?K:Error(String(K))}await U(q)}throw Error(B?.message??"Timed out waiting for the daemon runtime to become reachable")}function y(z){let G=M(),B=[...G.args,"--arion",z.arionName];if(typeof z.input.port==="number")B.push("--port",String(z.input.port));if(typeof z.input.intervalMs==="number")B.push("--interval-ms",String(z.input.intervalMs));if(Array.isArray(z.input.allowedToolCategories)&&z.input.allowedToolCategories.length>0)B.push("--allowed-tool-categories",z.input.allowedToolCategories.join(","));if(Array.isArray(z.input.allowedShellCommands)&&z.input.allowedShellCommands.length>0)B.push("--allowed-shell-commands",z.input.allowedShellCommands.join(","));if(typeof z.input.maxWriteOpsPerMinute==="number")B.push("--max-write-ops-per-minute",String(z.input.maxWriteOpsPerMinute));if(typeof z.input.maxGitPushesPerHour==="number")B.push("--max-git-pushes-per-hour",String(z.input.maxGitPushesPerHour));let K=I.join(z.ariaHome,"logs");Y(K,{recursive:!0});let V=k(I.join(K,"daemon-stderr.log"),"a");H(G.command,B,{cwd:z.cwd,env:{...process.env,ARIA_HOME:z.ariaHome},detached:!0,stdio:["ignore","ignore",V]}).unref(),F(V)}function D(z){let G=z.cli.ariaDir,B=!1,K=()=>z.getArionName?.()??z.arionName??"ARIA",V=(Q)=>{let J=typeof Q.arion==="string"?Q.arion.trim():"",W=K();if(J&&J!==W)throw Error(`daemon operations are scoped to ${W}; switch scope with arion.become before targeting ${J}`);return J||W},X=async()=>{if(!z.localControl)return null;try{return await z.localControl.getRuntimeStatus(),z.localControl}catch{return null}};return{async start(Q){let J=N(z.cli,V(Q),Q),W=await X();if(!W)return B=!0,y({ariaHome:G,cwd:z.cwd,arionName:J,input:Q}),R({ariaHome:G,requireRunning:!0});let $=await W.getRuntimeStatus();if($.autonomousLoop.status==="running")return B=!1,$;if(!W.startAutonomousLoop)throw Error("Live runtime does not expose autonomous-loop start control");return B=!0,W.startAutonomousLoop(P(Q))},async status(Q={}){V(Q);let J=await X();if(!J)throw Error("No live runtime is available for daemon.status");return J.getRuntimeStatus()},async stop(Q={}){V(Q);let J=await X();if(!J)throw Error("No live runtime is available for daemon.stop");if(!J.stopAutonomousLoop)throw Error("Live runtime does not expose autonomous-loop stop control");return B=!1,J.stopAutonomousLoop()},shouldStopOnShutdown(){return B},async releaseAll(){}}}
|
|
2
|
+
export{D as aa};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import{k as g}from"./index-j035n0mr.js";import{n as X$}from"./index-00jaxgt2.js";import{B as U$}from"./index-wbm34jf5.js";import{aa as e}from"./index-5v7br509.js";import{na as L}from"./index-sxga6d5s.js";import{ua as t,xa as H,ya as C}from"./index-nnqfqvqh.js";import{za as B}from"./index-9j6r3gr8.js";import{Command as e$}from"commander";import{Command as y$}from"commander";import{ArionManager as _$,ArionStorage as x$,MemoriaPool as B$}from"@aria-cli/aria";async function O(){let $=t(),J=new x$($),G=new B$($).toFactory(),Q=new _$(J,G);return await Q.initialize(),Q}function P(){let $=new y$("arions").description("Manage Arion personas");return $.command("list").description("List all Arions with status").option("--status <status>","Filter by status (active, resting, retired)").action(async(J)=>{try{let G=await(await O()).list(),Q=J.status?G.filter((U)=>U.status===J.status):G;if(Q.length===0){console.log("No Arions found.");return}console.log(`
|
|
2
|
+
Arions:`),console.log("─".repeat(60));for(let U of Q){let X=U.status==="active"?"●":U.status==="resting"?"○":"×";if(console.log(`${X} ${U.name} [${U.status}]`),console.log(` Style: ${U.personality.style}`),console.log(` Traits: ${U.personality.traits.join(", ")}`),U.skills.length>0)console.log(` Skills: ${U.skills.map((Z)=>Z.name).join(", ")}`);console.log()}}catch(z){console.error("Error listing Arions:",z.message),process.exit(1)}}),$.command("hatch").description("Create a new Arion").argument("<name>","Name for the new Arion").option("-t, --traits <traits>","Comma-separated personality traits").option("-s, --style <style>","Communication style (formal, casual, technical, friendly)").option("--skills <skills>","Comma-separated skills").action(async(J,z)=>{try{let G=await O(),Q=z.traits?z.traits.split(",").map((j)=>j.trim()):["helpful","curious"],U=z.style||"friendly",X=z.skills?z.skills.split(",").map((j)=>({name:j.trim(),level:"intermediate"})):[],Z=await G.hatch({name:J,personality:{traits:Q,style:U},skills:X,createdBy:"cli"});if(console.log(`
|
|
3
|
+
Hatched new Arion: ${Z.name}`),console.log(` ID: ${Z.id}`),console.log(` Status: ${Z.status}`),console.log(` Style: ${Z.personality.style}`),console.log(` Traits: ${Z.personality.traits.join(", ")}`),Z.skills.length>0)console.log(` Skills: ${Z.skills.map((j)=>j.name).join(", ")}`)}catch(G){console.error("Error hatching Arion:",G.message),process.exit(1)}}),$.command("become").description("Switch to an Arion").argument("<name>","Name of the Arion to switch to").action(async(J)=>{try{let z=await O(),G=await z.get(J);if(!G)console.error(`Arion not found: ${J}`),process.exit(1);if(G.status==="retired")console.error(`Cannot become retired Arion: ${J}`),process.exit(1);if(G.status==="resting")await z.wake(J);let Q=H();Q.activeArion=G.name,C(Q),console.log(`
|
|
4
|
+
Switched to Arion: ${G.name}`),console.log(` Style: ${G.personality.style}`),console.log(` Traits: ${G.personality.traits.join(", ")}`)}catch(z){console.error("Error switching Arion:",z.message),process.exit(1)}}),$.command("retire").description("Retire an Arion (permanent)").argument("<name>","Name of the Arion to retire").option("--confirm","Confirm retirement (required)").action(async(J,z)=>{try{if(!z.confirm)console.error("Retirement is permanent. Use --confirm to proceed."),process.exit(1);await(await O()).retire(J,{confirm:!0});let Q=H();if(Q.activeArion?.toLowerCase()===J.toLowerCase())delete Q.activeArion,C(Q);console.log(`
|
|
5
|
+
Retired Arion: ${J}`),console.log("The Arion can no longer be used but its memories are preserved.")}catch(G){console.error("Error retiring Arion:",G.message),process.exit(1)}}),$}import{Command as L$}from"commander";import{createInterface as k$}from"node:readline";import{ensureAuthProfileStore as H$,syncExternalCliCredentials as E$,isProfileInCooldown as O$,upsertAuthProfile as q$,updateAuthProfileStoreWithLockSync as o}from"@aria-cli/auth";var D$=["COPILOT_GITHUB_TOKEN","GH_TOKEN","GITHUB_TOKEN"];function C$($=process.env){for(let J of D$){let z=$[J];if(z&&z.length>8)return J}return null}async function P$(){let $=o({updater:(z)=>E$(z)})??H$(),J=Object.entries($.profiles);if(J.length===0){console.log("No auth profiles configured."),console.log("Add one with: aria auth add --provider <name>");return}for(let[z,G]of J){let U=O$($,z)?"cooldown":"active",X=G.type.padEnd(7);if(console.log(` ${z.padEnd(30)} [${X}] ${U}`),G.email)console.log(` email: ${G.email}`);if((G.type==="oauth"||G.type==="token")&&"expires"in G){let Z=G.expires;if(Z){let j=Z-Date.now(),b=j>0?`expires in ${Math.round(j/60000)}min`:"EXPIRED";console.log(` ${b}`)}}if(G.provider==="github-copilot"){let Z=C$();if(Z)console.log(` env override: ${Z}`)}}}async function v$($){let J=$.provider.toLowerCase().trim(),z=`${J}:manual`,G=k$({input:process.stdin,output:process.stdout}),Q=await new Promise((U)=>{G.question(`Paste API key for ${J}: `,(X)=>{G.close(),U(X.trim())})});if(!Q||Q.length<8)console.error("API key too short (minimum 8 characters)."),process.exit(1);q$({profileId:z,credential:{type:"api_key",provider:J,key:Q}}),console.log(`Saved auth profile: ${z}`)}async function A$($){let J=!1,z=o({updater:(G)=>{if(!G.profiles[$])return!1;return delete G.profiles[$],J=!0,!0}});if(!J||!z)console.error(`Profile not found: ${$}`),process.exit(1);console.log(`Removed auth profile: ${$}`)}function v(){let $=new L$("auth").description("Manage auth profiles");return $.command("status").description("Show all auth profiles and their health").action(P$),$.command("add").description("Add an API key for a provider").requiredOption("--provider <name>","Provider name (anthropic, openai, google)").action(v$),$.command("remove").description("Remove an auth profile").argument("<profile-id>","Profile ID to remove").action(A$),$}function A($,J,z){if($===void 0||$.trim()==="")return z;let G=Number.parseInt($,10);if(!Number.isFinite(G)||G<=0)throw Error(`${J} must be a positive integer`);return G}function a($){if(!$)return;let J=$.split(",").map((z)=>z.trim()).filter((z)=>z.length>0);return J.length>0?J:void 0}function F$($,J){if($===void 0||$.trim()==="")return J;let z=Number.parseInt($,10);if(!Number.isFinite(z)||z<0)throw Error("port must be a non-negative integer (0 = OS-assigned)");return z}function I$($){return{arion:$.arion,port:F$($.port,0),intervalMs:A($.intervalMs,"intervalMs",60000),allowedToolCategories:a($.allowedToolCategories),allowedShellCommands:a($.allowedShellCommands),maxWriteOpsPerMinute:$.maxWriteOpsPerMinute!==void 0?A($.maxWriteOpsPerMinute,"maxWriteOpsPerMinute",30):void 0,maxGitPushesPerHour:$.maxGitPushesPerHour!==void 0?A($.maxGitPushesPerHour,"maxGitPushesPerHour",5):void 0}}function R$($){if($.aborted)return Promise.resolve();return new Promise((J)=>{$.addEventListener("abort",()=>J(),{once:!0})})}function r($){return{...$.arion?{arion:$.arion}:{},...$.port>=0?{port:$.port}:{},intervalMs:$.intervalMs,...$.allowedToolCategories?{allowedToolCategories:$.allowedToolCategories}:{},...$.allowedShellCommands?{allowedShellCommands:$.allowedShellCommands}:{},...typeof $.maxWriteOpsPerMinute==="number"?{maxWriteOpsPerMinute:$.maxWriteOpsPerMinute}:{},...typeof $.maxGitPushesPerHour==="number"?{maxGitPushesPerHour:$.maxGitPushesPerHour}:{}}}async function F($={}){let J=I$($);await w$(J)}async function I(){let{resolveRuntimeRootDirectory:$,findRuntimeOwnerRecordByAriaHome:J,removeRuntimeOwnerRecord:z}=await import("@aria-cli/server"),{getAriaDir:G}=await import("./config.js"),Q=G(),U=$(),X=J(U,Q);if(!X){console.log("[daemon] no running daemon found");return}try{process.kill(X.runtimePid,"SIGINT"),console.log(`[daemon] sent SIGINT to pid ${X.runtimePid}`);let Z=Date.now()+5000;while(Date.now()<Z)try{process.kill(X.runtimePid,0),await new Promise((j)=>setTimeout(j,200))}catch{break}try{process.kill(X.runtimePid,0),process.kill(X.runtimePid,"SIGKILL"),console.log(`[daemon] force-killed pid ${X.runtimePid}`)}catch{}}catch{}z(U,X.nodeId),console.log("[daemon] stopped")}async function $$($={}){await I(),await new Promise((U)=>setTimeout(U,500));let{ensureDaemon:J}=await import("./ensure-daemon.js"),z=await L(),Q=await(await J(z)).control.listPeers();console.log(`[daemon] restarted (${Q.length} peers connected)`),await z.pool?.closeAll?.()}async function w$($){let J=new AbortController,z=()=>J.abort(),G=()=>J.abort(),Q=()=>{};process.on("SIGINT",z),process.on("SIGTERM",G),process.on("SIGHUP",Q);let U=H(),X=$.arion?.trim()||U.activeArion?.trim()||"ARIA",Z=await L({startupMode:"daemon"}),j=e({cli:Z,cwd:process.cwd(),arionName:X}),b=null;try{let M=await j.start(r($));console.log(`[daemon] runtime node ${String(M.nodeId??"unknown")}`),console.log(`[daemon] runtime ${String(M.runtimeId??"unknown")} listening on port ${String(M.port??"unknown")}`),console.log(`[daemon] running arion "${X}" (interval ${$.intervalMs}ms)`),b=setInterval(()=>{j.status({}).catch(()=>{})},Math.min(Math.max($.intervalMs,1000),5000)),await R$(J.signal)}catch(M){console.error(`[daemon] Runtime startup failed: ${M instanceof Error?M.message:String(M)}`),process.exitCode=1}finally{if(b)clearInterval(b),b=null;try{if(J.signal.aborted&&j.shouldStopOnShutdown?.())await j.stop?.(r($))}catch{}await j.releaseAll?.(),await Z.pool.closeAll().catch(()=>{}),process.removeListener("SIGINT",z),process.removeListener("SIGTERM",G),process.removeListener("SIGHUP",Q),console.log("[daemon] stopped")}}import{Command as g$}from"commander";import{existsSync as c$,readFileSync as R}from"node:fs";import{homedir as S$}from"node:os";import J$ from"node:path";function h$($){if(!$||$==="-"){let J=R(0,"utf8").trim();return J?JSON.parse(J):{}}return JSON.parse(R($,"utf8"))}function u$($,J){if($==="interaction.respond")return{kind:"interaction.respond",requestId:"call-1",...J};return{kind:"request",requestId:"call-1",op:$,input:J}}function T$(){if(process.env.ARIA_HOME)return process.env.ARIA_HOME;return J$.join(process.env.HOME||S$(),".aria")}function d$($){if(typeof $.arion==="string"&&$.arion.trim().length>0)return $.arion.trim();let J=J$.join(T$(),"config.json");if(!c$(J))return"ARIA";try{let z=JSON.parse(R(J,"utf8"));if(typeof z.activeArion==="string"&&z.activeArion.trim().length>0)return z.activeArion.trim()}catch{}return"ARIA"}function z$($){return{kind:"result",requestId:"call-1",op:$,ok:!1,error:{code:"NO_RESULT",message:`Operation ${$} produced no result frame`}}}async function f$($,J,z){let[{SessionHistory:G},{createSessionOperationHandlers:Q}]=await Promise.all([import("./history/index.js"),import("./session-ybzq2j2n.js")]),U=new G(G.resolvePerArionPath(T$(),d$(z)));try{let X=Q({sessionLedger:U}),Z=null;for await(let j of X[$]("call-1",J))if(j.kind==="result")Z=j;return Z??z$($)}finally{U.close()}}async function p$($,J,z){switch($){case"session.list":case"session.read":case"session.load":return f$($,J,z);default:return null}}async function l$($,J){try{let z=h$(J.inputJson),G=await p$($,z,J);if(G)return process.stdout.write(`${JSON.stringify(G)}
|
|
6
|
+
`),G.ok?0:1;let{createHeadlessKernelRuntime:Q}=await import("./kernel-0tytvcv0.js"),U=await Q({cwd:process.cwd(),arionName:J.arion});try{let X=null;for await(let Z of U.kernel.dispatch(u$($,z)))if(Z.kind==="result")X=Z;if(!X)return process.stdout.write(`${JSON.stringify(z$($))}
|
|
7
|
+
`),1;return process.stdout.write(`${JSON.stringify(X)}
|
|
8
|
+
`),X.ok?0:1}finally{await U.release()}}catch(z){return process.stderr.write(`${z instanceof Error?z.message:String(z)}
|
|
9
|
+
`),2}}function w(){return new g$("call").description("Execute one headless operation and print exactly one JSON result").argument("<operation>","Headless operation name").option("--input-json <path|->","Read JSON input from a file path or stdin","-").option("--arion <name>","Arion name for per-Arion session context").action(async($,J)=>{process.exitCode=await l$($,J)})}import{Command as m$}from"commander";function i$($){let J=Number.parseInt($,10);if(!Number.isFinite(J)||J<0)throw Error(`Invalid --duration-ms value: ${$}`);return J}function c(){let $=new m$("pairing").description("Invite and join peers over the internet");return $.command("invite").description("Create an end-user internet pairing invite").argument("[label]","Optional local label for the invite").option("--duration-ms <ms>","Invite lifetime in milliseconds",i$).action(async(J,z)=>{let G=await L();try{let{control:Q}=await g(G),U=await Q.createInvite({...J?.trim()?{inviteLabel:J.trim()}:{},...typeof z?.durationMs==="number"?{durationMs:z.durationMs}:{}});console.log("Invite token:"),console.log(U.inviteToken),console.log(""),console.log(`Join with: aria pairing join ${U.inviteToken}`)}catch(Q){console.error(`Failed to create invite: ${Q.message}`),process.exit(1)}finally{await G.pool?.closeAll?.()}}),$.command("join").description("Accept an internet pairing invite token").argument("<token>","Invite token to accept").action(async(J)=>{let z=await L();try{let{control:G}=await g(z),Q=await G.acceptInviteToken({inviteToken:J.trim()});console.log(`Paired with ${Q.displayNameSnapshot??Q.nodeId}`)}catch(G){console.error(`Failed to accept invite: ${G.message}`),process.exit(1)}finally{await z.pool?.closeAll?.()}}),$}import{Command as s$}from"commander";function S(){return new s$("runtime-cutover-reset").description("Destructively clear stale runtime state while preserving local node identity by default").option("--full-reset","Also remove local node identity material").option("--json","Emit the reset report as JSON").action(async($)=>{let{runtimeCutoverResetCommand:J}=await import("./runtime-cutover-reset-0nywfrh6.js");await J($)})}import{HEADLESS_OPERATION_SCHEMAS as G$,HeadlessInteractionResponseSchema as n$,HeadlessRequestIdSchema as Q$}from"@aria-cli/tools";var t$=200,o$=500;function a$($=process.stdout){let J=!1,z=()=>{J=!0};$.on?.("error",z);let G=(Q)=>{if(J)return!1;try{return $.write(`${JSON.stringify(Q)}
|
|
10
|
+
`),!0}catch{return J=!0,!1}};return G.close=()=>{$.off?.("error",z)},G}function r$($,J,z){let G;try{G=JSON.parse($)}catch{return z({kind:"result",requestId:`parse-error-${J}`,op:"unknown",ok:!1,error:{code:"PARSE_ERROR",message:"Malformed JSON input"}}),null}if(!G||typeof G!=="object")return z({kind:"result",requestId:`parse-error-${J}`,op:"unknown",ok:!1,error:{code:"PARSE_ERROR",message:"Input must be a JSON object"}}),null;let Q=G;if(Q.kind==="interaction.respond"&&Q$.safeParse(Q.requestId).success&&typeof Q.interactionId==="string")return Q;if(Q.kind==="request"&&Q$.safeParse(Q.requestId).success&&typeof Q.op==="string")return Q;return z({kind:"result",requestId:`parse-error-${J}`,op:"unknown",ok:!1,error:{code:"PARSE_ERROR",message:"Missing required kind/requestId/op fields"}}),null}async function h($){let J=a$(),z=null,G=null,Q=null,U=new Set,X=new Set,Z=new Set,j=new Map,b=0,M=null,x="",d=!1,f=!1,q=null,Z$=new Promise((T)=>{q=()=>{if(f)return;f=!0,T()}}),j$=()=>{return z??=U$($).then((T)=>{return G=T,T}),z},Y$=()=>{return Q??=(async()=>{if(G){await G.release();return}if(!z)return;try{let T=await z;G=T,await T.release()}catch{}})(),Q},N$=(T)=>Object.prototype.hasOwnProperty.call(G$,T),p=async(T,Y)=>{if(T.aborted)return{kind:"aborted"};return new Promise((y,V)=>{let K=!1,N=()=>{if(K)return;K=!0,T.removeEventListener("abort",N),y({kind:"aborted"})};T.addEventListener("abort",N),Y.then((W)=>{if(K)return;K=!0,T.removeEventListener("abort",N),y({kind:"value",value:W})},(W)=>{if(K)return;K=!0,T.removeEventListener("abort",N),V(W)})})},V$=async(T)=>{if(typeof T.return!=="function")return!0;try{let y=T.return().then(()=>{return},()=>{return}).finally(()=>{Z.delete(y)}),V=await Promise.race([y.then(()=>!0),new Promise((K)=>setTimeout(()=>K(!1),t$))]);if(!V)Z.add(y);return V}catch{return!1}},K$=(T,Y)=>J({kind:"result",requestId:T,op:Y,ok:!1,error:{code:"CONNECTION_CLOSED",message:"Connection closed before request completed"}}),l=()=>{return M??=(async()=>{for(let[T,Y]of j){if(Y.controller.abort(),Y.completed||Y.connectionClosedEmitted)continue;Y.connectionClosedEmitted=!0,K$(T,Y.op)}if(await Promise.allSettled([...j.values()].map((T)=>T.promise)),Z.size>0)await Promise.race([Promise.allSettled([...Z]),new Promise((T)=>setTimeout(()=>T(),o$))]);await Y$(),J.close(),process.stdin.removeListener("data",s),process.stdin.removeListener("end",E),process.stdin.removeListener("close",E),process.removeListener("SIGTERM",m)})(),M},m=()=>{process.stdin.pause(),l().finally(()=>q?.())};process.once("SIGTERM",m);let i=(T)=>{b+=1;let Y=r$(T,b,J);if(Y)W$(Y)},M$=()=>{while(!0){let T=x.indexOf(`
|
|
11
|
+
`);if(T<0)return;let Y=x.slice(0,T);if(Y.endsWith("\r"))Y=Y.slice(0,-1);x=x.slice(T+1),i(Y)}},s=(T)=>{x+=typeof T==="string"?T:T.toString("utf8"),M$()},E=()=>{if(d)return;d=!0;let T=x;if(T.endsWith("\r"))T=T.slice(0,-1);if(x="",T.trim().length>0)i(T);l().finally(()=>q?.())},W$=(T)=>{let Y=T.kind==="request"?T.op:"interaction.respond",y=[...j.values()].some((N)=>N.op==="arion.become");if(T.kind==="request"&&(T.op==="arion.become"&&U.size>0||T.op!=="arion.become"&&y)){J({kind:"result",requestId:T.requestId,op:Y,ok:!1,error:{code:"ARION_SCOPE_BUSY",message:T.op==="arion.become"?"arion.become requires an idle headless connection":"Headless scope is switching arions; wait for arion.become to finish"}}),X.add(T.requestId);return}if(U.has(T.requestId)){J({kind:"result",requestId:T.requestId,op:Y,ok:!1,error:{code:"DUPLICATE_REQUEST_ID",message:`Request ${T.requestId} is already in flight`}});return}if(X.has(T.requestId)){J({kind:"result",requestId:T.requestId,op:T.kind==="request"?T.op:"interaction.respond",ok:!1,error:{code:"DUPLICATE_REQUEST_ID",message:`Request ${T.requestId} has already been used on this connection`}});return}if(T.kind==="request"){if(!N$(T.op)){J({kind:"result",requestId:T.requestId,op:T.op,ok:!1,error:{code:"UNKNOWN_OPERATION",message:`Unknown operation ${T.op}`}}),X.add(T.requestId);return}if(!G$[T.op].input.safeParse(T.input).success){J({kind:"result",requestId:T.requestId,op:T.op,ok:!1,error:{code:"INVALID_INPUT",message:`Invalid input for ${T.op}`}}),X.add(T.requestId);return}}else if(!n$.safeParse(T).success){J({kind:"result",requestId:T.requestId,op:"interaction.respond",ok:!1,error:{code:"INVALID_INPUT",message:"Invalid input for interaction.respond"}}),X.add(T.requestId);return}U.add(T.requestId),X.add(T.requestId);let V=new AbortController,K=null;K=(async()=>{try{let N=await p(V.signal,j$().then((k)=>({runtime:k})));if(N.kind!=="value")return;let W=N.value.runtime.kernel.dispatch(T,{signal:V.signal})[Symbol.asyncIterator]();while(!0){let k=await p(V.signal,W.next().then((b$)=>({result:b$})));if(k.kind==="aborted"){await V$(W);return}if(k.value.result.done)return;let n=k.value.result.value,D=j.get(T.requestId);if(V.signal.aborted||D?.connectionClosedEmitted)continue;if(J(n),n.kind==="result"){if(D)D.completed=!0}}}catch(N){let W=j.get(T.requestId);if(V.signal.aborted||W?.connectionClosedEmitted)return;if(J({kind:"result",requestId:T.requestId,op:Y,ok:!1,error:{code:"INTERNAL_ERROR",message:N instanceof Error?N.message:String(N)}}),W)W.completed=!0}finally{U.delete(T.requestId),j.delete(T.requestId)}})(),j.set(T.requestId,{op:Y,controller:V,completed:!1,connectionClosedEmitted:!1,promise:K})};process.stdin.setEncoding("utf8"),process.stdin.on("data",s),process.stdin.once("end",E),process.stdin.once("close",E),await Z$}var _=new e$;_.name("aria").description("ARIA - Adaptive Reasoning Intelligence Agent").version(X$);_.addCommand(P());_.addCommand(v());_.addCommand(c());_.command("headless").description("Run the persistent headless stdio control server").option("--arion <name>","Arion name for per-Arion session context").action(async($)=>{await h({cwd:process.cwd(),arionName:$.arion})});_.addCommand(w());var u=_.command("daemon").description("Manage the ARIA daemon");u.command("start",{isDefault:!0}).description("Start the daemon (default)").option("--arion <name>","Run daemon for a specific Arion").option("--port <port>","Server port (default: 0 = OS-assigned)").option("--interval-ms <ms>","Wake loop interval in milliseconds (default: 60000)").option("--allowed-tool-categories <list>","Comma-separated tool category allowlist").option("--allowed-shell-commands <list>","Comma-separated shell command prefix allowlist").option("--max-write-ops-per-minute <count>","Rate limit for write operations per minute").option("--max-git-pushes-per-hour <count>","Rate limit for git pushes per hour").action(async($)=>{await F($)});u.command("stop").description("Stop the running daemon").action(async()=>{await I()});u.command("restart").description("Stop the daemon and start a fresh one").action(async()=>{await $$()});_.addCommand(S());
|
|
12
|
+
export{P as a,v as b,F as c,w as d,c as e,S as f,h as g,_ as h};
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import s from"better-sqlite3";import p from"node:crypto";import{existsSync as P,copyFileSync as JJ,mkdirSync as C,readdirSync as KJ}from"node:fs";import j from"node:path";import{log as O}from"@aria-cli/types";var VJ=2000;var N=globalThis;function x(J){N.__aria_stall_phase=J,N.__aria_stall_phase_ts=performance.now()}function M(){N.__aria_stall_phase=void 0,N.__aria_stall_phase_ts=void 0}function FJ(){let{__aria_stall_phase:J,__aria_stall_phase_ts:K}=N;if(!J||typeof K!=="number")return;return{label:J,ageMs:performance.now()-K}}function GJ(J){let K=J.thresholdMs??2000,X=performance.now(),Y=process.cpuUsage(),Z=setInterval(()=>{let W=performance.now(),$=W-X,Q=process.cpuUsage(Y);if(X=W,Y=process.cpuUsage(),$>K)if((Q.user+Q.system)/1000/$<0.05)J.onSleep?.($);else J.onStall($)},500);if(typeof Z==="object"&&Z!==null&&"unref"in Z)Z.unref();return()=>clearInterval(Z)}import{z as H}from"zod";import{log as h}from"@aria-cli/types";var g=H.object({type:H.literal("text"),text:H.string()}),m=H.object({type:H.literal("thinking"),content:H.string(),wordCount:H.number(),durationMs:H.number().optional(),verb:H.string().optional()}),d=H.object({type:H.literal("tool_use"),id:H.string(),name:H.string(),arguments:H.record(H.string(),H.unknown()),thoughtSignature:H.string().optional()}),c=H.object({type:H.literal("tool_result"),toolUseId:H.string(),content:H.string(),status:H.enum(["success","error"]),durationMs:H.number().optional(),resultData:H.unknown().optional(),usage:H.object({inputTokens:H.number(),outputTokens:H.number(),totalTokens:H.number(),estimatedCost:H.number()}).optional()}),w=H.object({type:H.literal("handoff"),target:H.string(),direction:H.enum(["to","from"])}),a=H.object({type:H.literal("error"),content:H.string(),suggestion:H.string().optional()}),f=H.discriminatedUnion("type",[g,m,d,c,w,a]),l=["cyan","magenta","yellow","green","blue","red","white"],v=H.object({name:H.string(),emoji:H.string(),color:H.enum(l).optional()}),T=H.object({id:H.string(),role:H.enum(["user","assistant","system","tool"]),content:H.array(f),arion:v.optional(),costUSD:H.number().optional(),durationMs:H.number().optional(),tokenUsage:H.object({input:H.number(),output:H.number()}).optional(),createdAt:H.string()});function R(J){return{id:crypto.randomUUID(),role:"user",content:[{type:"text",text:J}],createdAt:new Date().toISOString()}}function i(J){return{id:crypto.randomUUID(),role:"system",content:[{type:"text",text:J}],createdAt:new Date().toISOString()}}function n(J,K,X,Y){let Z=`synthetic_inbox_${crypto.randomUUID().slice(0,8)}`,W=new Date().toISOString(),$={id:crypto.randomUUID(),role:"assistant",content:[{type:"tool_use",id:Z,name:"check_messages",arguments:{unreadOnly:!0}}],createdAt:W},Q={id:crypto.randomUUID(),role:"tool",content:[{type:"tool_result",toolUseId:Z,content:JSON.stringify({messages:[{id:Y||crypto.randomUUID(),from:J,address:K,content:X,type:"incoming"}]}),status:"success"}],createdAt:W};return[$,Q]}function r(J,K){return{id:crypto.randomUUID(),role:"system",content:[{type:"error",content:J,...K?{suggestion:K}:{}}],createdAt:new Date().toISOString()}}function t(J){let K=[];for(let X of J)switch(X.role){case"assistant":{let Y=[],Z=[];for(let $ of X.content)if($.type==="text")Y.push($.text);else if($.type==="tool_use")Z.push({id:$.id,name:$.name,arguments:$.arguments,...$.thoughtSignature?{thoughtSignature:$.thoughtSignature}:{}});let W={role:"assistant",content:Y.join("")};if(Z.length>0)W.toolCalls=Z;K.push(W);break}case"tool":{for(let Y of X.content)if(Y.type==="tool_result")K.push({role:"tool",content:Y.content,toolCallId:Y.toolUseId});break}case"user":case"system":{let Y=[];for(let Z of X.content)if(Z.type==="text")Y.push(Z.text);K.push({role:X.role,content:Y.join("")});break}}return K}function e(J,K){let X=[];for(let Y of J){let Z=[],W=Y;if(W.thinking)for(let $ of W.thinking){let Q=$.thinking?$.thinking.split(/\s+/).filter(Boolean).length:0;Z.push({type:"thinking",content:$.thinking,wordCount:Q})}if(Y.role==="assistant"&&Y.toolCalls){if(Y.content)Z.push({type:"text",text:Y.content});for(let $ of Y.toolCalls)Z.push({type:"tool_use",id:$.id,name:$.name,arguments:$.arguments,...$.thoughtSignature?{thoughtSignature:$.thoughtSignature}:{}})}else if(Y.role==="tool")Z.push({type:"tool_result",toolUseId:Y.toolCallId??"",content:Y.content,status:"success"});else if(Y.content)Z.push({type:"text",text:Y.content});if(Z.length===0)Z.push({type:"text",text:""});X.push({id:crypto.randomUUID(),role:Y.role,content:Z,arion:K?.arion,createdAt:new Date().toISOString()})}return X}function B(J){let K=[];if(J.thinking)try{let X=JSON.parse(J.thinking);for(let Y of X)K.push({type:"thinking",content:Y.content??"",wordCount:Y.wordCount??0})}catch{h.warn(`[fromV1Columns] Corrupted thinking JSON in message row ${J.id} (session ${J.session_id}), skipping`)}if(J.tool_calls)try{let X=JSON.parse(J.tool_calls);for(let Y of X)K.push({type:"tool_use",id:Y.id,name:Y.name,arguments:Y.arguments??{},...Y.thoughtSignature?{thoughtSignature:Y.thoughtSignature}:{}})}catch{h.warn(`[fromV1Columns] Corrupted tool_calls JSON in message row ${J.id} (session ${J.session_id}), skipping`)}if(J.role==="tool"&&J.tool_call_id)K.push({type:"tool_result",toolUseId:J.tool_call_id,content:J.content,status:"success"});if(J.role!=="tool"&&J.content)K.push({type:"text",text:J.content});return{id:crypto.randomUUID(),role:J.role,content:K.length>0?K:[{type:"text",text:J.content??""}],arion:J.arion?{name:J.arion,emoji:"",color:void 0}:void 0,createdAt:J.created_at}}function o(J){let K=[];for(let X of J)for(let Y of X.content)switch(Y.type){case"thinking":K.push({id:`thinking-${crypto.randomUUID()}`,role:"thinking_history",content:Y.content,wordCount:Y.wordCount,durationSeconds:Y.durationMs?Y.durationMs/1000:void 0,verb:Y.verb,arionName:X.arion?.name,arionEmoji:X.arion?.emoji,arionColor:X.arion?.color});break;case"tool_use":K.push({id:`tool-${crypto.randomUUID()}`,role:"tool_history",tool:{id:Y.id,name:Y.name,status:"complete",args:Y.arguments,result:void 0,startTime:void 0,endTime:void 0}});break;case"tool_result":{let Z;for(let W=K.length-1;W>=0;W--){let $=K[W];if($.role==="tool_history"&&$.tool.id===Y.toolUseId){Z=$;break}}if(Z){if(Z.tool.status=Y.status==="error"?"error":"complete",Y.status==="error")Z.tool.error=Y.content;else Z.tool.result=Y.content;if(Y.resultData!==void 0)Z.tool.resultData=Y.resultData;if(Y.durationMs!==void 0)Z.tool.durationMs=Y.durationMs;if(Y.usage!==void 0)Z.tool.usage=Y.usage}break}case"handoff":K.push({id:`handoff-${crypto.randomUUID()}`,role:"handoff_history",target:Y.target,direction:Y.direction});break;case"error":K.push({id:`error-${crypto.randomUUID()}`,role:"error",content:Y.content,suggestion:Y.suggestion});break;case"text":K.push({id:`msg-${crypto.randomUUID()}`,role:X.role,content:Y.text,arion:X.arion?{name:X.arion.name,emoji:X.arion.emoji,color:X.arion.color}:void 0});break}return K}function L(J){return J.content.filter((K)=>K.type==="text").map((K)=>K.text).join("")}function U(J){let K=J.content.filter((X)=>X.type==="tool_use");if(K.length===0)return null;return JSON.stringify(K.map((X)=>({id:X.id,name:X.name,arguments:X.arguments,...X.thoughtSignature?{thoughtSignature:X.thoughtSignature}:{}})))}function S(J){let K=J.content.filter((X)=>X.type==="thinking");if(K.length===0)return null;return JSON.stringify(K.map((X)=>({id:crypto.randomUUID(),content:X.content,wordCount:X.wordCount})))}function q(J){for(let K of J.content)if(K.type==="tool_result")return K.toolUseId;return null}class k{db;sessionFtsEnabled=!1;incrementalSessions=new Set;static resolvePerArionPath(J,K){let X=j.join(J,"arions",K),Y=j.join(X,"history.db");if(!P(Y))C(X,{recursive:!0});return Y}static migrateJsonlLogs(J,K){let X=j.join(J,"arions",K,"logs"),Y=j.join(J,"logs");if(!P(X)&&P(Y)){C(X,{recursive:!0});try{let Z=KJ(Y).filter((W)=>W.endsWith(".jsonl"));for(let W of Z){let $=j.join(Y,W),Q=j.join(X,W);if(!P(Q))JJ($,Q)}}catch{}}if(!P(X))C(X,{recursive:!0});return X}constructor(J){this.db=new s(J),this.db.pragma("journal_mode = WAL"),this.db.pragma("busy_timeout = 5000"),this.db.pragma("foreign_keys = ON"),this.initialize()}initialize(){this.db.exec(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
created_at TEXT NOT NULL,
|
|
5
|
+
updated_at TEXT NOT NULL,
|
|
6
|
+
completed_at TEXT,
|
|
7
|
+
title TEXT,
|
|
8
|
+
arion TEXT NOT NULL,
|
|
9
|
+
model TEXT NOT NULL,
|
|
10
|
+
message_count INTEGER DEFAULT 0
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
14
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
15
|
+
session_id TEXT NOT NULL,
|
|
16
|
+
role TEXT NOT NULL,
|
|
17
|
+
content TEXT NOT NULL,
|
|
18
|
+
arion TEXT,
|
|
19
|
+
created_at TEXT NOT NULL,
|
|
20
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS input_history (
|
|
24
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
+
content TEXT NOT NULL UNIQUE,
|
|
26
|
+
used_at TEXT NOT NULL
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated_at DESC);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_input_history_used ON input_history(used_at DESC);
|
|
32
|
+
`);try{this.db.exec("ALTER TABLE sessions ADD COLUMN completed_at TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN tool_call_id TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN tool_calls TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN thinking TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}try{this.db.exec("ALTER TABLE messages ADD COLUMN data TEXT")}catch(J){if(!(J?.message??"").includes("duplicate column name"))throw J}this.db.exec(`
|
|
33
|
+
CREATE TABLE IF NOT EXISTS run_metrics (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
session_id TEXT NOT NULL,
|
|
36
|
+
turn_count INTEGER,
|
|
37
|
+
input_tokens INTEGER,
|
|
38
|
+
output_tokens INTEGER,
|
|
39
|
+
total_tokens INTEGER,
|
|
40
|
+
estimated_cost REAL,
|
|
41
|
+
wall_time_ms INTEGER,
|
|
42
|
+
tool_count INTEGER,
|
|
43
|
+
guardrail_fires INTEGER,
|
|
44
|
+
handoff_count INTEGER,
|
|
45
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
46
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_run_metrics_session ON run_metrics(session_id);
|
|
50
|
+
`),this.db.exec(`
|
|
51
|
+
CREATE TABLE IF NOT EXISTS session_runtime_state (
|
|
52
|
+
session_id TEXT PRIMARY KEY,
|
|
53
|
+
state_status TEXT NOT NULL DEFAULT 'idle',
|
|
54
|
+
active_run_id TEXT,
|
|
55
|
+
paused_state_json TEXT,
|
|
56
|
+
policy_snapshot_json TEXT,
|
|
57
|
+
last_event_seq INTEGER NOT NULL DEFAULT 0,
|
|
58
|
+
revision INTEGER NOT NULL DEFAULT 0,
|
|
59
|
+
lease_owner TEXT,
|
|
60
|
+
lease_expires_at TEXT,
|
|
61
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
62
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE TABLE IF NOT EXISTS session_interactions (
|
|
66
|
+
interaction_id TEXT PRIMARY KEY,
|
|
67
|
+
session_id TEXT NOT NULL,
|
|
68
|
+
request_id TEXT NOT NULL,
|
|
69
|
+
source TEXT NOT NULL,
|
|
70
|
+
kind TEXT NOT NULL,
|
|
71
|
+
status TEXT NOT NULL,
|
|
72
|
+
prompt_json TEXT NOT NULL,
|
|
73
|
+
response_json TEXT,
|
|
74
|
+
created_at TEXT NOT NULL,
|
|
75
|
+
answered_at TEXT,
|
|
76
|
+
applied_at TEXT,
|
|
77
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_session_runtime_state_status
|
|
81
|
+
ON session_runtime_state(state_status, updated_at DESC);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_session_interactions_session
|
|
83
|
+
ON session_interactions(session_id, created_at DESC);
|
|
84
|
+
CREATE INDEX IF NOT EXISTS idx_session_interactions_status
|
|
85
|
+
ON session_interactions(status, created_at DESC);
|
|
86
|
+
`),this.initializeSessionFts();try{this.db.pragma("wal_checkpoint(PASSIVE)")}catch{}}initializeSessionFts(){try{this.db.exec(`
|
|
87
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS fts_session_messages USING fts5(
|
|
88
|
+
message_id UNINDEXED,
|
|
89
|
+
session_id UNINDEXED,
|
|
90
|
+
content
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE TRIGGER IF NOT EXISTS trg_messages_ai_fts
|
|
94
|
+
AFTER INSERT ON messages BEGIN
|
|
95
|
+
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
96
|
+
VALUES (new.id, new.session_id, new.content);
|
|
97
|
+
END;
|
|
98
|
+
|
|
99
|
+
CREATE TRIGGER IF NOT EXISTS trg_messages_au_fts
|
|
100
|
+
AFTER UPDATE OF content, session_id ON messages BEGIN
|
|
101
|
+
DELETE FROM fts_session_messages WHERE message_id = old.id;
|
|
102
|
+
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
103
|
+
VALUES (new.id, new.session_id, new.content);
|
|
104
|
+
END;
|
|
105
|
+
|
|
106
|
+
CREATE TRIGGER IF NOT EXISTS trg_messages_ad_fts
|
|
107
|
+
AFTER DELETE ON messages BEGIN
|
|
108
|
+
DELETE FROM fts_session_messages WHERE message_id = old.id;
|
|
109
|
+
END;
|
|
110
|
+
`);let J=this.db.prepare("SELECT COUNT(*) as c FROM messages").get().c;if(this.db.prepare("SELECT COUNT(*) as c FROM fts_session_messages").get().c<J)this.db.exec(`
|
|
111
|
+
INSERT INTO fts_session_messages (message_id, session_id, content)
|
|
112
|
+
SELECT m.id, m.session_id, m.content
|
|
113
|
+
FROM messages m
|
|
114
|
+
LEFT JOIN fts_session_messages f ON f.message_id = m.id
|
|
115
|
+
WHERE f.message_id IS NULL;
|
|
116
|
+
`);this.sessionFtsEnabled=!0}catch(J){this.sessionFtsEnabled=!1,O.warn("[SessionHistory] Session FTS disabled:",J?.message??String(J))}}toFtsPrefixQuery(J){return J.trim().split(/\s+/).filter(Boolean).map((K)=>`"${K.replace(/"/g,'""')}"*`).join(" AND ")}withImmediateTransaction(J){this.db.exec("BEGIN IMMEDIATE");try{let K=J();return this.db.exec("COMMIT"),K}catch(K){try{this.db.exec("ROLLBACK")}catch{}throw K}}ensureSessionRuntimeRow(J){let K=new Date().toISOString();this.db.prepare(`INSERT INTO session_runtime_state (
|
|
117
|
+
session_id,
|
|
118
|
+
state_status,
|
|
119
|
+
last_event_seq,
|
|
120
|
+
revision,
|
|
121
|
+
updated_at
|
|
122
|
+
) VALUES (?, 'idle', 0, 0, ?)
|
|
123
|
+
ON CONFLICT(session_id) DO NOTHING`).run(J,K)}readSessionRuntimeStateRow(J){return this.ensureSessionRuntimeRow(J),this.db.prepare("SELECT * FROM session_runtime_state WHERE session_id = ?").get(J)??null}parseJsonColumn(J,K,X){if(!K)return X;try{return JSON.parse(K)}catch{return O.warn(`[SessionHistory] Corrupted ${J} JSON, using fallback value`),X}}toSessionRuntimeState(J){if(!J)return null;return{sessionId:J.session_id,stateStatus:J.state_status,activeRunId:J.active_run_id,pausedState:this.parseJsonColumn("paused_state_json",J.paused_state_json,null),policySnapshot:this.parseJsonColumn("policy_snapshot_json",J.policy_snapshot_json,null),lastEventSeq:J.last_event_seq,revision:J.revision,leaseOwner:J.lease_owner,leaseExpiresAt:J.lease_expires_at,updatedAt:J.updated_at}}toSessionInteractionRecord(J){if(!J)return null;return{interactionId:J.interaction_id,sessionId:J.session_id,requestId:J.request_id,source:J.source,kind:J.kind,status:J.status,prompt:this.parseJsonColumn("prompt_json",J.prompt_json,{}),response:this.parseJsonColumn("response_json",J.response_json,null),createdAt:J.created_at,answeredAt:J.answered_at,appliedAt:J.applied_at}}assertSessionMutationGuard(J,K,X){let Y=Date.now(),Z=J.lease_expires_at?Date.parse(J.lease_expires_at):null;if(K&&J.lease_owner&&J.lease_owner!==K&&Z!==null&&Number.isFinite(Z)&&Z>Y)throw Error(`Session ${J.session_id} is leased by ${J.lease_owner} until ${J.lease_expires_at}`);if(X!==void 0&&J.revision!==X)throw Error(`Session ${J.session_id} revision mismatch: expected ${X}, got ${J.revision}`)}createSession(J,K,X){X??=p.randomUUID();let Y=new Date().toISOString();return this.withImmediateTransaction(()=>{this.db.prepare(`
|
|
124
|
+
INSERT INTO sessions (id, created_at, updated_at, arion, model, message_count)
|
|
125
|
+
VALUES (?, ?, ?, ?, ?, 0)
|
|
126
|
+
`).run(X,Y,Y,J,K),this.db.prepare(`INSERT INTO session_runtime_state (
|
|
127
|
+
session_id,
|
|
128
|
+
state_status,
|
|
129
|
+
last_event_seq,
|
|
130
|
+
revision,
|
|
131
|
+
updated_at
|
|
132
|
+
) VALUES (?, 'idle', 0, 0, ?)`).run(X,Y)}),X}forkSession(J,K){let X=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(J);if(!X)throw Error(`Source session not found: ${J}`);let Y=p.randomUUID(),Z=new Date().toISOString(),W=K?.title??(X.title?`\uD83C\uDF74 ${X.title}`:"\uD83C\uDF74 Forked session"),$=K?.messageLimit!==void 0&&K.messageLimit>=0?this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC LIMIT ?"):this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC"),Q=K?.messageLimit!==void 0&&K.messageLimit>=0?$.all(J,K.messageLimit):$.all(J);return this.withImmediateTransaction(()=>{if(this.db.prepare(`INSERT INTO sessions (id, created_at, updated_at, arion, model, message_count, title)
|
|
133
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(Y,Z,Z,X.arion,X.model,Q.length,W),this.db.prepare(`INSERT INTO session_runtime_state (
|
|
134
|
+
session_id, state_status, last_event_seq, revision, updated_at
|
|
135
|
+
) VALUES (?, 'idle', 0, 0, ?)`).run(Y,Z),Q.length>0){let F=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
136
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let G of Q)F.run(Y,G.role,G.content,G.arion,G.tool_call_id,G.tool_calls,G.thinking,G.data,G.created_at)}}),{newSessionId:Y,sourceSessionId:J,messagesCopied:Q.length,title:W}}addMessage(J,K,X,Y){try{let Z=new Date().toISOString(),W=Y?.arion??null,$=Y?.toolCallId??null,Q=Y?.toolCalls?JSON.stringify(Y.toolCalls):null,F=Y?.thinking?JSON.stringify(Y.thinking):null;this.db.transaction(()=>{this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, created_at)
|
|
137
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(J,K,X,W,$,Q,F,Z),this.db.prepare(`UPDATE sessions
|
|
138
|
+
SET updated_at = ?,
|
|
139
|
+
message_count = message_count + 1,
|
|
140
|
+
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
141
|
+
WHERE id = ?`).run(Z,K,X,J)})()}catch(Z){O.warn("[SessionHistory] Failed to persist message:",Z?.message??Z)}}addConversationMessage(J,K){try{let X=new Date().toISOString(),Y=L(K);if(K.role==="tool"&&!Y){let V=K.content.find((E)=>E.type==="tool_result");if(V&&V.type==="tool_result")Y=V.content}let Z=K.arion?.name??null,W=q(K),$=U(K),Q=S(K),F=JSON.stringify(K);this.db.transaction(()=>{this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
142
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(J,K.role,Y,Z,W,$,Q,F,X),this.db.prepare(`UPDATE sessions
|
|
143
|
+
SET updated_at = ?,
|
|
144
|
+
message_count = message_count + 1,
|
|
145
|
+
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
146
|
+
WHERE id = ?`).run(X,K.role,Y,J)})(),this.incrementalSessions.add(J)}catch(X){O.warn("[SessionHistory] Failed to persist conversation message:",X?.message??X)}}addConversationMessages(J,K){if(K.length===0)return;if(K.length===1){this.addConversationMessage(J,K[0]);return}try{let X=new Date().toISOString(),Y=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
147
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),Z=this.db.prepare(`UPDATE sessions
|
|
148
|
+
SET updated_at = ?,
|
|
149
|
+
message_count = message_count + ?,
|
|
150
|
+
title = COALESCE(title, CASE WHEN ? = 'user' THEN substr(?, 1, 60) END)
|
|
151
|
+
WHERE id = ?`);this.db.transaction(()=>{let $=null;for(let Q of K){let F=L(Q);if(Q.role==="tool"&&!F){let y=Q.content.find((I)=>I.type==="tool_result");if(y&&y.type==="tool_result")F=y.content}if(Q.role==="user"&&!$)$=F;let G=Q.arion?.name??null,V=q(Q),E=U(Q),_=S(Q),A=JSON.stringify(Q);Y.run(J,Q.role,F,G,V,E,_,A,X)}Z.run(X,K.length,$?"user":"assistant",$??"",J)})()}catch(X){O.warn("[SessionHistory] Failed to persist conversation messages batch:",X?.message??X)}}replaceConversationMessages(J,K){if(this.incrementalSessions.has(J))return;try{let X=performance.now(),Y=this.db.prepare("SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?").get(J)?.cnt??0,Z=performance.now();x(`SessionHistory:replaceConversationMessages(del=${Y},ins=${K.length})`);let W=new Date().toISOString(),$=this.db.prepare(`INSERT INTO messages (session_id, role, content, arion, tool_call_id, tool_calls, thinking, data, created_at)
|
|
152
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);this.db.transaction(()=>{this.db.prepare("DELETE FROM messages WHERE session_id = ?").run(J);let G=null;for(let V of K){let E=L(V);if(V.role==="tool"&&!E){let _=V.content.find((A)=>A.type==="tool_result");if(_&&_.type==="tool_result")E=_.content}if(V.role==="user"&&!G)G=E;$.run(J,V.role,E,V.arion?.name??null,q(V),U(V),S(V),JSON.stringify(V),W)}this.db.prepare(`UPDATE sessions
|
|
153
|
+
SET updated_at = ?,
|
|
154
|
+
message_count = ?,
|
|
155
|
+
title = CASE
|
|
156
|
+
WHEN ? IS NOT NULL AND length(?) > 0 THEN substr(?, 1, 60)
|
|
157
|
+
ELSE title
|
|
158
|
+
END
|
|
159
|
+
WHERE id = ?`).run(W,K.length,G,G,G,J)})();let F=performance.now()-X;if(M(),process.env.DEBUG&&(F>200||Y>500))try{process.stderr.write(`[SessionHistory][DIAG] replaceConversationMessages: total=${F.toFixed(0)}ms (count=${(Z-X).toFixed(0)}ms txn=${(F-(Z-X)).toFixed(0)}ms) existingRows=${Y} newRows=${K.length} session=${J}
|
|
160
|
+
`)}catch{}}catch(X){M(),O.warn("[SessionHistory] Failed to replace conversation messages batch:",X?.message??X)}}loadSessionMessages(J){let K=this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(J);if(!K)return null;let Y=this.db.prepare("SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC").all(J).map((Z)=>{if(Z.data)try{let W=JSON.parse(Z.data),$=T.safeParse(W);if($.success)return $.data;return O.warn(`[loadSessionMessages] Schema validation failed for message row ${Z.id} (session ${J}), falling back to v1 columns`),B(Z)}catch{return O.warn(`[loadSessionMessages] Corrupted data column in message row ${Z.id} (session ${J}), falling back to v1 columns`),B(Z)}return B(Z)});return{id:K.id,arion:K.arion,model:K.model,messages:Y}}loadSession(J){let K=this.loadSessionMessages(J);if(!K)return null;let X=this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J)),Y=this.db.prepare(`SELECT * FROM session_interactions
|
|
161
|
+
WHERE session_id = ?
|
|
162
|
+
AND status = 'pending'
|
|
163
|
+
ORDER BY created_at DESC
|
|
164
|
+
LIMIT 1`).get(J)??null;return{session:K,runtimeState:X,pendingInteraction:this.toSessionInteractionRecord(Y)}}getSessionRuntimeState(J){return this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))}getInteraction(J){let K=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(J)??null;return this.toSessionInteractionRecord(K)}claimSessionForMutation(J,K,X){if(!K.trim())throw Error("claimSessionForMutation requires a non-empty ownerId");if(!Number.isFinite(X)||X<=0)throw Error("claimSessionForMutation requires a positive staleAfterMs");return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,K);let Z=new Date().toISOString(),W=new Date(Date.now()+X).toISOString();return this.db.prepare(`UPDATE session_runtime_state
|
|
165
|
+
SET lease_owner = ?,
|
|
166
|
+
lease_expires_at = ?,
|
|
167
|
+
updated_at = ?
|
|
168
|
+
WHERE session_id = ?`).run(K,W,Z,J),this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}recordPausedRun(J,K,X,Y,Z,W){return this.withImmediateTransaction(()=>{let $=this.readSessionRuntimeStateRow(J);if(!$)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard($,W?.ownerId,W?.expectedRevision);let Q=new Date().toISOString(),F=$.revision+1;if(this.db.prepare(`UPDATE session_runtime_state
|
|
169
|
+
SET state_status = 'paused',
|
|
170
|
+
active_run_id = ?,
|
|
171
|
+
paused_state_json = ?,
|
|
172
|
+
policy_snapshot_json = ?,
|
|
173
|
+
last_event_seq = ?,
|
|
174
|
+
revision = ?,
|
|
175
|
+
updated_at = ?
|
|
176
|
+
WHERE session_id = ?`).run(K,JSON.stringify(X),JSON.stringify(Y),W?.lastEventSeq??$.last_event_seq,F,Q,J),Z)this.db.prepare(`INSERT INTO session_interactions (
|
|
177
|
+
interaction_id,
|
|
178
|
+
session_id,
|
|
179
|
+
request_id,
|
|
180
|
+
source,
|
|
181
|
+
kind,
|
|
182
|
+
status,
|
|
183
|
+
prompt_json,
|
|
184
|
+
created_at
|
|
185
|
+
) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)`).run(Z.interactionId,J,Z.requestId,Z.source,Z.kind,JSON.stringify(Z.prompt),Q);return this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}recordInteractionResponse(J,K,X,Y){return this.withImmediateTransaction(()=>{let Z=this.readSessionRuntimeStateRow(J);if(!Z)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Z,Y?.ownerId,Y?.expectedRevision);let W=this.db.prepare(`SELECT * FROM session_interactions
|
|
186
|
+
WHERE session_id = ?
|
|
187
|
+
AND interaction_id = ?`).get(J,K)??null;if(!W)throw Error(`Interaction ${K} not found for session ${J}`);if(W.status!=="pending")throw Error(`Interaction ${K} is not pending (current status: ${W.status})`);let $=new Date().toISOString();this.db.prepare(`UPDATE session_interactions
|
|
188
|
+
SET status = 'answered',
|
|
189
|
+
response_json = ?,
|
|
190
|
+
answered_at = ?
|
|
191
|
+
WHERE interaction_id = ?`).run(JSON.stringify(X),$,K),this.db.prepare(`UPDATE session_runtime_state
|
|
192
|
+
SET revision = revision + 1,
|
|
193
|
+
updated_at = ?
|
|
194
|
+
WHERE session_id = ?`).run($,J);let Q=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(K)??null;return this.toSessionInteractionRecord(Q)})}cancelInteraction(J,K,X){return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,X?.ownerId,X?.expectedRevision);let Z=this.db.prepare(`SELECT * FROM session_interactions
|
|
195
|
+
WHERE session_id = ?
|
|
196
|
+
AND interaction_id = ?`).get(J,K)??null;if(!Z)throw Error(`Interaction ${K} not found for session ${J}`);if(Z.status!=="pending")throw Error(`Interaction ${K} is not pending (current status: ${Z.status})`);let W=new Date().toISOString();this.db.prepare(`UPDATE session_interactions
|
|
197
|
+
SET status = 'canceled',
|
|
198
|
+
answered_at = ?
|
|
199
|
+
WHERE interaction_id = ?`).run(W,K),this.db.prepare(`UPDATE session_runtime_state
|
|
200
|
+
SET state_status = 'completed',
|
|
201
|
+
active_run_id = NULL,
|
|
202
|
+
paused_state_json = NULL,
|
|
203
|
+
policy_snapshot_json = NULL,
|
|
204
|
+
revision = revision + 1,
|
|
205
|
+
updated_at = ?
|
|
206
|
+
WHERE session_id = ?`).run(W,J),this.db.prepare(`UPDATE sessions
|
|
207
|
+
SET completed_at = COALESCE(completed_at, ?),
|
|
208
|
+
updated_at = ?
|
|
209
|
+
WHERE id = ?`).run(W,W,J);let $=this.db.prepare("SELECT * FROM session_interactions WHERE interaction_id = ?").get(K)??null;return this.toSessionInteractionRecord($)})}completeRun(J,K,X){return this.withImmediateTransaction(()=>{let Y=this.readSessionRuntimeStateRow(J);if(!Y)throw Error(`Session ${J} not found`);this.assertSessionMutationGuard(Y,X?.ownerId,X?.expectedRevision);let Z=new Date().toISOString();return this.db.prepare(`UPDATE session_runtime_state
|
|
210
|
+
SET state_status = 'completed',
|
|
211
|
+
active_run_id = NULL,
|
|
212
|
+
paused_state_json = NULL,
|
|
213
|
+
policy_snapshot_json = NULL,
|
|
214
|
+
revision = revision + 1,
|
|
215
|
+
updated_at = ?
|
|
216
|
+
WHERE session_id = ?`).run(Z,J),this.db.prepare(`UPDATE session_interactions
|
|
217
|
+
SET status = CASE WHEN response_json IS NULL THEN 'expired' ELSE 'applied' END,
|
|
218
|
+
answered_at = COALESCE(answered_at, ?),
|
|
219
|
+
applied_at = CASE WHEN response_json IS NULL THEN applied_at ELSE ? END
|
|
220
|
+
WHERE session_id = ?
|
|
221
|
+
AND status IN ('pending', 'answered')`).run(Z,Z,J),this.db.prepare(`UPDATE sessions
|
|
222
|
+
SET completed_at = COALESCE(completed_at, ?),
|
|
223
|
+
updated_at = ?
|
|
224
|
+
WHERE id = ?`).run(Z,Z,J),this.toSessionRuntimeState(this.readSessionRuntimeStateRow(J))})}releaseSessionClaim(J,K){this.withImmediateTransaction(()=>{let X=this.readSessionRuntimeStateRow(J);if(!X)throw Error(`Session ${J} not found`);if(X.lease_owner&&X.lease_owner!==K)throw Error(`Cannot release session ${J} lease owned by ${X.lease_owner} with ${K}`);let Y=new Date().toISOString();this.db.prepare(`UPDATE session_runtime_state
|
|
225
|
+
SET lease_owner = NULL,
|
|
226
|
+
lease_expires_at = NULL,
|
|
227
|
+
updated_at = ?
|
|
228
|
+
WHERE session_id = ?`).run(Y,J)})}listSessions(J=20,K=0){return this.db.prepare(`
|
|
229
|
+
SELECT
|
|
230
|
+
s.*,
|
|
231
|
+
COALESCE(s.title, '') as preview
|
|
232
|
+
FROM sessions s
|
|
233
|
+
WHERE s.message_count > 0
|
|
234
|
+
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
235
|
+
LIMIT ? OFFSET ?
|
|
236
|
+
`).all(J,K).map((Y)=>({id:Y.id,createdAt:new Date(Y.created_at),updatedAt:new Date(Y.updated_at),completedAt:Y.completed_at?new Date(Y.completed_at):void 0,title:Y.title,arion:Y.arion,model:Y.model,messageCount:Y.message_count,preview:this.truncatePreview(Y.preview??"",60)}))}searchSessions(J,K=20,X=0){let Z=`%${J.replace(/[%_\\]/g,"\\$&")}%`;return this.db.prepare(`
|
|
237
|
+
SELECT DISTINCT
|
|
238
|
+
s.*,
|
|
239
|
+
(SELECT content FROM messages WHERE session_id = s.id AND role = 'user' ORDER BY id LIMIT 1) as preview
|
|
240
|
+
FROM sessions s
|
|
241
|
+
LEFT JOIN messages m ON m.session_id = s.id
|
|
242
|
+
WHERE s.message_count > 0
|
|
243
|
+
AND (s.title LIKE ? ESCAPE '\\' OR m.content LIKE ? ESCAPE '\\')
|
|
244
|
+
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
245
|
+
LIMIT ? OFFSET ?
|
|
246
|
+
`).all(Z,Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}searchSessionsFts(J,K=100,X=0){let Y=J.trim();if(!Y)return[];if(!this.sessionFtsEnabled)return this.searchSessions(Y,K,X);let Z=this.toFtsPrefixQuery(Y);if(!Z)return[];try{return this.db.prepare(`
|
|
247
|
+
WITH matched AS (
|
|
248
|
+
SELECT session_id, MIN(bm25(fts_session_messages)) as rank
|
|
249
|
+
FROM fts_session_messages
|
|
250
|
+
WHERE fts_session_messages MATCH ?
|
|
251
|
+
GROUP BY session_id
|
|
252
|
+
)
|
|
253
|
+
SELECT
|
|
254
|
+
s.*,
|
|
255
|
+
COALESCE(s.title, '') as preview
|
|
256
|
+
FROM matched m
|
|
257
|
+
JOIN sessions s ON s.id = m.session_id
|
|
258
|
+
WHERE s.message_count > 0
|
|
259
|
+
ORDER BY m.rank ASC, s.updated_at DESC, s.rowid DESC
|
|
260
|
+
LIMIT ? OFFSET ?
|
|
261
|
+
`).all(Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}catch(W){return this.searchSessions(Y,K,X)}}searchSessionSummaries(J,K=100,X=0){let Z=`%${J.replace(/[%_\\]/g,"\\$&")}%`;return this.db.prepare(`
|
|
262
|
+
SELECT
|
|
263
|
+
s.*,
|
|
264
|
+
COALESCE(s.title, '') as preview
|
|
265
|
+
FROM sessions s
|
|
266
|
+
WHERE s.message_count > 0
|
|
267
|
+
AND (
|
|
268
|
+
s.title LIKE ? ESCAPE '\\'
|
|
269
|
+
OR s.arion LIKE ? ESCAPE '\\'
|
|
270
|
+
OR s.model LIKE ? ESCAPE '\\'
|
|
271
|
+
OR s.id LIKE ? ESCAPE '\\'
|
|
272
|
+
)
|
|
273
|
+
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
274
|
+
LIMIT ? OFFSET ?
|
|
275
|
+
`).all(Z,Z,Z,Z,K,X).map(($)=>({id:$.id,createdAt:new Date($.created_at),updatedAt:new Date($.updated_at),completedAt:$.completed_at?new Date($.completed_at):void 0,title:$.title,arion:$.arion,model:$.model,messageCount:$.message_count,preview:this.truncatePreview($.preview??"",60)}))}getSession(J){let K=this.db.prepare(`
|
|
276
|
+
SELECT * FROM sessions WHERE id = ?
|
|
277
|
+
`).get(J);if(!K)return null;let X=this.db.prepare(`
|
|
278
|
+
SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC
|
|
279
|
+
`).all(J);return{id:K.id,arion:K.arion,model:K.model,messages:X.map((Y)=>({id:Y.id,role:Y.role,content:Y.content,arion:Y.arion??void 0,toolCallId:Y.tool_call_id??void 0,toolCalls:Y.tool_calls?(()=>{try{return JSON.parse(Y.tool_calls)}catch{O.warn(`[getSession] Corrupted tool_calls JSON in message row ${Y.id} (session ${J})`);return}})():void 0,thinking:Y.thinking?(()=>{try{return JSON.parse(Y.thinking)}catch{O.warn(`[getSession] Corrupted thinking JSON in message row ${Y.id} (session ${J})`);return}})():void 0,createdAt:new Date(Y.created_at)}))}}deleteSession(J){this.db.prepare("DELETE FROM sessions WHERE id = ?").run(J)}setSessionTitle(J,K){try{this.db.prepare("UPDATE sessions SET title = ? WHERE id = ?").run(K,J)}catch(X){O.warn("[SessionHistory] Failed to set session title:",X?.message??X)}}markCompleted(J){try{let K=new Date().toISOString();this.withImmediateTransaction(()=>{this.db.prepare(`UPDATE sessions
|
|
280
|
+
SET completed_at = COALESCE(completed_at, ?),
|
|
281
|
+
updated_at = ?
|
|
282
|
+
WHERE id = ?`).run(K,K,J),this.ensureSessionRuntimeRow(J),this.db.prepare(`UPDATE session_runtime_state
|
|
283
|
+
SET state_status = 'completed',
|
|
284
|
+
active_run_id = NULL,
|
|
285
|
+
paused_state_json = NULL,
|
|
286
|
+
policy_snapshot_json = NULL,
|
|
287
|
+
lease_owner = NULL,
|
|
288
|
+
lease_expires_at = NULL,
|
|
289
|
+
revision = revision + 1,
|
|
290
|
+
updated_at = ?
|
|
291
|
+
WHERE session_id = ?`).run(K,J)})}catch(K){O.warn("[SessionHistory] Failed to mark session completed:",K?.message??K)}}markStaleSessionsCompleted(J){try{let K=new Date(Date.now()-J*86400000).toISOString(),X=new Date().toISOString();return this.db.prepare(`UPDATE sessions
|
|
292
|
+
SET completed_at = COALESCE(completed_at, ?),
|
|
293
|
+
updated_at = ?
|
|
294
|
+
WHERE completed_at IS NULL
|
|
295
|
+
AND message_count > 0
|
|
296
|
+
AND updated_at < ?`).run(X,X,K).changes}catch(K){return O.warn("[SessionHistory] Failed to mark stale sessions completed:",K?.message??K),0}}getIncompleteSessions(J=10){return this.db.prepare(`
|
|
297
|
+
SELECT
|
|
298
|
+
s.*,
|
|
299
|
+
(SELECT content FROM messages WHERE session_id = s.id AND role = 'user' ORDER BY id LIMIT 1) as preview
|
|
300
|
+
FROM sessions s
|
|
301
|
+
WHERE s.message_count > 0
|
|
302
|
+
AND s.completed_at IS NULL
|
|
303
|
+
ORDER BY s.updated_at DESC, s.rowid DESC
|
|
304
|
+
LIMIT ?
|
|
305
|
+
`).all(J).map((X)=>({id:X.id,createdAt:new Date(X.created_at),updatedAt:new Date(X.updated_at),completedAt:X.completed_at?new Date(X.completed_at):void 0,title:X.title,arion:X.arion,model:X.model,messageCount:X.message_count,preview:this.truncatePreview(X.preview??"",60)}))}findSessionByPrefix(J){if(J.length===36)return this.db.prepare("SELECT id FROM sessions WHERE id = ? AND message_count > 0").get(J)?.id??null;if(J.length<8)return null;let K=this.db.prepare("SELECT id FROM sessions WHERE id LIKE ? AND message_count > 0 LIMIT 2").all(`${J}%`);return K.length===1?K[0].id:null}getSessionCount(){return this.db.prepare("SELECT COUNT(*) as count FROM sessions WHERE message_count > 0").get()?.count??0}truncatePreview(J,K){if(J.length<=K)return J;return J.slice(0,K-3)+"..."}addInputHistory(J){try{let K=new Date().toISOString();this.db.prepare(`
|
|
306
|
+
INSERT INTO input_history (content, used_at)
|
|
307
|
+
VALUES (?, ?)
|
|
308
|
+
ON CONFLICT(content) DO UPDATE SET used_at = excluded.used_at
|
|
309
|
+
`).run(J,K),this.db.prepare(`
|
|
310
|
+
DELETE FROM input_history
|
|
311
|
+
WHERE id NOT IN (
|
|
312
|
+
SELECT id FROM input_history ORDER BY used_at DESC LIMIT 500
|
|
313
|
+
)
|
|
314
|
+
`).run()}catch(K){O.warn("[SessionHistory] Failed to save input history:",K?.message??K)}}getInputHistory(J=100){return this.db.prepare(`
|
|
315
|
+
SELECT content FROM input_history
|
|
316
|
+
ORDER BY used_at DESC
|
|
317
|
+
LIMIT ?
|
|
318
|
+
`).all(J).map((X)=>X.content)}saveRunMetrics(J,K){try{this.db.prepare(`INSERT INTO run_metrics (id, session_id, turn_count, input_tokens, output_tokens, total_tokens, estimated_cost, wall_time_ms, tool_count, guardrail_fires, handoff_count)
|
|
319
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(K.id,J,K.turnCount??null,K.inputTokens??null,K.outputTokens??null,K.totalTokens??null,K.estimatedCost??null,K.wallTimeMs??null,K.toolCount??null,K.guardrailFires??null,K.handoffCount??null)}catch(X){O.warn("[SessionHistory] Failed to save run metrics:",X?.message??X)}}getRunMetrics(J){return this.db.prepare("SELECT * FROM run_metrics WHERE session_id = ? ORDER BY created_at ASC").all(J).map((X)=>({id:X.id,sessionId:X.session_id,turnCount:X.turn_count??void 0,inputTokens:X.input_tokens??void 0,outputTokens:X.output_tokens??void 0,totalTokens:X.total_tokens??void 0,estimatedCost:X.estimated_cost??void 0,wallTimeMs:X.wall_time_ms??void 0,toolCount:X.tool_count??void 0,guardrailFires:X.guardrail_fires??void 0,handoffCount:X.handoff_count??void 0,createdAt:X.created_at}))}close(){try{this.db.pragma("wal_checkpoint(TRUNCATE)")}catch{}this.db.close()}}function XJ(J){return typeof J!=="string"||J.trim().length>0}function YJ(J){let{toolCalls:K,...X}=J;return X}function ZJ(J,K,X){for(let Y=K;Y<J.length;Y++){let Z=J[Y];if(Z.role==="tool"&&Z.toolCallId===X)return!0}return!1}function $J(J){let K=[];for(let X=0;X<J.length;X++){let Y=J[X];if(Y.role==="assistant"&&Y.toolCalls?.length){let Z=new Set(Y.toolCalls.map((V)=>V.id)),W=new Set,$=[],Q=X+1;while(Q<J.length&&J[Q].role==="tool"){let V=J[Q];if(V.toolCallId&&Z.has(V.toolCallId)&&!W.has(V.toolCallId))W.add(V.toolCallId),$.push(V);Q++}let F=Y.toolCalls.filter((V)=>{if(W.has(V.id))return!0;return!ZJ(J,Q,V.id)}),G=F.filter((V)=>!W.has(V.id));if(F.length===Y.toolCalls.length)K.push(Y);else if(F.length>0)K.push({...Y,toolCalls:F});else if(XJ(Y.content))K.push(YJ(Y));K.push(...$);for(let V of G)K.push({role:"tool",content:`[Tool execution interrupted — no result for ${V.name}]`,toolCallId:V.id});X=Q-1;continue}if(Y.role==="tool")continue;K.push(Y)}return K}class D{textParts=[];thinkingBlocks=[];toolUseBlocks=[];handoffBlocks=[];toolResultMessages=[];seenToolIds=new Set;toolArgsAccumulator=new Map;thinkingInProgress=!1;pendingThinkingContent="";arion;verb;tokenUsage;snapshotMessages;previewAssistantId=`preview-${Date.now()}`;ingest(J){switch(J.type){case"text_delta":return this.textParts.push(J.content),"continue";case"thinking_start":return this.thinkingInProgress=!0,this.pendingThinkingContent="","continue";case"thinking_delta":return this.pendingThinkingContent+=J.content,"continue";case"thinking_end":{this.thinkingInProgress=!1;let K=Array.isArray(J.blocks)&&J.blocks.length>0?J.blocks[0]:void 0,X=typeof K?.thinking==="string"?K.thinking:this.pendingThinkingContent,Y=X.split(/\s+/).filter(Boolean).length,Z={type:"thinking",content:X,wordCount:Y,durationMs:J.durationMs,verb:this.verb};return this.thinkingBlocks.push(Z),this.pendingThinkingContent="","continue"}case"tool_start":{if(this.seenToolIds.has(J.id))return"continue";this.seenToolIds.add(J.id);let K={type:"tool_use",id:J.id,name:J.name,arguments:J.input??{}};return this.toolUseBlocks.push(K),"continue"}case"tool_args_delta":{let X=(this.toolArgsAccumulator.get(J.id)??"")+J.args;this.toolArgsAccumulator.set(J.id,X);try{let Y=JSON.parse(X),Z=this.toolUseBlocks.find((W)=>W.type==="tool_use"&&W.id===J.id);if(Z)Z.arguments=Y}catch{}return"continue"}case"tool_result":{if(J.input){let W=this.toolUseBlocks.find(($)=>$.type==="tool_use"&&$.id===J.id);if(W){let $=typeof J.input==="object"&&!Array.isArray(J.input)?J.input:{};if(Object.keys(W.arguments).length===0)W.arguments=$}}let K=J.result,X="usage"in J&&J.usage&&typeof J.usage==="object"&&typeof J.usage.inputTokens==="number"&&typeof J.usage.outputTokens==="number"&&typeof J.usage.totalTokens==="number"&&typeof J.usage.estimatedCost==="number"?J.usage:void 0,Y={type:"tool_result",toolUseId:J.id,content:typeof K.message==="string"?K.message:"",status:K.success===!0?"success":"error",durationMs:J.durationMs,resultData:K.data,usage:X},Z={id:crypto.randomUUID(),role:"tool",content:[Y],arion:this.arion,createdAt:new Date().toISOString()};return this.toolResultMessages.push(Z),"continue"}case"handoff_start":{let K={type:"handoff",target:J.target,direction:"to"};return this.handoffBlocks.push(K),"continue"}case"handoff_result":{let K={type:"handoff",target:J.target,direction:"from"};return this.handoffBlocks.push(K),"continue"}case"turn_complete":return"flush";case"messages_snapshot":return this.snapshotMessages=J.messages,"continue";default:return"continue"}}flush(){let J=[];if(this.thinkingInProgress&&this.pendingThinkingContent){let Y=this.pendingThinkingContent.trim(),Z=Y.length===0?0:Y.split(/\s+/).length,W={type:"thinking",content:this.pendingThinkingContent,wordCount:Z,verb:this.verb};this.thinkingBlocks.push(W)}let K=[];K.push(...this.thinkingBlocks);let X=this.textParts.join("");if(X)K.push({type:"text",text:X});if(K.push(...this.toolUseBlocks),K.push(...this.handoffBlocks),K.length>0){let Y={id:crypto.randomUUID(),role:"assistant",content:K,arion:this.arion,tokenUsage:this.tokenUsage,createdAt:new Date().toISOString()};J.push(Y)}if(J.push(...this.toolResultMessages),this.toolResultMessages.length>0&&this.toolUseBlocks.length>0){let Y=new Set(this.toolResultMessages.flatMap((Z)=>Z.content.filter((W)=>W.type==="tool_result").map((W)=>W.toolUseId)));for(let Z of this.toolUseBlocks){let W=Z.id;if(W&&!Y.has(W)){let $={id:crypto.randomUUID(),role:"tool",content:[{type:"tool_result",toolUseId:W,content:"Tool execution cancelled by user.",status:"error"}],arion:this.arion,createdAt:new Date().toISOString()};J.push($)}}}return this.textParts=[],this.thinkingBlocks=[],this.toolUseBlocks=[],this.handoffBlocks=[],this.toolResultMessages=[],this.seenToolIds=new Set,this.toolArgsAccumulator=new Map,this.thinkingInProgress=!1,this.pendingThinkingContent="",this.tokenUsage=void 0,this.verb=void 0,this.previewAssistantId=`preview-${Date.now()}`,J}snapshot(){let J=[];if(J.push(...this.thinkingBlocks.map((Y)=>({...Y}))),this.thinkingInProgress&&this.pendingThinkingContent){let Y=this.pendingThinkingContent,Z={type:"thinking",content:Y,wordCount:Y.split(/\s+/).filter(Boolean).length,verb:this.verb};J.push(Z)}let K=this.textParts.join("");if(K){let Y=K.lastIndexOf(`
|
|
320
|
+
`);if(Y>=0)J.push({type:"text",text:K.slice(0,Y+1)})}for(let Y of this.toolUseBlocks){let Z={...Y};if(Z.type==="tool_use"&&Object.keys(Z.arguments).length===0){let W=this.toolArgsAccumulator.get(Z.id);if(W){let $=D.tryParsePartialArgs(W);if($)Z.arguments=$}}J.push(Z)}J.push(...this.handoffBlocks.map((Y)=>({...Y})));let X=[];if(J.length>0)X.push({id:this.previewAssistantId,role:"assistant",content:J,arion:this.arion,createdAt:new Date().toISOString()});return X.push(...this.toolResultMessages.map((Y)=>({...Y,content:[...Y.content]}))),X}getSnapshotMessages(){return this.snapshotMessages}hasPendingContent(){return this.textParts.length>0||this.thinkingBlocks.length>0||this.toolUseBlocks.length>0||this.handoffBlocks.length>0||this.toolResultMessages.length>0||this.thinkingInProgress}setArion(J){this.arion=J}setVerb(J){this.verb=J}setTokenUsage(J){if(this.tokenUsage)this.tokenUsage={input:this.tokenUsage.input+J.input,output:this.tokenUsage.output+J.output};else this.tokenUsage={...J}}static tryParsePartialArgs(J){let K=J.trim();if(!K.startsWith("{")||K.length<4)return;try{return JSON.parse(K)}catch{}try{let X=JSON.parse(K+"}");if(Object.keys(X).length>0)return X}catch{}try{let X=JSON.parse(K+'"}');if(Object.keys(X).length>0)return X}catch{}for(let X=K.length-1;X>0;X--)if(K[X]===",")try{let Y=JSON.parse(K.slice(0,X)+"}");if(Object.keys(Y).length>0)return Y}catch{}return}}import{readFileSync as WJ,existsSync as z}from"node:fs";function b(J){if(!z(J))return[];let X=WJ(J,"utf-8").split(`
|
|
321
|
+
`).filter((W)=>W.trim().length>0),Y=new D,Z=[];for(let W of X){let $;try{$=JSON.parse(W)}catch{continue}if(!$.event||typeof $.event.type!=="string")continue;if($.event.type==="user_message"){if(Y.hasPendingContent())Z.push(...Y.flush());let F=$.event.content??"",G=$.event.id,V=R(F);if(G)V.id=G;Z.push(V);continue}if(Y.ingest($.event)==="flush"){let F=Y.flush();Z.push(...F)}}if(Y.hasPendingContent()){let W=Y.flush();Z.push(...W)}return Z}function u(J){for(let X of J.content){if(X.type==="tool_use"&&X.id)return`tool_use:${X.id}`;if(X.type==="tool_result"&&X.toolUseId)return`tool_result:${X.toolUseId}`}let K=J.content.filter((X)=>X.type==="text").map((X)=>X.text).join("");return`${J.role}:${K}`}function HJ(J,K){if(!K)return{messages:J,backfillMessages:[]};let X;try{X=b(K)}catch{return{messages:J,backfillMessages:[]}}if(X.length===0)return{messages:J,backfillMessages:[]};if(J.length>=X.length)return{messages:J,backfillMessages:[]};let Y=new Set(J.map(u)),Z=[];for(let $ of X){let Q=u($);if(!Y.has(Q))Z.push($)}return{messages:[...J,...Z],backfillMessages:Z}}function QJ(J,K,X){let Y=`${J}/arions/${K}/logs/${X}.jsonl`;if(z(Y))return Y;let Z=`${J}/logs/${X}.jsonl`;if(z(Z))return Z;return null}export{VJ as C,x as D,M as E,FJ as F,GJ as G,f as H,v as I,T as J,R as K,i as L,n as M,r as N,t as O,e as P,B as Q,o as R,L as S,U as T,S as U,q as V,k as W,$J as X,D as Y,b as Z,HJ as _,QJ as $};
|