@automagik/genie 4.260421.9 → 4.260421.11
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/genie.js
CHANGED
|
@@ -59,16 +59,43 @@ ${readFileSync4(params.extraArgs[fileIdx+1],"utf-8")}`,params.extraArgs.splice(f
|
|
|
59
59
|
`,lastSeenId=Number(seed[0]?.max_id??0),active=!0,drainChain=Promise.resolve(),drain=async()=>{if(!active)return;let conditions=["id > $1"],values=[lastSeenId],paramIdx=2;if(options.type)conditions.push(`event_type = $${paramIdx++}`),values.push(options.type);if(options.entity)conditions.push(`(entity_type = $${paramIdx} OR entity_id = $${paramIdx})`),paramIdx++,values.push(options.entity);if(options.errorsOnly)conditions.push("(event_type LIKE '%error%' OR details::text LIKE '%error%')");let where=`WHERE ${conditions.join(" AND ")}`,rows=await sql.unsafe(`SELECT id, entity_type, entity_id, event_type, actor, details, created_at
|
|
60
60
|
FROM audit_events ${where}
|
|
61
61
|
ORDER BY id ASC
|
|
62
|
-
LIMIT 200`,values);for(let row of rows)lastSeenId=row.id,onEvent(row)},queueDrain=()=>{drainChain=drainChain.then(drain).catch(()=>{})},listener=await sql.listen("genie_audit_event",()=>{queueDrain()}),pollTimer=setInterval(queueDrain,2000);return await drain(),{stop:async()=>{active=!1,clearInterval(pollTimer),await drainChain,await listener.unlisten()}}}async function queryErrorPatterns(since){let sql=await getConnection(),sinceTs=since?parseSince(since):new Date(Date.now()-86400000).toISOString()
|
|
62
|
+
LIMIT 200`,values);for(let row of rows)lastSeenId=row.id,onEvent(row)},queueDrain=()=>{drainChain=drainChain.then(drain).catch(()=>{})},listener=await sql.listen("genie_audit_event",()=>{queueDrain()}),pollTimer=setInterval(queueDrain,2000);return await drain(),{stop:async()=>{active=!1,clearInterval(pollTimer),await drainChain,await listener.unlisten()}}}async function queryErrorPatterns(since){let sql=await getConnection(),sinceTs=since?parseSince(since):new Date(Date.now()-86400000).toISOString(),messageExpr=`COALESCE(
|
|
63
|
+
NULLIF(details->>'error', ''),
|
|
64
|
+
NULLIF(details->>'message', ''),
|
|
65
|
+
NULLIF(details->>'error_type', ''),
|
|
66
|
+
NULLIF(details->>'reason', ''),
|
|
67
|
+
NULLIF(details->>'stderr', ''),
|
|
68
|
+
'(no message)'
|
|
69
|
+
)`;return await sql.unsafe(`SELECT
|
|
63
70
|
event_type,
|
|
64
71
|
entity_id,
|
|
65
|
-
COALESCE(
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
COALESCE(
|
|
73
|
+
NULLIF(details->>'error', ''),
|
|
74
|
+
NULLIF(details->>'message', ''),
|
|
75
|
+
NULLIF(details->>'error_type', ''),
|
|
76
|
+
NULLIF(details->>'reason', ''),
|
|
77
|
+
NULLIF(details->>'stderr', ''),
|
|
78
|
+
'(no message)'
|
|
79
|
+
) AS error_message,
|
|
80
|
+
COUNT(*)::int AS count,
|
|
81
|
+
MAX(created_at) AS last_seen
|
|
68
82
|
FROM audit_events
|
|
69
|
-
WHERE (
|
|
83
|
+
WHERE (
|
|
84
|
+
event_type LIKE '%error%'
|
|
85
|
+
OR event_type LIKE '%failed%'
|
|
86
|
+
OR event_type LIKE 'rot.%'
|
|
87
|
+
OR details ? 'error'
|
|
88
|
+
OR (event_type = 'state_changed' AND details->>'state' = 'error')
|
|
89
|
+
)
|
|
70
90
|
AND created_at >= $1::timestamptz
|
|
71
|
-
GROUP BY event_type, entity_id, COALESCE(
|
|
91
|
+
GROUP BY event_type, entity_id, COALESCE(
|
|
92
|
+
NULLIF(details->>'error', ''),
|
|
93
|
+
NULLIF(details->>'message', ''),
|
|
94
|
+
NULLIF(details->>'error_type', ''),
|
|
95
|
+
NULLIF(details->>'reason', ''),
|
|
96
|
+
NULLIF(details->>'stderr', ''),
|
|
97
|
+
'(no message)'
|
|
98
|
+
)
|
|
72
99
|
ORDER BY count DESC
|
|
73
100
|
LIMIT 50`,[sinceTs])}function getActor(){return process.env.GENIE_AGENT_NAME??"cli"}async function queryCostBreakdown(since,groupBy="agent"){let sql=await getConnection(),sinceTs=parseSince(since),groupExpr=groupBy==="agent"?"COALESCE(actor, 'unknown')":groupBy==="wish"?"COALESCE(details->>'wish_slug', entity_id)":"COALESCE(details->>'model', 'unknown')";return await sql.unsafe(`SELECT
|
|
74
101
|
${groupExpr} AS group_key,
|
|
@@ -727,7 +754,7 @@ Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.
|
|
|
727
754
|
UPDATE agents
|
|
728
755
|
SET metadata = metadata || ${sql.json(metadataPatch)}
|
|
729
756
|
WHERE role = ${name}
|
|
730
|
-
`}catch{}return updated}function loadIdentity(entry2){if(!entry2.dir)return null;let agentsPath=join25(entry2.dir,"AGENTS.md");if(existsSync23(agentsPath))return agentsPath;return null}function builtinToEntry(agent){return{name:agent.name,dir:"",promptMode:agent.promptMode??"append",model:agent.model,roles:[],registeredAt:"(built-in)"}}function roleToEntry(role,team,metadata,createdAt){if(!(metadata&&Object.keys(metadata).length>0)){let builtin=[...BUILTIN_ROLES,...BUILTIN_COUNCIL_MEMBERS].find((b2)=>b2.name===role);if(builtin)return builtinToEntry(builtin)}let registeredAt=(typeof metadata?.registeredAt==="string"?metadata.registeredAt:void 0)??createdAt??"";return{name:role,dir:metadata?.dir||"",promptMode:metadata?.promptMode||"append",model:metadata?.model,roles:[],registeredAt,description:metadata?.description,color:metadata?.color,provider:metadata?.provider,permissions:metadata?.permissions,disallowedTools:metadata?.disallowedTools,omniScopes:metadata?.omniScopes,hooks:metadata?.hooks,sdk:metadata?.sdk,...metadata?.repo?{repo:metadata.repo}:team?{repo:team}:{}}}function buildMetadata(entry2){let meta={};if(entry2.dir)meta.dir=entry2.dir;if(entry2.repo)meta.repo=entry2.repo;if(entry2.model)meta.model=entry2.model;if(entry2.promptMode&&entry2.promptMode!=="append")meta.promptMode=entry2.promptMode;if(entry2.description)meta.description=entry2.description;if(entry2.color)meta.color=entry2.color;if(entry2.provider)meta.provider=entry2.provider;if(entry2.permissions)meta.permissions=entry2.permissions;if(entry2.disallowedTools)meta.disallowedTools=entry2.disallowedTools;if(entry2.omniScopes)meta.omniScopes=entry2.omniScopes;if(entry2.hooks)meta.hooks=entry2.hooks;if(entry2.sdk)meta.sdk=entry2.sdk;return meta}function parseMetadata(raw){if(!raw)return{};if(typeof raw==="object"&&!Array.isArray(raw))return raw;if(typeof raw==="string")try{return JSON.parse(raw)}catch{return{}}return{}}var init_agent_directory=__esm(()=>{init_builtin_agents()});var exports_runtime_events={};__export(exports_runtime_events,{waitForRuntimeEvent:()=>waitForRuntimeEvent,publishSubjectEvent:()=>publishSubjectEvent,publishRuntimeEvent:()=>publishRuntimeEvent,listRuntimeEvents:()=>listRuntimeEvents,getLatestRuntimeEventId:()=>getLatestRuntimeEventId,
|
|
757
|
+
`}catch{}return updated}function loadIdentity(entry2){if(!entry2.dir)return null;let agentsPath=join25(entry2.dir,"AGENTS.md");if(existsSync23(agentsPath))return agentsPath;return null}function builtinToEntry(agent){return{name:agent.name,dir:"",promptMode:agent.promptMode??"append",model:agent.model,roles:[],registeredAt:"(built-in)"}}function roleToEntry(role,team,metadata,createdAt){if(!(metadata&&Object.keys(metadata).length>0)){let builtin=[...BUILTIN_ROLES,...BUILTIN_COUNCIL_MEMBERS].find((b2)=>b2.name===role);if(builtin)return builtinToEntry(builtin)}let registeredAt=(typeof metadata?.registeredAt==="string"?metadata.registeredAt:void 0)??createdAt??"";return{name:role,dir:metadata?.dir||"",promptMode:metadata?.promptMode||"append",model:metadata?.model,roles:[],registeredAt,description:metadata?.description,color:metadata?.color,provider:metadata?.provider,permissions:metadata?.permissions,disallowedTools:metadata?.disallowedTools,omniScopes:metadata?.omniScopes,hooks:metadata?.hooks,sdk:metadata?.sdk,...metadata?.repo?{repo:metadata.repo}:team?{repo:team}:{}}}function buildMetadata(entry2){let meta={};if(entry2.dir)meta.dir=entry2.dir;if(entry2.repo)meta.repo=entry2.repo;if(entry2.model)meta.model=entry2.model;if(entry2.promptMode&&entry2.promptMode!=="append")meta.promptMode=entry2.promptMode;if(entry2.description)meta.description=entry2.description;if(entry2.color)meta.color=entry2.color;if(entry2.provider)meta.provider=entry2.provider;if(entry2.permissions)meta.permissions=entry2.permissions;if(entry2.disallowedTools)meta.disallowedTools=entry2.disallowedTools;if(entry2.omniScopes)meta.omniScopes=entry2.omniScopes;if(entry2.hooks)meta.hooks=entry2.hooks;if(entry2.sdk)meta.sdk=entry2.sdk;return meta}function parseMetadata(raw){if(!raw)return{};if(typeof raw==="object"&&!Array.isArray(raw))return raw;if(typeof raw==="string")try{return JSON.parse(raw)}catch{return{}}return{}}var init_agent_directory=__esm(()=>{init_builtin_agents()});var exports_runtime_events={};__export(exports_runtime_events,{waitForRuntimeEvent:()=>waitForRuntimeEvent,queryRuntimeEventThroughput:()=>queryRuntimeEventThroughput,publishSubjectEvent:()=>publishSubjectEvent,publishRuntimeEvent:()=>publishRuntimeEvent,listRuntimeEvents:()=>listRuntimeEvents,getLatestRuntimeEventId:()=>getLatestRuntimeEventId,followRuntimeEvents:()=>followRuntimeEvents});class EventCircuitBreaker{failures=0;lastFailure=0;loggedOpen=!1;threshold=5;cooldown=30000;isOpen(){if(this.failures<this.threshold)return!1;if(Date.now()-this.lastFailure>this.cooldown)return this.failures=0,!1;return!0}recordSuccess(){if(this.failures>=this.threshold)console.warn("[runtime-events] circuit breaker closed \u2014 PG writes resumed");this.failures=0,this.loggedOpen=!1}recordFailure(){if(this.failures++,this.lastFailure=Date.now(),this.failures>=this.threshold&&!this.loggedOpen)console.warn(`[runtime-events] circuit breaker open \u2014 skipping PG writes for ${this.cooldown/1000}s after ${this.threshold} consecutive failures`),this.loggedOpen=!0}get state(){if(this.failures<this.threshold)return"closed";if(Date.now()-this.lastFailure>this.cooldown)return"half-open";return"open"}}function logFollowDrainError(context,error2,active){if(!active)return;let message=error2 instanceof Error?error2.message:String(error2);console.error(`[runtime-events] ${context} drain failed: ${message}`)}function rowToRuntimeEvent(row){return{id:Number(row.id),repoPath:row.repo_path,timestamp:row.created_at instanceof Date?row.created_at.toISOString():String(row.created_at),kind:row.kind,agent:row.agent,team:row.team??void 0,direction:row.direction??void 0,peer:row.peer??void 0,text:row.text,data:row.data??void 0,source:row.source,subject:row.subject??void 0,threadId:row.thread_id??void 0,traceId:row.trace_id??void 0,parentEventId:row.parent_event_id!=null?Number(row.parent_event_id):void 0}}function nextParam(values2,value){return values2.push(value),`$${values2.length}`}function buildScopeClause(query,values2){let scopeClauses=[];if(query.agentIds&&query.agentIds.length>0)scopeClauses.push(`agent = ANY(${nextParam(values2,query.agentIds)})`);if(query.team)scopeClauses.push(`team = ${nextParam(values2,query.team)}`);if(query.teamPrefix)scopeClauses.push(`team LIKE ${nextParam(values2,`${query.teamPrefix}%`)}`);if(scopeClauses.length===0)return null;if(scopeClauses.length===1)return scopeClauses[0];if(query.scopeMode==="any")return`(${scopeClauses.join(" OR ")})`;return`(${scopeClauses.join(" AND ")})`}function buildWhere(query){let values2=[],clauses=[];if(query.afterId!=null)clauses.push(`id > ${nextParam(values2,query.afterId)}`);if(query.repoPath)clauses.push(`repo_path = ${nextParam(values2,query.repoPath)}`);if(query.subject)clauses.push(`subject = ${nextParam(values2,query.subject)}`);if(query.kinds&&query.kinds.length>0)clauses.push(`kind = ANY(${nextParam(values2,query.kinds)})`);if(query.since)clauses.push(`created_at >= ${nextParam(values2,query.since)}`);if(query.threadId)clauses.push(`thread_id = ${nextParam(values2,query.threadId)}`);if(query.traceId)clauses.push(`trace_id = ${nextParam(values2,query.traceId)}`);let scopeClause=buildScopeClause(query,values2);if(scopeClause)clauses.push(scopeClause);return{clause:clauses.length>0?`WHERE ${clauses.join(" AND ")}`:"",values:values2}}async function publishRuntimeEvent(input){if(circuitBreaker.isOpen())throw Error("circuit breaker open \u2014 PG event write skipped");try{let sql=await getConnection(),threadId=input.threadId??`agent:${input.agent}`,rows=await sql`
|
|
731
758
|
INSERT INTO genie_runtime_events (
|
|
732
759
|
repo_path, subject, kind, source, agent, team, direction, peer, text, data, thread_id, trace_id, parent_event_id, created_at
|
|
733
760
|
)
|
|
@@ -748,7 +775,11 @@ Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.
|
|
|
748
775
|
${input.timestamp??new Date().toISOString()}
|
|
749
776
|
)
|
|
750
777
|
RETURNING id, repo_path, subject, kind, source, agent, team, direction, peer, text, data, thread_id, trace_id, parent_event_id, created_at
|
|
751
|
-
`;return circuitBreaker.recordSuccess(),
|
|
778
|
+
`;return circuitBreaker.recordSuccess(),rowToRuntimeEvent(rows[0])}catch(error2){throw circuitBreaker.recordFailure(),error2}}async function publishSubjectEvent(repoPath,subject,event){return publishRuntimeEvent({...event,repoPath,subject})}async function queryRuntimeEventThroughput(windowSeconds=60){if(!Number.isFinite(windowSeconds)||windowSeconds<=0)throw Error(`windowSeconds must be a positive number, got ${windowSeconds}`);return{emitted:(await(await getConnection())`
|
|
779
|
+
SELECT COUNT(*)::int AS emitted
|
|
780
|
+
FROM genie_runtime_events
|
|
781
|
+
WHERE created_at > NOW() - make_interval(secs => ${windowSeconds})
|
|
782
|
+
`)[0]?.emitted??0}}async function listRuntimeEvents(query={}){let sql=await getConnection(),{clause,values:values2}=buildWhere(query),limit=query.limit??500;return(await sql.unsafe(`
|
|
752
783
|
SELECT id, repo_path, subject, kind, source, agent, team, direction, peer, text, data, thread_id, trace_id, parent_event_id, created_at
|
|
753
784
|
FROM genie_runtime_events
|
|
754
785
|
${clause}
|
|
@@ -756,7 +787,7 @@ Next steps:`),console.log(" 1. Reload tmux: tmux source ~/.tmux.conf"),console.
|
|
|
756
787
|
LIMIT $${values2.length+1}
|
|
757
788
|
`,[...values2,limit])).map(rowToRuntimeEvent)}async function getLatestRuntimeEventId(){let rows=await(await getConnection())`
|
|
758
789
|
SELECT COALESCE(MAX(id), 0) AS max_id FROM genie_runtime_events
|
|
759
|
-
`;return Number(rows[0]?.max_id??0)}async function followRuntimeEvents(query,onEvent,options){let sql=await getConnection(),active=!0,lastSeenId=query.afterId??await getLatestRuntimeEventId(),drainChain=Promise.resolve(),drain=async()=>{if(!active)return;let events=await listRuntimeEvents({...query,afterId:lastSeenId});for(let event of events)lastSeenId=event.id,onEvent(event)},queueDrain=(context)=>{drainChain=drainChain.then(drain).catch((error2)=>{logFollowDrainError(context,error2,active)})},listener=await sql.listen("genie_runtime_event",()=>{queueDrain("notify")});await drain();let pollIntervalMs=options?.pollIntervalMs??1000,pollTimer=setInterval(()=>{queueDrain("poll")},pollIntervalMs);return{mode:"pg",stop:async()=>{active=!1,clearInterval(pollTimer);try{await drainChain}catch{}try{await listener.unlisten()}catch{}}}}async function waitForRuntimeEvent(query,timeoutMs,predicate){let afterId=query.afterId??0;return new Promise((resolve5,reject)=>{let settled=!1,handle=null,timer2=null,finish=async(event)=>{if(settled)return;if(settled=!0,timer2)clearTimeout(timer2);try{if(handle)await handle.stop()}catch{}resolve5(event)};(async()=>{try{if(handle=await followRuntimeEvents({...query,afterId},(event)=>{if(predicate&&!predicate(event))return;finish(event)},{pollIntervalMs:250}),settled){try{await handle.stop()}catch{}return}timer2=setTimeout(()=>{finish(null)},timeoutMs)}catch(err){if(!settled)settled=!0,reject(err)}})()})}var circuitBreaker
|
|
790
|
+
`;return Number(rows[0]?.max_id??0)}async function followRuntimeEvents(query,onEvent,options){let sql=await getConnection(),active=!0,lastSeenId=query.afterId??await getLatestRuntimeEventId(),drainChain=Promise.resolve(),drain=async()=>{if(!active)return;let events=await listRuntimeEvents({...query,afterId:lastSeenId});for(let event of events)lastSeenId=event.id,onEvent(event)},queueDrain=(context)=>{drainChain=drainChain.then(drain).catch((error2)=>{logFollowDrainError(context,error2,active)})},listener=await sql.listen("genie_runtime_event",()=>{queueDrain("notify")});await drain();let pollIntervalMs=options?.pollIntervalMs??1000,pollTimer=setInterval(()=>{queueDrain("poll")},pollIntervalMs);return{mode:"pg",stop:async()=>{active=!1,clearInterval(pollTimer);try{await drainChain}catch{}try{await listener.unlisten()}catch{}}}}async function waitForRuntimeEvent(query,timeoutMs,predicate){let afterId=query.afterId??0;return new Promise((resolve5,reject)=>{let settled=!1,handle=null,timer2=null,finish=async(event)=>{if(settled)return;if(settled=!0,timer2)clearTimeout(timer2);try{if(handle)await handle.stop()}catch{}resolve5(event)};(async()=>{try{if(handle=await followRuntimeEvents({...query,afterId},(event)=>{if(predicate&&!predicate(event))return;finish(event)},{pollIntervalMs:250}),settled){try{await handle.stop()}catch{}return}timer2=setTimeout(()=>{finish(null)},timeoutMs)}catch(err){if(!settled)settled=!0,reject(err)}})()})}var circuitBreaker;var init_runtime_events=__esm(()=>{init_db();circuitBreaker=new EventCircuitBreaker});var exports_interactivity={};__export(exports_interactivity,{isInteractive:()=>isInteractive,installWorkspaceCheck:()=>installWorkspaceCheck,ensureWorkspace:()=>ensureWorkspace,commandRequiresWorkspace:()=>commandRequiresWorkspace});function isInteractive(){if(!process.stdout.isTTY)return!1;if(process.env.CI)return!1;if(process.argv.includes("--no-interactive"))return!1;return!0}function getRootCommandName(cmd){let current=cmd;while(current.parent?.parent)current=current.parent;return current.name()}function commandRequiresWorkspace(cmd){return!WORKSPACE_EXEMPT.has(getRootCommandName(cmd))}async function ensureWorkspace(){if(findWorkspace())return;if(!isInteractive())console.error("No workspace found. Run `genie init` to set up."),process.exit(2);let{confirm}=await Promise.resolve().then(() => (init_esm14(),exports_esm));if(!await confirm({message:"No workspace found. Initialize? [Y/n]",default:!0}))console.error("No workspace found. Run `genie init` to set up."),process.exit(2);let{mkdirSync:mkdirSync11,writeFileSync:writeFileSync10}=await import("fs"),{basename:basename5,join:join28}=await import("path"),cwd=process.cwd(),genieDir=join28(cwd,".genie");mkdirSync11(genieDir,{recursive:!0});let config={name:basename5(cwd),agents:{defaults:{}},tmux:{socket:"genie"},sdk:{}};writeFileSync10(join28(genieDir,"workspace.json"),`${JSON.stringify(config,null,2)}
|
|
760
791
|
`),console.log(`Workspace initialized: ${cwd}`)}function installWorkspaceCheck(program2){program2.hook("preAction",async(_thisCommand,actionCommand)=>{if(!commandRequiresWorkspace(actionCommand))return;await ensureWorkspace()})}var WORKSPACE_EXEMPT;var init_interactivity=__esm(()=>{init_workspace();WORKSPACE_EXEMPT=new Set(["init","setup","doctor","update","uninstall","shortcuts","team","version","help"])});function extractValue(kv){let v=kv.value;if(v.stringValue!==void 0)return v.stringValue;if(v.intValue!==void 0)return typeof v.intValue==="string"?Number.parseInt(v.intValue,10):v.intValue;if(v.doubleValue!==void 0)return v.doubleValue;if(v.boolValue!==void 0)return v.boolValue;return}function attrsToObject(attrs){if(!attrs)return{};let obj={};for(let kv of attrs)obj[kv.key]=extractValue(kv);return obj}function extractResourceContext(resource){let attrs=attrsToObject(resource?.attributes);return{agentName:attrs["agent.name"],teamName:attrs["team.name"],wishSlug:attrs["wish.slug"],sessionId:attrs["session.id"],agentRole:attrs["agent.role"]}}function mapEventToEntityType(eventName){if(eventName.includes("tool_result"))return"otel_tool";if(eventName.includes("api_request")||eventName.includes("api_error"))return"otel_api";if(eventName.includes("user_prompt"))return"otel_prompt";if(eventName.includes("tool_decision"))return"otel_decision";return"otel_event"}function resolveEntityId(ctx){return ctx.sessionId??(ctx.agentName?`agent:${ctx.agentName}`:"unknown")}function mergeContext(details,ctx){if(ctx.teamName)details.team=ctx.teamName;if(ctx.wishSlug)details.wish_slug=ctx.wishSlug;if(ctx.agentRole)details.agent_role=ctx.agentRole;if(ctx.sessionId)details.session_id=ctx.sessionId}function logRecordToRow(record,ctx){let logAttrs=attrsToObject(record.attributes),eventName=logAttrs["event.name"]??record.body?.stringValue??"unknown",details={...logAttrs,event_name:eventName};if(mergeContext(details,ctx),record.severityText)details.severity=record.severityText;if(record.body?.kvlistValue?.values)Object.assign(details,attrsToObject(record.body.kvlistValue.values));return{entity_type:mapEventToEntityType(eventName),entity_id:resolveEntityId(ctx),event_type:eventName,actor:ctx.agentName??null,details}}function processLogs(payload){let rows=[];for(let resourceLog of payload.resourceLogs??[]){let ctx=extractResourceContext(resourceLog.resource);for(let scopeLog of resourceLog.scopeLogs??[])for(let record of scopeLog.logRecords??[])rows.push(logRecordToRow(record,ctx))}return rows}function buildMetricRow(metricName,entityId,actor,details){return{entity_type:"otel_metric",entity_id:entityId,event_type:metricName,actor,details}}function processSumGaugePoints(dataPoints,metricName,unit,entityId,ctx){return dataPoints.map((dp)=>{let dpAttrs=attrsToObject(dp.attributes),value=dp.asDouble??(dp.asInt!==void 0?Number(dp.asInt):void 0),details={metric_name:metricName,value,...dpAttrs};if(unit)details.unit=unit;return mergeContext(details,ctx),buildMetricRow(metricName,entityId,ctx.agentName??null,details)})}function metricToRows(metric,ctx){let metricName=metric.name??"unknown_metric",entityId=resolveEntityId(ctx),dataPoints=metric.sum?.dataPoints??metric.gauge?.dataPoints??[],rows=processSumGaugePoints(dataPoints,metricName,metric.unit,entityId,ctx);for(let dp of metric.histogram?.dataPoints??[]){let dpAttrs=attrsToObject(dp.attributes),details={metric_name:metricName,sum:dp.sum,count:dp.count!==void 0?Number(dp.count):void 0,...dpAttrs};if(metric.unit)details.unit=metric.unit;mergeContext(details,ctx),rows.push(buildMetricRow(metricName,entityId,ctx.agentName??null,details))}return rows}function processMetrics(payload){let rows=[];for(let resourceMetric of payload.resourceMetrics??[]){let ctx=extractResourceContext(resourceMetric.resource);for(let scopeMetric of resourceMetric.scopeMetrics??[])for(let metric of scopeMetric.metrics??[])rows.push(...metricToRows(metric,ctx))}return rows}async function flushToPg(rows){if(rows.length===0)return;try{let{getConnection:getConnection2,isAvailable:isAvailable2}=await Promise.resolve().then(() => (init_db(),exports_db));if(!await isAvailable2())return;let sql=await getConnection2();await sql`
|
|
761
792
|
INSERT INTO audit_events (entity_type, entity_id, event_type, actor, details)
|
|
762
793
|
SELECT * FROM unnest(
|
|
@@ -3548,7 +3579,7 @@ Bus `);for(let i2=1;i2<parts.length;i2++){let usb2=parseLinuxUsb(parts[i2]);resu
|
|
|
3548
3579
|
`)}init_setup();init_shortcuts();import{existsSync as existsSync19}from"fs";import{homedir as homedir19}from"os";import{join as join22}from"path";async function shortcutsShowCommand(){displayShortcuts();let home=homedir19(),tmuxConf=join22(home,".tmux.conf"),zshrc=join22(home,".zshrc"),bashrc=join22(home,".bashrc");if(console.log("Installation status:"),isShortcutsInstalled(tmuxConf))console.log(" \x1B[32m\u2713\x1B[0m tmux.conf");else console.log(" \x1B[33m-\x1B[0m tmux.conf");let shellRc=existsSync19(zshrc)?zshrc:bashrc;if(isShortcutsInstalled(shellRc))console.log(` \x1B[32m\u2713\x1B[0m ${shellRc.replace(home,"~")}`);else console.log(` \x1B[33m-\x1B[0m ${shellRc.replace(home,"~")}`);console.log(),console.log("Run \x1B[36mgenie shortcuts install\x1B[0m to install shortcuts."),console.log("Run \x1B[36mgenie shortcuts uninstall\x1B[0m to remove shortcuts."),console.log()}async function shortcutsInstallCommand(){await installShortcuts()}async function shortcutsUninstallCommand(){await uninstallShortcuts()}init_esm14();init_claude_settings();init_genie_config2();import{existsSync as existsSync20,lstatSync,rmSync as rmSync2,unlinkSync as unlinkSync8}from"fs";import{homedir as homedir20}from"os";import{join as join23}from"path";var ORCHESTRATION_RULES_PATH=join23(homedir20(),".claude","rules","genie-orchestration.md"),LOCAL_BIN=join23(homedir20(),".local","bin"),SYMLINKS=["genie","term"];function isGenieSymlink(path3){try{if(!existsSync20(path3))return!1;if(!lstatSync(path3).isSymbolicLink())return!1;return!0}catch{return!1}}function removeSymlinks(){let removed=[];for(let name of SYMLINKS){let symlinkPath=join23(LOCAL_BIN,name);if(isGenieSymlink(symlinkPath))try{unlinkSync8(symlinkPath),removed.push(name)}catch{}}return removed}function tryRemoveStep(label,successMsg,fn){console.log(`\x1B[2m${label}\x1B[0m`);try{fn(),console.log(` \x1B[32m+\x1B[0m ${successMsg}`)}catch(error){let message=error instanceof Error?error.message:String(error);console.log(` \x1B[33m!\x1B[0m ${label.replace("...","")} failed: ${message}`)}}function performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir){if(hasHookScript)tryRemoveStep("Removing hook script...","Hook script removed",()=>removeHookScript());if(existingSymlinks.length>0){console.log("\x1B[2mRemoving symlinks...\x1B[0m");let removed=removeSymlinks();if(removed.length>0)console.log(` \x1B[32m+\x1B[0m Removed: ${removed.join(", ")}`)}if(existsSync20(ORCHESTRATION_RULES_PATH))tryRemoveStep("Removing orchestration rules...","Orchestration rules removed (~/.claude/rules/genie-orchestration.md)",()=>unlinkSync8(ORCHESTRATION_RULES_PATH));if(hasGenieDir)tryRemoveStep("Removing genie directory...","Directory removed",()=>rmSync2(genieDir,{recursive:!0,force:!0}))}async function uninstallCommand(){console.log(),console.log("\x1B[1m\x1B[33m Uninstall Genie CLI\x1B[0m"),console.log();let genieDir=getGenieDir(),hasGenieDir=existsSync20(genieDir),hasHookScript=hookScriptExists(),hasOrchestrationRules=existsSync20(ORCHESTRATION_RULES_PATH),existingSymlinks=SYMLINKS.filter((name)=>isGenieSymlink(join23(LOCAL_BIN,name)));if(console.log("\x1B[2mThis will remove:\x1B[0m"),hasHookScript)console.log(" \x1B[31m-\x1B[0m Hook script (~/.claude/hooks/genie-bash-hook.sh)");if(hasOrchestrationRules)console.log(" \x1B[31m-\x1B[0m Orchestration rules (~/.claude/rules/genie-orchestration.md)");if(hasGenieDir)console.log(` \x1B[31m-\x1B[0m Genie directory (${contractPath(genieDir)})`);if(existingSymlinks.length>0)console.log(` \x1B[31m-\x1B[0m Symlinks from ~/.local/bin: ${existingSymlinks.join(", ")}`);if(console.log(),!hasGenieDir&&!hasHookScript&&!hasOrchestrationRules&&existingSymlinks.length===0){console.log("\x1B[33mNothing to uninstall.\x1B[0m"),console.log();return}if(!await esm_default4({message:"Are you sure you want to uninstall Genie CLI?",default:!1})){console.log(),console.log("\x1B[2mUninstall cancelled.\x1B[0m"),console.log();return}console.log(),performUninstall(hasHookScript,existingSymlinks,genieDir,hasGenieDir),console.log(),console.log("\x1B[32m+\x1B[0m Genie CLI uninstalled."),console.log(),console.log("\x1B[2mNote: If you installed via npm/bun, also run:\x1B[0m"),console.log(" \x1B[36mbun remove -g @automagik/genie\x1B[0m"),console.log(" \x1B[2mor\x1B[0m"),console.log(" \x1B[36mnpm uninstall -g @automagik/genie\x1B[0m"),console.log()}init_genie_config2();import{execSync as execSync4,spawn as spawn3}from"child_process";import{chmodSync as chmodSync2,copyFileSync as copyFileSync2,existsSync as existsSync21,mkdirSync as mkdirSync10,readFileSync as readFileSync15,readdirSync as readdirSync6,rmSync as rmSync3,writeFileSync as writeFileSync9}from"fs";import{chmod,copyFile,mkdir as mkdir4,unlink as unlink2}from"fs/promises";import{homedir as homedir21}from"os";import{join as join24}from"path";var GENIE_HOME2=process.env.GENIE_HOME||join24(homedir21(),".genie"),GENIE_SRC=join24(GENIE_HOME2,"src"),GENIE_BIN=join24(GENIE_HOME2,"bin"),LOCAL_BIN2=join24(homedir21(),".local","bin");function log(message){console.log(`\x1B[32m\u25B8\x1B[0m ${message}`)}function success(message){console.log(`\x1B[32m\u2714\x1B[0m ${message}`)}function error(message){console.log(`\x1B[31m\u2716\x1B[0m ${message}`)}async function runCommand(command,args,cwd){return new Promise((resolve3)=>{let output=[],child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"],env:{...process.env,FORCE_COLOR:"1"}});child.stdout?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stdout.write(str2)}),child.stderr?.on("data",(data)=>{let str2=data.toString();output.push(str2),process.stderr.write(str2)}),child.on("close",(code)=>{resolve3({success:code===0,output:output.join("")})}),child.on("error",(err)=>{error(err.message),resolve3({success:!1,output:err.message})})})}async function getGitInfo(cwd){try{let branchResult=await runCommandSilent("git",["rev-parse","--abbrev-ref","HEAD"],cwd),commitResult=await runCommandSilent("git",["rev-parse","--short","HEAD"],cwd),dateResult=await runCommandSilent("git",["log","-1","--format=%ci"],cwd);if(branchResult.success&&commitResult.success&&dateResult.success)return{branch:branchResult.output.trim(),commit:commitResult.output.trim(),commitDate:dateResult.output.trim().split(" ")[0]}}catch{}return null}async function runCommandSilent(command,args,cwd,timeoutMs=4000){return new Promise((resolve3)=>{let output=[],settled=!1,child=spawn3(command,args,{cwd,stdio:["inherit","pipe","pipe"]}),timer2=setTimeout(()=>{if(settled)return;settled=!0,child.kill("SIGTERM"),resolve3({success:!1,output:`Timed out after ${timeoutMs}ms`})},timeoutMs);child.stdout?.on("data",(data)=>{output.push(data.toString())}),child.stderr?.on("data",(data)=>{output.push(data.toString())}),child.on("close",(code)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve3({success:code===0,output:output.join("")})}),child.on("error",(err)=>{if(settled)return;settled=!0,clearTimeout(timer2),resolve3({success:!1,output:err.message})})})}function detectFromBinaryPath(path3){if(path3.includes(".bun"))return"bun";if(path3.includes("node_modules"))return"npm";if(path3===join24(LOCAL_BIN2,"genie")||path3.startsWith(GENIE_BIN))return"source";return null}async function detectInstallationType(){if(genieConfigExists())try{let config=await loadGenieConfig();if(config.installMethod)return config.installMethod}catch{}if(existsSync21(join24(GENIE_SRC,".git")))return"source";let result2=await runCommandSilent("which",["genie"]);if(!result2.success)return"unknown";let detected=detectFromBinaryPath(result2.output.trim());if(detected)return detected;return(await runCommandSilent("which",["bun"])).success?"bun":"npm"}async function updateViaBun(channel){try{__require("fs").unlinkSync(join24(homedir21(),".bun","install","global","bun.lock"))}catch{}if(log(`Updating via bun (channel: ${channel})...`),!(await runCommand("bun",["add","-g","--force","--no-cache",`@automagik/genie@${channel}`])).success)return error("Failed to update via bun"),!1;return console.log(),success(`Genie CLI updated via bun (${channel})!`),!0}async function updateViaNpm(channel){if(log(`Updating via npm (channel: ${channel})...`),!(await runCommand("npm",["install","-g",`@automagik/genie@${channel}`])).success)return error("Failed to update via npm"),!1;return console.log(),success(`Genie CLI updated via npm (${channel})!`),!0}async function detectGlobalInstalls(){let found=new Set,[npmResult,bunResult]=await Promise.all([runCommandSilent("npm",["list","-g","@automagik/genie"]),runCommandSilent("bun",["pm","ls","-g"])]);if(npmResult.success&&!npmResult.output.includes("(empty)"))found.add("npm");if(bunResult.success&&bunResult.output.includes("@automagik/genie"))found.add("bun");return found}async function updateSource(){let beforeInfo=await getGitInfo(GENIE_SRC);if(beforeInfo)console.log(`Current: \x1B[2m${beforeInfo.branch}@${beforeInfo.commit} (${beforeInfo.commitDate})\x1B[0m`),console.log();if(log("Fetching latest changes..."),!(await runCommand("git",["fetch","origin"],GENIE_SRC)).success)error("Failed to fetch from origin"),process.exit(1);if(log("Resetting to origin/main..."),!(await runCommand("git",["reset","--hard","origin/main"],GENIE_SRC)).success)error("Failed to reset to origin/main"),process.exit(1);console.log();let afterInfo=await getGitInfo(GENIE_SRC);if(beforeInfo&&afterInfo&&beforeInfo.commit===afterInfo.commit){success("Already up to date!"),console.log();return}if(log("Installing dependencies..."),!(await runCommand("bun",["install"],GENIE_SRC)).success)error("Failed to install dependencies"),process.exit(1);if(console.log(),log("Building..."),!(await runCommand("bun",["run","build"],GENIE_SRC)).success)error("Failed to build"),process.exit(1);console.log(),log("Installing binaries...");try{await mkdir4(GENIE_BIN,{recursive:!0}),await mkdir4(LOCAL_BIN2,{recursive:!0});let binaries=["genie.js","term.js"],names=["genie","term"];for(let i2=0;i2<binaries.length;i2++){let src=join24(GENIE_SRC,"dist",binaries[i2]),binDest=join24(GENIE_BIN,binaries[i2]),linkDest=join24(LOCAL_BIN2,names[i2]);await copyFile(src,binDest),await chmod(binDest,493),await symlinkOrCopy(binDest,linkDest)}for(let legacy of["claudio.js","claudio"]){let legacyBin=join24(GENIE_BIN,legacy),legacyLink=join24(LOCAL_BIN2,legacy);try{await unlink2(legacyBin)}catch{}try{await unlink2(legacyLink)}catch{}}success("Binaries installed")}catch(err){error(`Failed to install binaries: ${err}`),process.exit(1)}if(console.log(),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),success("Genie CLI updated successfully!"),console.log(),afterInfo)console.log(`Version: \x1B[36m${afterInfo.branch}@${afterInfo.commit}\x1B[0m (${afterInfo.commitDate})`),console.log()}async function symlinkOrCopy(src,dest){let{symlink:symlink2,unlink:unlink3}=await import("fs/promises");try{if(existsSync21(dest))await unlink3(dest);await symlink2(src,dest)}catch{await copyFile(src,dest)}}function copyDirSync(src,dest){mkdirSync10(dest,{recursive:!0});for(let entry2 of readdirSync6(src,{withFileTypes:!0})){let srcPath=join24(src,entry2.name),destPath=join24(dest,entry2.name);if(entry2.isDirectory())copyDirSync(srcPath,destPath);else copyFileSync2(srcPath,destPath)}}async function resolveGlobalPkgDir(installType){if(installType==="bun"){let bunPath=join24(homedir21(),".bun","install","global","node_modules","@automagik","genie");if(existsSync21(bunPath))return bunPath}if(installType==="npm"){let npmRootResult=await runCommandSilent("npm",["root","-g"]);if(npmRootResult.success){let npmPath=join24(npmRootResult.output.trim(),"@automagik","genie");if(existsSync21(npmPath))return npmPath}}let bunFallback=join24(homedir21(),".bun","install","global","node_modules","@automagik","genie");if(existsSync21(bunFallback))return bunFallback;let npmRootFallback=await runCommandSilent("npm",["root","-g"]);if(npmRootFallback.success){let npmPath=join24(npmRootFallback.output.trim(),"@automagik","genie");if(existsSync21(npmPath))return npmPath}return null}function updatePluginRegistry(claudePlugins,cacheDir,version){let registryPath=join24(claudePlugins,"installed_plugins.json");try{if(!existsSync21(registryPath))return;let registry=JSON.parse(readFileSync15(registryPath,"utf-8")),entries=registry.plugins?.["genie@automagik"];if(!Array.isArray(entries))return;for(let entry2 of entries)if(entry2.scope==="user")entry2.installPath=cacheDir,entry2.version=version,entry2.lastUpdated=new Date().toISOString();writeFileSync9(registryPath,JSON.stringify(registry,null,2))}catch(err){log(`Registry update failed (non-fatal): ${err}`)}}function syncTmuxConf(tmuxScriptsSrc){mkdirSync10(GENIE_HOME2,{recursive:!0});let tmuxConfSrc=join24(tmuxScriptsSrc,"genie.tmux.conf"),tmuxConfDest=join24(GENIE_HOME2,"tmux.conf");if(existsSync21(tmuxConfSrc))try{copyFileSync2(tmuxConfSrc,tmuxConfDest),success(`Installed tmux config to ${tmuxConfDest}`);try{let{tmuxBin:tmuxBin2}=(init_ensure_tmux(),__toCommonJS(exports_ensure_tmux));execSync4(`${tmuxBin2()} -L genie source-file '${tmuxConfDest}'`,{stdio:"ignore"}),success("Reloaded genie tmux server configuration")}catch{}}catch{}let tuiConfSrc=join24(tmuxScriptsSrc,"tui-tmux.conf"),tuiConfDest=join24(GENIE_HOME2,"tui-tmux.conf");if(existsSync21(tuiConfSrc))try{copyFileSync2(tuiConfSrc,tuiConfDest),success(`Installed TUI tmux config to ${tuiConfDest}`)}catch{}let osc52Src=join24(tmuxScriptsSrc,"osc52-copy.sh"),osc52Dest=join24(GENIE_HOME2,"scripts","osc52-copy.sh");if(existsSync21(osc52Src))try{copyFileSync2(osc52Src,osc52Dest),chmodSync2(osc52Dest,493),success(`Installed OSC 52 clipboard helper to ${osc52Dest}`)}catch{}}function syncTmuxScripts(globalPkgDir){let tmuxScriptsSrc=join24(globalPkgDir,"scripts","tmux");if(!existsSync21(tmuxScriptsSrc))return;let scriptsDir=join24(GENIE_HOME2,"scripts");mkdirSync10(scriptsDir,{recursive:!0});let scriptCount=0;for(let entry2 of readdirSync6(tmuxScriptsSrc))if(entry2.endsWith(".sh")||entry2==="genie.tmux.conf"||entry2==="tui-tmux.conf"){let src=join24(tmuxScriptsSrc,entry2),dest=join24(scriptsDir,entry2);copyFileSync2(src,dest);try{chmodSync2(dest,entry2.endsWith(".sh")?493:420)}catch{}scriptCount++}if(scriptCount>0)success(`Refreshed ${scriptCount} tmux scripts at ${scriptsDir}`);syncTmuxConf(tmuxScriptsSrc)}function syncMarketplaceVersion(claudePlugins,version){let marketplacePath=join24(claudePlugins,"marketplaces","automagik",".claude-plugin","marketplace.json");try{if(!existsSync21(marketplacePath))return;let data=JSON.parse(readFileSync15(marketplacePath,"utf-8"));if(Array.isArray(data.plugins)){for(let plugin of data.plugins)if(plugin.name==="genie")plugin.version=version}writeFileSync9(marketplacePath,JSON.stringify(data,null,2)),success(`Updated marketplace.json to v${version}`)}catch(err){log(`Marketplace version update failed (non-fatal): ${err}`)}}function syncPluginPackageVersion(claudePlugins,version){let pkgPath=join24(claudePlugins,"marketplaces","automagik","plugins","genie","package.json");try{if(!existsSync21(pkgPath))return;let data=JSON.parse(readFileSync15(pkgPath,"utf-8"));data.version=version,writeFileSync9(pkgPath,JSON.stringify(data,null,2)),success(`Updated plugin package.json to v${version}`)}catch(err){log(`Plugin package.json update failed (non-fatal): ${err}`)}}function syncSkillsSymlink(claudePlugins,version){let skillsLink=join24(claudePlugins,"marketplaces","automagik","plugins","genie","skills"),cacheSkills=join24("..","..","..","..","cache","automagik","genie",version,"skills");try{let{symlinkSync,unlinkSync:unlinkSync9,lstatSync:lstatSync2}=__require("fs");try{lstatSync2(skillsLink),unlinkSync9(skillsLink)}catch{}symlinkSync(cacheSkills,skillsLink),success(`Skills symlink \u2192 cache/${version}/skills`)}catch(err){log(`Skills symlink update failed (non-fatal): ${err}`)}}async function syncPlugin(installType){log("Syncing Claude Code plugin...");let globalPkgDir=await resolveGlobalPkgDir(installType);if(!globalPkgDir){log("Could not find installed package \u2014 skipping plugin sync");return}let pluginSrc=join24(globalPkgDir,"plugins","genie");if(!existsSync21(pluginSrc)){log("Plugin source not found in package \u2014 skipping plugin sync");return}let version;try{version=JSON.parse(readFileSync15(join24(globalPkgDir,"package.json"),"utf-8")).version}catch{log("Could not read package version \u2014 skipping plugin sync");return}let claudePlugins=join24(homedir21(),".claude","plugins"),cacheDir=join24(claudePlugins,"cache","automagik","genie",version);try{if(existsSync21(cacheDir))rmSync3(cacheDir,{recursive:!0,force:!0});copyDirSync(pluginSrc,cacheDir);let skillsSrc=join24(globalPkgDir,"skills");if(existsSync21(skillsSrc)&&!existsSync21(join24(cacheDir,"skills")))copyDirSync(skillsSrc,join24(cacheDir,"skills"))}catch(err){error(`Failed to copy plugin: ${err}`);return}updatePluginRegistry(claudePlugins,cacheDir,version),syncMarketplaceVersion(claudePlugins,version),syncPluginPackageVersion(claudePlugins,version),syncSkillsSymlink(claudePlugins,version),syncTmuxScripts(globalPkgDir),success(`Plugin synced to v${version}`)}async function resolveChannel(options){if(options.next)return"next";if(options.stable)return"latest";if(genieConfigExists())try{let config=await loadGenieConfig();if(config.updateChannel)return config.updateChannel}catch{}return"latest"}async function persistChannel(channel){try{let config=await loadGenieConfig();config.updateChannel=channel,await saveGenieConfig(config)}catch{}}async function updateCommand(options={}){console.log(),console.log("\x1B[1m\uD83E\uDDDE Genie CLI Update\x1B[0m"),console.log("\x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m"),console.log();let channel=await resolveChannel(options);if(options.next||options.stable)await persistChannel(channel);let installType=await detectInstallationType();if(log(`Detected installation: ${installType}`),log(`Channel: ${channel}${channel==="next"?" (dev builds)":" (stable)"}`),console.log(),installType==="unknown")error("No Genie CLI installation found"),console.log(),console.log("Install method not configured. Please reinstall genie:"),console.log("\x1B[36m curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash\x1B[0m"),console.log(),process.exit(1);if(installType==="source"){await updateSource();return}let globalInstalls=await detectGlobalInstalls(),primaryMethod=installType;if(!(primaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))process.exit(1);let secondaryMethod=primaryMethod==="bun"?"npm":"bun";if(globalInstalls.has(secondaryMethod)){if(console.log(),log(`Also updating ${secondaryMethod}-global install...`),!(secondaryMethod==="bun"?await updateViaBun(channel):await updateViaNpm(channel)))error(`Secondary update via ${secondaryMethod} failed (non-blocking)`)}await syncPlugin(installType)}init_version();init_emit();init_trace_context();import{execSync as execSync5}from"child_process";var MAX_COMMITS=5;function getRecentGitHistory(filePath,cwd){try{let trimmed=execSync5(`git log --oneline -n ${MAX_COMMITS} -- ${JSON.stringify(filePath)}`,{encoding:"utf-8",timeout:5000,cwd,stdio:["pipe","pipe","pipe"]}).trim();if(!trimmed)return null;return trimmed}catch{return null}}async function auditContext(payload){let input=payload.tool_input;if(!input)return;let filePath=input.file_path;if(!filePath)return;let cwd=payload.cwd??process.cwd(),history=getRecentGitHistory(filePath,cwd);if(!history)return;return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[audit-context] Recent git history for ${filePath}:
|
|
3549
3580
|
${history}`}}}function buildSearchNames(recipient,dirEntry){let names=new Set([recipient]);if(dirEntry){if(names.add(dirEntry.entry.name),dirEntry.entry.roles)for(let role of dirEntry.entry.roles)names.add(role)}return names}function buildSpawnArgs(template){let args=["spawn","--provider",template.provider,"--team",template.team];if(template.role)args.push("--role",template.role);if(template.skill)args.push("--skill",template.skill);if(template.cwd)args.push("--cwd",template.cwd);if(template.extraArgs)args.push(...template.extraArgs);return args}async function isRecipientLeader(recipient,teamName){try{let{getTeam:getTeam2}=await Promise.resolve().then(() => (init_team_manager(),exports_team_manager)),config=await getTeam2(teamName);return!!config?.leader&&recipient===config.leader}catch{return!1}}function extractAutoSpawnTarget(payload){let input=payload.tool_input;if(!input||input.type!=="message")return null;let recipient=input.recipient;if(!recipient)return null;let teamName=process.env.GENIE_TEAM??payload.team_name;if(!teamName)return null;if(recipient==="team-lead")return null;return{recipient,teamName}}async function executeAutoSpawn(recipient,teamName){let registryMod=await Promise.resolve().then(() => (init_agent_registry(),exports_agent_registry)),executorRegistryMod=await Promise.resolve().then(() => (init_executor_registry(),exports_executor_registry)),directoryMod=await Promise.resolve().then(() => (init_agent_directory(),exports_agent_directory)),existing=(await registryMod.list()).find((a)=>(a.role===recipient||a.id===recipient)&&a.team===teamName);if(existing&&await executorRegistryMod.resolveWorkerLivenessByTransport(existing))return;let dirEntry=await directoryMod.resolve(recipient),templates=await registryMod.listTemplates(),searchNames=buildSearchNames(recipient,dirEntry),template=templates.find((t)=>{if(t.team!==teamName)return!1;return[...searchNames].some((q)=>t.id===q||t.role===q)});if(!template){if(dirEntry)console.error(`[genie-hook] Agent "${recipient}" is registered in directory but has no spawn template in team "${teamName}".`);return}let{spawnSync:spawnSync2}=__require("child_process");spawnSync2("genie",buildSpawnArgs(template),{timeout:1e4,stdio:"ignore",env:{...process.env,GENIE_TEAM:teamName}}),console.error(`[genie-hook] Auto-spawned "${recipient}" in team "${teamName}"`)}async function autoSpawn(payload){let target=extractAutoSpawnTarget(payload);if(!target)return;let{recipient,teamName}=target;if(await isRecipientLeader(recipient,teamName))return;try{await executeAutoSpawn(recipient,teamName)}catch(err){let msg=err instanceof Error?err.message:String(err);return console.error(`[genie-hook] Auto-spawn failed for "${recipient}": ${msg}`),{hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:`auto-spawn warning: failed to spawn "${recipient}": ${msg}`}}}}import{existsSync as existsSync24}from"fs";import{basename as basename3,join as join26}from"path";var BRAIN_PKG="@khal-os/brain",BRAIN_DIR="node_modules/@khal-os/brain",enrichedSessions=new Set;function sessionKey(payload){return payload.session_id??`${process.pid}`}function isBrainAvailable(){return existsSync24(join26(BRAIN_DIR,"package.json"))}async function queryBrain(cwd){try{let brain=await import(BRAIN_PKG);if(!brain.search)return null;let projectName=basename3(cwd),results=await brain.search({query:`context for ${projectName}`,limit:5,minScore:0.5});if(!results||results.length===0)return null;return results.map((r)=>{return`- ${(r.content??r.text??"").slice(0,200)}`}).join(`
|
|
3550
3581
|
`)}catch{return null}}async function brainInject(payload){let key=sessionKey(payload);if(enrichedSessions.has(key))return;if(enrichedSessions.add(key),!isBrainAvailable())return;let cwd=payload.cwd??process.cwd();try{let context=await queryBrain(cwd);if(!context)return;return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[brain-inject] Prior context from knowledge base:
|
|
3551
|
-
${context}`}}}catch{return}}import{spawnSync as spawnSync2}from"child_process";var ALLOWED_MERGE_BASES=new Set(["dev"]),SYNC_DENY_PATTERNS=[{test:(cmd)=>/git\s+push\b/i.test(cmd)&&/(?:^|\s)(main|master)(?:\s|$)/.test(cmd),reason:"BLOCKED: Push to main/master is FORBIDDEN. Push to a feature branch and create a PR targeting dev."},{test:(cmd)=>/git\s+push\b/.test(cmd)&&/:(main|master)\b/.test(cmd),reason:"BLOCKED: Push refspec targeting main/master is FORBIDDEN."},{test:(cmd)=>/gh\s+pr\s+create\b/.test(cmd)&&!/(--base|-B)\s+\S/.test(cmd),reason:"BLOCKED: gh pr create requires explicit --base flag. Use: gh pr create --base dev (or --base main for releases)"},{test:(cmd)=>/git\s+checkout\s+(main|master)\s*[;&|]+\s*git\s+(commit|merge|cherry-pick|rebase|push|add)\b/.test(cmd),reason:"BLOCKED: Committing or mutating on main/master is FORBIDDEN. Work on feature branches."}],STDERR_SURFACE_CAP=500,defaultDeps={async resolvePrBase(prNum){let result2;try{result2=spawnSync2("gh",["pr","view",prNum,"--json","baseRefName","-q",".baseRefName"],{encoding:"utf8",timeout:1e4,stdio:["ignore","pipe","pipe"]})}catch(err){return{reason:`spawnSync threw: ${(err instanceof Error?err.message:String(err)).slice(0,STDERR_SURFACE_CAP)}`}}if(result2.error)return{reason:`subprocess error: ${result2.error.message.slice(0,STDERR_SURFACE_CAP)}`};let stderr=typeof result2.stderr==="string"?result2.stderr.trim():"";if(result2.status!==0){let tail=stderr.slice(-STDERR_SURFACE_CAP)||"no stderr captured";return{reason:`gh pr view exited ${result2.status}: ${tail}`}}let stdout=typeof result2.stdout==="string"?result2.stdout.trim():"";if(!stdout)return{reason:`gh pr view exited 0 with empty stdout (stderr: ${stderr.slice(-STDERR_SURFACE_CAP)||"none"})`};return{base:stdout}}};function extractPrNumber(cmd){let match=cmd.match(/gh\s+pr\s+merge\s+(\d+)\b/);return match?match[1]:null}async function branchGuard(payload,deps=defaultDeps){let input=payload.tool_input;if(!input)return;let command=input.command;if(!command)return;if(!/\b(git|gh)\b/.test(
|
|
3582
|
+
${context}`}}}catch{return}}import{spawnSync as spawnSync2}from"child_process";var ALLOWED_MERGE_BASES=new Set(["dev"]),SYNC_DENY_PATTERNS=[{test:(cmd)=>/git\s+push\b/i.test(cmd)&&/(?:^|\s)(main|master)(?:\s|$)/.test(cmd),reason:"BLOCKED: Push to main/master is FORBIDDEN. Push to a feature branch and create a PR targeting dev."},{test:(cmd)=>/git\s+push\b/.test(cmd)&&/:(main|master)\b/.test(cmd),reason:"BLOCKED: Push refspec targeting main/master is FORBIDDEN."},{test:(cmd)=>/gh\s+pr\s+create\b/.test(cmd)&&!/(--base|-B)\s+\S/.test(cmd),reason:"BLOCKED: gh pr create requires explicit --base flag. Use: gh pr create --base dev (or --base main for releases)"},{test:(cmd)=>/git\s+checkout\s+(main|master)\s*[;&|]+\s*git\s+(commit|merge|cherry-pick|rebase|push|add)\b/.test(cmd),reason:"BLOCKED: Committing or mutating on main/master is FORBIDDEN. Work on feature branches."}],STDERR_SURFACE_CAP=500,defaultDeps={async resolvePrBase(prNum){let result2;try{result2=spawnSync2("gh",["pr","view",prNum,"--json","baseRefName","-q",".baseRefName"],{encoding:"utf8",timeout:1e4,stdio:["ignore","pipe","pipe"]})}catch(err){return{reason:`spawnSync threw: ${(err instanceof Error?err.message:String(err)).slice(0,STDERR_SURFACE_CAP)}`}}if(result2.error)return{reason:`subprocess error: ${result2.error.message.slice(0,STDERR_SURFACE_CAP)}`};let stderr=typeof result2.stderr==="string"?result2.stderr.trim():"";if(result2.status!==0){let tail=stderr.slice(-STDERR_SURFACE_CAP)||"no stderr captured";return{reason:`gh pr view exited ${result2.status}: ${tail}`}}let stdout=typeof result2.stdout==="string"?result2.stdout.trim():"";if(!stdout)return{reason:`gh pr view exited 0 with empty stdout (stderr: ${stderr.slice(-STDERR_SURFACE_CAP)||"none"})`};return{base:stdout}}};function extractPrNumber(cmd){let match=cmd.match(/gh\s+pr\s+merge\s+(\d+)\b/);return match?match[1]:null}function stepUnquoted(ch){if(ch==="'")return{out:" ",next:"single",consumed:1};if(ch==='"')return{out:" ",next:"double",consumed:1};return{out:ch,next:"none",consumed:1}}function stepSingleQuoted(ch){return{out:" ",next:ch==="'"?"none":"single",consumed:1}}function stepDoubleQuoted(ch,hasNext){if(ch==="\\"&&hasNext)return{out:" ",next:"double",consumed:2};return{out:" ",next:ch==='"'?"none":"double",consumed:1}}function maskQuotedRegions(cmd){let out="",state="none",i2=0;while(i2<cmd.length){let step=state==="double"?stepDoubleQuoted(cmd[i2],i2+1<cmd.length):state==="single"?stepSingleQuoted(cmd[i2]):stepUnquoted(cmd[i2]);out+=step.out,state=step.next,i2+=step.consumed}return out}async function branchGuard(payload,deps=defaultDeps){let input=payload.tool_input;if(!input)return;let command=input.command;if(!command)return;let matchTarget=maskQuotedRegions(command);if(!/\b(git|gh)\b/.test(matchTarget))return;for(let pattern of SYNC_DENY_PATTERNS)if(pattern.test(matchTarget))return{decision:"deny",reason:pattern.reason};if(/gh\s+pr\s+merge\b/.test(matchTarget)){let prNum=extractPrNumber(matchTarget);if(!prNum)return{decision:"deny",reason:"BLOCKED: `gh pr merge` requires an explicit PR number so the target base branch can be verified. \xA719 (v2): agents merge PRs targeting `dev` only; main/master is humans-only via GitHub UI."};let resolved=await deps.resolvePrBase(prNum);if("reason"in resolved)return{decision:"deny",reason:`BLOCKED: could not resolve base branch of PR #${prNum} \u2014 ${resolved.reason}. \xA719 (v2): cannot merge without verifying base is \`dev\`. Check the PR exists and try again, or ask a human to merge via GitHub UI.`};let base=resolved.base;if(!ALLOWED_MERGE_BASES.has(base))return{decision:"deny",reason:`BLOCKED: PR #${prNum} targets \`${base}\`. \xA719 (v2): agents may merge PRs targeting \`dev\` only. Main/master merges are humans-only via GitHub UI.`}}return}import{execSync as execSync6}from"child_process";import{statSync as statSync3}from"fs";var STALENESS_THRESHOLD_SECS=120;function getLastCommitInfo(filePath,cwd){try{let trimmed=execSync6(`git log -1 --format="%at|%an|%s" -- ${JSON.stringify(filePath)}`,{encoding:"utf-8",timeout:5000,cwd,stdio:["pipe","pipe","pipe"]}).trim();if(!trimmed)return null;let[timestampStr,author,...messageParts]=trimmed.split("|"),timestamp2=Number.parseInt(timestampStr,10);if(Number.isNaN(timestamp2))return null;let age=Math.floor(Date.now()/1000)-timestamp2;return{author:author??"unknown",age,message:messageParts.join("|")}}catch{return null}}function getFileModAge(filePath){try{let stat2=statSync3(filePath);return Math.floor((Date.now()-stat2.mtimeMs)/1000)}catch{return null}}function buildCommitWarning(filePath,commitInfo){return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[freshness] Stale read warning: ${filePath} was modified ${commitInfo.age}s ago by "${commitInfo.author}" (${commitInfo.message}). Contents may have changed since you last read it.`}}}function checkUncommittedChanges(filePath,cwd,diskAge){try{if(execSync6(`git status --porcelain -- ${JSON.stringify(filePath)}`,{encoding:"utf-8",timeout:5000,cwd,stdio:["pipe","pipe","pipe"]}).trim())return{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",additionalContext:`[freshness] Stale read warning: ${filePath} has uncommitted changes (modified ${diskAge}s ago). Another agent may be editing this file concurrently.`}}}catch{}return}async function freshness(payload){let input=payload.tool_input;if(!input)return;let filePath=input.file_path;if(!filePath)return;let cwd=payload.cwd??process.cwd(),currentAgent=process.env.GENIE_AGENT_NAME,diskAge=getFileModAge(filePath);if(diskAge===null||diskAge>=STALENESS_THRESHOLD_SECS)return;let commitInfo=getLastCommitInfo(filePath,cwd);if(commitInfo&&commitInfo.age<STALENESS_THRESHOLD_SECS){if(currentAgent&&commitInfo.author.includes(currentAgent))return;return buildCommitWarning(filePath,commitInfo)}if(currentAgent)return checkUncommittedChanges(filePath,cwd,diskAge);return}async function identityInject(payload){let input=payload.tool_input;if(!input)return;let msgType=input.type;if(msgType&&msgType!=="message"&&msgType!=="broadcast")return;let agentName=process.env.GENIE_AGENT_NAME;if(!agentName)return;let contentField=input.content!==void 0?"content":"message",content=input[contentField];if(!content)return;if(content.startsWith(`[from:${agentName}]`))return;return{updatedInput:{...input,[contentField]:`[from:${agentName}] ${content}`}}}var NUDGE_PATTERNS=[{test:/tmux\s+capture-pane/,message:`If you're checking genie agent progress, use structured monitoring instead:
|
|
3552
3583
|
`+` genie task status <slug> \u2014 wish progress from PG
|
|
3553
3584
|
`+` genie agent list --json \u2014 executor state machine
|
|
3554
3585
|
`+` genie events timeline <id> \u2014 structured event log
|
|
@@ -3872,8 +3903,8 @@ coverage
|
|
|
3872
3903
|
|
|
3873
3904
|
_This file is maintained by the auto-memory system. New memories are added automatically._
|
|
3874
3905
|
`);let reposTarget=join59(workspaceRoot,"repos");if(existsSync52(reposTarget))try{symlinkSync(reposTarget,join59(agentDir,"repos"))}catch{}if(console.log(`Agent scaffolded: agents/${name}/`),console.log(" AGENTS.md, SOUL.md, HEARTBEAT.md"),console.log(" brain/memory/MEMORY.md (seeded)"),console.log(" .claude/settings.local.json (auto-memory enabled)"),existsSync52(join59(agentDir,"repos")))console.log(" repos -> ../repos (symlink)")}async function maybeBootstrapDefaultAgent(workspaceRoot){if(scanAgents(workspaceRoot).length>0)return!1;if(!await esm_default4({message:"No agent found in this workspace. Scaffold the default `genie` agent now?",default:!0}))return console.log(" Skipped default agent bootstrap. Run `genie init agent genie` later."),!1;return scaffoldAgentInWorkspace(workspaceRoot,"genie"),!0}async function syncWorkspaceAgents(workspaceRoot){let agents=scanAgents(workspaceRoot);if(agents.length===0)return;console.log(` Found ${agents.length} agent(s): ${agents.join(", ")}`);try{let{syncAgentDirectory:syncAgentDirectory2}=await Promise.resolve().then(() => (init_agent_sync(),exports_agent_sync)),result2=await syncAgentDirectory2(workspaceRoot);if(result2.registered.length>0)console.log(` Registered: ${result2.registered.join(", ")}`);if(result2.updated.length>0)console.log(` Updated: ${result2.updated.join(", ")}`)}catch{}}async function initWorkspace(){let cwd=process.cwd(),existing=findWorkspace(cwd);if(existing){if(console.log(`Already inside workspace: ${existing.root}`),await maybeBootstrapDefaultAgent(existing.root))await syncWorkspaceAgents(existing.root);return}let genieDir=join59(cwd,".genie");mkdirSync23(genieDir,{recursive:!0});let pgUrl=detectPgUrl(),config={name:basename10(cwd),pgUrl,agents:{defaults:{}},tmux:{socket:"genie"},sdk:{}};writeFileSync25(join59(genieDir,"workspace.json"),`${JSON.stringify(config,null,2)}
|
|
3875
|
-
`);let genieignorePath=join59(cwd,".genieignore");if(!existsSync52(genieignorePath))writeFileSync25(genieignorePath,GENIEIGNORE_DEFAULTS,"utf-8"),console.log(" Created .genieignore");if(console.log(`Workspace created: ${cwd}`),pgUrl)console.log(` pgUrl: ${pgUrl}`);await maybeBootstrapDefaultAgent(cwd),await syncWorkspaceAgents(cwd),await runPostInitFlow(cwd,config)}async function runPostInitFlow(workspaceRoot,config){if(!isInteractive())return;let discovered=await discoverExternalAgents(workspaceRoot);refreshPending(workspaceRoot,discovered);let pending=listPending(workspaceRoot),ctx={workspaceRoot,workspaceName:basename10(workspaceRoot),config,discovered,pending,canonicalAgentCount:scanAgents(workspaceRoot).length},result2=await runMiniWizard(ctx);if(result2.importedAgents.length>0){let toImport=pending.filter((p)=>result2.importedAgents.includes(p.name)),discoveredToImport=toImport.map((p)=>({name:p.name,path:p.path,relativePath:p.relativePath,isSubAgent:p.isSubAgent,parentName:p.parentName})),importResult=importAgents(workspaceRoot,discoveredToImport);for(let name of importResult.imported){let agent=toImport.find((a)=>a.name===name);if(agent)removePending(workspaceRoot,agent.path);console.log(` Imported: ${name}`)}for(let err of importResult.errors)console.error(` Import failed (${err.name}): ${err.error}`);await syncWorkspaceAgents(workspaceRoot)}}function resolveAgentsDir(wsRoot,dirOption){if(dirOption)return resolve9(dirOption);let cwd=process.cwd(),rel=relative4(wsRoot,cwd);if(rel.startsWith(".."))return join59(wsRoot,"agents");let segments=rel===""?[]:rel.split(sep2),idx=segments.indexOf("agents");if(idx===-1)return join59(wsRoot,"agents");return join59(wsRoot,...segments.slice(0,idx+1))}async function initAgent(name,options){if(!name||/[\/\\]/.test(name)||name==="."||name===".."||name.includes(".."))console.error("Error: Agent name must not contain path separators or traversal sequences."),process.exit(1);let cwd=process.cwd(),ws=findWorkspace(cwd);if(!ws)console.error("Error: Not in a genie workspace. Run `genie init` first."),process.exit(1);let agentsDir=resolveAgentsDir(ws.root,options.dir);try{scaffoldAgentInWorkspace(ws.root,name,agentsDir)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}function registerInitCommands(program2){program2.command("init").description("Initialize a genie workspace").action(async()=>{await ensureSetupCompleteForInit(),await initWorkspace()}).command("agent <name>").description("Scaffold a new agent in the workspace").option("--dir <path>","Target directory for agent (default: CWD if inside agents/, else workspace agents/)").action(async(name,options)=>{await ensureSetupCompleteForInit(),await initAgent(name,options)})}init_db();init_runtime_events();init_term_format();function parseSince4(since){let match=since.match(/^(\d+)([smhd])$/);if(!match)return since;let amount=Number.parseInt(match[1],10),unit=match[2],ms={s:1000,m:60000,h:3600000,d:86400000}[unit]??3600000;return new Date(Date.now()-amount*ms).toISOString()}async function metricsNowCommand(options){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),snapshots=await sql`SELECT * FROM machine_snapshots ORDER BY created_at DESC LIMIT 1`,agentCount=await sql`SELECT count(DISTINCT agent_id)::int as cnt FROM executors WHERE state NOT IN ('done', 'error', 'terminated')`,teamCount=await sql`SELECT count(*)::int as cnt FROM teams WHERE status = 'in_progress'`,snapshot=snapshots[0]??{},
|
|
3876
|
-
Event Throughput:`),console.log(` Emitted: ${data.
|
|
3906
|
+
`);let genieignorePath=join59(cwd,".genieignore");if(!existsSync52(genieignorePath))writeFileSync25(genieignorePath,GENIEIGNORE_DEFAULTS,"utf-8"),console.log(" Created .genieignore");if(console.log(`Workspace created: ${cwd}`),pgUrl)console.log(` pgUrl: ${pgUrl}`);await maybeBootstrapDefaultAgent(cwd),await syncWorkspaceAgents(cwd),await runPostInitFlow(cwd,config)}async function runPostInitFlow(workspaceRoot,config){if(!isInteractive())return;let discovered=await discoverExternalAgents(workspaceRoot);refreshPending(workspaceRoot,discovered);let pending=listPending(workspaceRoot),ctx={workspaceRoot,workspaceName:basename10(workspaceRoot),config,discovered,pending,canonicalAgentCount:scanAgents(workspaceRoot).length},result2=await runMiniWizard(ctx);if(result2.importedAgents.length>0){let toImport=pending.filter((p)=>result2.importedAgents.includes(p.name)),discoveredToImport=toImport.map((p)=>({name:p.name,path:p.path,relativePath:p.relativePath,isSubAgent:p.isSubAgent,parentName:p.parentName})),importResult=importAgents(workspaceRoot,discoveredToImport);for(let name of importResult.imported){let agent=toImport.find((a)=>a.name===name);if(agent)removePending(workspaceRoot,agent.path);console.log(` Imported: ${name}`)}for(let err of importResult.errors)console.error(` Import failed (${err.name}): ${err.error}`);await syncWorkspaceAgents(workspaceRoot)}}function resolveAgentsDir(wsRoot,dirOption){if(dirOption)return resolve9(dirOption);let cwd=process.cwd(),rel=relative4(wsRoot,cwd);if(rel.startsWith(".."))return join59(wsRoot,"agents");let segments=rel===""?[]:rel.split(sep2),idx=segments.indexOf("agents");if(idx===-1)return join59(wsRoot,"agents");return join59(wsRoot,...segments.slice(0,idx+1))}async function initAgent(name,options){if(!name||/[\/\\]/.test(name)||name==="."||name===".."||name.includes(".."))console.error("Error: Agent name must not contain path separators or traversal sequences."),process.exit(1);let cwd=process.cwd(),ws=findWorkspace(cwd);if(!ws)console.error("Error: Not in a genie workspace. Run `genie init` first."),process.exit(1);let agentsDir=resolveAgentsDir(ws.root,options.dir);try{scaffoldAgentInWorkspace(ws.root,name,agentsDir)}catch(error2){let message=error2 instanceof Error?error2.message:String(error2);console.error(`Error: ${message}`),process.exit(1)}}function registerInitCommands(program2){program2.command("init").description("Initialize a genie workspace").action(async()=>{await ensureSetupCompleteForInit(),await initWorkspace()}).command("agent <name>").description("Scaffold a new agent in the workspace").option("--dir <path>","Target directory for agent (default: CWD if inside agents/, else workspace agents/)").action(async(name,options)=>{await ensureSetupCompleteForInit(),await initAgent(name,options)})}init_db();init_runtime_events();init_term_format();function parseSince4(since){let match=since.match(/^(\d+)([smhd])$/);if(!match)return since;let amount=Number.parseInt(match[1],10),unit=match[2],ms={s:1000,m:60000,h:3600000,d:86400000}[unit]??3600000;return new Date(Date.now()-amount*ms).toISOString()}async function metricsNowCommand(options){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),snapshots=await sql`SELECT * FROM machine_snapshots ORDER BY created_at DESC LIMIT 1`,agentCount=await sql`SELECT count(DISTINCT agent_id)::int as cnt FROM executors WHERE state NOT IN ('done', 'error', 'terminated')`,teamCount=await sql`SELECT count(*)::int as cnt FROM teams WHERE status = 'in_progress'`,snapshot=snapshots[0]??{},throughput=await queryRuntimeEventThroughput(60),data={active_workers:snapshot.active_workers??agentCount[0]?.cnt??0,active_teams:snapshot.active_teams??teamCount[0]?.cnt??0,tmux_sessions:snapshot.tmux_sessions??0,cpu_percent:snapshot.cpu_percent??null,memory_mb:snapshot.memory_mb??null,snapshot_at:snapshot.created_at?new Date(snapshot.created_at).toISOString():null,events_emitted_last_60s:throughput.emitted};if(options.json){console.log(JSON.stringify(data,null,2));return}if(console.log("Machine State:"),console.log(` Workers: ${data.active_workers}`),console.log(` Teams: ${data.active_teams}`),console.log(` Tmux: ${data.tmux_sessions} sessions`),data.cpu_percent!==null)console.log(` CPU: ${data.cpu_percent}%`);if(data.memory_mb!==null)console.log(` Memory: ${data.memory_mb} MB`);if(data.snapshot_at)console.log(` As of: ${formatRelativeTimestamp(data.snapshot_at)}`);console.log(`
|
|
3907
|
+
Event Throughput (last 60s):`),console.log(` Emitted: ${data.events_emitted_last_60s}`)}async function metricsHistoryCommand(options){if(!await isAvailable())console.error("Database not available."),process.exit(1);let sql=await getConnection(),sinceTs=parseSince4(options.since??"1h"),rows=await sql`
|
|
3877
3908
|
SELECT active_workers, active_teams, tmux_sessions, cpu_percent, memory_mb, created_at
|
|
3878
3909
|
FROM machine_snapshots
|
|
3879
3910
|
WHERE created_at >= ${sinceTs}::timestamptz
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260421.
|
|
3
|
+
"version": "4.260421.11",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|