agentix-cli 0.15.0 → 0.16.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 (59) hide show
  1. package/README.md +12 -6
  2. package/dist/{agent-LRSSVFDR.js → agent-BCDPSPKU.js} +2 -2
  3. package/dist/{board-dashboard-DAPHL6W2.js → board-dashboard-LA7WW56M.js} +1227 -67
  4. package/dist/board-dashboard-LA7WW56M.js.map +1 -0
  5. package/dist/chunk-5F3J55LG.js +2 -0
  6. package/dist/chunk-5F3J55LG.js.map +1 -0
  7. package/dist/chunk-64P4QHSZ.js +2 -0
  8. package/dist/chunk-64P4QHSZ.js.map +1 -0
  9. package/dist/chunk-7FJQGD6U.js +6 -0
  10. package/dist/chunk-7FJQGD6U.js.map +1 -0
  11. package/dist/chunk-ABDP7TDL.js +71 -0
  12. package/dist/chunk-ABDP7TDL.js.map +1 -0
  13. package/dist/chunk-BFZUG66X.js +45 -0
  14. package/dist/chunk-BFZUG66X.js.map +1 -0
  15. package/dist/{chunk-RGUYBH77.js → chunk-FLOGK2U7.js} +2 -2
  16. package/dist/{chunk-AU37OREL.js → chunk-HVC6FJNP.js} +2 -2
  17. package/dist/chunk-K7BE4E35.js +138 -0
  18. package/dist/chunk-K7BE4E35.js.map +1 -0
  19. package/dist/{chunk-3XULOWYB.js → chunk-KXJSLLSQ.js} +2 -2
  20. package/dist/chunk-LEIYC3BF.js +104 -0
  21. package/dist/chunk-LEIYC3BF.js.map +1 -0
  22. package/dist/chunk-WZEYII2S.js +6 -0
  23. package/dist/chunk-WZEYII2S.js.map +1 -0
  24. package/dist/{chunk-HLRVDCNH.js → chunk-YI2T5QYB.js} +2 -2
  25. package/dist/cli.js +208 -190
  26. package/dist/cli.js.map +1 -1
  27. package/dist/{config-DCJYECL4.js → config-LN6JEHMF.js} +2 -2
  28. package/dist/config-mutator-24TH7PHM.js +2 -0
  29. package/dist/index.d.ts +854 -12
  30. package/dist/index.js +47 -44
  31. package/dist/index.js.map +1 -1
  32. package/dist/query-PKGYE5HR.js +2 -0
  33. package/dist/registry-ASC2QS5K.js +2 -0
  34. package/dist/scheduler-A3TQOCKT.js +2 -0
  35. package/dist/scheduler-A3TQOCKT.js.map +1 -0
  36. package/dist/types-OIFU3KSQ.js +2 -0
  37. package/dist/types-OIFU3KSQ.js.map +1 -0
  38. package/dist/wiki-UDPYFJBL.js +2 -0
  39. package/dist/wiki-UDPYFJBL.js.map +1 -0
  40. package/package.json +2 -2
  41. package/dist/board-dashboard-DAPHL6W2.js.map +0 -1
  42. package/dist/chunk-B4Q4X7D5.js +0 -6
  43. package/dist/chunk-B4Q4X7D5.js.map +0 -1
  44. package/dist/chunk-IEVEMKAI.js +0 -168
  45. package/dist/chunk-IEVEMKAI.js.map +0 -1
  46. package/dist/chunk-WVNSWBCU.js +0 -138
  47. package/dist/chunk-WVNSWBCU.js.map +0 -1
  48. package/dist/config-mutator-6EJHSP3Y.js +0 -2
  49. package/dist/registry-5ND7GLFJ.js +0 -2
  50. package/dist/scheduler-FCXOXCN5.js +0 -2
  51. /package/dist/{agent-LRSSVFDR.js.map → agent-BCDPSPKU.js.map} +0 -0
  52. /package/dist/{chunk-RGUYBH77.js.map → chunk-FLOGK2U7.js.map} +0 -0
  53. /package/dist/{chunk-AU37OREL.js.map → chunk-HVC6FJNP.js.map} +0 -0
  54. /package/dist/{chunk-3XULOWYB.js.map → chunk-KXJSLLSQ.js.map} +0 -0
  55. /package/dist/{chunk-HLRVDCNH.js.map → chunk-YI2T5QYB.js.map} +0 -0
  56. /package/dist/{config-DCJYECL4.js.map → config-LN6JEHMF.js.map} +0 -0
  57. /package/dist/{config-mutator-6EJHSP3Y.js.map → config-mutator-24TH7PHM.js.map} +0 -0
  58. /package/dist/{registry-5ND7GLFJ.js.map → query-PKGYE5HR.js.map} +0 -0
  59. /package/dist/{scheduler-FCXOXCN5.js.map → registry-ASC2QS5K.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -1537,20 +1537,36 @@ declare const daemonConfigSchema: z.ZodObject<{
1537
1537
  accounts: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
1538
1538
  token: z.ZodString;
1539
1539
  agentBinding: z.ZodString;
1540
+ /** Per-account sender allowlist. When set, OVERRIDES the global
1541
+ * `policy.allowFrom`. Entries accept:
1542
+ * - numeric user id ("1816212449") — matches sender (from.id)
1543
+ * - numeric chat id ("-1003861455814") — matches chat (chat.id)
1544
+ * - "@username" — matches sender username
1545
+ * A message is dispatched iff at least one entry matches. */
1546
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1540
1547
  }, "strip", z.ZodTypeAny, {
1541
1548
  token: string;
1542
1549
  agentBinding: string;
1550
+ allowFrom?: string[] | undefined;
1543
1551
  }, {
1544
1552
  token: string;
1545
1553
  agentBinding: string;
1554
+ allowFrom?: string[] | undefined;
1546
1555
  }>>>;
1547
1556
  policy: z.ZodDefault<z.ZodObject<{
1548
1557
  dm: z.ZodDefault<z.ZodEnum<["pair", "block"]>>;
1549
1558
  group: z.ZodDefault<z.ZodEnum<["mention-required", "all"]>>;
1559
+ /** Global sender allowlist applied to every account that doesn't set
1560
+ * its own `allowFrom`. When neither is configured, every incoming
1561
+ * message is dropped — closed by default. Same entry forms as the
1562
+ * per-account list (user id, chat id, @username). */
1563
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1550
1564
  }, "strip", z.ZodTypeAny, {
1551
1565
  dm: "block" | "pair";
1552
1566
  group: "all" | "mention-required";
1567
+ allowFrom?: string[] | undefined;
1553
1568
  }, {
1569
+ allowFrom?: string[] | undefined;
1554
1570
  dm?: "block" | "pair" | undefined;
1555
1571
  group?: "all" | "mention-required" | undefined;
1556
1572
  }>>;
@@ -1559,18 +1575,22 @@ declare const daemonConfigSchema: z.ZodObject<{
1559
1575
  accounts: Record<string, {
1560
1576
  token: string;
1561
1577
  agentBinding: string;
1578
+ allowFrom?: string[] | undefined;
1562
1579
  }>;
1563
1580
  policy: {
1564
1581
  dm: "block" | "pair";
1565
1582
  group: "all" | "mention-required";
1583
+ allowFrom?: string[] | undefined;
1566
1584
  };
1567
1585
  }, {
1568
1586
  enabled?: boolean | undefined;
1569
1587
  accounts?: Record<string, {
1570
1588
  token: string;
1571
1589
  agentBinding: string;
1590
+ allowFrom?: string[] | undefined;
1572
1591
  }> | undefined;
1573
1592
  policy?: {
1593
+ allowFrom?: string[] | undefined;
1574
1594
  dm?: "block" | "pair" | undefined;
1575
1595
  group?: "all" | "mention-required" | undefined;
1576
1596
  } | undefined;
@@ -1601,13 +1621,13 @@ declare const daemonConfigSchema: z.ZodObject<{
1601
1621
  group?: string | undefined;
1602
1622
  contact?: string | undefined;
1603
1623
  }[];
1604
- defaultAgent?: string | undefined;
1605
1624
  allowFrom?: string[] | undefined;
1625
+ defaultAgent?: string | undefined;
1606
1626
  }, {
1607
1627
  enabled?: boolean | undefined;
1628
+ allowFrom?: string[] | undefined;
1608
1629
  sessionDir?: string | undefined;
1609
1630
  defaultAgent?: string | undefined;
1610
- allowFrom?: string[] | undefined;
1611
1631
  routes?: {
1612
1632
  agent: string;
1613
1633
  group?: string | undefined;
@@ -1743,10 +1763,12 @@ declare const daemonConfigSchema: z.ZodObject<{
1743
1763
  accounts: Record<string, {
1744
1764
  token: string;
1745
1765
  agentBinding: string;
1766
+ allowFrom?: string[] | undefined;
1746
1767
  }>;
1747
1768
  policy: {
1748
1769
  dm: "block" | "pair";
1749
1770
  group: "all" | "mention-required";
1771
+ allowFrom?: string[] | undefined;
1750
1772
  };
1751
1773
  };
1752
1774
  whatsapp: {
@@ -1757,8 +1779,8 @@ declare const daemonConfigSchema: z.ZodObject<{
1757
1779
  group?: string | undefined;
1758
1780
  contact?: string | undefined;
1759
1781
  }[];
1760
- defaultAgent?: string | undefined;
1761
1782
  allowFrom?: string[] | undefined;
1783
+ defaultAgent?: string | undefined;
1762
1784
  };
1763
1785
  discord: {
1764
1786
  enabled: boolean;
@@ -1795,17 +1817,19 @@ declare const daemonConfigSchema: z.ZodObject<{
1795
1817
  accounts?: Record<string, {
1796
1818
  token: string;
1797
1819
  agentBinding: string;
1820
+ allowFrom?: string[] | undefined;
1798
1821
  }> | undefined;
1799
1822
  policy?: {
1823
+ allowFrom?: string[] | undefined;
1800
1824
  dm?: "block" | "pair" | undefined;
1801
1825
  group?: "all" | "mention-required" | undefined;
1802
1826
  } | undefined;
1803
1827
  } | undefined;
1804
1828
  whatsapp?: {
1805
1829
  enabled?: boolean | undefined;
1830
+ allowFrom?: string[] | undefined;
1806
1831
  sessionDir?: string | undefined;
1807
1832
  defaultAgent?: string | undefined;
1808
- allowFrom?: string[] | undefined;
1809
1833
  routes?: {
1810
1834
  agent: string;
1811
1835
  group?: string | undefined;
@@ -2403,6 +2427,9 @@ declare const daemonConfigSchema: z.ZodObject<{
2403
2427
  bind: z.ZodDefault<z.ZodString>;
2404
2428
  token: z.ZodOptional<z.ZodString>;
2405
2429
  daemonUrl: z.ZodDefault<z.ZodString>;
2430
+ /** Soft cap on output length. Claude Code CLI has no hard flag for this,
2431
+ * but appending an instruction to the prompt is reliably honored. Use
2432
+ * 1500 for briefs, 500 for status pings, 300 for pure classifiers. */
2406
2433
  daemons: z.ZodDefault<z.ZodArray<z.ZodObject<{
2407
2434
  name: z.ZodString;
2408
2435
  url: z.ZodString;
@@ -2452,6 +2479,70 @@ declare const daemonConfigSchema: z.ZodObject<{
2452
2479
  }[] | undefined;
2453
2480
  draftAgent?: string | undefined;
2454
2481
  }>>;
2482
+ graph: z.ZodDefault<z.ZodObject<{
2483
+ enabled: z.ZodDefault<z.ZodBoolean>;
2484
+ /** Where the schema/nodes/classifications live. Relative to cwd. */
2485
+ baseDir: z.ZodDefault<z.ZodString>;
2486
+ /** Which agent makes LLM classification proposals. Falls back to
2487
+ * `dashboard.draftAgent` at call sites if unset. */
2488
+ draftAgent: z.ZodOptional<z.ZodString>;
2489
+ /** Agent used by `agentx graph review` to triage pending classifications.
2490
+ * Should be an agent with the wiki skill so it can call `wiki query` for
2491
+ * context before deciding approve/reject. Falls back to draftAgent. */
2492
+ reviewAgent: z.ZodOptional<z.ZodString>;
2493
+ /** Structural auto-approval policy. Evaluated against each classification
2494
+ * independently of `autoApproveConfidence`; either triggers approval.
2495
+ * - "strict" : never approve via structure — every classification
2496
+ * waits for human review
2497
+ * - "extend-leaves" : auto-approve when the proposed path (a) reuses only
2498
+ * existing nodes, or (b) adds exactly one NEW node at
2499
+ * the deepest level. Structural changes (new mid-path
2500
+ * node, new root) still queue for review. Default.
2501
+ * - "any" : auto-approve every classification regardless of
2502
+ * structural change
2503
+ */
2504
+ autoApproveStructure: z.ZodDefault<z.ZodEnum<["strict", "extend-leaves", "any"]>>;
2505
+ /** Minimum classifier confidence (0..1) to auto-approve. OR'd with the
2506
+ * structural policy — either hitting the threshold lets the classification
2507
+ * bypass the pending queue. 1.0 (default) disables this knob, so approval
2508
+ * is driven by `autoApproveStructure` alone. Lower it to e.g. 0.7 if you
2509
+ * also want high-confidence structural changes auto-approved. */
2510
+ autoApproveConfidence: z.ZodDefault<z.ZodNumber>;
2511
+ /** Weights for the wiki hybrid retrieval score. Path-ancestry match vs
2512
+ * BM25 over article text. Sum need not be 1. */
2513
+ retrievalWeights: z.ZodDefault<z.ZodObject<{
2514
+ graph: z.ZodDefault<z.ZodNumber>;
2515
+ bm25: z.ZodDefault<z.ZodNumber>;
2516
+ }, "strip", z.ZodTypeAny, {
2517
+ graph: number;
2518
+ bm25: number;
2519
+ }, {
2520
+ graph?: number | undefined;
2521
+ bm25?: number | undefined;
2522
+ }>>;
2523
+ }, "strip", z.ZodTypeAny, {
2524
+ enabled: boolean;
2525
+ baseDir: string;
2526
+ autoApproveStructure: "any" | "strict" | "extend-leaves";
2527
+ autoApproveConfidence: number;
2528
+ retrievalWeights: {
2529
+ graph: number;
2530
+ bm25: number;
2531
+ };
2532
+ draftAgent?: string | undefined;
2533
+ reviewAgent?: string | undefined;
2534
+ }, {
2535
+ enabled?: boolean | undefined;
2536
+ draftAgent?: string | undefined;
2537
+ baseDir?: string | undefined;
2538
+ reviewAgent?: string | undefined;
2539
+ autoApproveStructure?: "any" | "strict" | "extend-leaves" | undefined;
2540
+ autoApproveConfidence?: number | undefined;
2541
+ retrievalWeights?: {
2542
+ graph?: number | undefined;
2543
+ bm25?: number | undefined;
2544
+ } | undefined;
2545
+ }>>;
2455
2546
  /** Registered inbound webhooks — an inventory the dashboard manages. Each
2456
2547
  * entry binds an (agent, source) pair to an optional signing secret. The
2457
2548
  * actual inbound URL is always POST /webhook/<agentId>/<source>. */
@@ -2528,6 +2619,18 @@ declare const daemonConfigSchema: z.ZodObject<{
2528
2619
  bind: string;
2529
2620
  defaultAgent?: string | undefined;
2530
2621
  };
2622
+ graph: {
2623
+ enabled: boolean;
2624
+ baseDir: string;
2625
+ autoApproveStructure: "any" | "strict" | "extend-leaves";
2626
+ autoApproveConfidence: number;
2627
+ retrievalWeights: {
2628
+ graph: number;
2629
+ bm25: number;
2630
+ };
2631
+ draftAgent?: string | undefined;
2632
+ reviewAgent?: string | undefined;
2633
+ };
2531
2634
  providers: Record<string, {
2532
2635
  apiKey?: string | undefined;
2533
2636
  defaultModel?: string | undefined;
@@ -2557,10 +2660,12 @@ declare const daemonConfigSchema: z.ZodObject<{
2557
2660
  accounts: Record<string, {
2558
2661
  token: string;
2559
2662
  agentBinding: string;
2663
+ allowFrom?: string[] | undefined;
2560
2664
  }>;
2561
2665
  policy: {
2562
2666
  dm: "block" | "pair";
2563
2667
  group: "all" | "mention-required";
2668
+ allowFrom?: string[] | undefined;
2564
2669
  };
2565
2670
  };
2566
2671
  whatsapp: {
@@ -2571,8 +2676,8 @@ declare const daemonConfigSchema: z.ZodObject<{
2571
2676
  group?: string | undefined;
2572
2677
  contact?: string | undefined;
2573
2678
  }[];
2574
- defaultAgent?: string | undefined;
2575
2679
  allowFrom?: string[] | undefined;
2680
+ defaultAgent?: string | undefined;
2576
2681
  };
2577
2682
  discord: {
2578
2683
  enabled: boolean;
@@ -2772,6 +2877,18 @@ declare const daemonConfigSchema: z.ZodObject<{
2772
2877
  interval?: number | undefined;
2773
2878
  } | undefined;
2774
2879
  } | undefined;
2880
+ graph?: {
2881
+ enabled?: boolean | undefined;
2882
+ draftAgent?: string | undefined;
2883
+ baseDir?: string | undefined;
2884
+ reviewAgent?: string | undefined;
2885
+ autoApproveStructure?: "any" | "strict" | "extend-leaves" | undefined;
2886
+ autoApproveConfidence?: number | undefined;
2887
+ retrievalWeights?: {
2888
+ graph?: number | undefined;
2889
+ bm25?: number | undefined;
2890
+ } | undefined;
2891
+ } | undefined;
2775
2892
  providers?: Record<string, {
2776
2893
  apiKey?: string | undefined;
2777
2894
  defaultModel?: string | undefined;
@@ -2801,17 +2918,19 @@ declare const daemonConfigSchema: z.ZodObject<{
2801
2918
  accounts?: Record<string, {
2802
2919
  token: string;
2803
2920
  agentBinding: string;
2921
+ allowFrom?: string[] | undefined;
2804
2922
  }> | undefined;
2805
2923
  policy?: {
2924
+ allowFrom?: string[] | undefined;
2806
2925
  dm?: "block" | "pair" | undefined;
2807
2926
  group?: "all" | "mention-required" | undefined;
2808
2927
  } | undefined;
2809
2928
  } | undefined;
2810
2929
  whatsapp?: {
2811
2930
  enabled?: boolean | undefined;
2931
+ allowFrom?: string[] | undefined;
2812
2932
  sessionDir?: string | undefined;
2813
2933
  defaultAgent?: string | undefined;
2814
- allowFrom?: string[] | undefined;
2815
2934
  routes?: {
2816
2935
  agent: string;
2817
2936
  group?: string | undefined;
@@ -3368,10 +3487,23 @@ declare function executeTask(agent: AgentDef, task: AgentTask, providers: Record
3368
3487
 
3369
3488
  type WikiAccess = "private" | "shared" | "public";
3370
3489
  /**
3371
- * Article metadata. Intentionally minimal — tags do the heavy lifting.
3490
+ * Article type — the organizational spine. Matches Farzapedia's
3491
+ * `type: person | project | place | concept | event`, extended with
3492
+ * `decision` and `pattern` for workflow-heavy corpora.
3493
+ * Optional on legacy articles; Phase 2 migration backfills it.
3494
+ */
3495
+ type WikiArticleType = "person" | "project" | "place" | "concept" | "event" | "decision" | "pattern";
3496
+ /**
3497
+ * Article metadata. `type` + `related` are the primary retrieval surface;
3498
+ * tags remain as a secondary hint but are no longer central.
3372
3499
  */
3373
3500
  interface WikiArticleMeta {
3374
3501
  title: string;
3502
+ /** Organizational spine — Phase 2 migration backfills any missing values. */
3503
+ type?: WikiArticleType;
3504
+ /** Wikilink targets (by title) — persisted from `[[wikilinks]]` in body. */
3505
+ related?: string[];
3506
+ /** Secondary hint, no longer the retrieval spine. */
3375
3507
  tags: string[];
3376
3508
  owner: string;
3377
3509
  access: WikiAccess;
@@ -3379,6 +3511,10 @@ interface WikiArticleMeta {
3379
3511
  created: string;
3380
3512
  lastUpdated: string;
3381
3513
  sources: string[];
3514
+ /** Intent graph path (root → leaf node ids) when the article was authored
3515
+ * under an active intent graph. Empty for legacy articles — retrieval
3516
+ * falls back to pure BM25 for those. */
3517
+ graphPath?: string[];
3382
3518
  }
3383
3519
  interface WikiArticle {
3384
3520
  meta: WikiArticleMeta;
@@ -3398,6 +3534,8 @@ interface WikiIndex {
3398
3534
  articles: Array<{
3399
3535
  path: string;
3400
3536
  title: string;
3537
+ type?: WikiArticleType;
3538
+ related?: string[];
3401
3539
  tags: string[];
3402
3540
  owner: string;
3403
3541
  access: WikiAccess;
@@ -3411,7 +3549,7 @@ interface WikiIndex {
3411
3549
  }
3412
3550
 
3413
3551
  declare class WikiStore {
3414
- private baseDir;
3552
+ readonly baseDir: string;
3415
3553
  private rawDir;
3416
3554
  private log;
3417
3555
  constructor(baseDir?: string, log?: (...args: unknown[]) => void);
@@ -3475,9 +3613,19 @@ declare class WikiStore {
3475
3613
  search(query: string, agentId: string, maxResults?: number): WikiArticle[];
3476
3614
  /**
3477
3615
  * Find articles relevant to a message (for context injection).
3478
- * Extracts keywords from the message and searches the wiki.
3616
+ *
3617
+ * Scoring:
3618
+ * - BM25 over title+tags+content (always)
3619
+ * - + ancestry bonus if the caller classified the message through the
3620
+ * intent graph and articles carry `graphPath` from a previous classification
3621
+ *
3622
+ * `weights.graph` is scaled against `weights.bm25`. When the caller omits
3623
+ * `messagePath`, retrieval collapses to pure BM25 and matches legacy behavior.
3479
3624
  */
3480
- findRelevant(message: string, agentId?: string, maxArticles?: number): WikiArticle[];
3625
+ findRelevant(message: string, agentId?: string, maxArticles?: number, messagePath?: string[], weights?: {
3626
+ graph: number;
3627
+ bm25: number;
3628
+ }): WikiArticle[];
3481
3629
  /**
3482
3630
  * Build context string from relevant wiki articles for prompt injection.
3483
3631
  * Token-efficient: includes title + first ~500 chars of each article.
@@ -3487,6 +3635,15 @@ declare class WikiStore {
3487
3635
  * Rebuild the master index.
3488
3636
  */
3489
3637
  rebuildIndex(): WikiIndex;
3638
+ /**
3639
+ * Write `_index.md` — the Farzapedia-style content catalog grouped by
3640
+ * article `type`. This is the one file the agentic query (Phase 3) reads
3641
+ * to pick candidate articles before walking the wikilink subgraph.
3642
+ *
3643
+ * Articles without a `type` land in "Untyped" at the bottom; the Phase 2
3644
+ * migration backfills those.
3645
+ */
3646
+ private writeCatalog;
3490
3647
  /**
3491
3648
  * Get wiki stats.
3492
3649
  */
@@ -3705,6 +3862,11 @@ declare class AgentRegistry {
3705
3862
  private tokenTracker;
3706
3863
  private landscape?;
3707
3864
  private messageQueue;
3865
+ /** Intent Knowledge Graph classifier. Null when graph.enabled=false. */
3866
+ private classifier?;
3867
+ private graphStore?;
3868
+ /** Runtime handover store — shared with MessageRouter via file on disk. */
3869
+ private handoverStore;
3708
3870
  /** Active soul profile per agent+chat session: "agentId:channel:chatId" → profile name */
3709
3871
  private activeSouls;
3710
3872
  /** Live output captured per running task id — drives the dashboard streaming modal. */
@@ -3719,6 +3881,12 @@ declare class AgentRegistry {
3719
3881
  * Set landscape builder (called after mesh init).
3720
3882
  */
3721
3883
  setLandscape(builder: LandscapeBuilder): void;
3884
+ /**
3885
+ * If there's an active handover routing TO this agent for this (channel,
3886
+ * chatId) pair AND the operator's summary hasn't been consumed yet, pull
3887
+ * + clear it so the target agent sees the note exactly once.
3888
+ */
3889
+ private buildHandoverNote;
3722
3890
  /**
3723
3891
  * Get agent definition by ID.
3724
3892
  */
@@ -3945,6 +4113,58 @@ interface ChannelAdapter {
3945
4113
  getChannelMeta?(chatId: string): Promise<ChannelMeta | undefined>;
3946
4114
  }
3947
4115
 
4116
+ interface HandoverOverride {
4117
+ channel: string;
4118
+ chatId: string;
4119
+ accountId?: string;
4120
+ fromAgent: string;
4121
+ toAgent: string;
4122
+ summary?: string;
4123
+ createdAt: string;
4124
+ createdBy?: string;
4125
+ /** When set, overrides past this time are treated as expired (ignored on
4126
+ * read, optionally pruned on access). null = indefinite. */
4127
+ expiresAt?: string | null;
4128
+ /** Set after the summary has been injected once. Route stays active. */
4129
+ summaryConsumedAt?: string;
4130
+ }
4131
+ interface HandoverFile {
4132
+ version: number;
4133
+ overrides: Record<string, HandoverOverride>;
4134
+ }
4135
+ declare class HandoverStore {
4136
+ readonly filePath: string;
4137
+ private log;
4138
+ constructor(opts?: {
4139
+ baseDir?: string;
4140
+ log?: (...args: unknown[]) => void;
4141
+ });
4142
+ /** Canonical key for an override. Using "-" for missing accountId keeps
4143
+ * the key shape uniform across channels. */
4144
+ key(channel: string, chatId: string, accountId?: string): string;
4145
+ load(): HandoverFile;
4146
+ private save;
4147
+ /** Return the active override for a chat, or undefined. Skips expired. */
4148
+ get(channel: string, chatId: string, accountId?: string): HandoverOverride | undefined;
4149
+ /** Create or replace an override. If `fromAgent` isn't supplied the caller
4150
+ * can pass "" and the router will fill it in from current routing. */
4151
+ set(o: Omit<HandoverOverride, "createdAt"> & {
4152
+ createdAt?: string;
4153
+ }): HandoverOverride;
4154
+ /** Remove an override (release the handover). Idempotent. */
4155
+ remove(channel: string, chatId: string, accountId?: string): boolean;
4156
+ /** Mark the summary as consumed (after it's been injected once). Route
4157
+ * stays active; subsequent messages just skip the note. */
4158
+ consumeSummary(channel: string, chatId: string, accountId?: string): string | undefined;
4159
+ /** List all non-expired overrides. Used by the admin UI. */
4160
+ listActive(): HandoverOverride[];
4161
+ /** Overrides pointing at this agent (incoming) or away from it (outgoing). */
4162
+ listByAgent(agentId: string): {
4163
+ incoming: HandoverOverride[];
4164
+ outgoing: HandoverOverride[];
4165
+ };
4166
+ }
4167
+
3948
4168
  interface ServiceTrigger {
3949
4169
  pattern: string;
3950
4170
  channel?: string;
@@ -4526,7 +4746,13 @@ declare class MessageRouter {
4526
4746
  private serviceMatcher?;
4527
4747
  private business?;
4528
4748
  private groupLog;
4749
+ /** Runtime per-chat routing overrides (handovers). Consulted at the top
4750
+ * of resolveAgent; config routes + mention matching only run when no
4751
+ * override applies. */
4752
+ private handoverStore;
4529
4753
  private log;
4754
+ /** Exposed so the admin panel + registry can share the same store. */
4755
+ getHandoverStore(): HandoverStore;
4530
4756
  /**
4531
4757
  * Short-TTL cache of recently processed incoming message IDs, keyed by
4532
4758
  * `<channel>:<accountId>:<id>`. Prevents duplicate replies from:
@@ -4628,6 +4854,7 @@ declare class MessageRouter {
4628
4854
  interface TelegramAccountConfig {
4629
4855
  token: string;
4630
4856
  agentBinding: string;
4857
+ allowFrom?: string[];
4631
4858
  }
4632
4859
  declare class TelegramAdapter implements ChannelAdapter {
4633
4860
  readonly name = "telegram";
@@ -4636,7 +4863,22 @@ declare class TelegramAdapter implements ChannelAdapter {
4636
4863
  private handler?;
4637
4864
  private polling;
4638
4865
  private log;
4639
- constructor(accounts: Record<string, TelegramAccountConfig>, log?: (...args: unknown[]) => void);
4866
+ /** Global allowlist fallback. When a per-account allowFrom is unset,
4867
+ * this list applies. When BOTH are unset, everything is rejected
4868
+ * (closed by default). */
4869
+ private globalAllowFrom?;
4870
+ constructor(accounts: Record<string, TelegramAccountConfig>, opts?: {
4871
+ policy?: {
4872
+ allowFrom?: string[];
4873
+ };
4874
+ }, log?: (...args: unknown[]) => void);
4875
+ /** Effective sender allowlist for an account. Returns undefined when the
4876
+ * account has no explicit config AND the global policy is unset — the
4877
+ * caller treats undefined as "closed, drop everything". */
4878
+ private effectiveAllowFrom;
4879
+ /** Accept a message only when at least one allowlist entry matches the
4880
+ * sender's user id, the chat id, or the sender's @username. */
4881
+ private isAllowed;
4640
4882
  onMessage(handler: (msg: IncomingMessage) => Promise<void>): void;
4641
4883
  start(): Promise<void>;
4642
4884
  stop(): Promise<void>;
@@ -4829,6 +5071,606 @@ declare class CronScheduler {
4829
5071
  };
4830
5072
  }
4831
5073
 
5074
+ declare const axisTypeSchema: z.ZodEnum<["enum", "free", "ref"]>;
5075
+ type AxisType = z.infer<typeof axisTypeSchema>;
5076
+ declare const axisDefSchema: z.ZodObject<{
5077
+ name: z.ZodString;
5078
+ type: z.ZodEnum<["enum", "free", "ref"]>;
5079
+ /** For type="enum": closed set of allowed values. */
5080
+ values: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5081
+ /** For type="ref": which level's nodes may be referenced. */
5082
+ refLevel: z.ZodOptional<z.ZodString>;
5083
+ /** If true, this axis may be absent from a node without failing validation.
5084
+ * Use for axes that apply conditionally (e.g. a department's "lead" ref
5085
+ * doesn't apply to a person-kind unit). Absent/false = required. */
5086
+ optional: z.ZodOptional<z.ZodBoolean>;
5087
+ /** Optional human-readable help, shown as tooltip in the admin UI. */
5088
+ description: z.ZodOptional<z.ZodString>;
5089
+ }, "strip", z.ZodTypeAny, {
5090
+ type: "enum" | "free" | "ref";
5091
+ name: string;
5092
+ values?: string[] | undefined;
5093
+ description?: string | undefined;
5094
+ refLevel?: string | undefined;
5095
+ optional?: boolean | undefined;
5096
+ }, {
5097
+ type: "enum" | "free" | "ref";
5098
+ name: string;
5099
+ values?: string[] | undefined;
5100
+ description?: string | undefined;
5101
+ refLevel?: string | undefined;
5102
+ optional?: boolean | undefined;
5103
+ }>;
5104
+ type AxisDef = z.infer<typeof axisDefSchema>;
5105
+ declare const levelDefSchema: z.ZodObject<{
5106
+ id: z.ZodString;
5107
+ /** Axes every node at this level MUST carry. Order matters for UI rendering. */
5108
+ axes: z.ZodArray<z.ZodObject<{
5109
+ name: z.ZodString;
5110
+ type: z.ZodEnum<["enum", "free", "ref"]>;
5111
+ /** For type="enum": closed set of allowed values. */
5112
+ values: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5113
+ /** For type="ref": which level's nodes may be referenced. */
5114
+ refLevel: z.ZodOptional<z.ZodString>;
5115
+ /** If true, this axis may be absent from a node without failing validation.
5116
+ * Use for axes that apply conditionally (e.g. a department's "lead" ref
5117
+ * doesn't apply to a person-kind unit). Absent/false = required. */
5118
+ optional: z.ZodOptional<z.ZodBoolean>;
5119
+ /** Optional human-readable help, shown as tooltip in the admin UI. */
5120
+ description: z.ZodOptional<z.ZodString>;
5121
+ }, "strip", z.ZodTypeAny, {
5122
+ type: "enum" | "free" | "ref";
5123
+ name: string;
5124
+ values?: string[] | undefined;
5125
+ description?: string | undefined;
5126
+ refLevel?: string | undefined;
5127
+ optional?: boolean | undefined;
5128
+ }, {
5129
+ type: "enum" | "free" | "ref";
5130
+ name: string;
5131
+ values?: string[] | undefined;
5132
+ description?: string | undefined;
5133
+ refLevel?: string | undefined;
5134
+ optional?: boolean | undefined;
5135
+ }>, "many">;
5136
+ description: z.ZodOptional<z.ZodString>;
5137
+ }, "strip", z.ZodTypeAny, {
5138
+ id: string;
5139
+ axes: {
5140
+ type: "enum" | "free" | "ref";
5141
+ name: string;
5142
+ values?: string[] | undefined;
5143
+ description?: string | undefined;
5144
+ refLevel?: string | undefined;
5145
+ optional?: boolean | undefined;
5146
+ }[];
5147
+ description?: string | undefined;
5148
+ }, {
5149
+ id: string;
5150
+ axes: {
5151
+ type: "enum" | "free" | "ref";
5152
+ name: string;
5153
+ values?: string[] | undefined;
5154
+ description?: string | undefined;
5155
+ refLevel?: string | undefined;
5156
+ optional?: boolean | undefined;
5157
+ }[];
5158
+ description?: string | undefined;
5159
+ }>;
5160
+ type LevelDef = z.infer<typeof levelDefSchema>;
5161
+ declare const graphSchemaSchema: z.ZodObject<{
5162
+ version: z.ZodDefault<z.ZodNumber>;
5163
+ /** Ordered from root to leaf. Max 5 to keep the taxonomy scannable. */
5164
+ levels: z.ZodArray<z.ZodObject<{
5165
+ id: z.ZodString;
5166
+ /** Axes every node at this level MUST carry. Order matters for UI rendering. */
5167
+ axes: z.ZodArray<z.ZodObject<{
5168
+ name: z.ZodString;
5169
+ type: z.ZodEnum<["enum", "free", "ref"]>;
5170
+ /** For type="enum": closed set of allowed values. */
5171
+ values: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5172
+ /** For type="ref": which level's nodes may be referenced. */
5173
+ refLevel: z.ZodOptional<z.ZodString>;
5174
+ /** If true, this axis may be absent from a node without failing validation.
5175
+ * Use for axes that apply conditionally (e.g. a department's "lead" ref
5176
+ * doesn't apply to a person-kind unit). Absent/false = required. */
5177
+ optional: z.ZodOptional<z.ZodBoolean>;
5178
+ /** Optional human-readable help, shown as tooltip in the admin UI. */
5179
+ description: z.ZodOptional<z.ZodString>;
5180
+ }, "strip", z.ZodTypeAny, {
5181
+ type: "enum" | "free" | "ref";
5182
+ name: string;
5183
+ values?: string[] | undefined;
5184
+ description?: string | undefined;
5185
+ refLevel?: string | undefined;
5186
+ optional?: boolean | undefined;
5187
+ }, {
5188
+ type: "enum" | "free" | "ref";
5189
+ name: string;
5190
+ values?: string[] | undefined;
5191
+ description?: string | undefined;
5192
+ refLevel?: string | undefined;
5193
+ optional?: boolean | undefined;
5194
+ }>, "many">;
5195
+ description: z.ZodOptional<z.ZodString>;
5196
+ }, "strip", z.ZodTypeAny, {
5197
+ id: string;
5198
+ axes: {
5199
+ type: "enum" | "free" | "ref";
5200
+ name: string;
5201
+ values?: string[] | undefined;
5202
+ description?: string | undefined;
5203
+ refLevel?: string | undefined;
5204
+ optional?: boolean | undefined;
5205
+ }[];
5206
+ description?: string | undefined;
5207
+ }, {
5208
+ id: string;
5209
+ axes: {
5210
+ type: "enum" | "free" | "ref";
5211
+ name: string;
5212
+ values?: string[] | undefined;
5213
+ description?: string | undefined;
5214
+ refLevel?: string | undefined;
5215
+ optional?: boolean | undefined;
5216
+ }[];
5217
+ description?: string | undefined;
5218
+ }>, "many">;
5219
+ /** Axis describing where a leaf classification came from (channel, cron, etc.). */
5220
+ leafInput: z.ZodOptional<z.ZodObject<{
5221
+ name: z.ZodString;
5222
+ type: z.ZodEnum<["enum", "free", "ref"]>;
5223
+ /** For type="enum": closed set of allowed values. */
5224
+ values: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5225
+ /** For type="ref": which level's nodes may be referenced. */
5226
+ refLevel: z.ZodOptional<z.ZodString>;
5227
+ /** If true, this axis may be absent from a node without failing validation.
5228
+ * Use for axes that apply conditionally (e.g. a department's "lead" ref
5229
+ * doesn't apply to a person-kind unit). Absent/false = required. */
5230
+ optional: z.ZodOptional<z.ZodBoolean>;
5231
+ /** Optional human-readable help, shown as tooltip in the admin UI. */
5232
+ description: z.ZodOptional<z.ZodString>;
5233
+ }, "strip", z.ZodTypeAny, {
5234
+ type: "enum" | "free" | "ref";
5235
+ name: string;
5236
+ values?: string[] | undefined;
5237
+ description?: string | undefined;
5238
+ refLevel?: string | undefined;
5239
+ optional?: boolean | undefined;
5240
+ }, {
5241
+ type: "enum" | "free" | "ref";
5242
+ name: string;
5243
+ values?: string[] | undefined;
5244
+ description?: string | undefined;
5245
+ refLevel?: string | undefined;
5246
+ optional?: boolean | undefined;
5247
+ }>>;
5248
+ /** Free-form description of the expected result of a leaf classification. */
5249
+ leafOutput: z.ZodOptional<z.ZodObject<{
5250
+ name: z.ZodString;
5251
+ type: z.ZodEnum<["enum", "free", "ref"]>;
5252
+ /** For type="enum": closed set of allowed values. */
5253
+ values: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
5254
+ /** For type="ref": which level's nodes may be referenced. */
5255
+ refLevel: z.ZodOptional<z.ZodString>;
5256
+ /** If true, this axis may be absent from a node without failing validation.
5257
+ * Use for axes that apply conditionally (e.g. a department's "lead" ref
5258
+ * doesn't apply to a person-kind unit). Absent/false = required. */
5259
+ optional: z.ZodOptional<z.ZodBoolean>;
5260
+ /** Optional human-readable help, shown as tooltip in the admin UI. */
5261
+ description: z.ZodOptional<z.ZodString>;
5262
+ }, "strip", z.ZodTypeAny, {
5263
+ type: "enum" | "free" | "ref";
5264
+ name: string;
5265
+ values?: string[] | undefined;
5266
+ description?: string | undefined;
5267
+ refLevel?: string | undefined;
5268
+ optional?: boolean | undefined;
5269
+ }, {
5270
+ type: "enum" | "free" | "ref";
5271
+ name: string;
5272
+ values?: string[] | undefined;
5273
+ description?: string | undefined;
5274
+ refLevel?: string | undefined;
5275
+ optional?: boolean | undefined;
5276
+ }>>;
5277
+ }, "strip", z.ZodTypeAny, {
5278
+ version: number;
5279
+ levels: {
5280
+ id: string;
5281
+ axes: {
5282
+ type: "enum" | "free" | "ref";
5283
+ name: string;
5284
+ values?: string[] | undefined;
5285
+ description?: string | undefined;
5286
+ refLevel?: string | undefined;
5287
+ optional?: boolean | undefined;
5288
+ }[];
5289
+ description?: string | undefined;
5290
+ }[];
5291
+ leafInput?: {
5292
+ type: "enum" | "free" | "ref";
5293
+ name: string;
5294
+ values?: string[] | undefined;
5295
+ description?: string | undefined;
5296
+ refLevel?: string | undefined;
5297
+ optional?: boolean | undefined;
5298
+ } | undefined;
5299
+ leafOutput?: {
5300
+ type: "enum" | "free" | "ref";
5301
+ name: string;
5302
+ values?: string[] | undefined;
5303
+ description?: string | undefined;
5304
+ refLevel?: string | undefined;
5305
+ optional?: boolean | undefined;
5306
+ } | undefined;
5307
+ }, {
5308
+ levels: {
5309
+ id: string;
5310
+ axes: {
5311
+ type: "enum" | "free" | "ref";
5312
+ name: string;
5313
+ values?: string[] | undefined;
5314
+ description?: string | undefined;
5315
+ refLevel?: string | undefined;
5316
+ optional?: boolean | undefined;
5317
+ }[];
5318
+ description?: string | undefined;
5319
+ }[];
5320
+ version?: number | undefined;
5321
+ leafInput?: {
5322
+ type: "enum" | "free" | "ref";
5323
+ name: string;
5324
+ values?: string[] | undefined;
5325
+ description?: string | undefined;
5326
+ refLevel?: string | undefined;
5327
+ optional?: boolean | undefined;
5328
+ } | undefined;
5329
+ leafOutput?: {
5330
+ type: "enum" | "free" | "ref";
5331
+ name: string;
5332
+ values?: string[] | undefined;
5333
+ description?: string | undefined;
5334
+ refLevel?: string | undefined;
5335
+ optional?: boolean | undefined;
5336
+ } | undefined;
5337
+ }>;
5338
+ type GraphSchema = z.infer<typeof graphSchemaSchema>;
5339
+ declare const graphNodeSchema: z.ZodObject<{
5340
+ id: z.ZodString;
5341
+ /** Matches a `levels[*].id` from the schema. */
5342
+ level: z.ZodString;
5343
+ /** null for root-level nodes (level[0]); otherwise the id of a node at level-1. */
5344
+ parentId: z.ZodNullable<z.ZodString>;
5345
+ /** Values for every axis declared at this level's schema entry. `ref` axes
5346
+ * hold the id of another node; `enum` axes hold one of the declared values;
5347
+ * `free` axes hold any string. */
5348
+ axes: z.ZodRecord<z.ZodString, z.ZodString>;
5349
+ createdAt: z.ZodString;
5350
+ createdBy: z.ZodOptional<z.ZodString>;
5351
+ }, "strip", z.ZodTypeAny, {
5352
+ id: string;
5353
+ createdAt: string;
5354
+ axes: Record<string, string>;
5355
+ level: string;
5356
+ parentId: string | null;
5357
+ createdBy?: string | undefined;
5358
+ }, {
5359
+ id: string;
5360
+ createdAt: string;
5361
+ axes: Record<string, string>;
5362
+ level: string;
5363
+ parentId: string | null;
5364
+ createdBy?: string | undefined;
5365
+ }>;
5366
+ type GraphNode = z.infer<typeof graphNodeSchema>;
5367
+ declare const classificationSourceSchema: z.ZodEnum<["llm", "user", "cache"]>;
5368
+ type ClassificationSource = z.infer<typeof classificationSourceSchema>;
5369
+ declare const classificationStatusSchema: z.ZodEnum<["pending", "approved", "rejected"]>;
5370
+ type ClassificationStatus = z.infer<typeof classificationStatusSchema>;
5371
+ declare const classificationSchema: z.ZodObject<{
5372
+ ts: z.ZodString;
5373
+ msgHash: z.ZodString;
5374
+ agentId: z.ZodOptional<z.ZodString>;
5375
+ channel: z.ZodOptional<z.ZodString>;
5376
+ sender: z.ZodOptional<z.ZodString>;
5377
+ /** Node ids from root to leaf, one per level. Shorter-than-full paths are
5378
+ * allowed if the classifier was only confident down to a certain depth. */
5379
+ path: z.ZodArray<z.ZodString, "many">;
5380
+ /** Axis values asserted by the classifier for new nodes it proposed along
5381
+ * the path. Keyed by node id. */
5382
+ proposedAxes: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>>;
5383
+ /** Leaf-level extras. */
5384
+ leaf: z.ZodDefault<z.ZodObject<{
5385
+ input: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5386
+ output: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5387
+ }, "strip", z.ZodTypeAny, {
5388
+ output?: string | undefined;
5389
+ input?: string | undefined;
5390
+ }, {
5391
+ output?: string | undefined;
5392
+ input?: string | undefined;
5393
+ }>>;
5394
+ source: z.ZodEnum<["llm", "user", "cache"]>;
5395
+ status: z.ZodEnum<["pending", "approved", "rejected"]>;
5396
+ confidence: z.ZodOptional<z.ZodNumber>;
5397
+ /** Redacted first ~200 chars of the message, for the approval UI. */
5398
+ preview: z.ZodOptional<z.ZodString>;
5399
+ }, "strip", z.ZodTypeAny, {
5400
+ path: string[];
5401
+ status: "pending" | "approved" | "rejected";
5402
+ source: "user" | "llm" | "cache";
5403
+ ts: string;
5404
+ msgHash: string;
5405
+ proposedAxes: Record<string, Record<string, string>>;
5406
+ leaf: {
5407
+ output?: string | undefined;
5408
+ input?: string | undefined;
5409
+ };
5410
+ channel?: string | undefined;
5411
+ agentId?: string | undefined;
5412
+ sender?: string | undefined;
5413
+ confidence?: number | undefined;
5414
+ preview?: string | undefined;
5415
+ }, {
5416
+ path: string[];
5417
+ status: "pending" | "approved" | "rejected";
5418
+ source: "user" | "llm" | "cache";
5419
+ ts: string;
5420
+ msgHash: string;
5421
+ channel?: string | undefined;
5422
+ agentId?: string | undefined;
5423
+ sender?: string | undefined;
5424
+ proposedAxes?: Record<string, Record<string, string>> | undefined;
5425
+ leaf?: {
5426
+ output?: string | undefined;
5427
+ input?: string | undefined;
5428
+ } | undefined;
5429
+ confidence?: number | undefined;
5430
+ preview?: string | undefined;
5431
+ }>;
5432
+ type Classification = z.infer<typeof classificationSchema>;
5433
+ /** Row in the fingerprint → path snap cache. */
5434
+ declare const fingerprintEntrySchema: z.ZodObject<{
5435
+ fingerprint: z.ZodString;
5436
+ path: z.ZodArray<z.ZodString, "many">;
5437
+ leaf: z.ZodDefault<z.ZodObject<{
5438
+ input: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5439
+ output: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5440
+ }, "strip", z.ZodTypeAny, {
5441
+ output?: string | undefined;
5442
+ input?: string | undefined;
5443
+ }, {
5444
+ output?: string | undefined;
5445
+ input?: string | undefined;
5446
+ }>>;
5447
+ updatedAt: z.ZodString;
5448
+ }, "strip", z.ZodTypeAny, {
5449
+ path: string[];
5450
+ leaf: {
5451
+ output?: string | undefined;
5452
+ input?: string | undefined;
5453
+ };
5454
+ fingerprint: string;
5455
+ updatedAt: string;
5456
+ }, {
5457
+ path: string[];
5458
+ fingerprint: string;
5459
+ updatedAt: string;
5460
+ leaf?: {
5461
+ output?: string | undefined;
5462
+ input?: string | undefined;
5463
+ } | undefined;
5464
+ }>;
5465
+ type FingerprintEntry = z.infer<typeof fingerprintEntrySchema>;
5466
+ /** Nodes file is a plain list, not a nested tree — lookups are by id. */
5467
+ declare const nodesFileSchema: z.ZodObject<{
5468
+ version: z.ZodDefault<z.ZodNumber>;
5469
+ nodes: z.ZodDefault<z.ZodArray<z.ZodObject<{
5470
+ id: z.ZodString;
5471
+ /** Matches a `levels[*].id` from the schema. */
5472
+ level: z.ZodString;
5473
+ /** null for root-level nodes (level[0]); otherwise the id of a node at level-1. */
5474
+ parentId: z.ZodNullable<z.ZodString>;
5475
+ /** Values for every axis declared at this level's schema entry. `ref` axes
5476
+ * hold the id of another node; `enum` axes hold one of the declared values;
5477
+ * `free` axes hold any string. */
5478
+ axes: z.ZodRecord<z.ZodString, z.ZodString>;
5479
+ createdAt: z.ZodString;
5480
+ createdBy: z.ZodOptional<z.ZodString>;
5481
+ }, "strip", z.ZodTypeAny, {
5482
+ id: string;
5483
+ createdAt: string;
5484
+ axes: Record<string, string>;
5485
+ level: string;
5486
+ parentId: string | null;
5487
+ createdBy?: string | undefined;
5488
+ }, {
5489
+ id: string;
5490
+ createdAt: string;
5491
+ axes: Record<string, string>;
5492
+ level: string;
5493
+ parentId: string | null;
5494
+ createdBy?: string | undefined;
5495
+ }>, "many">>;
5496
+ }, "strip", z.ZodTypeAny, {
5497
+ version: number;
5498
+ nodes: {
5499
+ id: string;
5500
+ createdAt: string;
5501
+ axes: Record<string, string>;
5502
+ level: string;
5503
+ parentId: string | null;
5504
+ createdBy?: string | undefined;
5505
+ }[];
5506
+ }, {
5507
+ version?: number | undefined;
5508
+ nodes?: {
5509
+ id: string;
5510
+ createdAt: string;
5511
+ axes: Record<string, string>;
5512
+ level: string;
5513
+ parentId: string | null;
5514
+ createdBy?: string | undefined;
5515
+ }[] | undefined;
5516
+ }>;
5517
+ type NodesFile = z.infer<typeof nodesFileSchema>;
5518
+ /** Index file — record of fingerprints. Hot path; kept as a map on disk. */
5519
+ declare const indexFileSchema: z.ZodObject<{
5520
+ version: z.ZodDefault<z.ZodNumber>;
5521
+ entries: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
5522
+ fingerprint: z.ZodString;
5523
+ path: z.ZodArray<z.ZodString, "many">;
5524
+ leaf: z.ZodDefault<z.ZodObject<{
5525
+ input: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5526
+ output: z.ZodOptional<z.ZodOptional<z.ZodString>>;
5527
+ }, "strip", z.ZodTypeAny, {
5528
+ output?: string | undefined;
5529
+ input?: string | undefined;
5530
+ }, {
5531
+ output?: string | undefined;
5532
+ input?: string | undefined;
5533
+ }>>;
5534
+ updatedAt: z.ZodString;
5535
+ }, "strip", z.ZodTypeAny, {
5536
+ path: string[];
5537
+ leaf: {
5538
+ output?: string | undefined;
5539
+ input?: string | undefined;
5540
+ };
5541
+ fingerprint: string;
5542
+ updatedAt: string;
5543
+ }, {
5544
+ path: string[];
5545
+ fingerprint: string;
5546
+ updatedAt: string;
5547
+ leaf?: {
5548
+ output?: string | undefined;
5549
+ input?: string | undefined;
5550
+ } | undefined;
5551
+ }>>>;
5552
+ }, "strip", z.ZodTypeAny, {
5553
+ entries: Record<string, {
5554
+ path: string[];
5555
+ leaf: {
5556
+ output?: string | undefined;
5557
+ input?: string | undefined;
5558
+ };
5559
+ fingerprint: string;
5560
+ updatedAt: string;
5561
+ }>;
5562
+ version: number;
5563
+ }, {
5564
+ entries?: Record<string, {
5565
+ path: string[];
5566
+ fingerprint: string;
5567
+ updatedAt: string;
5568
+ leaf?: {
5569
+ output?: string | undefined;
5570
+ input?: string | undefined;
5571
+ } | undefined;
5572
+ }> | undefined;
5573
+ version?: number | undefined;
5574
+ }>;
5575
+ type IndexFile = z.infer<typeof indexFileSchema>;
5576
+
5577
+ /**
5578
+ * Ships with the install. When .agentx/graph/schema.json is missing, the
5579
+ * store seeds this so a fresh daemon has something to classify against.
5580
+ *
5581
+ * Five levels, three primaries at the leaf (who / what / where) — matches
5582
+ * the "primary colors per level" design from the plan.
5583
+ */
5584
+ declare const STARTER_SCHEMA: GraphSchema;
5585
+
5586
+ interface GraphStoreOptions {
5587
+ baseDir?: string;
5588
+ log?: (...args: unknown[]) => void;
5589
+ }
5590
+ declare class GraphStore {
5591
+ readonly baseDir: string;
5592
+ private log;
5593
+ constructor(opts?: GraphStoreOptions);
5594
+ schemaPath(): string;
5595
+ nodesPath(): string;
5596
+ indexPath(): string;
5597
+ classificationsPath(): string;
5598
+ /** Load the graph schema, seeding STARTER_SCHEMA if the file is missing. */
5599
+ loadSchema(): GraphSchema;
5600
+ saveSchema(schema: GraphSchema): void;
5601
+ loadNodes(): NodesFile;
5602
+ saveNodes(file: NodesFile): void;
5603
+ /** Validate a node against the schema AND uniqueness within the nodes file. */
5604
+ validateNode(node: GraphNode, schema: GraphSchema, all: GraphNode[]): void;
5605
+ /**
5606
+ * Commit a full classification path: for each path element that doesn't
5607
+ * yet exist, infer its schema level by matching the proposed axes against
5608
+ * the level's required axes (first match ≥ cursor wins — this handles
5609
+ * paths that skip levels, like business → noqta where location is
5610
+ * absent). Refreshes the node list between adds so callers in a loop
5611
+ * don't hit "Node id already exists" on the second iteration.
5612
+ */
5613
+ commitNodesAlongPath(path: string[], proposedAxes: Record<string, Record<string, string>>, schema: GraphSchema, createdBy?: string): {
5614
+ added: GraphNode[];
5615
+ skipped: string[];
5616
+ };
5617
+ /** Append a node. Caller is responsible for id uniqueness; we check and throw. */
5618
+ addNode(node: GraphNode): GraphNode;
5619
+ appendClassification(c: Classification): boolean;
5620
+ /**
5621
+ * All pending classifications, newest first. Collapses the append-only
5622
+ * ledger by msgHash — the most recent entry per message wins (so if an
5623
+ * entry was updated via updateClassificationStatus, we see the current
5624
+ * state, not the original).
5625
+ */
5626
+ listPendingClassifications(limit?: number): Classification[];
5627
+ /** Same contract as listPendingClassifications but filtered to any status. */
5628
+ listByStatus(status: Classification["status"], limit?: number): Classification[];
5629
+ /**
5630
+ * Read every classification, collapse by msgHash keeping the newest entry
5631
+ * per message. Used by listByStatus + the review loop to see current state.
5632
+ * Returns newest-first order.
5633
+ */
5634
+ private readAllCollapsed;
5635
+ /**
5636
+ * Append a status-update entry for an existing classification. The ledger
5637
+ * stays append-only; readers collapse by msgHash. Returns the updated
5638
+ * classification, or null if no prior entry for msgHash exists.
5639
+ */
5640
+ updateClassificationStatus(msgHash: string, update: {
5641
+ status: Classification["status"];
5642
+ reviewer?: string;
5643
+ reviewReason?: string;
5644
+ }): Classification | null;
5645
+ /** Read the last N classifications, newest first. Cheap enough for the admin UI. */
5646
+ readRecentClassifications(limit?: number): Classification[];
5647
+ /**
5648
+ * Hash that represents "this kind of message" for snap-to-path caching.
5649
+ * Normalizes casing + whitespace; includes channel + sender so two people
5650
+ * writing the same words can still land on different paths if they should.
5651
+ */
5652
+ fingerprint(msg: {
5653
+ text: string;
5654
+ channel?: string;
5655
+ sender?: string;
5656
+ }): string;
5657
+ loadIndex(): IndexFile;
5658
+ saveIndex(file: IndexFile): void;
5659
+ getFingerprint(fp: string): FingerprintEntry | undefined;
5660
+ setFingerprint(fp: string, entry: Omit<FingerprintEntry, "fingerprint" | "updatedAt">): void;
5661
+ /** Update the axes on an existing node. Schema-validates the result. */
5662
+ updateNodeAxes(id: string, axes: Record<string, string>): GraphNode;
5663
+ /** Remove a node. Refuses to delete if any other node still references it
5664
+ * (child via parentId, or axis ref). */
5665
+ deleteNode(id: string): void;
5666
+ /** Approve a pending classification. Commits any new nodes along its path,
5667
+ * stamps the fingerprint index so future similar messages hit the cache,
5668
+ * and appends an audit entry. Idempotent — no-op if already cached. */
5669
+ approveClassification(c: Classification): void;
5670
+ /** Record rejection — no nodes committed, no fingerprint set. */
5671
+ rejectClassification(c: Classification): void;
5672
+ }
5673
+
4832
5674
  interface ProviderCapabilities {
4833
5675
  streaming: boolean;
4834
5676
  tools: boolean;
@@ -4891,4 +5733,4 @@ declare function handleError(error: unknown): void;
4891
5733
  */
4892
5734
  declare function getPackageInfo(): PackageJson;
4893
5735
 
4894
- export { A2AClient, A2AMesh, A2AServer, A2AServerConfig, ALL_TOOL_NAMES, AgentCard, AgentConfig, AgentContext, AgentDef, AgentProvider, AgentRegistry, AgentResponse, AgentTask, AgentXDaemon, AgentXRuntime, AnthropicMessage, AuthConfig, BLOCKING_EVENTS, ChannelAdapter, ClaudeCodeProvider, ClaudeProvider, ContentBlock, ContextBuilder, CronJobDef, CronJobState, CronRunResult, CronScheduler, DaemonConfig, EnhanceConfig, EnhanceEngine, EnhanceResult, GenerateOptions, GenerateResult, GenerateStreamEvent, GeneratedFile, GenerationMessage, GenerationResult, GitCommitResult, GitDiffFile, GitLogEntry, GitManager, GitStatus, HOOK_EVENTS, HealConfig, HealEngine, HealResult, HookContext, HookDefinition, HookEvent, HookHandler, HookRegistry, HookResult, IncomingMessage, Memory, MemoryEntry, MemoryHierarchy, MemoryStore, MeshPeer, MessageRouter, MiddlewareFn, ModelUsage, OUTPUT_CONFIGS, OUTPUT_TYPES, OutgoingMessage, OutputConfig, OutputType, PERMISSION_MODES, PROVIDER_CAPABILITIES, PermissionAction, PermissionConfig, PermissionManager, PermissionMode, PermissionRule, Pipeline, PipelineRequest, PipelineResponse, ProjectSchemas, ProviderCapabilities, ProviderName, ProviderOptions, RawGenerationResult, ReplEngine, ReplOptions, RuntimeConfig, Session, StepUsage, StreamEvent, Task, TaskArtifact, TaskMessage, TaskState, TaskStatusUpdate, TechStack, TelegramAdapter, ToolCallInput, ToolExecutor, ToolExecutorOptions, ToolResult, UsageSummary, UsageTracker, WhatsAppAdapter, WikiAccess, WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiStore, agentConfigSchema$1 as agentConfigSchema, checkCapabilities, createAgentContext, createProvider, createSession, daemonConfigSchema, debug, detectSchemas, detectTechStack, ensureCredentials, executeClaudeCode, executeOrchestrator, executeSdk, executeTask, exportSession, formatSchemas, formatTechStack, formatToolsForSystemPrompt, gatherContext7Docs, generate, generateSkill, generateSkillMd, generateStream, getAnthropicTools, getCommand, getLegacyTools, getPackageInfo, globalHooks, globalPermissions, globalTracker, handleError, installSkillPackage, isCommand, isDebug, listInstalledSkills, listSessions, loadAuthConfig, loadDaemonConfig, loadHooks, loadLatestSession, loadLocalSkills, loadProjectInstructions, loadSession, logger, matchSkillsToTask, outputTypeDescriptions, parseCommand, parseSkillContent, parseSkillFile, permissionConfigSchema, permissionModeSchema, registerCommand, resolveAtImports, resolveOutputType, resolveToken, runModelSetup, saveAuthConfig, saveSession, setDebug, startMcpServer, validateWorkspaces };
5736
+ export { A2AClient, A2AMesh, A2AServer, A2AServerConfig, ALL_TOOL_NAMES, AgentCard, AgentConfig, AgentContext, AgentDef, AgentProvider, AgentRegistry, AgentResponse, AgentTask, AgentXDaemon, AgentXRuntime, AnthropicMessage, AuthConfig, AxisDef, AxisType, BLOCKING_EVENTS, ChannelAdapter, Classification, ClassificationSource, ClassificationStatus, ClaudeCodeProvider, ClaudeProvider, ContentBlock, ContextBuilder, CronJobDef, CronJobState, CronRunResult, CronScheduler, DaemonConfig, EnhanceConfig, EnhanceEngine, EnhanceResult, FingerprintEntry, GenerateOptions, GenerateResult, GenerateStreamEvent, GeneratedFile, GenerationMessage, GenerationResult, GitCommitResult, GitDiffFile, GitLogEntry, GitManager, GitStatus, GraphNode, GraphSchema, GraphStore, GraphStoreOptions, HOOK_EVENTS, HealConfig, HealEngine, HealResult, HookContext, HookDefinition, HookEvent, HookHandler, HookRegistry, HookResult, IncomingMessage, IndexFile, LevelDef, Memory, MemoryEntry, MemoryHierarchy, MemoryStore, MeshPeer, MessageRouter, MiddlewareFn, ModelUsage, NodesFile, OUTPUT_CONFIGS, OUTPUT_TYPES, OutgoingMessage, OutputConfig, OutputType, PERMISSION_MODES, PROVIDER_CAPABILITIES, PermissionAction, PermissionConfig, PermissionManager, PermissionMode, PermissionRule, Pipeline, PipelineRequest, PipelineResponse, ProjectSchemas, ProviderCapabilities, ProviderName, ProviderOptions, RawGenerationResult, ReplEngine, ReplOptions, RuntimeConfig, STARTER_SCHEMA, Session, StepUsage, StreamEvent, Task, TaskArtifact, TaskMessage, TaskState, TaskStatusUpdate, TechStack, TelegramAdapter, ToolCallInput, ToolExecutor, ToolExecutorOptions, ToolResult, UsageSummary, UsageTracker, WhatsAppAdapter, WikiAccess, WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiStore, agentConfigSchema$1 as agentConfigSchema, checkCapabilities, createAgentContext, createProvider, createSession, daemonConfigSchema, debug, detectSchemas, detectTechStack, ensureCredentials, executeClaudeCode, executeOrchestrator, executeSdk, executeTask, exportSession, formatSchemas, formatTechStack, formatToolsForSystemPrompt, gatherContext7Docs, generate, generateSkill, generateSkillMd, generateStream, getAnthropicTools, getCommand, getLegacyTools, getPackageInfo, globalHooks, globalPermissions, globalTracker, handleError, installSkillPackage, isCommand, isDebug, listInstalledSkills, listSessions, loadAuthConfig, loadDaemonConfig, loadHooks, loadLatestSession, loadLocalSkills, loadProjectInstructions, loadSession, logger, matchSkillsToTask, outputTypeDescriptions, parseCommand, parseSkillContent, parseSkillFile, permissionConfigSchema, permissionModeSchema, registerCommand, resolveAtImports, resolveOutputType, resolveToken, runModelSetup, saveAuthConfig, saveSession, setDebug, startMcpServer, validateWorkspaces };