@automagik/genie 4.260421.17 → 4.260421.19

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/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
  -->
26
26
 
27
27
  <!-- METRICS:START -->
28
- **🚀 31 commits** this week · **6 releases** · **+18.4K LoC** · **5 contributors**
28
+ **⚡ 50 PRs merged** this week · **0 releases** (24h) · **0.7h** avg merge · **100% SHIP**
29
29
 
30
30
  ![Commits per day (30d, all branches)](.genie/assets/commits-30d.svg)
31
31
 
package/dist/genie.js CHANGED
@@ -3706,7 +3706,7 @@ Registering in Omni (${omniUrl})...`);let existingId=await findOmniAgent(name);i
3706
3706
  ORDER BY id ASC
3707
3707
  LIMIT $${values2.length+1}`,[...values2,limit]);for(let row of rows){if(row.id=Number(row.id),row.duration_ms!=null)row.duration_ms=Number(row.duration_ms);if(row.schema_version!=null)row.schema_version=Number(row.schema_version)}return rows}async function getLatestEventId(){let rows=await(await getConnection())`
3708
3708
  SELECT COALESCE(MAX(id), 0)::bigint AS max_id FROM genie_runtime_events
3709
- `;return Number(rows[0]?.max_id??0)}var DEFAULT_CHANNEL_PREFIXES=["cli","agent","wish","hook","resume","executor","mailbox","error","state_transition","schema","session","tmux","cache","runbook","consumer","permissions","team"];init_term_format();init_emit();import{createHmac as createHmac5,randomBytes as randomBytes2}from"crypto";import{writeFileSync as writeFileSync16}from"fs";import{hostname,userInfo}from"os";init_db();import{createHash as createHash6,createHmac as createHmac3}from"crypto";async function verifyAuditChain(opts={}){let sql=await getConnection(),sinceId=opts.since_id??0,limit=opts.limit??1e5,rows=await sql`
3709
+ `;return Number(rows[0]?.max_id??0)}var DEFAULT_CHANNEL_PREFIXES=["cli","agent","wish","hook","resume","executor","mailbox","error","state_transition","schema","session","tmux","cache","runbook","consumer","permissions","team"];init_otel_receiver();init_term_format();init_emit();import{createHmac as createHmac5,randomBytes as randomBytes2}from"crypto";import{writeFileSync as writeFileSync16}from"fs";import{hostname,userInfo}from"os";init_db();import{createHash as createHash6,createHmac as createHmac3}from"crypto";async function verifyAuditChain(opts={}){let sql=await getConnection(),sinceId=opts.since_id??0,limit=opts.limit??1e5,rows=await sql`
3710
3710
  SELECT id, kind, agent, text, data, trace_id::text AS trace_id, span_id::text AS span_id,
3711
3711
  severity, created_at::text AS created_at, chain_hash, chain_key_version
3712
3712
  FROM genie_runtime_events_audit
@@ -3817,12 +3817,12 @@ Registering in Omni (${omniUrl})...`);let existingId=await findOmniAgent(name);i
3817
3817
  FROM tree
3818
3818
  ORDER BY created_at ASC, id ASC
3819
3819
  `;async function loadTimelineRows(traceId){return await(await getConnection()).unsafe(TIMELINE_CTE,[traceId])}function indent(depth){if(depth===0)return"";return`${"\u2502 ".repeat(Math.max(0,depth-1))}\u251C\u2500 `}function renderTreeAscii(rows){let lines=[];for(let r of rows){let ts3=new Date(r.created_at).toISOString().replace("T"," ").slice(11,19),sev=r.severity??"-",sevColor=sev==="error"||sev==="fatal"?color("red",sev.padEnd(5)):sev==="warn"?color("yellow",sev.padEnd(5)):sev==="debug"?color("dim",sev.padEnd(5)):color("cyan",sev.padEnd(5)),span=r.span_id?color("dim",` [${r.span_id.slice(0,8)}]`):"",dur=r.duration_ms!=null?color("dim",` (${r.duration_ms}ms)`):"",subject=r.subject??r.text??"unknown";lines.push(`${color("dim",ts3)} ${sevColor} ${indent(r.depth)}${color("brightCyan",subject)}${span}${dur}`)}return lines}async function timelineCommand(traceId,options={}){let rows=await loadTimelineRows(traceId);if(options.json){console.log(JSON.stringify(rows,null,2));return}if(rows.length===0){console.log(`No events found for trace_id=${traceId}`);return}console.log(color("dim",`Trace ${traceId} \u2014 ${rows.length} event${rows.length===1?"":"s"}`)),console.log("");for(let line of renderTreeAscii(rows))console.log(line)}function printEventsTable(rows){if(rows.length===0){console.log("No audit events found.");return}let sorted=[...rows].reverse(),headers=["Time","Type","Entity","Event","Actor","Details"],data=sorted.map((r)=>[formatRelativeTimestamp(r.created_at),r.entity_type,r.entity_id,r.event_type,r.actor??"-",summarizeDetails(r.details)]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))}),header=headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ");console.log(header),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data){let line=row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | ");console.log(line)}console.log(`
