agentix-cli 0.80.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/{App-2UCGXCX3.js → App-HF6W6CV2.js} +2 -2
  2. package/dist/{App-2UCGXCX3.js.map → App-HF6W6CV2.js.map} +1 -1
  3. package/dist/ChatApp-74VBWP7R.js +7 -0
  4. package/dist/{ChatApp-IRPSBYC7.js.map → ChatApp-74VBWP7R.js.map} +1 -1
  5. package/dist/{agent-UPTK3HFR.js → agent-BDEPUFBQ.js} +2 -2
  6. package/dist/{board-dashboard-GAUAYKWV.js → board-dashboard-TWEF5XVE.js} +189 -169
  7. package/dist/board-dashboard-TWEF5XVE.js.map +1 -0
  8. package/dist/{chunk-PXIGWFIQ.js → chunk-4KJ3PCAI.js} +2 -2
  9. package/dist/{chunk-2YJ2ZIYC.js → chunk-5GXCOHDM.js} +2 -2
  10. package/dist/{chunk-2YJ2ZIYC.js.map → chunk-5GXCOHDM.js.map} +1 -1
  11. package/dist/{chunk-3GYCFRBK.js → chunk-74FSHUB3.js} +2 -2
  12. package/dist/{chunk-AIHWGU4P.js → chunk-ATXE3EMV.js} +2 -2
  13. package/dist/{chunk-BIJB7CNG.js → chunk-BB3ESU74.js} +2 -2
  14. package/dist/{chunk-Z6G26FWC.js → chunk-BDM4VTBR.js} +52 -52
  15. package/dist/chunk-BDM4VTBR.js.map +1 -0
  16. package/dist/chunk-BYD5B3P3.js +9 -0
  17. package/dist/{chunk-Z3IP66SL.js.map → chunk-BYD5B3P3.js.map} +1 -1
  18. package/dist/chunk-EFV7U5LD.js +152 -0
  19. package/dist/chunk-EFV7U5LD.js.map +1 -0
  20. package/dist/chunk-ES7Z64Z5.js +22 -0
  21. package/dist/chunk-ES7Z64Z5.js.map +1 -0
  22. package/dist/{chunk-WP6KLXTP.js → chunk-GLQLCBJS.js} +4 -4
  23. package/dist/chunk-GLQLCBJS.js.map +1 -0
  24. package/dist/{chunk-PHFOYJUB.js → chunk-GUAJNZIX.js} +2 -2
  25. package/dist/{chunk-4NUF3SXN.js → chunk-HUQRPEDP.js} +2 -2
  26. package/dist/{chunk-36TJTWG3.js → chunk-HYE2UUQ4.js} +248 -217
  27. package/dist/chunk-HYE2UUQ4.js.map +1 -0
  28. package/dist/chunk-JG3O5GL6.js +5 -0
  29. package/dist/{chunk-I2Z6D3MI.js.map → chunk-JG3O5GL6.js.map} +1 -1
  30. package/dist/chunk-JXF54PT7.js +2 -0
  31. package/dist/chunk-JXF54PT7.js.map +1 -0
  32. package/dist/chunk-LTHQXWZN.js +51 -0
  33. package/dist/chunk-LTHQXWZN.js.map +1 -0
  34. package/dist/{chunk-BBI3HG77.js → chunk-LUL4ILAQ.js} +2 -2
  35. package/dist/{chunk-N6EWZGIX.js → chunk-PN6XHTG5.js} +6 -6
  36. package/dist/{chunk-N6EWZGIX.js.map → chunk-PN6XHTG5.js.map} +1 -1
  37. package/dist/{chunk-KAFUQILA.js → chunk-TW4L6RP2.js} +2 -2
  38. package/dist/chunk-UCKKAWLZ.js +2 -0
  39. package/dist/chunk-UCKKAWLZ.js.map +1 -0
  40. package/dist/{chunk-PT5Z5WW4.js → chunk-VVW4JYV6.js} +24 -24
  41. package/dist/chunk-VVW4JYV6.js.map +1 -0
  42. package/dist/{chunk-Z522XZBL.js → chunk-WWU2D65N.js} +2 -2
  43. package/dist/chunk-XF65CDNS.js +5 -0
  44. package/dist/{chunk-AFSM3IY3.js.map → chunk-XF65CDNS.js.map} +1 -1
  45. package/dist/{chunk-O67KV3DX.js → chunk-XQ7MVPWP.js} +7 -7
  46. package/dist/chunk-XQ7MVPWP.js.map +1 -0
  47. package/dist/{chunk-7EIUNFDF.js → chunk-ZDDJNKU5.js} +2 -2
  48. package/dist/{chunk-D3FDPA74.js → chunk-ZUAV3PTL.js} +2 -2
  49. package/dist/cli.js +1 -1
  50. package/dist/cli.js.map +1 -1
  51. package/dist/client-JDY2FZUF.js +2 -0
  52. package/dist/config-JCETBKWT.js +2 -0
  53. package/dist/config-mutator-YQWTY47O.js +2 -0
  54. package/dist/doctor-6EWW7NC2.js +2 -0
  55. package/dist/{facts-YY2364CP.js → facts-5T5GRUTG.js} +6 -6
  56. package/dist/{facts-YY2364CP.js.map → facts-5T5GRUTG.js.map} +1 -1
  57. package/dist/{failure-candidates-RIXA3Y6D.js → failure-candidates-PBPF45GN.js} +2 -2
  58. package/dist/index.d.ts +630 -502
  59. package/dist/index.js +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/{chunk-ECEDX6C6.js → program-FUYHN2F7.js} +193 -183
  62. package/dist/program-FUYHN2F7.js.map +1 -0
  63. package/dist/promote-ZZWMGVO2.js +2 -0
  64. package/dist/query-OQBB7EFS.js +2 -0
  65. package/dist/registry-PLSOZ3CL.js +2 -0
  66. package/dist/request-planner-HX44G2SX.js +2 -0
  67. package/dist/{request-planner-RNXA2QAH.js.map → request-planner-HX44G2SX.js.map} +1 -1
  68. package/dist/review-candidates-FBDLPU6H.js +4 -0
  69. package/dist/{review-candidates-THKWXS7S.js.map → review-candidates-FBDLPU6H.js.map} +1 -1
  70. package/dist/routing-3SZHWHUA.js +2 -0
  71. package/dist/schedule-tool-5FULSHWJ.js +2 -0
  72. package/dist/scheduler-ITOKSMYT.js +2 -0
  73. package/dist/seat-2HJG3UNW.js +2 -0
  74. package/dist/select-UKAOL7QB.js +2 -0
  75. package/dist/{select-PRQP2B6G.js.map → select-UKAOL7QB.js.map} +1 -1
  76. package/dist/set-enabled-ADFSNG5A.js +2 -0
  77. package/dist/{set-enabled-E2ML2E33.js.map → set-enabled-ADFSNG5A.js.map} +1 -1
  78. package/dist/signal-exit-WL7G3EEZ.js +2 -0
  79. package/dist/signal-exit-WL7G3EEZ.js.map +1 -0
  80. package/dist/{surface-usage-HVVP22SA.js → surface-usage-O5L4KLGS.js} +2 -2
  81. package/dist/{tool-4WPUUUE4.js → tool-MSXWU44P.js} +2 -2
  82. package/dist/{tool-4WPUUUE4.js.map → tool-MSXWU44P.js.map} +1 -1
  83. package/dist/tool-X7YEIJVZ.js +4 -0
  84. package/dist/tool-X7YEIJVZ.js.map +1 -0
  85. package/dist/wiki-QUVWB4IN.js +2 -0
  86. package/package.json +1 -1
  87. package/dist/ChatApp-IRPSBYC7.js +0 -7
  88. package/dist/board-dashboard-GAUAYKWV.js.map +0 -1
  89. package/dist/chunk-36TJTWG3.js.map +0 -1
  90. package/dist/chunk-445P5QPS.js +0 -15
  91. package/dist/chunk-445P5QPS.js.map +0 -1
  92. package/dist/chunk-6TLQ4I32.js +0 -57
  93. package/dist/chunk-6TLQ4I32.js.map +0 -1
  94. package/dist/chunk-AFSM3IY3.js +0 -5
  95. package/dist/chunk-ECEDX6C6.js.map +0 -1
  96. package/dist/chunk-I2Z6D3MI.js +0 -5
  97. package/dist/chunk-KBSBMOOL.js +0 -152
  98. package/dist/chunk-KBSBMOOL.js.map +0 -1
  99. package/dist/chunk-NMFXY3QU.js +0 -2
  100. package/dist/chunk-NMFXY3QU.js.map +0 -1
  101. package/dist/chunk-O67KV3DX.js.map +0 -1
  102. package/dist/chunk-PT5Z5WW4.js.map +0 -1
  103. package/dist/chunk-WP6KLXTP.js.map +0 -1
  104. package/dist/chunk-Z3IP66SL.js +0 -9
  105. package/dist/chunk-Z6G26FWC.js.map +0 -1
  106. package/dist/client-ABDGDO7S.js +0 -2
  107. package/dist/config-XPFCUOQT.js +0 -2
  108. package/dist/config-mutator-WYHQV2XF.js +0 -2
  109. package/dist/doctor-XLLNQRRT.js +0 -2
  110. package/dist/program-KZOBDSXQ.js +0 -2
  111. package/dist/promote-YUZL3ZU2.js +0 -2
  112. package/dist/query-3XH7I6WX.js +0 -2
  113. package/dist/registry-5OD2IN5G.js +0 -2
  114. package/dist/request-planner-RNXA2QAH.js +0 -2
  115. package/dist/review-candidates-THKWXS7S.js +0 -4
  116. package/dist/routing-X45VX723.js +0 -2
  117. package/dist/schedule-tool-ZTL6UZCC.js +0 -2
  118. package/dist/scheduler-VH7IJ4VA.js +0 -2
  119. package/dist/seat-LQ47SSNN.js +0 -2
  120. package/dist/select-PRQP2B6G.js +0 -2
  121. package/dist/set-enabled-E2ML2E33.js +0 -2
  122. package/dist/tool-67JK7SK6.js +0 -4
  123. package/dist/tool-67JK7SK6.js.map +0 -1
  124. package/dist/wiki-AS5YHSR7.js +0 -2
  125. package/dist/wiki-AS5YHSR7.js.map +0 -1
  126. /package/dist/{agent-UPTK3HFR.js.map → agent-BDEPUFBQ.js.map} +0 -0
  127. /package/dist/{chunk-PXIGWFIQ.js.map → chunk-4KJ3PCAI.js.map} +0 -0
  128. /package/dist/{chunk-3GYCFRBK.js.map → chunk-74FSHUB3.js.map} +0 -0
  129. /package/dist/{chunk-AIHWGU4P.js.map → chunk-ATXE3EMV.js.map} +0 -0
  130. /package/dist/{chunk-BIJB7CNG.js.map → chunk-BB3ESU74.js.map} +0 -0
  131. /package/dist/{chunk-PHFOYJUB.js.map → chunk-GUAJNZIX.js.map} +0 -0
  132. /package/dist/{chunk-4NUF3SXN.js.map → chunk-HUQRPEDP.js.map} +0 -0
  133. /package/dist/{chunk-BBI3HG77.js.map → chunk-LUL4ILAQ.js.map} +0 -0
  134. /package/dist/{chunk-KAFUQILA.js.map → chunk-TW4L6RP2.js.map} +0 -0
  135. /package/dist/{chunk-Z522XZBL.js.map → chunk-WWU2D65N.js.map} +0 -0
  136. /package/dist/{chunk-7EIUNFDF.js.map → chunk-ZDDJNKU5.js.map} +0 -0
  137. /package/dist/{chunk-D3FDPA74.js.map → chunk-ZUAV3PTL.js.map} +0 -0
  138. /package/dist/{client-ABDGDO7S.js.map → client-JDY2FZUF.js.map} +0 -0
  139. /package/dist/{config-XPFCUOQT.js.map → config-JCETBKWT.js.map} +0 -0
  140. /package/dist/{config-mutator-WYHQV2XF.js.map → config-mutator-YQWTY47O.js.map} +0 -0
  141. /package/dist/{doctor-XLLNQRRT.js.map → doctor-6EWW7NC2.js.map} +0 -0
  142. /package/dist/{failure-candidates-RIXA3Y6D.js.map → failure-candidates-PBPF45GN.js.map} +0 -0
  143. /package/dist/{program-KZOBDSXQ.js.map → promote-ZZWMGVO2.js.map} +0 -0
  144. /package/dist/{promote-YUZL3ZU2.js.map → query-OQBB7EFS.js.map} +0 -0
  145. /package/dist/{query-3XH7I6WX.js.map → registry-PLSOZ3CL.js.map} +0 -0
  146. /package/dist/{registry-5OD2IN5G.js.map → routing-3SZHWHUA.js.map} +0 -0
  147. /package/dist/{routing-X45VX723.js.map → schedule-tool-5FULSHWJ.js.map} +0 -0
  148. /package/dist/{schedule-tool-ZTL6UZCC.js.map → scheduler-ITOKSMYT.js.map} +0 -0
  149. /package/dist/{scheduler-VH7IJ4VA.js.map → seat-2HJG3UNW.js.map} +0 -0
  150. /package/dist/{seat-LQ47SSNN.js.map → surface-usage-O5L4KLGS.js.map} +0 -0
  151. /package/dist/{surface-usage-HVVP22SA.js.map → wiki-QUVWB4IN.js.map} +0 -0
@@ -3,9 +3,9 @@ import{a as i,b as c}from"./chunk-FCPTN6NF.js";var m="[Institutional Wiki";funct
3
3
  task_id, agent_id, channel, chat_id, workflow_run_id, workflow_id,
4
4
  workflow_node_id, intent_event_id, intent_decided_by, resume_session_id,
5
5
  model, status, started_at, message_preview, original_message,
6
- resume_origin, resume_attempt, resumed_from
7
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?, ?, ?, ?)
8
- `).run(t,n.agentId,n.channel??null,n.chatId??null,n.workflowRunId??null,n.workflowId??null,n.workflowNodeId??null,n.intentEventId??null,n.intentDecidedBy??null,n.resumeSessionId??null,n.model??null,Date.now(),n.messagePreview??null,n.originalMessage??null,n.resumeOrigin??null,n.resumeAttempt??0,n.resumedFrom??null),t}function T(e,n,t){let r=Date.now();e.prepare(`
6
+ resume_origin, resume_attempt, resumed_from, person
7
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?, ?, ?, ?, ?)
8
+ `).run(t,n.agentId,n.channel??null,n.chatId??null,n.workflowRunId??null,n.workflowId??null,n.workflowNodeId??null,n.intentEventId??null,n.intentDecidedBy??null,n.resumeSessionId??null,n.model??null,Date.now(),n.messagePreview??null,n.originalMessage??null,n.resumeOrigin??null,n.resumeAttempt??0,n.resumedFrom??null,n.person??null),t}function T(e,n,t){let r=Date.now();e.prepare(`
9
9
  UPDATE task_traces SET
10
10
  status = ?,
11
11
  final_session_id = ?,
@@ -58,4 +58,4 @@ import{a as i,b as c}from"./chunk-FCPTN6NF.js";var m="[Institutional Wiki";funct
58
58
  ORDER BY started_at DESC
59
59
  LIMIT ?