3820
- (${rows.length} event${rows.length===1?"":"s"})`)}function summarizeDetails(details){if(!details)return"";if(typeof details==="string")try{return summarizeDetails(JSON.parse(details))}catch{return details.slice(0,40)}if(Object.keys(details).length===0)return"";let keys=Object.keys(details);if(keys.length===1){let val=details[keys[0]];if(typeof val==="string")return val.slice(0,40);return JSON.stringify(val).slice(0,40)}if(details.error)return`error: ${String(details.error).slice(0,35)}`;if(details.duration_ms)return`${details.duration_ms}ms`;return JSON.stringify(details).slice(0,40)}function printErrorsTable(patterns2){if(patterns2.length===0){console.log("No error patterns found.");return}let headers=["Count","Event","Command","Error","Last Seen"],data=patterns2.map((p)=>[String(p.count),p.event_type,p.entity_id,p.error_message.slice(0,50),formatRelativeTimestamp(p.last_seen)]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(50,Math.max(h.length,...colVals.map((v)=>v.length)))}),header=headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ");console.log(header),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data){let line=row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | ");console.log(line)}console.log(`
3820
+ (${rows.length} event${rows.length===1?"":"s"})`)}function summarizeDetails(details){if(!details)return"";if(typeof details==="string")try{return summarizeDetails(JSON.parse(details))}catch{return details.slice(0,40)}if(Object.keys(details).length===0)return"";let keys=Object.keys(details);if(keys.length===1){let val=details[keys[0]];if(typeof val==="string")return val.slice(0,40);return JSON.stringify(val).slice(0,40)}if(details.error)return`error: ${String(details.error).slice(0,35)}`;if(details.duration_ms)return`${details.duration_ms}ms`;return JSON.stringify(details).slice(0,40)}function printOtelScopeWarning(opts){if(console.log(`
3821
+ \u26A0 OTel-derived events only cover genie-spawned sessions.`),opts.empty){let port=null;try{port=getOtelPort()}catch{port=null}let endpoint=port?`http://127.0.0.1:${port}`:"http://127.0.0.1:<otel-port>";console.log(" If you expected user-session activity, export the OTel vars in your shell rc:"),console.log(` export OTEL_EXPORTER_OTLP_ENDPOINT=${endpoint}`),console.log(" export CLAUDE_CODE_ENABLE_TELEMETRY=1"),console.log(" Then restart your Claude Code session.")}else console.log(" User-initiated Claude Code sessions are not captured unless they export OTLP.")}function isOtelTypeFilter(type2){return typeof type2==="string"&&type2.startsWith("otel_")}function printErrorsTable(patterns2){if(patterns2.length===0){console.log("No error patterns found.");return}let headers=["Count","Event","Command","Error","Last Seen"],data=patterns2.map((p)=>[String(p.count),p.event_type,p.entity_id,p.error_message.slice(0,50),formatRelativeTimestamp(p.last_seen)]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(50,Math.max(h.length,...colVals.map((v)=>v.length)))}),header=headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ");console.log(header),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data){let line=row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | ");console.log(line)}console.log(`
3821
3822
  (${patterns2.length} pattern${patterns2.length===1?"":"s"})`)}function printV2EventsTable(rows){if(rows.length===0){console.log("No events found.");return}let headers=["Time","Subject","Agent","TraceId","SpanId","Severity","Duration"],data=rows.map((r)=>[formatRelativeTimestamp(r.created_at),r.subject??r.text??"-",r.agent,r.trace_id?r.trace_id.slice(0,8):"-",r.span_id?r.span_id.slice(0,8):"-",r.severity??"-",r.duration_ms!=null?`${r.duration_ms}ms`:"-"]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))}),header=headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ");console.log(header),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data){let line=row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | ");console.log(line)}console.log(`