60
60
  `;return r.push(s),e.prepare(a).all(...r).map(d)}export{p as a,h as b,T as c,E as d,g as e,b as f,R as g,C as h,S as i,A as j,D as k};
61
- //# sourceMappingURL=chunk-WP6KLXTP.js.map
61
+ //# sourceMappingURL=chunk-GLQLCBJS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/injected-context.ts","../src/storage/traces.ts"],"sourcesContent":["import type { InjectedContext } from \"@/storage/traces\"\n\n// --- Injected lessons per task (#98) ---\n//\n// Which memory facts, procedures and wiki catalog actually reached the\n// prompt. Candidates are not enough: the request-context selector can drop\n// a whole layer, and the layer budgets in buildAgentContext can cut a layer\n// short. So a lesson counts as injected only when its text is in the\n// assembled context. Only ids are recorded, never content, and the lists\n// are capped, so the trace row stays small.\n\nexport const MAX_INJECTED_IDS = 20\nconst MAX_ID_LENGTH = 80\n\nexport interface InjectionCandidates {\n memory?: Array<{ id: string; content: string }>\n procedures?: Array<{ id: string; title: string }>\n /** The wiki catalog block offered to the prompt, if any. */\n wikiContext?: string\n}\n\n/** The first line of the wiki catalog block; see buildWikiContext. */\nconst WIKI_MARKER = \"[Institutional Wiki\"\n\nfunction capIds(ids: string[]): string[] {\n return [...new Set(ids)].slice(0, MAX_INJECTED_IDS).map((id) => id.slice(0, MAX_ID_LENGTH))\n}\n\nexport function injectedContextOf(assembled: string, candidates: InjectionCandidates): InjectedContext {\n const text = assembled ?? \"\"\n return {\n memory: capIds((candidates.memory ?? []).filter((m) => m.content && text.includes(m.content)).map((m) => m.id)),\n procedures: capIds(\n (candidates.procedures ?? []).filter((p) => text.includes(`[Known procedure: ${p.title}]`)).map((p) => p.id),\n ),\n wiki: Boolean(candidates.wikiContext) && text.includes(WIKI_MARKER),\n }\n}\n\n/** Clamp an InjectedContext from any source to the recorded bounds. */\nexport function boundInjectedContext(ctx: InjectedContext): InjectedContext {\n return { memory: capIds(ctx.memory), procedures: capIds(ctx.procedures), wiki: ctx.wiki === true }\n}\n","import type Database from \"better-sqlite3\"\nimport { newEventId } from \"@/intent/ulid\"\nimport { boundInjectedContext } from \"@/agents/injected-context\"\n\n// --- Task trace store ---\n//\n// Improvement plan #2 — per-task observability backed by SQLite. One\n// task_traces row per executeTask invocation, an append-only stream of\n// task_trace_steps inside it. The store is intentionally dumb: it stores\n// what callers give it. Callers (capture sites in src/agents/runtime.ts)\n// are responsible for byte-capping large step payloads so the daemon\n// memory stays bounded under tool-heavy turns.\n//\n// Why a separate store layer (vs writing inline in runtime.ts)?\n// - Tests can exercise the trace lifecycle against a temp SQLite without\n// spinning up the agent runtime.\n// - The HTTP endpoints (GET /task/:id/trace) read through the same\n// functions producers write through, so there's a single source of\n// truth on field names + semantics.\n// - Future capture sites (sdk tier, orchestrator tier) reuse this API\n// without copying SQL.\n//\n// Why ULID for task_id?\n// - URL-safe in HTTP routes (GET /task/:id/trace).\n// - Time-sortable, so listTraces ORDER BY started_at and ORDER BY\n// task_id agree without an explicit timestamp column index.\n// - Already in-tree (src/intent/ulid.ts); no new dep.\n//\n// Cross-DB FK note:\n// intent_event_id and intent_decided_by are logical foreign keys into\n// the intent ledger at .agentx/intent/ledger.sqlite. better-sqlite3\n// doesn't enforce cross-database FKs and we don't ATTACH the ledger\n// here on purpose — the rescue plan's append-only contract on the\n// ledger is honoured by routing all writes through src/intent/ledger.ts.\n// Joins happen at the HTTP / CLI layer when needed.\n\nexport interface TraceStartInput {\n agentId: string\n channel?: string | null\n chatId?: string | null\n messagePreview?: string | null\n /** Full untruncated user message — used by `agentx trace replay <taskId>`\n * to re-fire a recorded task against the current agent config. NULL on\n * rows from before migration v8, in which case replay falls back to\n * messagePreview (which is capped at 200 chars). */\n originalMessage?: string | null\n workflowRunId?: string | null\n workflowId?: string | null\n workflowNodeId?: string | null\n intentEventId?: string | null\n intentDecidedBy?: string | null\n resumeSessionId?: string | null\n model?: string | null\n /** How to re-enter this run after a restart (JSON, see agents/resume). */\n resumeOrigin?: string | null\n /** 0 for a fresh run; n for the n-th resume of a cut-off run. */\n resumeAttempt?: number | null\n /** The cut-off run this one continues. */\n resumedFrom?: string | null\n /** The known person who started the chain (people, #384). */\n person?: string | null\n}\n\nexport interface TraceEndInput {\n status: \"ok\" | \"error\" | \"timeout\"\n finalSessionId?: string | null\n inputTokens?: number | null\n outputTokens?: number | null\n cacheReadTokens?: number | null\n cacheCreateTokens?: number | null\n tier2InputTokens?: number | null\n tier2OutputTokens?: number | null\n tier2CacheReadTokens?: number | null\n tier2CacheCreateTokens?: number | null\n /** Whether the turn continued a provider session. The resume decision\n * is made after task:started, so it is recorded at the end. Omitted\n * leaves both resumed and resume_session_id untouched. */\n resumed?: boolean | null\n resumeSessionId?: string | null\n /** Request-gate experiment arm: \"treatment\" | \"holdout\". */\n jevArm?: string | null\n /** Runtime-reported turn count (Claude `num_turns`). */\n numTurns?: number | null\n /** Lessons injected into the prompt. See InjectedContext. */\n injectedContext?: InjectedContext | null\n error?: string | null\n /** The agent's final reply text. Stored verbatim so `replay --diff`\n * can compare original output vs the new run's output without\n * reconstructing it from the step ledger. NULL when the response\n * wasn't captured (older rows or non-text outputs). */\n finalResponse?: string | null\n}\n\n/** Ids of the lessons injected into one task's prompt. Memory facts and\n * procedures are matched per message, so their ids are recorded; the wiki\n * is injected as a whole catalog, so only its presence is. */\nexport interface InjectedContext {\n memory: string[]\n procedures: string[]\n wiki: boolean\n}\n\nexport interface TraceStepInput {\n /** Coarse step kind. Conventional values: \"tool_use\" | \"tool_result\" |\n * \"llm_message\" | \"session_rotation\" | \"error\" | \"preflight\". Free-form\n * strings allowed so future capture sites don't need a schema bump. */\n name: string\n /** Fine-grained name within the kind. For \"tool_use\", this is the tool\n * name (e.g. \"Bash\", \"Edit\"). Optional. */\n action?: string | null\n status?: \"ok\" | \"error\" | \"in-flight\" | null\n /** JSON-stringified input or human-readable summary. Caller-byte-capped. */\n inputSummary?: string | null\n outputSummary?: string | null\n error?: string | null\n /** Step duration when known. Optional — many step kinds are point-in-time. */\n ms?: number | null\n}\n\nexport interface TraceRecord {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n workflowRunId: string | null\n workflowId: string | null\n workflowNodeId: string | null\n intentEventId: string | null\n intentDecidedBy: string | null\n resumeSessionId: string | null\n finalSessionId: string | null\n model: string | null\n status: string\n startedAt: number\n finishedAt: number | null\n durationMs: number | null\n inputTokens: number | null\n outputTokens: number | null\n cacheReadTokens: number | null\n cacheCreateTokens: number | null\n tier2InputTokens: number | null\n tier2OutputTokens: number | null\n tier2CacheReadTokens: number | null\n tier2CacheCreateTokens: number | null\n /** NULL on rows recorded before migration v12. */\n resumed: boolean | null\n /** NULL when the request gate was not active (or before migration v13). */\n jevArm: string | null\n /** NULL on rows recorded before lesson-impact capture (#98) or when the\n * runtime does not report a turn count. */\n numTurns: number | null\n /** NULL on rows recorded before lesson-impact capture (#98). */\n injectedContext: InjectedContext | null\n error: string | null\n messagePreview: string | null\n /** Full untruncated user message — populated for traces from migration v8\n * onward. NULL on older rows; consumers should fall back to messagePreview. */\n originalMessage: string | null\n /** Agent's final reply text — populated for traces from migration v8\n * onward when the executor records it on end. */\n finalResponse: string | null\n}\n\nexport interface TraceStepRecord {\n taskId: string\n seq: number\n name: string\n action: string | null\n status: string | null\n inputSummary: string | null\n outputSummary: string | null\n error: string | null\n ms: number | null\n startedAt: number\n}\n\nexport interface ListTracesFilters {\n agentId?: string\n channel?: string\n chatId?: string\n workflowRunId?: string\n status?: string\n /** ms epoch */\n since?: number\n /** ms epoch */\n until?: number\n /** Default 100, capped at 1000. */\n limit?: number\n}\n\n/**\n * Insert an in-flight trace row and return its ULID. Callers thread the\n * returned id through the executor and call recordTraceEnd at finish time.\n *\n * `taskId` is optional — when supplied, the caller has already allocated\n * a ULID upstream (e.g. registry.execute generating it before the bus\n * event so the runtime can capture per-step rows under the same id).\n * When omitted, a fresh ULID is allocated here.\n */\nexport function recordTraceStart(\n db: Database.Database,\n input: TraceStartInput,\n taskId: string = newEventId(),\n): string {\n db.prepare(`\n INSERT INTO task_traces (\n task_id, agent_id, channel, chat_id, workflow_run_id, workflow_id,\n workflow_node_id, intent_event_id, intent_decided_by, resume_session_id,\n model, status, started_at, message_preview, original_message,\n resume_origin, resume_attempt, resumed_from, person\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?, ?, ?, ?, ?)\n `).run(\n taskId,\n input.agentId,\n input.channel ?? null,\n input.chatId ?? null,\n input.workflowRunId ?? null,\n input.workflowId ?? null,\n input.workflowNodeId ?? null,\n input.intentEventId ?? null,\n input.intentDecidedBy ?? null,\n input.resumeSessionId ?? null,\n input.model ?? null,\n Date.now(),\n input.messagePreview ?? null,\n input.originalMessage ?? null,\n input.resumeOrigin ?? null,\n input.resumeAttempt ?? 0,\n input.resumedFrom ?? null,\n input.person ?? null,\n )\n return taskId\n}\n\n/**\n * Finalize a trace. duration_ms is computed from finished_at - started_at\n * inside the UPDATE so the two columns can never disagree. Idempotent —\n * calling twice on the same task_id overwrites the prior end values; the\n * second call's status wins. (Soft-overwrite is intentional: timeout\n * handlers may write before a late stream-completion arrives.)\n */\nexport function recordTraceEnd(db: Database.Database, taskId: string, input: TraceEndInput): void {\n const finishedAt = Date.now()\n db.prepare(`\n UPDATE task_traces SET\n status = ?,\n final_session_id = ?,\n input_tokens = ?,\n output_tokens = ?,\n cache_read_tokens = ?,\n cache_create_tokens = ?,\n tier2_input_tokens = ?,\n tier2_output_tokens = ?,\n tier2_cache_read_tokens = ?,\n tier2_cache_create_tokens = ?,\n resumed = COALESCE(?, resumed),\n resume_session_id = COALESCE(?, resume_session_id),\n jev_arm = COALESCE(?, jev_arm),\n num_turns = COALESCE(?, num_turns),\n injected_context = COALESCE(?, injected_context),\n error = ?,\n final_response = COALESCE(?, final_response),\n finished_at = ?,\n duration_ms = ? - started_at\n WHERE task_id = ?\n `).run(\n input.status,\n input.finalSessionId ?? null,\n input.inputTokens ?? null,\n input.outputTokens ?? null,\n input.cacheReadTokens ?? null,\n input.cacheCreateTokens ?? null,\n input.tier2InputTokens ?? null,\n input.tier2OutputTokens ?? null,\n input.tier2CacheReadTokens ?? null,\n input.tier2CacheCreateTokens ?? null,\n input.resumed == null ? null : input.resumed ? 1 : 0,\n input.resumeSessionId ?? null,\n input.jevArm ?? null,\n input.numTurns ?? null,\n input.injectedContext ? JSON.stringify(boundInjectedContext(input.injectedContext)) : null,\n input.error ?? null,\n input.finalResponse ?? null,\n finishedAt,\n finishedAt,\n taskId,\n )\n}\n\n/**\n * Append a step. seq is auto-allocated as MAX(seq)+1 within a transaction\n * so concurrent step writes for the same task_id can't collide. Returns\n * the assigned seq, useful for downstream correlation.\n */\nexport function recordTraceStep(db: Database.Database, taskId: string, input: TraceStepInput): number {\n const startedAt = Date.now()\n const allocateAndInsert = db.transaction((): number => {\n const row = db\n .prepare(\"SELECT MAX(seq) AS max_seq FROM task_trace_steps WHERE task_id = ?\")\n .get(taskId) as { max_seq: number | null } | undefined\n const seq = ((row?.max_seq ?? -1) as number) + 1\n db.prepare(`\n INSERT INTO task_trace_steps (\n task_id, seq, name, action, status, input_summary, output_summary, error, ms, started_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n taskId,\n seq,\n input.name,\n input.action ?? null,\n input.status ?? null,\n input.inputSummary ?? null,\n input.outputSummary ?? null,\n input.error ?? null,\n input.ms ?? null,\n startedAt,\n )\n return seq\n })\n return allocateAndInsert()\n}\n\nexport function parseInjectedContext(raw: unknown): InjectedContext | null {\n if (typeof raw !== \"string\") return null\n try {\n const v = JSON.parse(raw)\n if (!v || typeof v !== \"object\") return null\n const ids = (x: unknown) => (Array.isArray(x) ? x.filter((i): i is string => typeof i === \"string\") : [])\n return { memory: ids(v.memory), procedures: ids(v.procedures), wiki: v.wiki === true }\n } catch {\n return null\n }\n}\n\nfunction rowToTrace(row: Record<string, unknown>): TraceRecord {\n return {\n taskId: row.task_id as string,\n agentId: row.agent_id as string,\n channel: (row.channel as string) ?? null,\n chatId: (row.chat_id as string) ?? null,\n workflowRunId: (row.workflow_run_id as string) ?? null,\n workflowId: (row.workflow_id as string) ?? null,\n workflowNodeId: (row.workflow_node_id as string) ?? null,\n intentEventId: (row.intent_event_id as string) ?? null,\n intentDecidedBy: (row.intent_decided_by as string) ?? null,\n resumeSessionId: (row.resume_session_id as string) ?? null,\n finalSessionId: (row.final_session_id as string) ?? null,\n model: (row.model as string) ?? null,\n status: row.status as string,\n startedAt: row.started_at as number,\n finishedAt: (row.finished_at as number) ?? null,\n durationMs: (row.duration_ms as number) ?? null,\n inputTokens: (row.input_tokens as number) ?? null,\n outputTokens: (row.output_tokens as number) ?? null,\n cacheReadTokens: (row.cache_read_tokens as number) ?? null,\n cacheCreateTokens: (row.cache_create_tokens as number) ?? null,\n tier2InputTokens: (row.tier2_input_tokens as number) ?? null,\n tier2OutputTokens: (row.tier2_output_tokens as number) ?? null,\n tier2CacheReadTokens: (row.tier2_cache_read_tokens as number) ?? null,\n tier2CacheCreateTokens: (row.tier2_cache_create_tokens as number) ?? null,\n resumed: row.resumed == null ? null : row.resumed === 1,\n jevArm: (row.jev_arm as string) ?? null,\n numTurns: (row.num_turns as number) ?? null,\n injectedContext: parseInjectedContext(row.injected_context),\n error: (row.error as string) ?? null,\n messagePreview: (row.message_preview as string) ?? null,\n originalMessage: (row.original_message as string) ?? null,\n finalResponse: (row.final_response as string) ?? null,\n }\n}\n\nfunction rowToStep(row: Record<string, unknown>): TraceStepRecord {\n return {\n taskId: row.task_id as string,\n seq: row.seq as number,\n name: row.name as string,\n action: (row.action as string) ?? null,\n status: (row.status as string) ?? null,\n inputSummary: (row.input_summary as string) ?? null,\n outputSummary: (row.output_summary as string) ?? null,\n error: (row.error as string) ?? null,\n ms: (row.ms as number) ?? null,\n startedAt: row.started_at as number,\n }\n}\n\n/** Fetch a trace + its ordered steps. Returns null if no such task_id. */\nexport function getTrace(\n db: Database.Database,\n taskId: string,\n): { task: TraceRecord; steps: TraceStepRecord[] } | null {\n const row = db.prepare(\"SELECT * FROM task_traces WHERE task_id = ?\").get(taskId) as\n | Record<string, unknown>\n | undefined\n if (!row) return null\n const stepRows = db\n .prepare(\"SELECT * FROM task_trace_steps WHERE task_id = ? ORDER BY seq\")\n .all(taskId) as Record<string, unknown>[]\n return { task: rowToTrace(row), steps: stepRows.map(rowToStep) }\n}\n\n/**\n * Cancel any in-flight trace rows left over from a previous daemon\n * lifetime. Mirrors the intent ledger's startup cleanup (rescue plan\n * Phase 1 commit a8514d9): a hard-killed daemon never gets to fire\n * task:completed, so the row sits \"in-flight\" forever and contaminates\n * triage queries (`agentx trace list --status in-flight`) with stale\n * orphans. Run once at daemon boot before subscribers attach.\n *\n * Returns the number of rows updated. duration_ms is intentionally NOT\n * computed — we don't know when the task actually ended; preserving\n * NULL there is more honest than backdating to \"now\".\n */\nexport function cleanupOrphanedTraces(db: Database.Database): number {\n const now = Date.now()\n const r = db.prepare(`\n UPDATE task_traces\n SET status = 'canceled',\n error = 'daemon-restart (orphaned in-flight)',\n finished_at = ?\n WHERE status = 'in-flight'\n `).run(now)\n return (r.changes ?? 0) as number\n}\n\n// --- Resume after restart (#103) -------------------------------------------\n\n/** A run that was still going when the previous daemon stopped. */\nexport interface InterruptedRun {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n workflowRunId: string | null\n startedAt: number\n originalMessage: string | null\n resumeOrigin: string | null\n resumeAttempt: number\n /** Tool calls it had made, in order, for the resume note. */\n toolCalls: Array<{ action: string | null; inputSummary: string | null }>\n}\n\n/** Close every run left in flight by the previous daemon, marking it\n * `interrupted` for the resume planner, and return them. One transaction,\n * so a second process booting on the same database gets nothing. */\nexport function takeInterruptedRuns(db: Database.Database, now = Date.now()): InterruptedRun[] {\n const take = db.transaction(() => {\n const rows = db.prepare(`\n SELECT task_id, agent_id, channel, chat_id, workflow_run_id, started_at,\n original_message, resume_origin, resume_attempt\n FROM task_traces WHERE status = 'in-flight' ORDER BY started_at\n `).all() as Array<Record<string, any>>\n db.prepare(`\n UPDATE task_traces\n SET status = 'canceled', error = 'daemon-restart (interrupted)',\n finished_at = ?, resume_decision = 'interrupted'\n WHERE status = 'in-flight'\n `).run(now)\n return rows\n })\n const steps = db.prepare(`\n SELECT action, input_summary FROM task_trace_steps\n WHERE task_id = ? AND name = 'tool_use' ORDER BY seq\n `)\n return take().map((r) => ({\n taskId: r.task_id,\n agentId: r.agent_id,\n channel: r.channel ?? null,\n chatId: r.chat_id ?? null,\n workflowRunId: r.workflow_run_id ?? null,\n startedAt: r.started_at,\n originalMessage: r.original_message ?? null,\n resumeOrigin: r.resume_origin ?? null,\n resumeAttempt: r.resume_attempt ?? 0,\n toolCalls: (steps.all(r.task_id) as Array<Record<string, any>>).map((s) => ({\n action: s.action ?? null, inputSummary: s.input_summary ?? null,\n })),\n }))\n}\n\n/** Claim an interrupted run before deciding what to do with it. Returns\n * false when another process already claimed or decided it, so a run is\n * never resumed — or its chat told — twice. */\nexport function claimResume(db: Database.Database, taskId: string): boolean {\n const r = db.prepare(`\n UPDATE task_traces SET resume_decision = 'deciding'\n WHERE task_id = ? AND resume_decision = 'interrupted'\n `).run(taskId)\n return (r.changes ?? 0) === 1\n}\n\nexport type ResumeDecision = \"resumed\" | \"reported\" | \"skipped\" | \"resume-failed\"\n\nexport function recordResumeDecision(\n db: Database.Database, taskId: string, decision: ResumeDecision, reason: string,\n): void {\n db.prepare(\"UPDATE task_traces SET resume_decision = ?, resume_reason = ? WHERE task_id = ?\")\n .run(decision, reason.slice(0, 500), taskId)\n}\n\n/** Triage / dashboard surface — list traces newest-first, filtered. */\nexport function listTraces(db: Database.Database, filters: ListTracesFilters = {}): TraceRecord[] {\n const where: string[] = []\n const params: unknown[] = []\n if (filters.agentId) { where.push(\"agent_id = ?\"); params.push(filters.agentId) }\n if (filters.channel) { where.push(\"channel = ?\"); params.push(filters.channel) }\n if (filters.chatId) { where.push(\"chat_id = ?\"); params.push(filters.chatId) }\n if (filters.workflowRunId) { where.push(\"workflow_run_id = ?\"); params.push(filters.workflowRunId) }\n if (filters.status) { where.push(\"status = ?\"); params.push(filters.status) }\n if (filters.since !== undefined) { where.push(\"started_at >= ?\"); params.push(filters.since) }\n if (filters.until !== undefined) { where.push(\"started_at <= ?\"); params.push(filters.until) }\n\n const limit = Math.max(1, Math.min(filters.limit ?? 100, 1000))\n const sql = `\n SELECT * FROM task_traces\n ${where.length > 0 ? \"WHERE \" + where.join(\" AND \") : \"\"}\n ORDER BY started_at DESC\n LIMIT ?\n `\n params.push(limit)\n return (db.prepare(sql).all(...params) as Record<string, unknown>[]).map(rowToTrace)\n}\n"],"mappings":"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","names":["WIKI_MARKER","capIds","ids","id","injectedContextOf","assembled","candidates","text","m","p","boundInjectedContext","ctx","init_ulid","recordTraceStart","db","input","taskId","newEventId","recordTraceEnd","finishedAt","boundInjectedContext","recordTraceStep","startedAt","seq","parseInjectedContext","raw","v","ids","x","i","rowToTrace","row","rowToStep","getTrace","stepRows","cleanupOrphanedTraces","now","takeInterruptedRuns","take","rows","steps","r","s","claimResume","recordResumeDecision","decision","reason","listTraces","filters","where","params","limit","sql"]}
@@ -1,6 +1,6 @@
1
- import{a as O,b as $,c as U,d as T,e as j}from"./chunk-WPNRDEHW.js";import{t as R,v as E,w as W}from"./chunk-2YJ2ZIYC.js";import{a as z,b as C,f as V}from"./chunk-72SZI2UW.js";import{a as B,b as re}from"./chunk-FX3D7YON.js";import{o as J,p as te}from"./chunk-5MUJZODV.js";V();var we="wiki-rerank",be=30,se=900;function xe(a){let e=a.excerptChars??se;return{query:a.query,candidates:a.candidates.map(t=>({id:t.id,title:t.title,tags:t.tags?.length?t.tags.join(", "):null,excerpt:ne(t.excerpt,e)}))}}function Se(a){let e={};for(let t of a)e[t.id]=t.title;return{best:C(e,"Which candidate answers the query?"),answerable:z("Do any of the candidates answer the query?")}}function Ne(a,e){let t=a.best,r={};for(let i of e)r[i.id]=t.probabilities[i.id]??0;let n=new Map(e.map((i,s)=>[i.id,s]));return{ranked:[...e.map(i=>i.id)].sort((i,s)=>{let c=r[s]-r[i];return c!==0?c:(n.get(i)??0)-(n.get(s)??0)}),scores:r,answerable:a.answerable.noul,confidence:t.confidence}}function ne(a,e){let t=String(a??"").replace(/\s+/g," ").trim();return t.length>e?t.slice(0,e):t}var x={version:2,levels:[{id:"category",description:"Top-level kind of work. Closed set \u2014 pick the closest fit.",axes:[{name:"kind",type:"enum",values:["code","ops","support","admin","knowledge","social","system"],description:"Which category this work belongs in."}]},{id:"verb",description:"Specific intent \u2014 verb-level only, NOT client/project-bound.",axes:[{name:"name",type:"free",description:"Lower-kebab dot-namespaced verb. Examples: review.merge-request, fix.bug, investigate.error, deploy.staging, deploy.production, rollback.release, spec.feature, triage.issue, document.feature, chat.greeting, chat.support-request, schedule.add, config.change, ingest.contact, transcribe.audio, brief.daily, summarize.thread, plan.work."}]}],leafInput:{name:"input",type:"enum",values:["telegram","whatsapp","slack","discord","gitlab-mr","gitlab-issue","github-issue","github-pr","cron","webhook","mesh","http"],description:"Where the message entered the system."},leafOutput:{name:"output",type:"free",description:"One short sentence describing what the agent is expected to produce. Generic \u2014 refers to the verb's outcome, not the specific client/project (those are on the event metadata already)."}},G=[{category:"code",verb:"review.merge-request",description:"Review a GitLab MR or GitHub PR"},{category:"code",verb:"review.code-change",description:"General code review (snippet, diff)"},{category:"code",verb:"fix.bug",description:"Fix a reported bug"},{category:"code",verb:"implement.feature",description:"Build a new feature"},{category:"code",verb:"investigate.error",description:"Investigate a failing test, exception, pipeline"},{category:"code",verb:"refactor.code",description:"Restructure existing code without behaviour change"},{category:"code",verb:"spec.feature",description:"Write or update a feature spec / RFC"},{category:"code",verb:"triage.issue",description:"Classify, label, or assign an issue"},{category:"code",verb:"answer.code-question",description:"Answer a code-related question"},{category:"ops",verb:"deploy.staging",description:"Deploy to a staging/preview environment"},{category:"ops",verb:"deploy.production",description:"Deploy to production"},{category:"ops",verb:"rollback.release",description:"Roll back a release"},{category:"ops",verb:"investigate.incident",description:"Investigate a production incident"},{category:"ops",verb:"monitor.system",description:"Check system status / metrics"},{category:"ops",verb:"rotate.credential",description:"Rotate a token, key, certificate"},{category:"ops",verb:"audit.security",description:"Review for security issues"},{category:"support",verb:"chat.greeting",description:"A casual hello, no actionable request"},{category:"support",verb:"chat.support-request",description:"End-user / customer asking for help"},{category:"support",verb:"chat.casual",description:"Informal back-and-forth chat"},{category:"support",verb:"answer.question",description:"Answer an open-ended question"},{category:"support",verb:"route.request",description:"Forward a request to the right agent"},{category:"admin",verb:"config.change",description:"Change agentx.json / environment / config"},{category:"admin",verb:"schedule.add",description:"Add a new cron / scheduled task"},{category:"admin",verb:"schedule.remove",description:"Remove or disable a schedule"},{category:"admin",verb:"token.create",description:"Mint a scoped API token"},{category:"admin",verb:"agent.add",description:"Configure a new agent"},{category:"admin",verb:"channel.add",description:"Wire up a new channel"},{category:"knowledge",verb:"document.feature",description:"Write or update documentation"},{category:"knowledge",verb:"summarize.thread",description:"Summarize a long conversation/thread"},{category:"knowledge",verb:"research.topic",description:"Investigate / gather info on a topic"},{category:"knowledge",verb:"wiki.absorb",description:"Roll raw entries into typed wiki articles"},{category:"social",verb:"brief.daily",description:"Compose a daily brief / digest"},{category:"social",verb:"draft.post",description:"Draft a marketing post / announcement"},{category:"social",verb:"report.weekly",description:"Compose a weekly status report"},{category:"system",verb:"classify.intent",description:"Internal: graph-classifier sub-call"}];import{readFileSync as I,writeFileSync as M,appendFileSync as ie,existsSync as S,mkdirSync as F,renameSync as oe,statSync as Q}from"fs";import{resolve as A,dirname as X}from"path";import{createHash as ae}from"crypto";var _=class{baseDir;log;parsed=new Map;constructor(e={}){this.baseDir=e.baseDir??A(process.cwd(),".agentx/graph"),this.log=e.log??console.error.bind(console,"[graph]"),F(this.baseDir,{recursive:!0})}schemaPath(){return A(this.baseDir,"schema.json")}nodesPath(){return A(this.baseDir,"nodes.json")}indexPath(){return A(this.baseDir,"index.json")}classificationsPath(){return A(this.baseDir,"classifications.jsonl")}loadSchema(){let e=this.schemaPath();if(!S(e))return this.saveSchema(x),this.log("seeded starter schema at",e),x;let t=I(e,"utf-8"),r=O.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);if((r.data.version??1)<(x.version??2)){let n=e.replace(/\.json$/,`.v${r.data.version??1}.bak.json`);try{M(n,t),this.log(`migrated graph schema v${r.data.version??1} -> v${x.version}; old saved at ${n}`)}catch(i){this.log(`could not back up old schema: ${i?.message??i}`)}this.saveSchema(x);let o=this.nodesPath();if(S(o)){let i=o.replace(/\.json$/,".v1.bak.json");try{M(i,I(o,"utf-8")),this.log(`archived v1 nodes.json -> ${i}`)}catch(s){this.log(`could not back up old nodes: ${s?.message??s}`)}try{let s=K();this.saveNodes(s)}catch(s){this.log(`could not seed v2 nodes: ${s?.message??s}`)}}return x}return r.data}saveSchema(e){let t=O.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid schema: ${t.error.issues.map(r=>r.message).join("; ")}`);Y(this.schemaPath(),t.data)}loadNodes(){let e=this.nodesPath();if(!S(e)){let t=K();return this.saveNodes(t),t}return structuredClone(this.readParsed(e,t=>{let r=T.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}))}saveNodes(e){let t=T.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid nodes file: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.nodesPath(),t.data)}readParsed(e,t){let{mtimeMs:r,size:n}=Q(e),o=this.parsed.get(e);if(o&&o.mtimeMs===r&&o.size===n)return o.data;let i=t(I(e,"utf-8"));return this.parsed.set(e,{mtimeMs:r,size:n,data:i}),i}writeParsed(e,t){this.parsed.delete(e),Y(e,t);let{mtimeMs:r,size:n}=Q(e);this.parsed.set(e,{mtimeMs:r,size:n,data:t})}validateNode(e,t,r){let n=t.levels.find(s=>s.id===e.level);if(!n)throw new Error(`Unknown level: "${e.level}"`);let o=n.axes.filter(s=>!s.optional).filter(s=>!(s.name in e.axes));if(o.length)throw new Error(`Node ${e.id} (${e.level}) missing required axes: ${o.map(s=>s.name).join(", ")}`);for(let s of n.axes){let c=e.axes[s.name];if(c!=null){if(s.type==="enum"&&s.values&&!s.values.includes(c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" not in enum ${JSON.stringify(s.values)}`);if(s.type==="ref"){if(!r.some(l=>l.id===c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" refers to unknown node`);if(s.refLevel){let l=r.find(h=>h.id===c);if(l.level!==s.refLevel)throw new Error(`Node ${e.id}: axis ${s.name} expected level "${s.refLevel}" but got "${l.level}"`)}}}}let i=t.levels.findIndex(s=>s.id===e.level);if(i===0){if(e.parentId!==null)throw new Error(`Root-level node ${e.id} must have parentId: null`)}else{if(!e.parentId)throw new Error(`Non-root node ${e.id} must have a parentId`);let s=r.find(l=>l.id===e.parentId);if(!s)throw new Error(`Node ${e.id}: parent "${e.parentId}" not found`);let c=t.levels.findIndex(l=>l.id===s.level);if(c<0||c>=i)throw new Error(`Node ${e.id} at level "${e.level}" has parent at level "${s.level}" \u2014 parent must be at a higher level`)}}commitNodesAlongPath(e,t,r,n){let o=[],i=[],s=new Date().toISOString();for(let c=0;c<e.length;c++){let l=e[c],h=this.loadNodes().nodes;if(h.find(p=>p.id===l)){i.push(l);continue}let g=0;for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(w=>w.id===y)||o.find(w=>w.id===y);if(N){g=r.levels.findIndex(w=>w.id===N.level)+1;break}}let m=t[l]??{},d=null;for(let p=g;p<r.levels.length;p++){let y=r.levels[p];if(y.axes.filter(w=>!w.optional).filter(w=>!(w.name in m)).length===0){d=y.id,g=p+1;break}}if(!d&&g<r.levels.length&&(d=r.levels[g].id,g++),!d)throw new Error(`Can't place node ${l} \u2014 no schema level left (cursor=${g}, levels=${r.levels.length})`);let f=null,v=r.levels.findIndex(p=>p.id===d);for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(k=>k.id===y)||o.find(k=>k.id===y);if(!N)continue;let w=r.levels.findIndex(k=>k.id===N.level);if(w>=0&&w<v){f=y;break}}let u={id:l,level:d,parentId:f,axes:m,createdAt:s,createdBy:n};this.addNode(u),o.push(u)}return{added:o,skipped:i}}addNode(e){let t=this.loadSchema(),r=this.loadNodes();if(r.nodes.some(n=>n.id===e.id))throw new Error(`Node id already exists: ${e.id}`);return this.validateNode(e,t,[...r.nodes,e]),r.nodes.push(e),this.saveNodes(r),e}appendClassification(e){let t=$.safeParse(e);if(!t.success){let o=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join(" \xB7 ");return this.log(`skipped invalid classification \u2014 ${o} \xB7`,`path=${JSON.stringify(e.path)}`,`axes-keys=${JSON.stringify(Object.keys(e.proposedAxes||{}))}`),!1}let r=JSON.stringify(t.data)+`
1
+ import{a as O,b as $,c as U,d as T,e as j}from"./chunk-WPNRDEHW.js";import{t as R,v as E,w as W}from"./chunk-5GXCOHDM.js";import{a as z,b as C,f as V}from"./chunk-72SZI2UW.js";import{a as B,b as re}from"./chunk-FX3D7YON.js";import{o as J,p as te}from"./chunk-5MUJZODV.js";V();var we="wiki-rerank",be=30,se=900;function xe(a){let e=a.excerptChars??se;return{query:a.query,candidates:a.candidates.map(t=>({id:t.id,title:t.title,tags:t.tags?.length?t.tags.join(", "):null,excerpt:ne(t.excerpt,e)}))}}function Se(a){let e={};for(let t of a)e[t.id]=t.title;return{best:C(e,"Which candidate answers the query?"),answerable:z("Do any of the candidates answer the query?")}}function Ne(a,e){let t=a.best,r={};for(let i of e)r[i.id]=t.probabilities[i.id]??0;let n=new Map(e.map((i,s)=>[i.id,s]));return{ranked:[...e.map(i=>i.id)].sort((i,s)=>{let c=r[s]-r[i];return c!==0?c:(n.get(i)??0)-(n.get(s)??0)}),scores:r,answerable:a.answerable.noul,confidence:t.confidence}}function ne(a,e){let t=String(a??"").replace(/\s+/g," ").trim();return t.length>e?t.slice(0,e):t}var x={version:2,levels:[{id:"category",description:"Top-level kind of work. Closed set \u2014 pick the closest fit.",axes:[{name:"kind",type:"enum",values:["code","ops","support","admin","knowledge","social","system"],description:"Which category this work belongs in."}]},{id:"verb",description:"Specific intent \u2014 verb-level only, NOT client/project-bound.",axes:[{name:"name",type:"free",description:"Lower-kebab dot-namespaced verb. Examples: review.merge-request, fix.bug, investigate.error, deploy.staging, deploy.production, rollback.release, spec.feature, triage.issue, document.feature, chat.greeting, chat.support-request, schedule.add, config.change, ingest.contact, transcribe.audio, brief.daily, summarize.thread, plan.work."}]}],leafInput:{name:"input",type:"enum",values:["telegram","whatsapp","slack","discord","gitlab-mr","gitlab-issue","github-issue","github-pr","cron","webhook","mesh","http"],description:"Where the message entered the system."},leafOutput:{name:"output",type:"free",description:"One short sentence describing what the agent is expected to produce. Generic \u2014 refers to the verb's outcome, not the specific client/project (those are on the event metadata already)."}},G=[{category:"code",verb:"review.merge-request",description:"Review a GitLab MR or GitHub PR"},{category:"code",verb:"review.code-change",description:"General code review (snippet, diff)"},{category:"code",verb:"fix.bug",description:"Fix a reported bug"},{category:"code",verb:"implement.feature",description:"Build a new feature"},{category:"code",verb:"investigate.error",description:"Investigate a failing test, exception, pipeline"},{category:"code",verb:"refactor.code",description:"Restructure existing code without behaviour change"},{category:"code",verb:"spec.feature",description:"Write or update a feature spec / RFC"},{category:"code",verb:"triage.issue",description:"Classify, label, or assign an issue"},{category:"code",verb:"answer.code-question",description:"Answer a code-related question"},{category:"ops",verb:"deploy.staging",description:"Deploy to a staging/preview environment"},{category:"ops",verb:"deploy.production",description:"Deploy to production"},{category:"ops",verb:"rollback.release",description:"Roll back a release"},{category:"ops",verb:"investigate.incident",description:"Investigate a production incident"},{category:"ops",verb:"monitor.system",description:"Check system status / metrics"},{category:"ops",verb:"rotate.credential",description:"Rotate a token, key, certificate"},{category:"ops",verb:"audit.security",description:"Review for security issues"},{category:"support",verb:"chat.greeting",description:"A casual hello, no actionable request"},{category:"support",verb:"chat.support-request",description:"End-user / customer asking for help"},{category:"support",verb:"chat.casual",description:"Informal back-and-forth chat"},{category:"support",verb:"answer.question",description:"Answer an open-ended question"},{category:"support",verb:"route.request",description:"Forward a request to the right agent"},{category:"admin",verb:"config.change",description:"Change agentx.json / environment / config"},{category:"admin",verb:"schedule.add",description:"Add a new cron / scheduled task"},{category:"admin",verb:"schedule.remove",description:"Remove or disable a schedule"},{category:"admin",verb:"token.create",description:"Mint a scoped API token"},{category:"admin",verb:"agent.add",description:"Configure a new agent"},{category:"admin",verb:"channel.add",description:"Wire up a new channel"},{category:"knowledge",verb:"document.feature",description:"Write or update documentation"},{category:"knowledge",verb:"summarize.thread",description:"Summarize a long conversation/thread"},{category:"knowledge",verb:"research.topic",description:"Investigate / gather info on a topic"},{category:"knowledge",verb:"wiki.absorb",description:"Roll raw entries into typed wiki articles"},{category:"social",verb:"brief.daily",description:"Compose a daily brief / digest"},{category:"social",verb:"draft.post",description:"Draft a marketing post / announcement"},{category:"social",verb:"report.weekly",description:"Compose a weekly status report"},{category:"system",verb:"classify.intent",description:"Internal: graph-classifier sub-call"}];import{readFileSync as I,writeFileSync as M,appendFileSync as ie,existsSync as S,mkdirSync as F,renameSync as oe,statSync as Q}from"fs";import{resolve as A,dirname as X}from"path";import{createHash as ae}from"crypto";var _=class{baseDir;log;parsed=new Map;constructor(e={}){this.baseDir=e.baseDir??A(process.cwd(),".agentx/graph"),this.log=e.log??console.error.bind(console,"[graph]"),F(this.baseDir,{recursive:!0})}schemaPath(){return A(this.baseDir,"schema.json")}nodesPath(){return A(this.baseDir,"nodes.json")}indexPath(){return A(this.baseDir,"index.json")}classificationsPath(){return A(this.baseDir,"classifications.jsonl")}loadSchema(){let e=this.schemaPath();if(!S(e))return this.saveSchema(x),this.log("seeded starter schema at",e),x;let t=I(e,"utf-8"),r=O.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);if((r.data.version??1)<(x.version??2)){let n=e.replace(/\.json$/,`.v${r.data.version??1}.bak.json`);try{M(n,t),this.log(`migrated graph schema v${r.data.version??1} -> v${x.version}; old saved at ${n}`)}catch(i){this.log(`could not back up old schema: ${i?.message??i}`)}this.saveSchema(x);let o=this.nodesPath();if(S(o)){let i=o.replace(/\.json$/,".v1.bak.json");try{M(i,I(o,"utf-8")),this.log(`archived v1 nodes.json -> ${i}`)}catch(s){this.log(`could not back up old nodes: ${s?.message??s}`)}try{let s=K();this.saveNodes(s)}catch(s){this.log(`could not seed v2 nodes: ${s?.message??s}`)}}return x}return r.data}saveSchema(e){let t=O.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid schema: ${t.error.issues.map(r=>r.message).join("; ")}`);Y(this.schemaPath(),t.data)}loadNodes(){let e=this.nodesPath();if(!S(e)){let t=K();return this.saveNodes(t),t}return structuredClone(this.readParsed(e,t=>{let r=T.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}))}saveNodes(e){let t=T.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid nodes file: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.nodesPath(),t.data)}readParsed(e,t){let{mtimeMs:r,size:n}=Q(e),o=this.parsed.get(e);if(o&&o.mtimeMs===r&&o.size===n)return o.data;let i=t(I(e,"utf-8"));return this.parsed.set(e,{mtimeMs:r,size:n,data:i}),i}writeParsed(e,t){this.parsed.delete(e),Y(e,t);let{mtimeMs:r,size:n}=Q(e);this.parsed.set(e,{mtimeMs:r,size:n,data:t})}validateNode(e,t,r){let n=t.levels.find(s=>s.id===e.level);if(!n)throw new Error(`Unknown level: "${e.level}"`);let o=n.axes.filter(s=>!s.optional).filter(s=>!(s.name in e.axes));if(o.length)throw new Error(`Node ${e.id} (${e.level}) missing required axes: ${o.map(s=>s.name).join(", ")}`);for(let s of n.axes){let c=e.axes[s.name];if(c!=null){if(s.type==="enum"&&s.values&&!s.values.includes(c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" not in enum ${JSON.stringify(s.values)}`);if(s.type==="ref"){if(!r.some(l=>l.id===c))throw new Error(`Node ${e.id}: axis ${s.name}="${c}" refers to unknown node`);if(s.refLevel){let l=r.find(h=>h.id===c);if(l.level!==s.refLevel)throw new Error(`Node ${e.id}: axis ${s.name} expected level "${s.refLevel}" but got "${l.level}"`)}}}}let i=t.levels.findIndex(s=>s.id===e.level);if(i===0){if(e.parentId!==null)throw new Error(`Root-level node ${e.id} must have parentId: null`)}else{if(!e.parentId)throw new Error(`Non-root node ${e.id} must have a parentId`);let s=r.find(l=>l.id===e.parentId);if(!s)throw new Error(`Node ${e.id}: parent "${e.parentId}" not found`);let c=t.levels.findIndex(l=>l.id===s.level);if(c<0||c>=i)throw new Error(`Node ${e.id} at level "${e.level}" has parent at level "${s.level}" \u2014 parent must be at a higher level`)}}commitNodesAlongPath(e,t,r,n){let o=[],i=[],s=new Date().toISOString();for(let c=0;c<e.length;c++){let l=e[c],h=this.loadNodes().nodes;if(h.find(p=>p.id===l)){i.push(l);continue}let g=0;for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(w=>w.id===y)||o.find(w=>w.id===y);if(N){g=r.levels.findIndex(w=>w.id===N.level)+1;break}}let m=t[l]??{},d=null;for(let p=g;p<r.levels.length;p++){let y=r.levels[p];if(y.axes.filter(w=>!w.optional).filter(w=>!(w.name in m)).length===0){d=y.id,g=p+1;break}}if(!d&&g<r.levels.length&&(d=r.levels[g].id,g++),!d)throw new Error(`Can't place node ${l} \u2014 no schema level left (cursor=${g}, levels=${r.levels.length})`);let f=null,v=r.levels.findIndex(p=>p.id===d);for(let p=c-1;p>=0;p--){let y=e[p],N=h.find(k=>k.id===y)||o.find(k=>k.id===y);if(!N)continue;let w=r.levels.findIndex(k=>k.id===N.level);if(w>=0&&w<v){f=y;break}}let u={id:l,level:d,parentId:f,axes:m,createdAt:s,createdBy:n};this.addNode(u),o.push(u)}return{added:o,skipped:i}}addNode(e){let t=this.loadSchema(),r=this.loadNodes();if(r.nodes.some(n=>n.id===e.id))throw new Error(`Node id already exists: ${e.id}`);return this.validateNode(e,t,[...r.nodes,e]),r.nodes.push(e),this.saveNodes(r),e}appendClassification(e){let t=$.safeParse(e);if(!t.success){let o=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join(" \xB7 ");return this.log(`skipped invalid classification \u2014 ${o} \xB7`,`path=${JSON.stringify(e.path)}`,`axes-keys=${JSON.stringify(Object.keys(e.proposedAxes||{}))}`),!1}let r=JSON.stringify(t.data)+`
2
2
  `,n=this.classificationsPath();return S(n)||F(X(n),{recursive:!0}),ie(n,r),!0}listPendingClassifications(e=200){return this.listByStatus("pending",e)}listAllClassifications(){return this.readAllCollapsed()}listByStatus(e,t=200){return this.readAllCollapsed().filter(n=>n.status===e).slice(0,t)}readAllCollapsed(){let e=this.classificationsPath();if(!S(e))return[];let r=I(e,"utf-8").split(`
3
3
  `).filter(Boolean),n=new Map;for(let o of r)try{let i=$.safeParse(JSON.parse(o));if(!i.success)continue;n.set(i.data.msgHash,i.data)}catch{}return Array.from(n.values()).sort((o,i)=>o.ts<i.ts?1:-1)}updateClassificationStatus(e,t){let n=this.readAllCollapsed().find(i=>i.msgHash===e);if(!n)return null;let o={...n,status:t.status,ts:new Date().toISOString()};if(t.reviewer||t.reviewReason){let i=` \xB7 ${t.reviewer?`reviewer=${t.reviewer}`:""}${t.reviewReason?` \xB7 ${t.reviewReason}`:""}`;o.preview=((n.preview||"")+i).slice(0,500)}return this.appendClassification(o),o}readRecentClassifications(e=50){let t=this.classificationsPath();if(!S(t))return[];let n=I(t,"utf-8").split(`
4
4
  `).filter(Boolean),o=[];for(let i=n.length-1;i>=0&&o.length<e;i--)try{let s=$.safeParse(JSON.parse(n[i]));s.success&&o.push(s.data)}catch{}return o}fingerprint(e){let r=[ce(e.text),e.channel??""].join("");return ae("sha256").update(r).digest("hex").slice(0,32)}loadIndex(){return structuredClone(this.index())}saveIndex(e){let t=j.safeParse(e);if(!t.success)throw new Error(`Refusing to save invalid index: ${t.error.issues.map(r=>r.message).join("; ")}`);this.writeParsed(this.indexPath(),t.data)}index(){let e=this.indexPath();return S(e)?this.readParsed(e,t=>{let r=j.safeParse(JSON.parse(t));if(!r.success)throw new Error(`Invalid ${e}: ${r.error.issues.map(n=>n.message).join("; ")}`);return r.data}):{version:1,entries:{}}}getFingerprint(e){let t=this.index().entries[e];return t&&structuredClone(t)}setFingerprint(e,t){let r=U.safeParse({...t,fingerprint:e,updatedAt:new Date().toISOString()});if(!r.success)throw new Error(`Refusing to save invalid index entry: ${r.error.issues.map(o=>o.message).join("; ")}`);let n=this.index();this.writeParsed(this.indexPath(),{...n,entries:{...n.entries,[e]:r.data}})}updateNodeAxes(e,t){let r=this.loadSchema(),n=this.loadNodes(),o=n.nodes.find(s=>s.id===e);if(!o)throw new Error(`Node not found: ${e}`);let i={...o,axes:t};return this.validateNode(i,r,n.nodes.map(s=>s.id===e?i:s)),n.nodes=n.nodes.map(s=>s.id===e?i:s),this.saveNodes(n),i}deleteNode(e){let t=this.loadNodes(),r=t.nodes.find(o=>o.parentId===e);if(r)throw new Error(`Cannot delete "${e}" \u2014 child node "${r.id}" still points to it`);let n=t.nodes.find(o=>Object.values(o.axes).some(i=>i===e));if(n)throw new Error(`Cannot delete "${e}" \u2014 node "${n.id}" references it via an axis`);t.nodes=t.nodes.filter(o=>o.id!==e),this.saveNodes(t)}approveClassification(e){if(this.getFingerprint(e.msgHash))return;let t=this.loadSchema(),r=new Set(this.loadNodes().nodes.map(n=>n.id));for(let n=0;n<e.path.length;n++){let o=e.path[n];if(r.has(o))continue;let i=t.levels[n]?.id;if(!i)break;let s=e.proposedAxes?.[o]??{},c=n===0?null:e.path[n-1];this.addNode({id:o,level:i,parentId:c,axes:s,createdAt:new Date().toISOString(),createdBy:e.agentId}),r.add(o)}this.setFingerprint(e.msgHash,{path:e.path,leaf:e.leaf}),this.appendClassification({...e,status:"approved",ts:new Date().toISOString()})}rejectClassification(e){this.appendClassification({...e,status:"rejected",ts:new Date().toISOString()})}};function Y(a,e){F(X(a),{recursive:!0});let t=`${a}.tmp-${process.pid}`;M(t,JSON.stringify(e,null,2)),oe(t,a)}function K(){let a=new Date().toISOString(),e=[],t=new Set;for(let r of G)t.has(r.category)||(e.push({id:r.category,level:"category",parentId:null,axes:{kind:r.category},createdAt:a,createdBy:"starter"}),t.add(r.category));for(let r of G)e.push({id:r.verb,level:"verb",parentId:r.category,axes:{name:r.verb,...r.description?{description:r.description}:{}},createdAt:a,createdBy:"starter"});return{version:1,nodes:e}}function ce(a){return a.toLowerCase().replace(/https?:\/\/\S+/g," url ").replace(/[@#][\w.\/-]+/g," ref ").replace(/\b[0-9a-f]{7,}\b/g," id ").replace(/\d+/g," num ").replace(/[^\p{L}\p{N}\s]+/gu," ").replace(/\s+/g," ").trim().slice(0,400)}re();te();W();import{createHash as me}from"crypto";V();W();var P="intent-path",de=.5,le=.3;function pe(a){return{message:fe(a.message,2e3),channel:a.channel??null,sender:a.sender??null,agent:a.agent??null}}function Z(a,e){let t={};for(let r of a)t[r.id]=he(r);return C(t,e)}function ge(a){return{category:Z(a,"Which category of work does this message ask for or report on? Pick the one a reviewer would file it under.")}}function ue(a){return{verb:Z(a,"Within that category, which specific action does the message ask for or report on? Prefer the most specific verb that fits; a casual or ambiguous message belongs to the most general one.")}}async function D(a,e,t={}){if(R(P)==="off")return null;let r=e.filter(m=>m.parentId===null);if(r.length<2)return null;let n=pe(a),o={agent:a.agent??"unknown",channel:a.channel??"unknown"},i=a.agent?[{kind:"agent",id:a.agent}]:void 0,s=await E(P,n,ge(r),{incumbent:t.incumbent?.[0]?{category:t.incumbent[0]}:void 0,features:{...o,stage:"category"},links:i});if(!s)return null;let c=s.answers.category,l=c.pMax,h=c.pMax>=de,b=[c.choice],g=e.filter(m=>m.parentId===c.choice);if(g.length>=2){let m=t.incumbent?.[0]===c.choice,d=await E(P,{...n,category:c.choice},ue(g),{incumbent:m&&t.incumbent?.[1]?{verb:t.incumbent[1]}:void 0,features:{...o,stage:"verb",category:c.choice},links:i});if(!d)return null;let f=d.answers.verb;l=Math.min(l,f.pMax),h=h&&f.pMax>=le,b.push(f.choice)}else g.length===1&&b.push(g[0].id);return{path:b,confidence:l,confident:h,mode:s.mode}}function he(a){let e=a.axes?.description?.trim()||void 0,t=a.axes?.name?.trim(),r=t&&t!==a.id?t:void 0;return e&&r?`${r}: ${e}`:e??r??null}function fe(a,e){return a.length>e?`${a.slice(0,e)}\u2026`:a}var L=class{store;daemonUrl;token;draftAgent;autoApprove;autoApproveStructure;classifierModel;classifierProviderName;providerInstance;log;constructor(e){this.store=e.store,this.daemonUrl=e.daemonUrl.replace(/\/+$/,""),this.token=e.token,this.draftAgent=e.draftAgent,this.autoApprove=e.autoApproveConfidence??1,this.autoApproveStructure=e.autoApproveStructure??"extend-leaves",this.classifierModel=e.classifierModel??"claude-haiku-4-5-20251001",this.classifierProviderName=e.classifierProvider??"claude-code",this.log=e.log??console.error.bind(console,"[classifier]")}getProvider(){return this.providerInstance||(this.providerInstance=J(this.classifierProviderName)),this.providerInstance}async classify(e){let t=this.store.fingerprint({text:e.text,channel:e.channel,sender:e.sender}),r=this.store.getFingerprint(t);if(r)return this.store.appendClassification({ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,chatId:e.chatId,path:r.path,proposedAxes:{},leaf:r.leaf,source:"cache",status:"approved",preview:e.text.slice(0,200)}),{path:r.path,pathId:H(r.path),pathLabel:q(r.path,this.store.loadNodes().nodes),axes:{},leaf:r.leaf,source:"cache",status:"approved"};let n=this.store.loadSchema(),o=this.store.loadNodes().nodes,i=await this.propose(e,n,o);if(!i)return null;let{path:s,proposedAxes:c,confidence:l,leaf:h}=i;if(s.length===0)return null;let b={ts:new Date().toISOString(),msgHash:t,agentId:e.agentId,channel:e.channel,sender:e.sender,chatId:e.chatId,path:s,proposedAxes:c,leaf:h,source:i.source,status:"pending",confidence:l,preview:e.text.slice(0,200)},g=new Set(o.map(u=>u.id)),m=s.map((u,p)=>g.has(u)?-1:p).filter(u=>u>=0),d=!1;if(this.autoApproveStructure==="any")d=!0;else if(this.autoApproveStructure==="extend-leaves"){let u=m.length===0,p=m.length===1&&m[0]===s.length-1;d=u||p}let f=l!==void 0&&l>=this.autoApprove,v="pending";if(d||f)try{this.commitNewNodes(s,c,n,o,e.sender),this.store.setFingerprint(t,{path:s,leaf:h}),v="approved"}catch(u){this.log("auto-approve failed \u2014 staying pending \xB7",`path=${JSON.stringify(s)}`,`reason=${(u?.message||u).toString().slice(0,200)}`)}return b.status=v,this.store.appendClassification(b),{path:s,pathId:H(s),pathLabel:q(s,this.store.loadNodes().nodes),axes:c,leaf:h,source:i.source,status:v,confidence:l}}async propose(e,t,r){let n=R(P),o={message:e.text,channel:e.channel,sender:e.sender,agent:e.agentId};if(n==="active"){let s=await D(o,r).catch(c=>(this.log("intent-path seat failed:",c?.message||c),null));if(s?.confident)return{path:s.path,proposedAxes:{},leaf:{},confidence:s.confidence,source:"seat"}}let i=await this.proposePath(e,t,r).catch(s=>(this.log("LLM proposal failed:",s?.message||s),null));return n==="shadow"&&i&&D(o,r,{incumbent:i.path}).catch(()=>{}),i?{...i,source:"llm"}:null}async proposePath(e,t,r){let n=r.map(d=>({id:d.id,level:d.level,parentId:d.parentId,axes:d.axes})),o=["You are the intent classifier for AgentX. You answer ONE question:",'"what kind of work does this message describe?" \u2014 verb-level only.',"","IMPORTANT \u2014 what NOT to encode in the path:","- Client / company / project / team names. Those are already on the event"," metadata (project, channel, agentId). Embedding them in the path causes"," duplicate nodes (one per client) for the same verb.","- The specific subject (issue number, file name, person name). Same reason.","- The agent's name or role. Pick the verb the *requester* intended.","","SCHEMA (fixed levels \u2014 pick one node per level):","```json",JSON.stringify(t,null,2),"```","","EXISTING NODES (prefer reusing these; only invent a new node when no","existing one fits):","```json",JSON.stringify(n,null,2),"```","","MESSAGE:","```",e.text.slice(0,2e3),"```",`channel: ${e.channel??"?"}`,`sender: ${e.sender??"?"}`,"","TASK:","1. Classify into 'category' (closed enum): code, ops, support, admin,"," knowledge, social, system. Pick the closest fit.","2. Pick or propose a 'verb' node. Verb ids are dot-namespaced lower-kebab,",' e.g. "review.merge-request", "deploy.staging", "investigate.error",',' "chat.greeting", "fix.bug". Reuse an existing verb when the message is'," the same kind of work as something already classified, even when the"," client / project / subject differs.","","Examples (right vs wrong):",'- "Please review MR #957 on globex/system" \u2192 ["code", "review.merge-request"]',' NOT ["business", "acme", "globex-v2", "review-mr-957-system"]','- "Deploy initech-v2 to staging please" \u2192 ["ops", "deploy.staging"]',' NOT ["business", "acme", "initech-v2", "deploy-initech-v2-to-staging"]','- "Hello Atlas" \u2192 ["support", "chat.greeting"]',"","NODE ID RULES (strict \u2014 invalid ids get dropped):","- lowercase-kebab + dots only: [a-z0-9][a-z0-9._-]*","- no spaces, no uppercase, no Arabic/other non-Latin",'- verb ids should use a "category.specific" or "verb.modifier" shape',"","Return ONE JSON object on one line, no prose, no fences:",' { "path": string[], "proposedAxes": { [nodeId]: { [axisName]: string } }, "leaf": { "input"?: string, "output"?: string }, "confidence": number }',"confidence in [0,1]. Prefer low confidence over guessing."].join(`
5
5
  `),i=await this.callProvider(o),s=B(i);if(!s||!Array.isArray(s.path))return null;let c=/^[a-z0-9][a-z0-9._-]*$/,l=new Map,h=s.path.filter(d=>typeof d=="string"&&d.length>0).map(d=>{let f=d.trim(),v=ee(f);return f!==v&&l.set(f,v),v}).filter(d=>c.test(d));if(h.length===0)return null;let b={};if(s.proposedAxes&&typeof s.proposedAxes=="object")for(let[d,f]of Object.entries(s.proposedAxes)){if(!f||typeof f!="object")continue;let v=l.get(d)??ee(d);if(!v)continue;let u={};for(let[p,y]of Object.entries(f))typeof y=="string"&&(u[p]=y);!u.name&&d!==v&&(u.name=d.trim()),b[v]=u}let g={};s.leaf&&typeof s.leaf=="object"&&(typeof s.leaf.input=="string"&&(g.input=s.leaf.input),typeof s.leaf.output=="string"&&(g.output=s.leaf.output));let m=typeof s.confidence=="number"?Math.max(0,Math.min(1,s.confidence)):void 0;return{path:h,proposedAxes:b,confidence:m,leaf:g}}commitNewNodes(e,t,r,n,o){this.store.commitNodesAlongPath(e,t,r,o)}async callProvider(e){let t=this.getProvider(),r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{return(await t.generate([{role:"system",content:"You are a taxonomy classifier. Respond with a single JSON object on one line. No prose, no code fences."},{role:"user",content:e}],{model:this.classifierModel,maxTokens:800,abortSignal:r.signal,bare:!0})).content||""}finally{clearTimeout(n)}}};function ee(a){let e=a.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"").replace(/-{2,}/g,"-");return e?/^[a-z0-9]/.test(e)?e:`n-${e}`.replace(/[-_]+$/,""):""}function H(a){return me("sha1").update(a.join("")).digest("hex").slice(0,16)}function q(a,e){return a.map(t=>{let r=e.find(o=>o.id===t);return r&&(r.axes?.name||r.axes?.what)||t}).join(" \u203A ")}function ve(a,e){if(a.length===0||e.length===0)return 0;let t=0;for(let n=0;n<Math.min(a.length,e.length)&&a[n]===e[n];n++)t++;if(t===0)return 0;let r=Math.max(a.length,e.length);return t/r}export{we as a,be as b,xe as c,Se as d,Ne as e,x as f,_ as g,L as h,q as i,ve as j};
6
- //# sourceMappingURL=chunk-PHFOYJUB.js.map
6
+ //# sourceMappingURL=chunk-GUAJNZIX.js.map
@@ -1,4 +1,4 @@
1
- import{a as j,b as O,c as T,d as D,e as _,j as N}from"./chunk-PHFOYJUB.js";import{b as R}from"./chunk-2GIDVZ4H.js";import{v as C,w as I}from"./chunk-2YJ2ZIYC.js";import{b as v,c as W}from"./chunk-QOYAX2FT.js";import{readFileSync as Y,existsSync as B}from"fs";I();import{resolve as x}from"path";import{execSync as L}from"child_process";async function nt(n,a,o,t={}){let u=t.selectorModel??"haiku",g=t.synthModel??"sonnet",l=t.maxCandidates??3,r=t.maxHops??2,s=t.maxArticles??8,h=t.timeoutMs??6e4,p=t.log??console.error.bind(console,"[wiki-query]"),m=t.messagePath?.length?t.messagePath:void 0,w=t.graphWeight??$,i=x(a.baseDir,"_index.md");if(!B(i))return A("no-catalog",n,"No _index.md found \u2014 run `agentx wiki status` to rebuild.");let e=Y(i,"utf-8"),d=Date.now(),f=[],y="";try{let c=await G(n,a,o,l,m,w);c?(f=c,y=`[wiki-rerank seat] ${c.map(k=>k.title).join(" | ")}`):(y=await Q(q(n,e,l,m),u,h),f=K(y))}catch(c){return p("selector failed:",c?.message),{...A("error",n,`Selector: ${c?.message||"unknown"}`),trace:{selectorMs:Date.now()-d,synthesisMs:0,selectorOutput:y}}}let S=Date.now()-d;if(f.length===0)return{...A("no-candidates",n,"Selector returned no candidates."),trace:{selectorMs:S,synthesisMs:0,selectorOutput:y}};let b=F(f,a,o,r,s);if(b.length===0)return{...A("no-candidates",n,"Candidates did not resolve to readable articles."),candidates:f,trace:{selectorMs:S,synthesisMs:0,selectorOutput:y}};let M=Date.now(),P="";try{P=await Q(J(n,b),g,h*2)}catch(c){return p("synthesis failed:",c?.message),{...A("error",n,`Synthesis: ${c?.message||"unknown"}`),candidates:f,walked:b.map(k=>({title:k.meta.title,path:k.path,type:k.meta.type,hop:k.hop??0})),trace:{selectorMs:S,synthesisMs:Date.now()-M,selectorOutput:y}}}let E=Date.now()-M;return{answer:P.trim(),citations:b.map(c=>({title:c.meta.title,path:c.path,type:c.meta.type})),candidates:f,walked:b.map(c=>({title:c.meta.title,path:c.path,type:c.meta.type,hop:c.hop??0})),status:"ok",trace:{selectorMs:S,synthesisMs:E,selectorOutput:y}}}function A(n,a,o){return{answer:"",citations:[],candidates:[],walked:[],status:n,error:o}}function F(n,a,o,t,u){let g=new Map;for(let s of a.listArticles(o||""))g.set(s.meta.title.toLowerCase(),s.path);let l=new Map,r=[];for(let s of n)l.has(s.path)||r.push({path:s.path,hop:0});for(;r.length&&l.size<u;){let s=r.shift();if(l.has(s.path)||s.hop>t)continue;let h=o?a.readArticleAs(s.path,o):a.readArticle(s.path);if(h&&(l.set(s.path,{...h,hop:s.hop}),!(s.hop>=t)))for(let p of h.meta.related||[]){let m=g.get(p.toLowerCase());m&&!l.has(m)&&r.push({path:m,hop:s.hop+1})}}return Array.from(l.values())}async function G(n,a,o,t,u,g=$){try{let r=(a.rebuildIndex().articles??[]).filter(i=>i.path&&!i.path.includes("/_versions/"));if(r.length<2)return null;let h=H(n,r,u,g).slice(0,O).map(i=>({id:`k${i}`,title:r[i].title||r[i].path,tags:r[i].tags,excerpt:[r[i].type?`type: ${r[i].type}`:"",(r[i].related??[]).length?`related: ${(r[i].related??[]).join(", ")}`:"",(r[i].graphPath??[]).length?`graph: ${(r[i].graphPath??[]).join(" \u203A ")}`:""].filter(Boolean).join(" \xB7 ")})),p=await C(j,T({query:n,candidates:h,excerptChars:300}),D(h),{features:{agent:o??"unknown",stage:"catalog-selector"}});if(!p||p.mode!=="active")return null;let w=_(p.answers,h).ranked.slice(0,t).map(i=>r[Number(i.slice(1))]).filter(Boolean).map(i=>({title:i.title,path:i.path}));return w.length>0?w:null}catch{return null}}var $=.6;function H(n,a,o,t=$){let u=a.map(e=>[e.title,(e.tags??[]).join(" "),(e.related??[]).join(" ")].join(" ")),g=W(n,v(u)),l=g.reduce((e,d)=>Math.max(e,d.score),0),r=new Map(g.map(e=>[e.docIndex,l>0?e.score/l:0])),s=!!o?.length,h=e=>s&&e.graphPath?.length?N(o,e.graphPath):0,p=(e,d)=>d.score-e.score||e.i-d.i,m=a.map((e,d)=>({i:d,score:(r.get(d)??0)*(1+t*h(e))})).filter(e=>r.has(e.i)).sort(p),w=a.map((e,d)=>({i:d,score:h(e)})).filter(e=>!r.has(e.i)&&e.score>0).sort(p),i=[...m,...w].map(e=>e.i);for(let e=0;e<a.length;e++)i.includes(e)||i.push(e);return i}function q(n,a,o,t){let u=t?.length?`
1
+ import{a as j,b as O,c as T,d as D,e as _,j as N}from"./chunk-GUAJNZIX.js";import{b as R}from"./chunk-2GIDVZ4H.js";import{v as C,w as I}from"./chunk-5GXCOHDM.js";import{b as v,c as W}from"./chunk-QOYAX2FT.js";import{readFileSync as Y,existsSync as B}from"fs";I();import{resolve as x}from"path";import{execSync as L}from"child_process";async function nt(n,a,o,t={}){let u=t.selectorModel??"haiku",g=t.synthModel??"sonnet",l=t.maxCandidates??3,r=t.maxHops??2,s=t.maxArticles??8,h=t.timeoutMs??6e4,p=t.log??console.error.bind(console,"[wiki-query]"),m=t.messagePath?.length?t.messagePath:void 0,w=t.graphWeight??$,i=x(a.baseDir,"_index.md");if(!B(i))return A("no-catalog",n,"No _index.md found \u2014 run `agentx wiki status` to rebuild.");let e=Y(i,"utf-8"),d=Date.now(),f=[],y="";try{let c=await G(n,a,o,l,m,w);c?(f=c,y=`[wiki-rerank seat] ${c.map(k=>k.title).join(" | ")}`):(y=await Q(q(n,e,l,m),u,h),f=K(y))}catch(c){return p("selector failed:",c?.message),{...A("error",n,`Selector: ${c?.message||"unknown"}`),trace:{selectorMs:Date.now()-d,synthesisMs:0,selectorOutput:y}}}let S=Date.now()-d;if(f.length===0)return{...A("no-candidates",n,"Selector returned no candidates."),trace:{selectorMs:S,synthesisMs:0,selectorOutput:y}};let b=F(f,a,o,r,s);if(b.length===0)return{...A("no-candidates",n,"Candidates did not resolve to readable articles."),candidates:f,trace:{selectorMs:S,synthesisMs:0,selectorOutput:y}};let M=Date.now(),P="";try{P=await Q(J(n,b),g,h*2)}catch(c){return p("synthesis failed:",c?.message),{...A("error",n,`Synthesis: ${c?.message||"unknown"}`),candidates:f,walked:b.map(k=>({title:k.meta.title,path:k.path,type:k.meta.type,hop:k.hop??0})),trace:{selectorMs:S,synthesisMs:Date.now()-M,selectorOutput:y}}}let E=Date.now()-M;return{answer:P.trim(),citations:b.map(c=>({title:c.meta.title,path:c.path,type:c.meta.type})),candidates:f,walked:b.map(c=>({title:c.meta.title,path:c.path,type:c.meta.type,hop:c.hop??0})),status:"ok",trace:{selectorMs:S,synthesisMs:E,selectorOutput:y}}}function A(n,a,o){return{answer:"",citations:[],candidates:[],walked:[],status:n,error:o}}function F(n,a,o,t,u){let g=new Map;for(let s of a.listArticles(o||""))g.set(s.meta.title.toLowerCase(),s.path);let l=new Map,r=[];for(let s of n)l.has(s.path)||r.push({path:s.path,hop:0});for(;r.length&&l.size<u;){let s=r.shift();if(l.has(s.path)||s.hop>t)continue;let h=o?a.readArticleAs(s.path,o):a.readArticle(s.path);if(h&&(l.set(s.path,{...h,hop:s.hop}),!(s.hop>=t)))for(let p of h.meta.related||[]){let m=g.get(p.toLowerCase());m&&!l.has(m)&&r.push({path:m,hop:s.hop+1})}}return Array.from(l.values())}async function G(n,a,o,t,u,g=$){try{let r=(a.rebuildIndex().articles??[]).filter(i=>i.path&&!i.path.includes("/_versions/"));if(r.length<2)return null;let h=H(n,r,u,g).slice(0,O).map(i=>({id:`k${i}`,title:r[i].title||r[i].path,tags:r[i].tags,excerpt:[r[i].type?`type: ${r[i].type}`:"",(r[i].related??[]).length?`related: ${(r[i].related??[]).join(", ")}`:"",(r[i].graphPath??[]).length?`graph: ${(r[i].graphPath??[]).join(" \u203A ")}`:""].filter(Boolean).join(" \xB7 ")})),p=await C(j,T({query:n,candidates:h,excerptChars:300}),D(h),{features:{agent:o??"unknown",stage:"catalog-selector"}});if(!p||p.mode!=="active")return null;let w=_(p.answers,h).ranked.slice(0,t).map(i=>r[Number(i.slice(1))]).filter(Boolean).map(i=>({title:i.title,path:i.path}));return w.length>0?w:null}catch{return null}}var $=.6;function H(n,a,o,t=$){let u=a.map(e=>[e.title,(e.tags??[]).join(" "),(e.related??[]).join(" ")].join(" ")),g=W(n,v(u)),l=g.reduce((e,d)=>Math.max(e,d.score),0),r=new Map(g.map(e=>[e.docIndex,l>0?e.score/l:0])),s=!!o?.length,h=e=>s&&e.graphPath?.length?N(o,e.graphPath):0,p=(e,d)=>d.score-e.score||e.i-d.i,m=a.map((e,d)=>({i:d,score:(r.get(d)??0)*(1+t*h(e))})).filter(e=>r.has(e.i)).sort(p),w=a.map((e,d)=>({i:d,score:h(e)})).filter(e=>!r.has(e.i)&&e.score>0).sort(p),i=[...m,...w].map(e=>e.i);for(let e=0;e<a.length;e++)i.includes(e)||i.push(e);return i}function q(n,a,o,t){let u=t?.length?`
2
2
  ## Intent
3
3
 
4
4
  The request was classified under the intent-graph path "${t.join(" \u203A ")}". Prefer articles filed under the same branch when their titles are equally plausible.
@@ -46,4 +46,4 @@ ${o}
46
46
  Answer the question in 2\u20136 sentences. Cite articles by their title in square brackets like [Article Title]. If the articles do not answer the question, say so plainly (do not invent). Prefer concrete facts over hedging.
47
47
 
48
48
  Output ONLY the answer \u2014 no preamble, no "here is my answer:", no markdown fencing.`}function K(n){let a=n.match(/\[[\s\S]*?\]/);if(!a)return[];try{let o=JSON.parse(a[0]);return Array.isArray(o)?o.filter(t=>t&&typeof t.title=="string"&&typeof t.path=="string").map(t=>({title:t.title,path:t.path})):[]}catch{return[]}}async function Q(n,a,o){let{writeFileSync:t,mkdirSync:u,rmSync:g}=await import("fs"),{tmpdir:l}=await import("os"),r=x(l(),`agentx-wiki-query-${process.pid}`);u(r,{recursive:!0});let s=x(r,`prompt-${Date.now()}.txt`);t(s,n);try{let h=`cat '${s}' | claude -p - --output-format json --max-turns 1 --model ${a} --disallowedTools "Bash Read Write Edit Glob Grep Agent WebSearch WebFetch NotebookEdit"`,p=L(h,{env:R({...process.env}),encoding:"utf-8",timeout:o,maxBuffer:4*1024*1024});try{let m=JSON.parse(p);return String(m.result||m.content||"")}catch{return p}}finally{try{g(s,{force:!0})}catch{}}}export{nt as a,$ as b,H as c};
49
- //# sourceMappingURL=chunk-4NUF3SXN.js.map
49
+ //# sourceMappingURL=chunk-HUQRPEDP.js.map