3822
- (${rows.length} event${rows.length===1?"":"s"})`)}async function eventsListV2Command(options){try{let limit=options.limit?Number.parseInt(options.limit,10):50,rows=await queryV2Batch({kindPrefix:options.kind,severity:options.severity,since:options.since??"1h",limit});if(options.json)console.log(JSON.stringify(rows,null,2));else printV2EventsTable(rows)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying v2 events: ${msg}`),process.exit(1)}}async function eventsListCommand(options){if(options.v2)return eventsListV2Command(options);try{let queryOpts={type:options.type,entity:options.entity,since:options.since??"1h",errorsOnly:options.errorsOnly,limit:options.limit?Number.parseInt(options.limit,10):50};if(options.follow){let{followAuditEvents:followAuditEvents2}=await Promise.resolve().then(() => (init_audit(),exports_audit));console.log("Following audit events (Ctrl+C to stop)...");let handle=await followAuditEvents2(queryOpts,(row)=>{if(options.json)console.log(JSON.stringify(row));else{let time=formatRelativeTimestamp(row.created_at),entity=`${row.entity_type}:${row.entity_id}`.slice(0,40),event=row.event_type.padEnd(24),details=summarizeDetails(row.details).slice(0,60);console.log(`${time} ${event} ${entity} ${details}`)}}),shutdown3=()=>{handle.stop(),process.exit(0)};process.on("SIGINT",shutdown3),process.on("SIGTERM",shutdown3),await new Promise(()=>{});return}let rows=await queryAuditEvents(queryOpts);if(options.json)console.log(JSON.stringify(rows,null,2));else printEventsTable(rows)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying events: ${msg}`),process.exit(1)}}var DEFAULT_HIDDEN_EVENT_TYPES=new Set(["command_success","sdk.hook.started"]);async function eventsStreamCommand(options){let{followAuditEvents:followAuditEvents2}=await Promise.resolve().then(() => (init_audit(),exports_audit)),{followRuntimeEvents:followRuntimeEvents2}=await Promise.resolve().then(() => (init_runtime_events(),exports_runtime_events)),{color:color2}=await Promise.resolve().then(() => (init_term_format(),exports_term_format)),{renderAuditEvent:renderAuditEvent2,renderRuntimeEvent:renderRuntimeEvent2,formatEventLine:formatEventLine2}=await Promise.resolve().then(() => (init_event_renderer(),exports_event_renderer)),handles2=[],clockTime=(iso)=>{return(iso instanceof Date?iso:new Date(iso)).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})};if(!options.json){let sources=options.auditOnly?"audit":options.runtimeOnly?"runtime":"audit + runtime";console.log(color2("dim",`Streaming ${sources} events (Ctrl+C to stop)...`))}if(!options.runtimeOnly){let auditHandle=await followAuditEvents2({type:options.type,entity:options.entity,errorsOnly:options.errorsOnly},(row)=>{if(!options.all&&!options.type&&DEFAULT_HIDDEN_EVENT_TYPES.has(row.event_type))return;if(options.json){console.log(JSON.stringify({stream:"audit",...row}));return}console.log(formatEventLine2(clockTime(row.created_at),renderAuditEvent2({entity_type:row.entity_type,entity_id:row.entity_id,event_type:row.event_type,details:row.details})))});handles2.push(auditHandle)}if(!options.auditOnly){let validKinds=["user","assistant","message","state","tool_call","tool_result","system","qa"],kinds=options.kind&&validKinds.includes(options.kind)?[options.kind]:void 0,agentIds=options.agent?[options.agent]:void 0,runtimeHandle=await followRuntimeEvents2({kinds,agentIds,scopeMode:"any"},(event)=>{if(options.json){console.log(JSON.stringify({stream:"runtime",...event}));return}console.log(formatEventLine2(clockTime(event.timestamp),renderRuntimeEvent2({kind:event.kind,agent:event.agent,team:event.team,text:event.text})))},{pollIntervalMs:2000});handles2.push(runtimeHandle)}let shutdown3=async()=>{for(let h of handles2)await h.stop();process.exit(0)};process.on("SIGINT",shutdown3),process.on("SIGTERM",shutdown3),await new Promise(()=>{})}async function eventsErrorsCommand(options){try{let patterns2=await queryErrorPatterns(options.since);if(options.json)console.log(JSON.stringify(patterns2,null,2));else printErrorsTable(patterns2)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying error patterns: ${msg}`),process.exit(1)}}function resolveCostsGroupBy(options){if(options.byWish)return"wish";if(options.byModel)return"model";return"agent"}function printCostsTable(rows,groupBy){if(rows.length===0){console.log("No cost data found.");return}let headers=[groupBy==="agent"?"Agent":groupBy==="wish"?"Wish":"Model","Total Cost","Requests","Avg Cost"],data=rows.map((r)=>[r.group_key,`$${r.total_cost.toFixed(4)}`,String(r.request_count),`$${r.avg_cost.toFixed(4)}`]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))});console.log(headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ")),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data)console.log(row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | "));let totalCost=rows.reduce((sum,r)=>sum+r.total_cost,0),totalReqs=rows.reduce((sum,r)=>sum+r.request_count,0);console.log(`
3823
- Total: $${totalCost.toFixed(4)} across ${totalReqs} requests`)}async function eventsCostsCommand(options){try{let since=options.today?"24h":options.since??"24h",groupBy=resolveCostsGroupBy(options),rows=await queryCostBreakdown(since,groupBy);if(options.json)console.log(JSON.stringify(rows,null,2));else printCostsTable(rows,groupBy),console.log(`
3824
- \u26A0 OTel costs only include genie-spawned sessions. For full server costs: npx ccusage monthly`)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying costs: ${msg}`),process.exit(1)}}function printToolsTable(rows,groupBy){if(rows.length===0){console.log("No tool usage data found.");return}let headers=[groupBy==="tool"?"Tool":"Agent","Calls","Success","Errors","Avg Duration"],data=rows.map((r)=>[r.group_key,String(r.total_calls),String(r.success_count),String(r.error_count),r.avg_duration_ms!=null?`${r.avg_duration_ms.toFixed(0)}ms`:"-"]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))});console.log(headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ")),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data)console.log(row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | "));let totalCalls=rows.reduce((sum,r)=>sum+r.total_calls,0);console.log(`
3825
- (${totalCalls} total tool calls)`)}async function eventsToolsCommand(options){try{let since=options.since??"24h",groupBy=options.byAgent?"agent":"tool",rows=await queryToolUsage(since,groupBy);if(options.json)console.log(JSON.stringify(rows,null,2));else printToolsTable(rows,groupBy)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying tool usage: ${msg}`),process.exit(1)}}async function eventsTimelineCommand(entityId,options){try{let rows=await queryTimeline(entityId);if(options.json)console.log(JSON.stringify(rows,null,2));else printEventsTable(rows)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying timeline: ${msg}`),process.exit(1)}}function printSummary(summary){console.log("Event Summary"),console.log("============="),console.log(`Total events: ${summary.total_events}`),console.log(`Agents spawned: ${summary.agents_spawned}`),console.log(`Tasks moved: ${summary.tasks_moved}`),console.log(`API requests: ${summary.api_requests}`),console.log(`Tool calls: ${summary.tool_calls}`),console.log(`Total cost: $${summary.total_cost.toFixed(4)}`),console.log(`Errors: ${summary.error_count}`)}async function eventsSummaryCommand(options){try{let since=options.today?"24h":options.since??"24h",summary=await querySummary(since);if(options.json)console.log(JSON.stringify(summary,null,2));else printSummary(summary)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying summary: ${msg}`),process.exit(1)}}async function eventsScanCommand(options){let{spawnSync:spawnSync6}=__require("child_process"),args=["ccusage","monthly"];if(options.since)args.push("--since",options.since);if(options.json)args.push("--json");if(options.breakdown)args.push("--breakdown");let result2=spawnSync6("npx",args,{stdio:options.json?"pipe":"inherit",timeout:30000,env:{...process.env,NODE_NO_WARNINGS:"1"}});if(result2.error)console.error("ccusage not available. Install with: npm install -g ccusage"),console.error("Or run directly: npx ccusage monthly"),process.exit(1);if(options.json&&result2.stdout)process.stdout.write(result2.stdout);if(result2.status!==0)process.exit(result2.status??1)}function registerEventsCommands(program2){let events=program2.command("events").description("Audit event log from PG");events.command("list",{isDefault:!0}).description("List recent audit events (add --v2 for the enriched genie_runtime_events surface)").option("--type <type>","Filter by event_type").option("--entity <entity>","Filter by entity_type or entity_id").option("--since <duration>","Time window (e.g., 1h, 30m, 2d)","1h").option("--errors-only","Show only error events").option("--limit <n>","Max rows to return","50").option("--json","Output as JSON").option("-f, --follow","Follow mode \u2014 real-time streaming (alias: genie events stream)").option("--v2","Use enriched genie_runtime_events surface with TraceId/SpanId/Severity/Duration columns").option("--kind <prefix>","Filter v2 rows by kind/subject prefix (e.g., mailbox, agent.lifecycle)").option("--severity <level>","Filter v2 rows by severity (debug|info|warn|error|fatal)").action(async(options)=>{await eventsListCommand(options)}),events.command("timeline-v2 <trace-id>").description("Render causal tree for a trace_id from genie_runtime_events (v2 enriched surface)").option("--json","Output as JSON").action(async(traceId,options)=>{await timelineCommand(traceId,options)}),events.command("stream-follow").description("Follow-stream enriched genie_runtime_events via LISTEN/NOTIFY + id-cursor (v2)").option("--follow","Continuously follow the stream",!0).option("--kind <prefix>","Filter by subject/kind prefix (supports `*` globs, e.g. `detector.*`)").option("--severity <level>","Filter by severity (debug|info|warn|error|fatal)").option("--since <duration>","Seed window (e.g., 5m, 1h)").option("--consumer-id <id>","Persistent consumer id for cursor resume").option("--json","Output as NDJSON").action(async(options)=>{await streamCommand({...options,follow:!0})}),events.command("migrate").description("Backfill legacy audit_events rows into genie_runtime_events (one-shot)").option("--audit","Migrate audit_events \u2192 genie_runtime_events with sentinel source tag").option("--dry-run","Report row deltas without writing").option("--since <duration>","Only migrate rows created within this window").option("--limit <n>","Cap the number of rows migrated per run",(v)=>Number.parseInt(v,10)).option("--json","Output summary as JSON").action(async(options)=>{await migrateCommand(options)}),events.command("stream").description("Stream audit + runtime events in real-time (tail -f style)").option("--type <type>","Filter by event_type").option("--entity <entity>","Filter by entity_type or entity_id").option("--errors-only","Show only error events").option("--kind <kind>","Filter runtime events by kind (tool_call, message, prompt, etc)").option("--agent <agent>","Filter runtime events by agent").option("--audit-only","Stream only audit_events (skip runtime)").option("--runtime-only","Stream only runtime events (skip audit)").option("--all","Show all events including noisy ones (command_success, etc)").option("--json","Output as JSON").action(async(options)=>{await eventsStreamCommand(options)}),events.command("errors").description("Show aggregated error patterns").option("--since <duration>","Time window (e.g., 1h, 24h, 7d)").option("--json","Output as JSON").action(async(options)=>{await eventsErrorsCommand(options)}),events.command("costs").description("Cost breakdown from OTel API request events").option("--today","Show costs from the last 24h").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--by-agent","Group by agent").option("--by-wish","Group by wish").option("--by-model","Group by model").option("--json","Output as JSON").action(async(options)=>{await eventsCostsCommand(options)}),events.command("tools").description("Tool usage analytics from OTel tool events").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--by-tool","Group by tool name (default)").option("--by-agent","Group by agent").option("--json","Output as JSON").action(async(options)=>{await eventsToolsCommand(options)}),events.command("timeline <entity-id>").description("Full event timeline for a task, agent, wish, or traceId").option("--json","Output as JSON").action(async(entityId,options)=>{await eventsTimelineCommand(entityId,options)}),events.command("summary").description("High-level stats: agents spawned, tasks moved, costs, errors").option("--today","Show summary for the last 24h").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--json","Output as JSON").action(async(options)=>{await eventsSummaryCommand(options)}),events.command("scan").description("Full server cost scan via ccusage (all CC sessions, not just genie-spawned)").option("--since <date>","Start date in YYYYMMDD format").option("--json","Output as JSON").option("--breakdown","Show per-model breakdown").action(async(options)=>{await eventsScanCommand(options)}),events.command("subscribe").description("Mint a signed subscription token for genie events stream --follow").requiredOption("--role <role>","RBAC role: events:admin|events:operator|events:subscriber|events:audit").option("--types <csv>","Comma-separated allowed event types (subset of role defaults)").option("--channels <csv>","Comma-separated allowed LISTEN channels (subset of role defaults)").option("--ttl <duration>","Token time-to-live (e.g., 30m, 1h, 24h). Defaults to 1h.").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--subscriber-id <id>","Stable id for the subscriber agent").option("--json","Output as JSON").action(async(options)=>{await subscribeCommand(options)});let admin=events.command("admin").description("Incident-response admin commands (sentinel H6 audited)");admin.command("revoke-subscriber").description("Add a subscription token to the revocation list").requiredOption("--token-id <id>","Token id from `genie events subscribe` output").option("--subscriber-id <id>","Subscriber id associated with the token").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--reason <text>","IR justification for revocation").option("--json","Output as JSON").action(async(options)=>{await revokeSubscriberCommand(options)}),admin.command("rotate-redaction-keys").description("Rotate redaction + audit HMAC keys, preserving prior versions for lookup").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--new-key <material>","Explicit key material (default: 32 bytes hex from /dev/urandom)").option("--target <scope>","redaction|audit|both (default: both)").option("--json","Output as JSON").action(async(options)=>{await rotateRedactionKeysCommand(options)}),admin.command("un-hash").description("Admin reverse-lookup for a Tier-A hash (emits audit.un_hash)").requiredOption("--namespace <ns>","Hash namespace (e.g., agent, actor, session)").requiredOption("--hashed-value <hash>","Tier-A hash tag to reverse").option("--candidates <csv>","Comma-separated candidate plaintexts to brute-force").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--reason <text>","IR justification (appears in audit.un_hash)").option("--ticket <ref>","Incident ticket reference").option("--json","Output as JSON").action(async(options)=>{await unHashCommand(options)}),admin.command("export-audit").description("Produce a signed audit-chain bundle (emits audit.export)").option("--signed","Require GENIE_AUDIT_EXPORT_SECRET for HMAC signing",!0).option("--since <duration>","Advisory time window (authoritative cursor is --since-id)").option("--since-id <n>","Authoritative id cursor to resume from").option("--limit <n>","Max rows to include").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--output <path>","Write bundle to file; omit to print to stdout").option("--reason <text>","IR justification (appears in audit.export)").option("--json","Output as JSON").action(async(options)=>{await exportAuditCommand(options)}),admin.command("verify-chain").description("Quick chain-integrity check (no export)").option("--since-id <n>","Start id","0").option("--limit <n>","Max rows to verify").option("--json","Output as JSON").action(async(options)=>{await verifyChainCommand(options)}),admin.command("list-revocations").description("List revoked token ids for a tenant").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--json","Output as JSON").action(async(options)=>{await listRevocationsCommand(options)})}init_term_format();import{execSync as execSync11}from"child_process";import{existsSync as existsSync38,mkdirSync as mkdirSync16,readFileSync as readFileSync25,writeFileSync as writeFileSync18}from"fs";import{dirname as dirname8,join as join45}from"path";var _boardService;async function getBoardService(){if(!_boardService)_boardService=await Promise.resolve().then(() => (init_board_service(),exports_board_service));return _boardService}var _taskService3;async function getTaskService3(){if(!_taskService3)_taskService3=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService3}var _templateService;async function getTemplateService(){if(!_templateService)_templateService=await Promise.resolve().then(() => (init_template_service(),exports_template_service));return _templateService}async function resolveProjectId(name){let project=await(await getTaskService3()).getProjectByName(name);if(!project)throw Error(`Project not found: ${name}`);return project.id}async function resolveBoard(name,projectName){let bs=await getBoardService(),projectId;if(projectName)projectId=await resolveProjectId(projectName);let board=await bs.getBoard(name,projectId);if(!board)throw Error(`Board not found: ${name}`);return board}function printBoardTable(boards,projectMap){console.log(` ${padRight("NAME",24)} ${padRight("PROJECT",20)} ${padRight("COLUMNS",10)} CREATED`),console.log(` ${"\u2500".repeat(70)}`);for(let b2 of boards){let projName=b2.projectId?projectMap.get(b2.projectId)??b2.projectId:"-",colCount=String(b2.columns.length),created=formatDate(b2.createdAt);console.log(` ${padRight(truncate2(b2.name,22),24)} ${padRight(truncate2(projName,18),20)} ${padRight(colCount,10)} ${created}`)}console.log(`
3823
+ (${rows.length} event${rows.length===1?"":"s"})`)}async function eventsListV2Command(options){try{let limit=options.limit?Number.parseInt(options.limit,10):50,rows=await queryV2Batch({kindPrefix:options.kind,severity:options.severity,since:options.since??"1h",limit});if(options.json)console.log(JSON.stringify(rows,null,2));else printV2EventsTable(rows)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying v2 events: ${msg}`),process.exit(1)}}async function eventsListCommand(options){if(options.v2)return eventsListV2Command(options);try{let queryOpts={type:options.type,entity:options.entity,since:options.since??"1h",errorsOnly:options.errorsOnly,limit:options.limit?Number.parseInt(options.limit,10):50};if(options.follow){let{followAuditEvents:followAuditEvents2}=await Promise.resolve().then(() => (init_audit(),exports_audit));console.log("Following audit events (Ctrl+C to stop)...");let handle=await followAuditEvents2(queryOpts,(row)=>{if(options.json)console.log(JSON.stringify(row));else{let time=formatRelativeTimestamp(row.created_at),entity=`${row.entity_type}:${row.entity_id}`.slice(0,40),event=row.event_type.padEnd(24),details=summarizeDetails(row.details).slice(0,60);console.log(`${time} ${event} ${entity} ${details}`)}}),shutdown3=()=>{handle.stop(),process.exit(0)};process.on("SIGINT",shutdown3),process.on("SIGTERM",shutdown3),await new Promise(()=>{});return}let rows=await queryAuditEvents(queryOpts);if(options.json)console.log(JSON.stringify(rows,null,2));else if(printEventsTable(rows),isOtelTypeFilter(options.type))printOtelScopeWarning({empty:rows.length===0})}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying events: ${msg}`),process.exit(1)}}var DEFAULT_HIDDEN_EVENT_TYPES=new Set(["command_success","sdk.hook.started"]);async function eventsStreamCommand(options){let{followAuditEvents:followAuditEvents2}=await Promise.resolve().then(() => (init_audit(),exports_audit)),{followRuntimeEvents:followRuntimeEvents2}=await Promise.resolve().then(() => (init_runtime_events(),exports_runtime_events)),{color:color2}=await Promise.resolve().then(() => (init_term_format(),exports_term_format)),{renderAuditEvent:renderAuditEvent2,renderRuntimeEvent:renderRuntimeEvent2,formatEventLine:formatEventLine2}=await Promise.resolve().then(() => (init_event_renderer(),exports_event_renderer)),handles2=[],clockTime=(iso)=>{return(iso instanceof Date?iso:new Date(iso)).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})};if(!options.json){let sources=options.auditOnly?"audit":options.runtimeOnly?"runtime":"audit + runtime";console.log(color2("dim",`Streaming ${sources} events (Ctrl+C to stop)...`))}if(!options.runtimeOnly){let auditHandle=await followAuditEvents2({type:options.type,entity:options.entity,errorsOnly:options.errorsOnly},(row)=>{if(!options.all&&!options.type&&DEFAULT_HIDDEN_EVENT_TYPES.has(row.event_type))return;if(options.json){console.log(JSON.stringify({stream:"audit",...row}));return}console.log(formatEventLine2(clockTime(row.created_at),renderAuditEvent2({entity_type:row.entity_type,entity_id:row.entity_id,event_type:row.event_type,details:row.details})))});handles2.push(auditHandle)}if(!options.auditOnly){let validKinds=["user","assistant","message","state","tool_call","tool_result","system","qa"],kinds=options.kind&&validKinds.includes(options.kind)?[options.kind]:void 0,agentIds=options.agent?[options.agent]:void 0,runtimeHandle=await followRuntimeEvents2({kinds,agentIds,scopeMode:"any"},(event)=>{if(options.json){console.log(JSON.stringify({stream:"runtime",...event}));return}console.log(formatEventLine2(clockTime(event.timestamp),renderRuntimeEvent2({kind:event.kind,agent:event.agent,team:event.team,text:event.text})))},{pollIntervalMs:2000});handles2.push(runtimeHandle)}let shutdown3=async()=>{for(let h of handles2)await h.stop();process.exit(0)};process.on("SIGINT",shutdown3),process.on("SIGTERM",shutdown3),await new Promise(()=>{})}async function eventsErrorsCommand(options){try{let patterns2=await queryErrorPatterns(options.since);if(options.json)console.log(JSON.stringify(patterns2,null,2));else printErrorsTable(patterns2)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying error patterns: ${msg}`),process.exit(1)}}function resolveCostsGroupBy(options){if(options.byWish)return"wish";if(options.byModel)return"model";return"agent"}function printCostsTable(rows,groupBy){if(rows.length===0){console.log("No cost data found.");return}let headers=[groupBy==="agent"?"Agent":groupBy==="wish"?"Wish":"Model","Total Cost","Requests","Avg Cost"],data=rows.map((r)=>[r.group_key,`$${r.total_cost.toFixed(4)}`,String(r.request_count),`$${r.avg_cost.toFixed(4)}`]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))});console.log(headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ")),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data)console.log(row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | "));let totalCost=rows.reduce((sum,r)=>sum+r.total_cost,0),totalReqs=rows.reduce((sum,r)=>sum+r.request_count,0);console.log(`
3824
+ Total: $${totalCost.toFixed(4)} across ${totalReqs} requests`)}async function eventsCostsCommand(options){try{let since=options.today?"24h":options.since??"24h",groupBy=resolveCostsGroupBy(options),rows=await queryCostBreakdown(since,groupBy);if(options.json)console.log(JSON.stringify(rows,null,2));else if(printCostsTable(rows,groupBy),printOtelScopeWarning({empty:rows.length===0}),rows.length>0)console.log(" For full server costs: npx ccusage monthly")}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying costs: ${msg}`),process.exit(1)}}function printToolsTable(rows,groupBy){if(rows.length===0){console.log("No tool usage data found.");return}let headers=[groupBy==="tool"?"Tool":"Agent","Calls","Success","Errors","Avg Duration"],data=rows.map((r)=>[r.group_key,String(r.total_calls),String(r.success_count),String(r.error_count),r.avg_duration_ms!=null?`${r.avg_duration_ms.toFixed(0)}ms`:"-"]),widths=headers.map((h,i2)=>{let colVals=data.map((row)=>row[i2]);return Math.min(40,Math.max(h.length,...colVals.map((v)=>v.length)))});console.log(headers.map((h,i2)=>padRight(h,widths[i2])).join(" | ")),console.log(widths.map((w)=>"-".repeat(w)).join("-+-"));for(let row of data)console.log(row.map((v,i2)=>padRight(v.slice(0,widths[i2]),widths[i2])).join(" | "));let totalCalls=rows.reduce((sum,r)=>sum+r.total_calls,0);console.log(`
3825
+ (${totalCalls} total tool calls)`)}async function eventsToolsCommand(options){try{let since=options.since??"24h",groupBy=options.byAgent?"agent":"tool",rows=await queryToolUsage(since,groupBy);if(options.json)console.log(JSON.stringify(rows,null,2));else printToolsTable(rows,groupBy),printOtelScopeWarning({empty:rows.length===0})}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying tool usage: ${msg}`),process.exit(1)}}async function eventsTimelineCommand(entityId,options){try{let rows=await queryTimeline(entityId);if(options.json)console.log(JSON.stringify(rows,null,2));else printEventsTable(rows)}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying timeline: ${msg}`),process.exit(1)}}function printSummary(summary){console.log("Event Summary"),console.log("============="),console.log(`Total events: ${summary.total_events}`),console.log(`Agents spawned: ${summary.agents_spawned}`),console.log(`Tasks moved: ${summary.tasks_moved}`),console.log(`API requests: ${summary.api_requests}`),console.log(`Tool calls: ${summary.tool_calls}`),console.log(`Total cost: $${summary.total_cost.toFixed(4)}`),console.log(`Errors: ${summary.error_count}`)}async function eventsSummaryCommand(options){try{let since=options.today?"24h":options.since??"24h",summary=await querySummary(since);if(options.json)console.log(JSON.stringify(summary,null,2));else{printSummary(summary);let allOtelEmpty=summary.tool_calls===0&&summary.api_requests===0&&summary.total_cost===0;printOtelScopeWarning({empty:allOtelEmpty})}}catch(err){let msg=err instanceof Error?err.message:String(err);console.error(`Error querying summary: ${msg}`),process.exit(1)}}async function eventsScanCommand(options){let{spawnSync:spawnSync6}=__require("child_process"),args=["ccusage","monthly"];if(options.since)args.push("--since",options.since);if(options.json)args.push("--json");if(options.breakdown)args.push("--breakdown");let result2=spawnSync6("npx",args,{stdio:options.json?"pipe":"inherit",timeout:30000,env:{...process.env,NODE_NO_WARNINGS:"1"}});if(result2.error)console.error("ccusage not available. Install with: npm install -g ccusage"),console.error("Or run directly: npx ccusage monthly"),process.exit(1);if(options.json&&result2.stdout)process.stdout.write(result2.stdout);if(result2.status!==0)process.exit(result2.status??1)}function registerEventsCommands(program2){let events=program2.command("events").description("Audit event log from PG");events.command("list",{isDefault:!0}).description("List recent audit events (add --v2 for the enriched genie_runtime_events surface)").option("--type <type>","Filter by event_type").option("--entity <entity>","Filter by entity_type or entity_id").option("--since <duration>","Time window (e.g., 1h, 30m, 2d)","1h").option("--errors-only","Show only error events").option("--limit <n>","Max rows to return","50").option("--json","Output as JSON").option("-f, --follow","Follow mode \u2014 real-time streaming (alias: genie events stream)").option("--v2","Use enriched genie_runtime_events surface with TraceId/SpanId/Severity/Duration columns").option("--kind <prefix>","Filter v2 rows by kind/subject prefix (e.g., mailbox, agent.lifecycle)").option("--severity <level>","Filter v2 rows by severity (debug|info|warn|error|fatal)").action(async(options)=>{await eventsListCommand(options)}),events.command("timeline-v2 <trace-id>").description("Render causal tree for a trace_id from genie_runtime_events (v2 enriched surface)").option("--json","Output as JSON").action(async(traceId,options)=>{await timelineCommand(traceId,options)}),events.command("stream-follow").description("Follow-stream enriched genie_runtime_events via LISTEN/NOTIFY + id-cursor (v2)").option("--follow","Continuously follow the stream",!0).option("--kind <prefix>","Filter by subject/kind prefix (supports `*` globs, e.g. `detector.*`)").option("--severity <level>","Filter by severity (debug|info|warn|error|fatal)").option("--since <duration>","Seed window (e.g., 5m, 1h)").option("--consumer-id <id>","Persistent consumer id for cursor resume").option("--json","Output as NDJSON").action(async(options)=>{await streamCommand({...options,follow:!0})}),events.command("migrate").description("Backfill legacy audit_events rows into genie_runtime_events (one-shot)").option("--audit","Migrate audit_events \u2192 genie_runtime_events with sentinel source tag").option("--dry-run","Report row deltas without writing").option("--since <duration>","Only migrate rows created within this window").option("--limit <n>","Cap the number of rows migrated per run",(v)=>Number.parseInt(v,10)).option("--json","Output summary as JSON").action(async(options)=>{await migrateCommand(options)}),events.command("stream").description("Stream audit + runtime events in real-time (tail -f style)").option("--type <type>","Filter by event_type").option("--entity <entity>","Filter by entity_type or entity_id").option("--errors-only","Show only error events").option("--kind <kind>","Filter runtime events by kind (tool_call, message, prompt, etc)").option("--agent <agent>","Filter runtime events by agent").option("--audit-only","Stream only audit_events (skip runtime)").option("--runtime-only","Stream only runtime events (skip audit)").option("--all","Show all events including noisy ones (command_success, etc)").option("--json","Output as JSON").action(async(options)=>{await eventsStreamCommand(options)}),events.command("errors").description("Show aggregated error patterns").option("--since <duration>","Time window (e.g., 1h, 24h, 7d)").option("--json","Output as JSON").action(async(options)=>{await eventsErrorsCommand(options)}),events.command("costs").description("Cost breakdown from OTel API request events").option("--today","Show costs from the last 24h").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--by-agent","Group by agent").option("--by-wish","Group by wish").option("--by-model","Group by model").option("--json","Output as JSON").action(async(options)=>{await eventsCostsCommand(options)}),events.command("tools").description("Tool usage analytics from OTel tool events").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--by-tool","Group by tool name (default)").option("--by-agent","Group by agent").option("--json","Output as JSON").action(async(options)=>{await eventsToolsCommand(options)}),events.command("timeline <entity-id>").description("Full event timeline for a task, agent, wish, or traceId").option("--json","Output as JSON").action(async(entityId,options)=>{await eventsTimelineCommand(entityId,options)}),events.command("summary").description("High-level stats: agents spawned, tasks moved, costs, errors").option("--today","Show summary for the last 24h").option("--since <duration>","Time window (e.g., 1h, 7d)","24h").option("--json","Output as JSON").action(async(options)=>{await eventsSummaryCommand(options)}),events.command("scan").description("Full server cost scan via ccusage (all CC sessions, not just genie-spawned)").option("--since <date>","Start date in YYYYMMDD format").option("--json","Output as JSON").option("--breakdown","Show per-model breakdown").action(async(options)=>{await eventsScanCommand(options)}),events.command("subscribe").description("Mint a signed subscription token for genie events stream --follow").requiredOption("--role <role>","RBAC role: events:admin|events:operator|events:subscriber|events:audit").option("--types <csv>","Comma-separated allowed event types (subset of role defaults)").option("--channels <csv>","Comma-separated allowed LISTEN channels (subset of role defaults)").option("--ttl <duration>","Token time-to-live (e.g., 30m, 1h, 24h). Defaults to 1h.").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--subscriber-id <id>","Stable id for the subscriber agent").option("--json","Output as JSON").action(async(options)=>{await subscribeCommand(options)});let admin=events.command("admin").description("Incident-response admin commands (sentinel H6 audited)");admin.command("revoke-subscriber").description("Add a subscription token to the revocation list").requiredOption("--token-id <id>","Token id from `genie events subscribe` output").option("--subscriber-id <id>","Subscriber id associated with the token").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--reason <text>","IR justification for revocation").option("--json","Output as JSON").action(async(options)=>{await revokeSubscriberCommand(options)}),admin.command("rotate-redaction-keys").description("Rotate redaction + audit HMAC keys, preserving prior versions for lookup").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--new-key <material>","Explicit key material (default: 32 bytes hex from /dev/urandom)").option("--target <scope>","redaction|audit|both (default: both)").option("--json","Output as JSON").action(async(options)=>{await rotateRedactionKeysCommand(options)}),admin.command("un-hash").description("Admin reverse-lookup for a Tier-A hash (emits audit.un_hash)").requiredOption("--namespace <ns>","Hash namespace (e.g., agent, actor, session)").requiredOption("--hashed-value <hash>","Tier-A hash tag to reverse").option("--candidates <csv>","Comma-separated candidate plaintexts to brute-force").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--reason <text>","IR justification (appears in audit.un_hash)").option("--ticket <ref>","Incident ticket reference").option("--json","Output as JSON").action(async(options)=>{await unHashCommand(options)}),admin.command("export-audit").description("Produce a signed audit-chain bundle (emits audit.export)").option("--signed","Require GENIE_AUDIT_EXPORT_SECRET for HMAC signing",!0).option("--since <duration>","Advisory time window (authoritative cursor is --since-id)").option("--since-id <n>","Authoritative id cursor to resume from").option("--limit <n>","Max rows to include").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--output <path>","Write bundle to file; omit to print to stdout").option("--reason <text>","IR justification (appears in audit.export)").option("--json","Output as JSON").action(async(options)=>{await exportAuditCommand(options)}),admin.command("verify-chain").description("Quick chain-integrity check (no export)").option("--since-id <n>","Start id","0").option("--limit <n>","Max rows to verify").option("--json","Output as JSON").action(async(options)=>{await verifyChainCommand(options)}),admin.command("list-revocations").description("List revoked token ids for a tenant").option("--tenant <id>",'Tenant id. Defaults to "default".').option("--json","Output as JSON").action(async(options)=>{await listRevocationsCommand(options)})}init_term_format();import{execSync as execSync11}from"child_process";import{existsSync as existsSync38,mkdirSync as mkdirSync16,readFileSync as readFileSync25,writeFileSync as writeFileSync18}from"fs";import{dirname as dirname8,join as join45}from"path";var _boardService;async function getBoardService(){if(!_boardService)_boardService=await Promise.resolve().then(() => (init_board_service(),exports_board_service));return _boardService}var _taskService3;async function getTaskService3(){if(!_taskService3)_taskService3=await Promise.resolve().then(() => (init_task_service(),exports_task_service));return _taskService3}var _templateService;async function getTemplateService(){if(!_templateService)_templateService=await Promise.resolve().then(() => (init_template_service(),exports_template_service));return _templateService}async function resolveProjectId(name){let project=await(await getTaskService3()).getProjectByName(name);if(!project)throw Error(`Project not found: ${name}`);return project.id}async function resolveBoard(name,projectName){let bs=await getBoardService(),projectId;if(projectName)projectId=await resolveProjectId(projectName);let board=await bs.getBoard(name,projectId);if(!board)throw Error(`Board not found: ${name}`);return board}function printBoardTable(boards,projectMap){console.log(` ${padRight("NAME",24)} ${padRight("PROJECT",20)} ${padRight("COLUMNS",10)} CREATED`),console.log(` ${"\u2500".repeat(70)}`);for(let b2 of boards){let projName=b2.projectId?projectMap.get(b2.projectId)??b2.projectId:"-",colCount=String(b2.columns.length),created=formatDate(b2.createdAt);console.log(` ${padRight(truncate2(b2.name,22),24)} ${padRight(truncate2(projName,18),20)} ${padRight(colCount,10)} ${created}`)}console.log(`
3826
3826
  ${boards.length} board${boards.length===1?"":"s"}`)}function printColumnPipeline(columns,header){console.log(`
3827
3827
  ${header}`),console.log("\u2500".repeat(60));let sorted=[...columns].sort((a,b2)=>a.position-b2.position);for(let i2=0;i2<sorted.length;i2++){let c=sorted[i2],arrow=i2<sorted.length-1?" \u2192":"",gate=` [gate: ${c.gate}]`,action=c.action?` (action: ${c.action})`:"";console.log(` ${i2+1}. ${c.label??c.name}${gate}${action}${arrow}`)}console.log("")}function printTemplateTable(templates){console.log(` ${padRight("NAME",24)} ${padRight("COLUMNS",10)} ${padRight("BUILTIN",10)} DESCRIPTION`),console.log(` ${"\u2500".repeat(80)}`);for(let t of templates){let colCount=String(t.columns.length),builtin=t.isBuiltin?"yes":"no",desc=t.description?truncate2(t.description,30):"-";console.log(` ${padRight(truncate2(t.name,22),24)} ${padRight(colCount,10)} ${padRight(builtin,10)} ${desc}`)}console.log(`
3828
3828
  ${templates.length} template${templates.length===1?"":"s"}`)}async function handleBoardCreate(name,options){let bs=await getBoardService(),tmpl=await getTemplateService(),projectId;if(options.project)projectId=await resolveProjectId(options.project);let columns;if(options.from){let template=await tmpl.getTemplate(options.from);if(!template)throw Error(`Template not found: ${options.from}`);columns=template.columns}else if(options.columns)columns=options.columns.split(",").map((colName,i2)=>({name:colName.trim(),label:colName.trim(),gate:"human",position:i2}));let board=await bs.createBoard({name,projectId,description:options.description,columns});console.log(`Created board "${board.name}" (${board.id}) with ${board.columns.length} columns`)}async function handleBoardList(options){let bs=await getBoardService(),ts3=await getTaskService3(),projectId;if(options.project)projectId=await resolveProjectId(options.project);let boards=await bs.listBoards(projectId,options.all);if(options.json){console.log(JSON.stringify(boards,null,2));return}let projects=await ts3.listProjects(),projectMap=new Map;for(let p of projects)projectMap.set(p.id,p.name);printBoardTable(boards,projectMap)}async function handleBoardShow(name,options){let ts3=await getTaskService3(),board=await resolveBoard(name,options.project);if(options.json){console.log(JSON.stringify(board,null,2));return}let projectName="-";if(board.projectId){let proj=(await ts3.listProjects()).find((p)=>p.id===board.projectId);if(proj)projectName=proj.name}if(console.log(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260421.17",
3
+ "version": "4.260421.19",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260421.17",
3
+ "version": "4.260421.19",
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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260421.17",
3
+ "version": "4.260421.19",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",