@statechange/council 0.10.0 → 0.11.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 (119) hide show
  1. package/dist/cli.js +6 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/discuss.js +20 -4
  4. package/dist/commands/discuss.js.map +1 -1
  5. package/dist/commands/update.d.ts +1 -0
  6. package/dist/commands/update.js +100 -0
  7. package/dist/commands/update.js.map +1 -0
  8. package/dist/core/conversation-engine.js +15 -0
  9. package/dist/core/conversation-engine.js.map +1 -1
  10. package/dist/core/preflight.d.ts +17 -0
  11. package/dist/core/preflight.js +56 -0
  12. package/dist/core/preflight.js.map +1 -0
  13. package/dist/electron/ipc-handlers.js +27 -3
  14. package/dist/electron/ipc-handlers.js.map +1 -1
  15. package/dist/types.d.ts +2 -0
  16. package/dist-electron/main.js +638 -577
  17. package/dist-renderer/assets/{ar-SA-G6X2FPQ2-DJTj94ZY.js → ar-SA-G6X2FPQ2-DT1ABS9g.js} +1 -1
  18. package/dist-renderer/assets/{arc-3qXpUeCd.js → arc-B7OfCKe9.js} +1 -1
  19. package/dist-renderer/assets/{az-AZ-76LH7QW2-1qnzBARG.js → az-AZ-76LH7QW2-D8wBYMaH.js} +1 -1
  20. package/dist-renderer/assets/{bg-BG-XCXSNQG7-BIZ5IFAv.js → bg-BG-XCXSNQG7-BzDdz5-g.js} +1 -1
  21. package/dist-renderer/assets/{blockDiagram-38ab4fdb-JwSYiuLB.js → blockDiagram-38ab4fdb-DRwhQ-xk.js} +1 -1
  22. package/dist-renderer/assets/{bn-BD-2XOGV67Q-DiYpgYAg.js → bn-BD-2XOGV67Q-Bhihwwmv.js} +1 -1
  23. package/dist-renderer/assets/{c4Diagram-3d4e48cf-DUCtOTzV.js → c4Diagram-3d4e48cf-BKt-lwYH.js} +1 -1
  24. package/dist-renderer/assets/{ca-ES-6MX7JW3Y-CV2JFVcm.js → ca-ES-6MX7JW3Y-BXRLXOfx.js} +1 -1
  25. package/dist-renderer/assets/channel-BThr2Pht.js +1 -0
  26. package/dist-renderer/assets/{classDiagram-70f12bd4-DY_je9I9.js → classDiagram-70f12bd4-DCF0wJjS.js} +1 -1
  27. package/dist-renderer/assets/{classDiagram-v2-f2320105-Dm2xf0kS.js → classDiagram-v2-f2320105-DUqV3auX.js} +1 -1
  28. package/dist-renderer/assets/clone-Dzrmu-hX.js +1 -0
  29. package/dist-renderer/assets/{createText-2e5e7dd3-BU4YlynJ.js → createText-2e5e7dd3-jZiKHT8b.js} +1 -1
  30. package/dist-renderer/assets/{cs-CZ-2BRQDIVT-DgefxJv2.js → cs-CZ-2BRQDIVT-C2n_W20l.js} +1 -1
  31. package/dist-renderer/assets/{da-DK-5WZEPLOC-CQeMoU_Y.js → da-DK-5WZEPLOC-BMyGcTrK.js} +1 -1
  32. package/dist-renderer/assets/{de-DE-XR44H4JA-Cm7XiExL.js → de-DE-XR44H4JA-DSalSqLg.js} +1 -1
  33. package/dist-renderer/assets/{edges-e0da2a9e-DU4SF3SK.js → edges-e0da2a9e-CxH4eozj.js} +1 -1
  34. package/dist-renderer/assets/{el-GR-BZB4AONW-BKDtOlnf.js → el-GR-BZB4AONW-6JczKU8m.js} +1 -1
  35. package/dist-renderer/assets/{erDiagram-9861fffd-D_cCijmv.js → erDiagram-9861fffd-zrWbiPwE.js} +1 -1
  36. package/dist-renderer/assets/{es-ES-U4NZUMDT-Blb_L7K-.js → es-ES-U4NZUMDT-W3x9nuJM.js} +1 -1
  37. package/dist-renderer/assets/{eu-ES-A7QVB2H4-BZJBLMeO.js → eu-ES-A7QVB2H4-DWPIl7U2.js} +1 -1
  38. package/dist-renderer/assets/{fa-IR-HGAKTJCU-C8gu07sI.js → fa-IR-HGAKTJCU-6f-gS7va.js} +1 -1
  39. package/dist-renderer/assets/{fi-FI-Z5N7JZ37-0j8c6s09.js → fi-FI-Z5N7JZ37-D9INJayl.js} +1 -1
  40. package/dist-renderer/assets/{flowDb-956e92f1-BYeD7SW0.js → flowDb-956e92f1-BcD3knfQ.js} +1 -1
  41. package/dist-renderer/assets/{flowDiagram-66a62f08-D_7wXttk.js → flowDiagram-66a62f08-ueJuroOL.js} +1 -1
  42. package/dist-renderer/assets/flowDiagram-v2-96b9c2cf-Bc_edFJX.js +1 -0
  43. package/dist-renderer/assets/{flowchart-elk-definition-4a651766-G1tSg-iY.js → flowchart-elk-definition-4a651766-YvyrdIKN.js} +1 -1
  44. package/dist-renderer/assets/{fr-FR-RHASNOE6-_cfaQNNq.js → fr-FR-RHASNOE6-Cs8X8O3s.js} +1 -1
  45. package/dist-renderer/assets/{ganttDiagram-c361ad54-Dk5lBh7P.js → ganttDiagram-c361ad54-DUs5xgl-.js} +1 -1
  46. package/dist-renderer/assets/{gitGraphDiagram-72cf32ee-BzJAQtIC.js → gitGraphDiagram-72cf32ee-DerrZoOI.js} +1 -1
  47. package/dist-renderer/assets/{gl-ES-HMX3MZ6V-GM5nrSrW.js → gl-ES-HMX3MZ6V-id5cZnrR.js} +1 -1
  48. package/dist-renderer/assets/{graph-C_xi4PaI.js → graph-qZGJ3a_0.js} +1 -1
  49. package/dist-renderer/assets/{he-IL-6SHJWFNN-DvBtF7-G.js → he-IL-6SHJWFNN-ClkmOrEY.js} +1 -1
  50. package/dist-renderer/assets/{hi-IN-IWLTKZ5I-CNEB0-5K.js → hi-IN-IWLTKZ5I-XcT0be4B.js} +1 -1
  51. package/dist-renderer/assets/{hu-HU-A5ZG7DT2-BmzYfJwp.js → hu-HU-A5ZG7DT2-BauiuWYa.js} +1 -1
  52. package/dist-renderer/assets/{id-ID-SAP4L64H-CGCjaOLU.js → id-ID-SAP4L64H-BjwDtEsw.js} +1 -1
  53. package/dist-renderer/assets/{index-3862675e-C8a4355J.js → index-3862675e--n2KjoQQ.js} +1 -1
  54. package/dist-renderer/assets/{index-Cc7m7vZn.js → index-Bff8gOpX.js} +29 -29
  55. package/dist-renderer/assets/{index-x_yLI1Xq.js → index-DiVVwzho.js} +4 -4
  56. package/dist-renderer/assets/index-qNRDTlPC.css +1 -0
  57. package/dist-renderer/assets/{infoDiagram-f8f76790-BsJdteru.js → infoDiagram-f8f76790-D5cAW55N.js} +1 -1
  58. package/dist-renderer/assets/{it-IT-JPQ66NNP-vK6cBs4I.js → it-IT-JPQ66NNP-GSOK3zyA.js} +1 -1
  59. package/dist-renderer/assets/{ja-JP-DBVTYXUO-oUvELdsq.js → ja-JP-DBVTYXUO-BqdBOVtd.js} +1 -1
  60. package/dist-renderer/assets/{journeyDiagram-49397b02-BZcn-joQ.js → journeyDiagram-49397b02-D3g-8QZM.js} +1 -1
  61. package/dist-renderer/assets/{kaa-6HZHGXH3-39-zh5xR.js → kaa-6HZHGXH3-BhCfH7Nw.js} +1 -1
  62. package/dist-renderer/assets/{kab-KAB-ZGHBKWFO-DIwwJSlv.js → kab-KAB-ZGHBKWFO-BiEpzhMA.js} +1 -1
  63. package/dist-renderer/assets/{kk-KZ-P5N5QNE5-jEG0G6v4.js → kk-KZ-P5N5QNE5-DQL7tI7B.js} +1 -1
  64. package/dist-renderer/assets/{km-KH-HSX4SM5Z-f0MtADYu.js → km-KH-HSX4SM5Z-BNzGZwqS.js} +1 -1
  65. package/dist-renderer/assets/{ko-KR-MTYHY66A-D0sjNbcb.js → ko-KR-MTYHY66A-BrTGfdJs.js} +1 -1
  66. package/dist-renderer/assets/{ku-TR-6OUDTVRD-D_uqAOZU.js → ku-TR-6OUDTVRD-DV6qxsd3.js} +1 -1
  67. package/dist-renderer/assets/{layout-Bho0HnCB.js → layout-qt9ncKQO.js} +1 -1
  68. package/dist-renderer/assets/{line-BvfrpBJA.js → line-LCvRLu_z.js} +1 -1
  69. package/dist-renderer/assets/{linear-CzjqC3F_.js → linear-B1dFt2Mi.js} +1 -1
  70. package/dist-renderer/assets/{lt-LT-XHIRWOB4-Ct0yC4CT.js → lt-LT-XHIRWOB4-WVGEZ27s.js} +1 -1
  71. package/dist-renderer/assets/{lv-LV-5QDEKY6T-nkNbPHg0.js → lv-LV-5QDEKY6T-77cng2TE.js} +1 -1
  72. package/dist-renderer/assets/{mindmap-definition-fc14e90a-BHot8rEp.js → mindmap-definition-fc14e90a-DNtcEEqa.js} +1 -1
  73. package/dist-renderer/assets/{mr-IN-CRQNXWMA-B861rik7.js → mr-IN-CRQNXWMA-BFexevhO.js} +1 -1
  74. package/dist-renderer/assets/{my-MM-5M5IBNSE-SOXg7PeE.js → my-MM-5M5IBNSE-C9Vf2u64.js} +1 -1
  75. package/dist-renderer/assets/{nb-NO-T6EIAALU-D22gGzt7.js → nb-NO-T6EIAALU-B6nE3WpA.js} +1 -1
  76. package/dist-renderer/assets/{nl-NL-IS3SIHDZ-CJxOBLb1.js → nl-NL-IS3SIHDZ-CaRaqbQC.js} +1 -1
  77. package/dist-renderer/assets/{nn-NO-6E72VCQL-FGcbdlO3.js → nn-NO-6E72VCQL-DgeqKi0O.js} +1 -1
  78. package/dist-renderer/assets/{oc-FR-POXYY2M6-s7Swo1Cu.js → oc-FR-POXYY2M6-BE5foCrM.js} +1 -1
  79. package/dist-renderer/assets/{pa-IN-N4M65BXN-DFJMREPh.js → pa-IN-N4M65BXN-YstXUC1N.js} +1 -1
  80. package/dist-renderer/assets/{percentages-BXMCSKIN-BhceqxTM.js → percentages-BXMCSKIN-ClEmrH5S.js} +7 -7
  81. package/dist-renderer/assets/{pica-ej4Z4fjh.js → pica-BzhwS7O9.js} +1 -1
  82. package/dist-renderer/assets/{pieDiagram-8a3498a8-CnDnQfd0.js → pieDiagram-8a3498a8-Gm6b2Dvv.js} +1 -1
  83. package/dist-renderer/assets/{pl-PL-T2D74RX3-uXVmB6im.js → pl-PL-T2D74RX3-BYANIPnT.js} +1 -1
  84. package/dist-renderer/assets/{pt-BR-5N22H2LF-8kdgECeZ.js → pt-BR-5N22H2LF-Crb41rJn.js} +1 -1
  85. package/dist-renderer/assets/{pt-PT-UZXXM6DQ-D4vr9vo6.js → pt-PT-UZXXM6DQ-BZb84OUI.js} +1 -1
  86. package/dist-renderer/assets/{quadrantDiagram-120e2f19-DlUESmO2.js → quadrantDiagram-120e2f19-uZf8ZOq7.js} +1 -1
  87. package/dist-renderer/assets/{requirementDiagram-deff3bca-CfOs9jR8.js → requirementDiagram-deff3bca-CXv-XkpA.js} +1 -1
  88. package/dist-renderer/assets/{ro-RO-JPDTUUEW-CztO0tWv.js → ro-RO-JPDTUUEW-pVMFDrzX.js} +1 -1
  89. package/dist-renderer/assets/{ru-RU-B4JR7IUQ-aVURliDr.js → ru-RU-B4JR7IUQ-BqvZXiAC.js} +1 -1
  90. package/dist-renderer/assets/{sankeyDiagram-04a897e0-DRRc8FSN.js → sankeyDiagram-04a897e0-BE7SzdTQ.js} +1 -1
  91. package/dist-renderer/assets/{sequenceDiagram-704730f1-BaswaqQO.js → sequenceDiagram-704730f1-mDPi1i-N.js} +1 -1
  92. package/dist-renderer/assets/{si-LK-N5RQ5JYF-B2KWtx6N.js → si-LK-N5RQ5JYF-CJNPpP3j.js} +1 -1
  93. package/dist-renderer/assets/{sk-SK-C5VTKIMK-DlRzLxRJ.js → sk-SK-C5VTKIMK-BrOHOeIl.js} +1 -1
  94. package/dist-renderer/assets/{sl-SI-NN7IZMDC-Ox8yiRTS.js → sl-SI-NN7IZMDC-CS9lfsZo.js} +1 -1
  95. package/dist-renderer/assets/{stateDiagram-587899a1-DSEEonbL.js → stateDiagram-587899a1-X1op9_rl.js} +1 -1
  96. package/dist-renderer/assets/{stateDiagram-v2-d93cdb3a-C135NgbB.js → stateDiagram-v2-d93cdb3a-DW1QycRH.js} +1 -1
  97. package/dist-renderer/assets/{styles-6aaf32cf-X5nh1pD3.js → styles-6aaf32cf-DPaq63ON.js} +1 -1
  98. package/dist-renderer/assets/{styles-9a916d00-BCZu272E.js → styles-9a916d00-BuzHNqFw.js} +1 -1
  99. package/dist-renderer/assets/{styles-c10674c1-C5JGHSaS.js → styles-c10674c1-DMm_j-y2.js} +1 -1
  100. package/dist-renderer/assets/{subset-shared.chunk-CzgdV5hf.js → subset-shared.chunk-3Aplsfln.js} +1 -1
  101. package/dist-renderer/assets/{subset-worker.chunk-DfLYxc1O.js → subset-worker.chunk-4W4tHba_.js} +1 -1
  102. package/dist-renderer/assets/{sv-SE-XGPEYMSR-CizFbLCT.js → sv-SE-XGPEYMSR-DmtGm_CR.js} +1 -1
  103. package/dist-renderer/assets/{svgDrawCommon-08f97a94-Cv5ZIzzk.js → svgDrawCommon-08f97a94-Cwi8wjQD.js} +1 -1
  104. package/dist-renderer/assets/{ta-IN-2NMHFXQM-B66K2LEN.js → ta-IN-2NMHFXQM-6iYbXM4R.js} +1 -1
  105. package/dist-renderer/assets/{th-TH-HPSO5L25-DvHt1SBY.js → th-TH-HPSO5L25-CeMt3K_X.js} +1 -1
  106. package/dist-renderer/assets/{timeline-definition-85554ec2-C955-u4m.js → timeline-definition-85554ec2-DDvzM2vU.js} +1 -1
  107. package/dist-renderer/assets/{tr-TR-DEFEU3FU-u0AuqRoD.js → tr-TR-DEFEU3FU-kKNTgK1x.js} +1 -1
  108. package/dist-renderer/assets/{uk-UA-QMV73CPH-IwAiPvJL.js → uk-UA-QMV73CPH-DXv_zymS.js} +1 -1
  109. package/dist-renderer/assets/{vi-VN-M7AON7JQ-Dh6Aj3f5.js → vi-VN-M7AON7JQ-DeRc6V7y.js} +1 -1
  110. package/dist-renderer/assets/{xychartDiagram-e933f94c-Bst4jMma.js → xychartDiagram-e933f94c-Bwdd1C-0.js} +1 -1
  111. package/dist-renderer/assets/{zh-CN-LNUGB5OW-BVXMa9T3.js → zh-CN-LNUGB5OW-DAkhZJEJ.js} +1 -1
  112. package/dist-renderer/assets/{zh-HK-E62DVLB3-DYEIu92z.js → zh-HK-E62DVLB3-MU8npHxs.js} +1 -1
  113. package/dist-renderer/assets/{zh-TW-RAJ6MFWO-Dm9oSthu.js → zh-TW-RAJ6MFWO-BHTDbzbd.js} +1 -1
  114. package/dist-renderer/index.html +2 -2
  115. package/package.json +1 -1
  116. package/dist-renderer/assets/channel-BFQOS5-A.js +0 -1
  117. package/dist-renderer/assets/clone-BdgQjyvt.js +0 -1
  118. package/dist-renderer/assets/flowDiagram-v2-96b9c2cf-ue4yLZei.js +0 -1
  119. package/dist-renderer/assets/index-CYsh274_.css +0 -1
@@ -1,51 +1,51 @@
1
- import { shell as te, dialog as Ae, app as D, protocol as fe, Menu as ne, net as Ie, BrowserWindow as ge, ipcMain as $e } from "electron";
2
- import { join as u, basename as P, resolve as F, dirname as Oe } from "node:path";
1
+ import { shell as ne, dialog as $e, app as K, protocol as ge, Menu as oe, net as Ae, BrowserWindow as he, ipcMain as Ie } from "electron";
2
+ import { join as u, basename as N, resolve as W, dirname as Oe } from "node:path";
3
3
  import { fileURLToPath as Pe, pathToFileURL as Ce } from "node:url";
4
- import { existsSync as _, mkdirSync as xe, writeFileSync as Ne, appendFileSync as Re } from "node:fs";
5
- import { homedir as b } from "node:os";
6
- import { readFile as w, readdir as V, stat as he, mkdir as C, rm as M, writeFile as O, appendFile as Te } from "node:fs/promises";
4
+ import { existsSync as E, mkdirSync as Ne, writeFileSync as xe, appendFileSync as Te } from "node:fs";
5
+ import { homedir as k } from "node:os";
6
+ import { readFile as w, readdir as Q, stat as ye, mkdir as x, rm as Y, writeFile as C, appendFile as Re } from "node:fs/promises";
7
7
  import { execFile as R } from "node:child_process";
8
- import { promisify as T } from "node:util";
9
- import X from "gray-matter";
10
- import { z as k } from "zod";
8
+ import { promisify as U } from "node:util";
9
+ import Z from "gray-matter";
10
+ import { z as S } from "zod";
11
11
  import Ue from "@anthropic-ai/sdk";
12
12
  import Le from "openai";
13
13
  import { GoogleGenerativeAI as De } from "@google/generative-ai";
14
14
  import { Ollama as je } from "ollama";
15
15
  import { createRequire as Ke } from "node:module";
16
16
  import "dotenv/config";
17
- const Be = k.object({
18
- name: k.string(),
19
- description: k.string(),
20
- interests: k.array(k.string()).default([]),
21
- backend: k.enum(["anthropic", "openai", "google", "ollama"]),
22
- model: k.string().optional(),
23
- skills: k.array(k.string()).default([]),
24
- temperature: k.number().min(0).max(2).optional(),
25
- avatar: k.string().optional()
26
- }), Ge = (o, s) => [
17
+ const Be = S.object({
18
+ name: S.string(),
19
+ description: S.string(),
20
+ interests: S.array(S.string()).default([]),
21
+ backend: S.enum(["anthropic", "openai", "google", "ollama"]),
22
+ model: S.string().optional(),
23
+ skills: S.array(S.string()).default([]),
24
+ temperature: S.number().min(0).max(2).optional(),
25
+ avatar: S.string().optional()
26
+ }), Me = (o, s) => [
27
27
  u(o, "skills", s, "SKILL.md"),
28
28
  u(process.cwd(), ".claude", "skills", s, "SKILL.md"),
29
- u(b(), ".agents", "skills", s, "SKILL.md"),
30
- u(b(), ".claude", "skills", s, "SKILL.md")
29
+ u(k(), ".agents", "skills", s, "SKILL.md"),
30
+ u(k(), ".claude", "skills", s, "SKILL.md")
31
31
  ];
32
- async function Fe(o, s) {
33
- for (const t of Ge(s, o))
34
- if (_(t)) {
35
- const e = await w(t, "utf-8"), { content: r } = X(e);
32
+ async function Ge(o, s) {
33
+ for (const n of Me(s, o))
34
+ if (E(n)) {
35
+ const e = await w(n, "utf-8"), { content: r } = Z(e);
36
36
  return r.trim();
37
37
  }
38
38
  return null;
39
39
  }
40
- async function Me(o, s) {
41
- const t = [];
40
+ async function Fe(o, s) {
41
+ const n = [];
42
42
  for (const e of o) {
43
- const r = await Fe(e, s);
44
- r && t.push(`## Skill: ${e}
43
+ const r = await Ge(e, s);
44
+ r && n.push(`## Skill: ${e}
45
45
 
46
46
  ${r}`);
47
47
  }
48
- return t.join(`
48
+ return n.join(`
49
49
 
50
50
  `);
51
51
  }
@@ -53,140 +53,140 @@ function We(o, s) {
53
53
  return o ? o.startsWith("http://") || o.startsWith("https://") ? o : `council-file://${o.startsWith("/") ? o : u(s, o)}` : void 0;
54
54
  }
55
55
  async function Ye(o, s) {
56
- const t = /\{\{(.+?)\}\}/g;
56
+ const n = /\{\{(.+?)\}\}/g;
57
57
  let e = o;
58
- for (const r of o.matchAll(t)) {
59
- const n = r[1].trim(), a = u(s, n);
60
- if (_(a)) {
58
+ for (const r of o.matchAll(n)) {
59
+ const t = r[1].trim(), a = u(s, t);
60
+ if (E(a)) {
61
61
  const i = await w(a, "utf-8");
62
62
  e = e.replace(r[0], i.trim());
63
63
  } else
64
- e = e.replace(r[0], `[Reference not found: ${n}]`);
64
+ e = e.replace(r[0], `[Reference not found: ${t}]`);
65
65
  }
66
66
  return e;
67
67
  }
68
- async function oe(o) {
69
- const s = F(o), t = u(s, "ABOUT.md");
70
- if (!_(t))
68
+ async function re(o) {
69
+ const s = W(o), n = u(s, "ABOUT.md");
70
+ if (!E(n))
71
71
  throw new Error(`No ABOUT.md found in ${s}`);
72
- const e = await w(t, "utf-8"), { data: r, content: n } = X(e), a = Be.parse(r);
73
- let i = await Ye(n.trim(), s);
72
+ const e = await w(n, "utf-8"), { data: r, content: t } = Z(e), a = Be.parse(r);
73
+ let i = await Ye(t.trim(), s);
74
74
  if (a.skills.length > 0) {
75
- const l = await Me(a.skills, s);
76
- l && (i += `
75
+ const c = await Fe(a.skills, s);
76
+ c && (i += `
77
77
 
78
- ` + l);
78
+ ` + c);
79
79
  }
80
80
  return {
81
- id: P(s),
81
+ id: N(s),
82
82
  frontmatter: a,
83
83
  systemPrompt: i,
84
84
  dirPath: s,
85
85
  avatarUrl: We(a.avatar, s)
86
86
  };
87
87
  }
88
- async function re(o, s) {
89
- const t = [], e = /* @__PURE__ */ new Set();
88
+ async function se(o, s) {
89
+ const n = [], e = /* @__PURE__ */ new Set();
90
90
  if (s?.length) {
91
91
  for (const r of s)
92
- if (_(u(r, "ABOUT.md")))
92
+ if (E(u(r, "ABOUT.md")))
93
93
  try {
94
- const n = await oe(r);
95
- e.has(n.id) || (t.push(n), e.add(n.id));
94
+ const t = await re(r);
95
+ e.has(t.id) || (n.push(t), e.add(t.id));
96
96
  } catch {
97
97
  }
98
98
  }
99
- if (_(o)) {
100
- const r = await V(o);
101
- for (const n of r) {
102
- const a = u(o, n);
103
- (await he(a)).isDirectory() && _(u(a, "ABOUT.md")) && (e.has(P(a)) || (t.push(await oe(a)), e.add(P(a))));
99
+ if (E(o)) {
100
+ const r = await Q(o);
101
+ for (const t of r) {
102
+ const a = u(o, t);
103
+ (await ye(a)).isDirectory() && E(u(a, "ABOUT.md")) && (e.has(N(a)) || (n.push(await re(a)), e.add(N(a))));
104
104
  }
105
105
  }
106
- if (t.length === 0)
106
+ if (n.length === 0)
107
107
  throw new Error(
108
108
  `No councilors found. Searched ${o}${s?.length ? ` and ${s.length} registered path(s)` : ""}.
109
109
  Create one with: mkdir -p ~/.ai-council/councilors/my-councilor && council councilor add ~/.ai-council/councilors/my-councilor`
110
110
  );
111
- return t;
111
+ return n;
112
112
  }
113
- const He = T(R), ye = u(b(), ".ai-council", "config.json"), se = u(b(), ".ai-council", "councilors");
114
- async function Q() {
113
+ const He = U(R), we = u(k(), ".ai-council", "config.json"), ae = u(k(), ".ai-council", "councilors");
114
+ async function q() {
115
115
  try {
116
- return JSON.parse(await w(ye, "utf-8"));
116
+ return JSON.parse(await w(we, "utf-8"));
117
117
  } catch {
118
118
  return { backends: {} };
119
119
  }
120
120
  }
121
- async function Z(o) {
122
- const s = u(b(), ".ai-council");
123
- await C(s, { recursive: !0 }), await O(ye, JSON.stringify(o, null, 2), "utf-8");
121
+ async function ee(o) {
122
+ const s = u(k(), ".ai-council");
123
+ await x(s, { recursive: !0 }), await C(we, JSON.stringify(o, null, 2), "utf-8");
124
124
  }
125
125
  function Je(o) {
126
126
  return o.councilors ?? o.counsellors ?? {};
127
127
  }
128
- function ae(o) {
128
+ function ie(o) {
129
129
  return Object.values(Je(o)).map((s) => s.path);
130
130
  }
131
131
  async function ze(o) {
132
- const s = F(o), t = u(s, "ABOUT.md");
133
- if (!_(t))
132
+ const s = W(o), n = u(s, "ABOUT.md");
133
+ if (!E(n))
134
134
  throw new Error(`No ABOUT.md found in ${s}`);
135
- const e = P(s), r = await Q(), n = r.councilors ?? {};
136
- if (n[e])
137
- throw new Error(`Councilor "${e}" is already registered (path: ${n[e].path})`);
138
- const l = (await w(t, "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? e;
139
- return n[e] = {
135
+ const e = N(s), r = await q(), t = r.councilors ?? {};
136
+ if (t[e])
137
+ throw new Error(`Councilor "${e}" is already registered (path: ${t[e].path})`);
138
+ const c = (await w(n, "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? e;
139
+ return t[e] = {
140
140
  path: s,
141
141
  source: "local",
142
142
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
143
- }, r.councilors = n, await Z(r), { id: e, name: l };
143
+ }, r.councilors = t, await ee(r), { id: e, name: c };
144
144
  }
145
145
  async function Ve(o) {
146
- await C(se, { recursive: !0 });
147
- const s = P(o, ".git").replace(/\.git$/, ""), t = u(se, s);
148
- if (_(t))
149
- throw new Error(`Directory already exists: ${t}. Remove it first or use a different URL.`);
150
- await He("git", ["clone", "--depth", "1", o, t]);
151
- const e = [], r = await Q(), n = r.councilors ?? {};
152
- if (_(u(t, "ABOUT.md"))) {
146
+ await x(ae, { recursive: !0 });
147
+ const s = N(o, ".git").replace(/\.git$/, ""), n = u(ae, s);
148
+ if (E(n))
149
+ throw new Error(`Directory already exists: ${n}. Remove it first or use a different URL.`);
150
+ await He("git", ["clone", "--depth", "1", o, n]);
151
+ const e = [], r = await q(), t = r.councilors ?? {};
152
+ if (E(u(n, "ABOUT.md"))) {
153
153
  const a = s;
154
- if (n[a])
154
+ if (t[a])
155
155
  throw new Error(`Councilor "${a}" is already registered`);
156
- const c = (await w(u(t, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? a;
157
- n[a] = {
158
- path: t,
156
+ const l = (await w(u(n, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? a;
157
+ t[a] = {
158
+ path: n,
159
159
  source: "git",
160
160
  url: o,
161
161
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
162
- }, e.push({ id: a, name: c });
162
+ }, e.push({ id: a, name: l });
163
163
  } else {
164
- const a = await V(t);
164
+ const a = await Q(n);
165
165
  for (const i of a) {
166
166
  if (i.startsWith(".")) continue;
167
- const l = u(t, i);
168
- if ((await he(l)).isDirectory() && _(u(l, "ABOUT.md"))) {
169
- const f = i;
170
- if (n[f]) continue;
171
- const g = (await w(u(l, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? f;
172
- n[f] = {
173
- path: l,
167
+ const c = u(n, i);
168
+ if ((await ye(c)).isDirectory() && E(u(c, "ABOUT.md"))) {
169
+ const m = i;
170
+ if (t[m]) continue;
171
+ const g = (await w(u(c, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? m;
172
+ t[m] = {
173
+ path: c,
174
174
  source: "git",
175
175
  url: o,
176
176
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
177
- }, e.push({ id: f, name: g });
177
+ }, e.push({ id: m, name: g });
178
178
  }
179
179
  }
180
180
  if (e.length === 0)
181
- throw await M(t, { recursive: !0, force: !0 }), new Error("No councilors found in cloned repository (no ABOUT.md files)");
181
+ throw await Y(n, { recursive: !0, force: !0 }), new Error("No councilors found in cloned repository (no ABOUT.md files)");
182
182
  }
183
- return r.councilors = n, await Z(r), e;
183
+ return r.councilors = t, await ee(r), e;
184
184
  }
185
185
  async function Xe(o, s = !1) {
186
- const t = await Q(), e = t.councilors ?? {}, r = e[o];
186
+ const n = await q(), e = n.councilors ?? {}, r = e[o];
187
187
  if (!r)
188
188
  throw new Error(`Councilor "${o}" is not registered`);
189
- s && r.source === "git" && _(r.path) && await M(r.path, { recursive: !0, force: !0 }), delete e[o], t.councilors = e, await Z(t);
189
+ s && r.source === "git" && E(r.path) && await Y(r.path, { recursive: !0, force: !0 }), delete e[o], n.councilors = e, await ee(n);
190
190
  }
191
191
  function Qe(o) {
192
192
  const s = new Ue({
@@ -196,38 +196,38 @@ function Qe(o) {
196
196
  return {
197
197
  name: "anthropic",
198
198
  defaultModel: "claude-sonnet-4-6",
199
- async chat(t) {
199
+ async chat(n) {
200
200
  const e = await s.messages.create({
201
- model: t.model,
201
+ model: n.model,
202
202
  max_tokens: 4096,
203
- system: t.systemPrompt,
204
- messages: t.messages.map((n) => ({
205
- role: n.role,
206
- content: n.content
203
+ system: n.systemPrompt,
204
+ messages: n.messages.map((t) => ({
205
+ role: t.role,
206
+ content: t.content
207
207
  })),
208
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {}
208
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {}
209
209
  });
210
210
  return {
211
- content: e.content.find((n) => n.type === "text")?.text ?? "",
211
+ content: e.content.find((t) => t.type === "text")?.text ?? "",
212
212
  tokenUsage: {
213
213
  input: e.usage.input_tokens,
214
214
  output: e.usage.output_tokens
215
215
  }
216
216
  };
217
217
  },
218
- async *chatStream(t) {
218
+ async *chatStream(n) {
219
219
  const e = s.messages.stream({
220
- model: t.model,
220
+ model: n.model,
221
221
  max_tokens: 4096,
222
- system: t.systemPrompt,
223
- messages: t.messages.map((n) => ({
224
- role: n.role,
225
- content: n.content
222
+ system: n.systemPrompt,
223
+ messages: n.messages.map((t) => ({
224
+ role: t.role,
225
+ content: t.content
226
226
  })),
227
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {}
227
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {}
228
228
  });
229
- for await (const n of e)
230
- n.type === "content_block_delta" && n.delta.type === "text_delta" && (yield { delta: n.delta.text });
229
+ for await (const t of e)
230
+ t.type === "content_block_delta" && t.delta.type === "text_delta" && (yield { delta: t.delta.text });
231
231
  const r = await e.finalMessage();
232
232
  yield {
233
233
  delta: "",
@@ -238,14 +238,14 @@ function Qe(o) {
238
238
  };
239
239
  },
240
240
  async listModels() {
241
- const t = [];
241
+ const n = [];
242
242
  for await (const e of s.models.list({ limit: 100 }))
243
- t.push({
243
+ n.push({
244
244
  id: e.id,
245
245
  name: e.display_name,
246
246
  created: e.created_at
247
247
  });
248
- return t.sort((e, r) => e.id.localeCompare(r.id));
248
+ return n.sort((e, r) => e.id.localeCompare(r.id));
249
249
  }
250
250
  };
251
251
  }
@@ -257,40 +257,40 @@ function Ze(o) {
257
257
  return {
258
258
  name: "openai",
259
259
  defaultModel: "gpt-4o",
260
- async chat(t) {
260
+ async chat(n) {
261
261
  const e = await s.chat.completions.create({
262
- model: t.model,
262
+ model: n.model,
263
263
  messages: [
264
- { role: "system", content: t.systemPrompt },
265
- ...t.messages.map((n) => ({
266
- role: n.role,
267
- content: n.content
264
+ { role: "system", content: n.systemPrompt },
265
+ ...n.messages.map((t) => ({
266
+ role: t.role,
267
+ content: t.content
268
268
  }))
269
269
  ],
270
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {}
270
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {}
271
271
  });
272
272
  return {
273
273
  content: e.choices[0]?.message?.content ?? "",
274
274
  tokenUsage: e.usage ? { input: e.usage.prompt_tokens, output: e.usage.completion_tokens } : void 0
275
275
  };
276
276
  },
277
- async *chatStream(t) {
277
+ async *chatStream(n) {
278
278
  const e = await s.chat.completions.create({
279
- model: t.model,
279
+ model: n.model,
280
280
  messages: [
281
- { role: "system", content: t.systemPrompt },
282
- ...t.messages.map((r) => ({
281
+ { role: "system", content: n.systemPrompt },
282
+ ...n.messages.map((r) => ({
283
283
  role: r.role,
284
284
  content: r.content
285
285
  }))
286
286
  ],
287
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {},
287
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {},
288
288
  stream: !0,
289
289
  stream_options: { include_usage: !0 }
290
290
  });
291
291
  for await (const r of e) {
292
- const n = r.choices[0]?.delta?.content;
293
- n && (yield { delta: n }), r.usage && (yield {
292
+ const t = r.choices[0]?.delta?.content;
293
+ t && (yield { delta: t }), r.usage && (yield {
294
294
  delta: "",
295
295
  tokenUsage: {
296
296
  input: r.usage.prompt_tokens,
@@ -300,61 +300,61 @@ function Ze(o) {
300
300
  }
301
301
  },
302
302
  async listModels() {
303
- const t = await s.models.list(), e = [];
304
- for await (const r of t)
303
+ const n = await s.models.list(), e = [];
304
+ for await (const r of n)
305
305
  e.push({
306
306
  id: r.id,
307
307
  created: new Date(r.created * 1e3).toISOString()
308
308
  });
309
- return e.sort((r, n) => r.id.localeCompare(n.id));
309
+ return e.sort((r, t) => r.id.localeCompare(t.id));
310
310
  }
311
311
  };
312
312
  }
313
313
  function qe(o) {
314
- const s = o.apiKey ?? process.env.GOOGLE_API_KEY ?? "", t = new De(s);
314
+ const s = o.apiKey ?? process.env.GOOGLE_API_KEY ?? "", n = new De(s);
315
315
  return {
316
316
  name: "google",
317
317
  defaultModel: "gemini-2.0-flash",
318
318
  async chat(e) {
319
- const r = t.getGenerativeModel({
319
+ const r = n.getGenerativeModel({
320
320
  model: e.model,
321
321
  systemInstruction: e.systemPrompt,
322
322
  generationConfig: {
323
323
  ...e.temperature !== void 0 ? { temperature: e.temperature } : {}
324
324
  }
325
- }), n = e.messages.slice(0, -1).map((f) => ({
326
- role: f.role === "assistant" ? "model" : "user",
327
- parts: [{ text: f.content }]
328
- })), a = r.startChat({ history: n }), i = e.messages[e.messages.length - 1], c = (await a.sendMessage(i?.content ?? "")).response;
325
+ }), t = e.messages.slice(0, -1).map((m) => ({
326
+ role: m.role === "assistant" ? "model" : "user",
327
+ parts: [{ text: m.content }]
328
+ })), a = r.startChat({ history: t }), i = e.messages[e.messages.length - 1], l = (await a.sendMessage(i?.content ?? "")).response;
329
329
  return {
330
- content: c.text(),
331
- tokenUsage: c.usageMetadata ? {
332
- input: c.usageMetadata.promptTokenCount ?? 0,
333
- output: c.usageMetadata.candidatesTokenCount ?? 0
330
+ content: l.text(),
331
+ tokenUsage: l.usageMetadata ? {
332
+ input: l.usageMetadata.promptTokenCount ?? 0,
333
+ output: l.usageMetadata.candidatesTokenCount ?? 0
334
334
  } : void 0
335
335
  };
336
336
  },
337
337
  async *chatStream(e) {
338
- const r = t.getGenerativeModel({
338
+ const r = n.getGenerativeModel({
339
339
  model: e.model,
340
340
  systemInstruction: e.systemPrompt,
341
341
  generationConfig: {
342
342
  ...e.temperature !== void 0 ? { temperature: e.temperature } : {}
343
343
  }
344
- }), n = e.messages.slice(0, -1).map((f) => ({
345
- role: f.role === "assistant" ? "model" : "user",
346
- parts: [{ text: f.content }]
347
- })), a = r.startChat({ history: n }), i = e.messages[e.messages.length - 1], l = await a.sendMessageStream(i?.content ?? "");
348
- for await (const f of l.stream) {
349
- const y = f.text();
350
- y && (yield { delta: y });
344
+ }), t = e.messages.slice(0, -1).map((m) => ({
345
+ role: m.role === "assistant" ? "model" : "user",
346
+ parts: [{ text: m.content }]
347
+ })), a = r.startChat({ history: t }), i = e.messages[e.messages.length - 1], c = await a.sendMessageStream(i?.content ?? "");
348
+ for await (const m of c.stream) {
349
+ const h = m.text();
350
+ h && (yield { delta: h });
351
351
  }
352
- const c = await l.response;
352
+ const l = await c.response;
353
353
  yield {
354
354
  delta: "",
355
- tokenUsage: c.usageMetadata ? {
356
- input: c.usageMetadata.promptTokenCount ?? 0,
357
- output: c.usageMetadata.candidatesTokenCount ?? 0
355
+ tokenUsage: l.usageMetadata ? {
356
+ input: l.usageMetadata.promptTokenCount ?? 0,
357
+ output: l.usageMetadata.candidatesTokenCount ?? 0
358
358
  } : void 0
359
359
  };
360
360
  },
@@ -363,11 +363,11 @@ function qe(o) {
363
363
  `https://generativelanguage.googleapis.com/v1beta/models?key=${s}&pageSize=100`
364
364
  );
365
365
  if (!e.ok) throw new Error(`Google API error: ${e.status}`);
366
- return ((await e.json()).models || []).filter((n) => n.name.startsWith("models/gemini")).map((n) => ({
367
- id: n.name.replace("models/", ""),
368
- name: n.displayName,
369
- description: n.description
370
- })).sort((n, a) => n.id.localeCompare(a.id));
366
+ return ((await e.json()).models || []).filter((t) => t.name.startsWith("models/gemini")).map((t) => ({
367
+ id: t.name.replace("models/", ""),
368
+ name: t.displayName,
369
+ description: t.description
370
+ })).sort((t, a) => t.id.localeCompare(a.id));
371
371
  }
372
372
  };
373
373
  }
@@ -378,18 +378,18 @@ function et(o) {
378
378
  return {
379
379
  name: "ollama",
380
380
  defaultModel: "llama3.2",
381
- async chat(t) {
381
+ async chat(n) {
382
382
  const e = await s.chat({
383
- model: t.model,
383
+ model: n.model,
384
384
  messages: [
385
- { role: "system", content: t.systemPrompt },
386
- ...t.messages.map((r) => ({
385
+ { role: "system", content: n.systemPrompt },
386
+ ...n.messages.map((r) => ({
387
387
  role: r.role,
388
388
  content: r.content
389
389
  }))
390
390
  ],
391
391
  options: {
392
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {}
392
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {}
393
393
  }
394
394
  });
395
395
  return {
@@ -400,27 +400,27 @@ function et(o) {
400
400
  } : void 0
401
401
  };
402
402
  },
403
- async *chatStream(t) {
403
+ async *chatStream(n) {
404
404
  const e = await s.chat({
405
- model: t.model,
405
+ model: n.model,
406
406
  messages: [
407
- { role: "system", content: t.systemPrompt },
408
- ...t.messages.map((a) => ({
407
+ { role: "system", content: n.systemPrompt },
408
+ ...n.messages.map((a) => ({
409
409
  role: a.role,
410
410
  content: a.content
411
411
  }))
412
412
  ],
413
413
  options: {
414
- ...t.temperature !== void 0 ? { temperature: t.temperature } : {}
414
+ ...n.temperature !== void 0 ? { temperature: n.temperature } : {}
415
415
  },
416
416
  stream: !0
417
417
  });
418
- let r, n;
418
+ let r, t;
419
419
  for await (const a of e)
420
- a.message.content && (yield { delta: a.message.content }), a.done && (r = a.prompt_eval_count, n = a.eval_count);
420
+ a.message.content && (yield { delta: a.message.content }), a.done && (r = a.prompt_eval_count, t = a.eval_count);
421
421
  yield {
422
422
  delta: "",
423
- tokenUsage: r !== void 0 ? { input: r ?? 0, output: n ?? 0 } : void 0
423
+ tokenUsage: r !== void 0 ? { input: r ?? 0, output: t ?? 0 } : void 0
424
424
  };
425
425
  },
426
426
  async listModels() {
@@ -432,46 +432,46 @@ function et(o) {
432
432
  }
433
433
  };
434
434
  }
435
- const ie = {
435
+ const ce = {
436
436
  anthropic: Qe,
437
437
  openai: Ze,
438
438
  google: qe,
439
439
  ollama: et
440
440
  };
441
- let U = null;
441
+ let L = null;
442
442
  async function tt() {
443
- if (U) return U;
444
- const o = u(b(), ".ai-council", "config.json");
443
+ if (L) return L;
444
+ const o = u(k(), ".ai-council", "config.json");
445
445
  try {
446
446
  const s = await w(o, "utf-8");
447
- U = JSON.parse(s);
447
+ L = JSON.parse(s);
448
448
  } catch {
449
- U = { backends: {} };
449
+ L = { backends: {} };
450
450
  }
451
- return U;
451
+ return L;
452
452
  }
453
- const z = /* @__PURE__ */ new Map();
454
- function we() {
455
- U = null, z.clear();
453
+ const X = /* @__PURE__ */ new Map();
454
+ function be() {
455
+ L = null, X.clear();
456
456
  }
457
- async function j(o) {
458
- const s = z.get(o);
457
+ async function D(o) {
458
+ const s = X.get(o);
459
459
  if (s) return s;
460
- const t = ie[o];
461
- if (!t)
462
- throw new Error(`Unknown backend: "${o}". Available: ${Object.keys(ie).join(", ")}`);
463
- const r = (await tt()).backends[o] ?? {}, n = t(r);
464
- return z.set(o, n), n;
460
+ const n = ce[o];
461
+ if (!n)
462
+ throw new Error(`Unknown backend: "${o}". Available: ${Object.keys(ce).join(", ")}`);
463
+ const r = (await tt()).backends[o] ?? {}, t = n(r);
464
+ return X.set(o, t), t;
465
465
  }
466
466
  const nt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
467
467
  __proto__: null,
468
- clearCaches: we,
469
- getBackend: j
468
+ clearCaches: be,
469
+ getBackend: D
470
470
  }, Symbol.toStringTag, { value: "Module" }));
471
471
  function ot() {
472
472
  return '\n## Excalidraw Element Reference\n\nOutput a JSON array of Excalidraw elements. Each element needs these fields:\n\n### Common Fields (all elements)\n- `type`: "rectangle" | "ellipse" | "diamond" | "text" | "arrow" | "line"\n- `id`: unique string (e.g. "rect1", "text1", "arrow1")\n- `x`, `y`: number (top-left origin, x increases right, y increases down)\n- `width`, `height`: number\n- `strokeColor`: hex string (e.g. "#1e1e1e")\n- `backgroundColor`: hex string or "transparent"\n- `fillStyle`: "solid" | "hachure" | "cross-hatch"\n- `strokeWidth`: 1 | 2 | 4\n- `roughness`: 0 (sharp) | 1 (sketchy)\n- `opacity`: 100\n- `angle`: 0\n- `seed`: any integer (e.g. 1)\n- `version`: 1\n- `isDeleted`: false\n- `groupIds`: []\n- `boundElements`: null or array of { id: string, type: "text" | "arrow" }\n- `link`: null\n- `locked`: false\n\n### Text Elements\nAdditional fields: `text`, `fontSize` (16-24), `fontFamily` (1=hand, 2=normal, 3=mono), `textAlign` ("left"|"center"|"right"), `verticalAlign` ("top"|"middle"), `baseline`: 0, `containerId`: null or parent shape id\n\n### Arrow/Line Elements\nAdditional fields: `points` (array of [x,y] relative to element x,y — first point always [0,0]), `startBinding` and `endBinding`: null or { elementId: string, focus: 0, gap: 5 }, `lastCommittedPoint`: null, `startArrowhead`: null, `endArrowhead`: "arrow" | null\n\n### Color Palette\n- Blue: "#1971c2", Light blue bg: "#a5d8ff"\n- Green: "#2f9e44", Light green bg: "#b2f2bb"\n- Red: "#e03131", Light red bg: "#ffc9c9"\n- Orange: "#e8590c", Light orange bg: "#ffd8a8"\n- Purple: "#7048e8", Light purple bg: "#d0bfff"\n- Yellow: "#f08c00", Light yellow bg: "#ffec99"\n- Gray: "#868e96", Light gray bg: "#dee2e6"\n- Dark: "#1e1e1e"\n\n### Layout Tips\n- Space shapes ~200px apart horizontally, ~150px vertically\n- Typical shape size: 160×80 for rectangles, 120×60 for ellipses\n- Center text inside shapes using containerId\n- Use arrows to show relationships (agreement, disagreement, influence)\n\n### Compact Example\n```json\n[\n {"type":"rectangle","id":"r1","x":50,"y":50,"width":160,"height":80,"strokeColor":"#1971c2","backgroundColor":"#a5d8ff","fillStyle":"solid","strokeWidth":2,"roughness":1,"opacity":100,"angle":0,"seed":1,"version":1,"isDeleted":false,"groupIds":[],"boundElements":[{"id":"t1","type":"text"},{"id":"a1","type":"arrow"}],"link":null,"locked":false},\n {"type":"text","id":"t1","x":60,"y":70,"width":140,"height":40,"text":"Councilor A","fontSize":16,"fontFamily":2,"textAlign":"center","verticalAlign":"middle","baseline":0,"containerId":"r1","strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"roughness":0,"opacity":100,"angle":0,"seed":2,"version":1,"isDeleted":false,"groupIds":[],"boundElements":null,"link":null,"locked":false},\n {"type":"rectangle","id":"r2","x":350,"y":50,"width":160,"height":80,"strokeColor":"#2f9e44","backgroundColor":"#b2f2bb","fillStyle":"solid","strokeWidth":2,"roughness":1,"opacity":100,"angle":0,"seed":3,"version":1,"isDeleted":false,"groupIds":[],"boundElements":[{"id":"t2","type":"text"},{"id":"a1","type":"arrow"}],"link":null,"locked":false},\n {"type":"text","id":"t2","x":360,"y":70,"width":140,"height":40,"text":"Councilor B","fontSize":16,"fontFamily":2,"textAlign":"center","verticalAlign":"middle","baseline":0,"containerId":"r2","strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1,"roughness":0,"opacity":100,"angle":0,"seed":4,"version":1,"isDeleted":false,"groupIds":[],"boundElements":null,"link":null,"locked":false},\n {"type":"arrow","id":"a1","x":210,"y":90,"width":140,"height":0,"points":[[0,0],[140,0]],"startBinding":{"elementId":"r1","focus":0,"gap":5},"endBinding":{"elementId":"r2","focus":0,"gap":5},"startArrowhead":null,"endArrowhead":"arrow","strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"roughness":1,"opacity":100,"angle":0,"seed":5,"version":1,"isDeleted":false,"groupIds":[],"boundElements":null,"link":null,"locked":false,"lastCommittedPoint":null}\n]\n```\n'.trim();
473
473
  }
474
- const W = "---EXCALIDRAW---", rt = `You are the Secretary of a council discussion. Your job is to synthesize a clear, structured summary of the conversation that just took place.
474
+ const H = "---EXCALIDRAW---", rt = `You are the Secretary of a council discussion. Your job is to synthesize a clear, structured summary of the conversation that just took place.
475
475
 
476
476
  Structure your summary with these sections:
477
477
 
@@ -491,100 +491,100 @@ Be concise but thorough. Use markdown formatting.`;
491
491
  function st(o) {
492
492
  const s = [];
493
493
  s.push(`Topic: ${o.topic}`), s.push(`Councilors: ${o.councilors.map((e) => e.name).join(", ")}`), s.push(`Rounds: ${o.rounds}`), s.push("");
494
- let t = 0;
494
+ let n = 0;
495
495
  for (const e of o.turns)
496
- e.round !== t && (t = e.round, s.push(`--- Round ${t} ---`), s.push("")), s.push(`[${e.councilorName}]:`), s.push(e.content), s.push("");
496
+ e.round !== n && (n = e.round, s.push(`--- Round ${n} ---`), s.push("")), s.push(`[${e.councilorName}]:`), s.push(e.content), s.push("");
497
497
  return s.join(`
498
498
  `);
499
499
  }
500
500
  async function at({
501
501
  result: o,
502
502
  config: s,
503
- onChunk: t,
503
+ onChunk: n,
504
504
  signal: e
505
505
  }) {
506
506
  const r = s.secretary;
507
507
  if (!r?.backend)
508
508
  throw new Error("No secretary backend configured");
509
- const n = await j(r.backend), a = r.model ?? n.defaultModel, i = r.systemPrompt || rt, l = ot(), c = `${i}
509
+ const t = await D(r.backend), a = r.model ?? t.defaultModel, i = r.systemPrompt || rt, c = ot(), l = `${i}
510
510
 
511
- ${l}
511
+ ${c}
512
512
 
513
- After your text summary, output \`${W}\` on its own line, then a JSON array of Excalidraw elements showing a visual map of where each councilor stands on the topic. Use shapes for each councilor with their name, arrows to show relationships (agreement/disagreement), and position them to visually represent the discussion dynamics.`, f = st(o), y = {
513
+ After your text summary, output \`${H}\` on its own line, then a JSON array of Excalidraw elements showing a visual map of where each councilor stands on the topic. Use shapes for each councilor with their name, arrows to show relationships (agreement/disagreement), and position them to visually represent the discussion dynamics.`, m = st(o), h = {
514
514
  model: a,
515
- systemPrompt: c,
515
+ systemPrompt: l,
516
516
  messages: [{ role: "user", content: `Please summarize this council discussion and create a position diagram:
517
517
 
518
- ${f}` }],
518
+ ${m}` }],
519
519
  temperature: 0.5
520
520
  };
521
- let h = "";
522
- if (n.chatStream)
523
- for await (const m of n.chatStream(y)) {
521
+ let y = "";
522
+ if (t.chatStream)
523
+ for await (const p of t.chatStream(h)) {
524
524
  if (e?.aborted) break;
525
- h += m.delta, m.delta && t && t(m.delta);
525
+ y += p.delta, p.delta && n && n(p.delta);
526
526
  }
527
527
  else
528
- h = (await n.chat(y)).content, t && t(h);
529
- const g = h.indexOf(W);
528
+ y = (await t.chat(h)).content, n && n(y);
529
+ const g = y.indexOf(H);
530
530
  if (g === -1)
531
- return { text: h.trim() };
532
- const L = h.slice(0, g).trim(), d = h.slice(g + W.length).trim();
533
- let p;
531
+ return { text: y.trim() };
532
+ const j = y.slice(0, g).trim(), f = y.slice(g + H.length).trim();
533
+ let _;
534
534
  try {
535
- const m = d.match(/\[[\s\S]*\]/);
536
- m && (p = JSON.parse(m[0]));
535
+ const p = f.match(/\[[\s\S]*\]/);
536
+ p && (_ = JSON.parse(p[0]));
537
537
  } catch {
538
538
  }
539
- return { text: L, diagram: p };
539
+ return { text: j, diagram: _ };
540
540
  }
541
541
  const it = "You are the Secretary of a council debate. Briefly summarize this round of discussion. Note emerging agreements, disagreements, and shifts in position. 2-3 paragraphs max. Use markdown formatting.";
542
542
  async function ct({
543
543
  result: o,
544
544
  roundNumber: s,
545
- config: t,
545
+ config: n,
546
546
  onChunk: e,
547
547
  signal: r
548
548
  }) {
549
- const n = t.secretary;
550
- if (!n?.backend)
549
+ const t = n.secretary;
550
+ if (!t?.backend)
551
551
  throw new Error("No secretary backend configured");
552
- const a = await j(n.backend), i = n.model ?? a.defaultModel, l = o.turns.filter((h) => h.round === s), c = [];
553
- c.push(`Topic: ${o.topic}`), c.push(`Round ${s}${s === 1 ? " (Constructive)" : " (Rebuttal)"}`), c.push("");
554
- for (const h of l)
555
- c.push(`[${h.councilorName}]:`), c.push(h.content), c.push("");
556
- const f = {
552
+ const a = await D(t.backend), i = t.model ?? a.defaultModel, c = o.turns.filter((y) => y.round === s), l = [];
553
+ l.push(`Topic: ${o.topic}`), l.push(`Round ${s}${s === 1 ? " (Constructive)" : " (Rebuttal)"}`), l.push("");
554
+ for (const y of c)
555
+ l.push(`[${y.councilorName}]:`), l.push(y.content), l.push("");
556
+ const m = {
557
557
  model: i,
558
558
  systemPrompt: it,
559
559
  messages: [{ role: "user", content: `Please summarize this round:
560
560
 
561
- ${c.join(`
561
+ ${l.join(`
562
562
  `)}` }],
563
563
  temperature: 0.5
564
564
  };
565
- let y = "";
565
+ let h = "";
566
566
  if (a.chatStream)
567
- for await (const h of a.chatStream(f)) {
567
+ for await (const y of a.chatStream(m)) {
568
568
  if (r?.aborted) break;
569
- y += h.delta, h.delta && e && e(h.delta);
569
+ h += y.delta, y.delta && e && e(y.delta);
570
570
  }
571
571
  else
572
- y = (await a.chat(f)).content, e && e(y);
573
- return y.trim();
572
+ h = (await a.chat(m)).content, e && e(h);
573
+ return h.trim();
574
574
  }
575
575
  async function lt({
576
576
  topic: o,
577
577
  firstRoundTurns: s,
578
- config: t
578
+ config: n
579
579
  }) {
580
- const e = t.secretary;
580
+ const e = n.secretary;
581
581
  if (!e?.backend)
582
582
  throw new Error("No secretary backend configured");
583
- const r = await j(e.backend), n = e.model ?? r.defaultModel, a = s.map((l) => `[${l.councilorName}]: ${l.content.slice(0, 300)}`).join(`
583
+ const r = await D(e.backend), t = e.model ?? r.defaultModel, a = s.map((c) => `[${c.councilorName}]: ${c.content.slice(0, 300)}`).join(`
584
584
 
585
585
  `);
586
586
  return (await r.chat({
587
- model: n,
587
+ model: t,
588
588
  systemPrompt: "Generate a concise title (max 8 words) for this council discussion. Return only the title, no quotes or punctuation at the end.",
589
589
  messages: [
590
590
  {
@@ -598,92 +598,92 @@ ${a}`
598
598
  temperature: 0.3
599
599
  })).content.trim().replace(/^["']+|["']+$/g, "").replace(/[.!?]+$/, "").trim();
600
600
  }
601
- const be = u(b(), ".ai-council"), ut = u(be, "council.log");
602
- let ce = !1;
601
+ const ve = u(k(), ".ai-council"), ut = u(ve, "council.log");
602
+ let le = !1;
603
603
  async function dt() {
604
- ce || (await C(be, { recursive: !0 }), ce = !0);
604
+ le || (await x(ve, { recursive: !0 }), le = !0);
605
605
  }
606
- function mt(o, s, t, e) {
607
- let n = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${o} [${s}] ${t}`;
606
+ function mt(o, s, n, e) {
607
+ let t = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${o} [${s}] ${n}`;
608
608
  if (e !== void 0) {
609
609
  const a = e instanceof Error ? `${e.message}
610
610
  ${e.stack ?? ""}` : typeof e == "string" ? e : JSON.stringify(e, null, 2);
611
- n += `
611
+ t += `
612
612
  ${a.replace(/\n/g, `
613
613
  `)}`;
614
614
  }
615
- return n + `
615
+ return t + `
616
616
  `;
617
617
  }
618
- async function Y(o, s, t, e) {
618
+ async function J(o, s, n, e) {
619
619
  try {
620
- await dt(), await Te(ut, mt(o, s, t, e));
620
+ await dt(), await Re(ut, mt(o, s, n, e));
621
621
  } catch {
622
622
  }
623
623
  }
624
624
  const v = {
625
- info: (o, s, t) => Y("INFO", o, s, t),
626
- warn: (o, s, t) => Y("WARN", o, s, t),
627
- error: (o, s, t) => Y("ERROR", o, s, t)
625
+ info: (o, s, n) => J("INFO", o, s, n),
626
+ warn: (o, s, n) => J("WARN", o, s, n),
627
+ error: (o, s, n) => J("ERROR", o, s, n)
628
628
  };
629
- function pt(o, s, t, e, r) {
630
- const n = [{ role: "user", content: o }];
629
+ function pt(o, s, n, e, r) {
630
+ const t = [{ role: "user", content: o }];
631
631
  if (e?.length) {
632
632
  for (const a of e)
633
- a.councilorId === t ? n.push({ role: "assistant", content: a.content }) : n.push({
633
+ a.councilorId === n ? t.push({ role: "assistant", content: a.content }) : t.push({
634
634
  role: "user",
635
635
  content: `[${a.councilorName}, Round ${a.round}]: ${a.content}`
636
636
  });
637
- r && n.push({
637
+ r && t.push({
638
638
  role: "user",
639
639
  content: `[Secretary Summary]: ${r}`
640
640
  });
641
641
  }
642
642
  for (const a of s)
643
- a.councilorId === t ? n.push({ role: "assistant", content: a.content }) : n.push({
643
+ a.councilorId === n ? t.push({ role: "assistant", content: a.content }) : t.push({
644
644
  role: "user",
645
645
  content: `[${a.councilorName}, Round ${a.round}]: ${a.content}`
646
646
  });
647
- return n;
647
+ return t;
648
648
  }
649
- function ft(o, s, t, e) {
649
+ function ft(o, s, n, e) {
650
650
  const r = [{ role: "user", content: o }];
651
651
  if (e === 1)
652
652
  return r;
653
- const n = s.filter((i) => i.round === 1);
654
- for (const i of n)
655
- i.councilorId === t ? r.push({ role: "assistant", content: i.content }) : r.push({
653
+ const t = s.filter((i) => i.round === 1);
654
+ for (const i of t)
655
+ i.councilorId === n ? r.push({ role: "assistant", content: i.content }) : r.push({
656
656
  role: "user",
657
657
  content: `[${i.councilorName}, Constructive]: ${i.content}`
658
658
  });
659
659
  const a = e - 1;
660
660
  if (a > 1) {
661
- const i = s.filter((l) => l.round === a);
662
- for (const l of i)
663
- l.councilorId === t ? r.push({ role: "assistant", content: l.content }) : r.push({
661
+ const i = s.filter((c) => c.round === a);
662
+ for (const c of i)
663
+ c.councilorId === n ? r.push({ role: "assistant", content: c.content }) : r.push({
664
664
  role: "user",
665
- content: `[${l.councilorName}, Round ${a}]: ${l.content}`
665
+ content: `[${c.councilorName}, Round ${a}]: ${c.content}`
666
666
  });
667
667
  }
668
668
  for (const i of s)
669
- i.councilorId === t && i.round !== 1 && i.round !== a && i.round < e && r.push({ role: "assistant", content: i.content });
669
+ i.councilorId === n && i.round !== 1 && i.round !== a && i.round < e && r.push({ role: "assistant", content: i.content });
670
670
  return r;
671
671
  }
672
672
  function gt(o, s) {
673
- const t = [...o];
673
+ const n = [...o];
674
674
  let e = s | 0;
675
675
  const r = () => {
676
676
  e = e + 1831565813 | 0;
677
- let n = Math.imul(e ^ e >>> 15, 1 | e);
678
- return n = n + Math.imul(n ^ n >>> 7, 61 | n) ^ n, ((n ^ n >>> 14) >>> 0) / 4294967296;
677
+ let t = Math.imul(e ^ e >>> 15, 1 | e);
678
+ return t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t, ((t ^ t >>> 14) >>> 0) / 4294967296;
679
679
  };
680
- for (let n = t.length - 1; n > 0; n--) {
681
- const a = Math.floor(r() * (n + 1));
682
- [t[n], t[a]] = [t[a], t[n]];
680
+ for (let t = n.length - 1; t > 0; t--) {
681
+ const a = Math.floor(r() * (t + 1));
682
+ [n[t], n[a]] = [n[a], n[t]];
683
683
  }
684
- return t;
684
+ return n;
685
685
  }
686
- function H(o, s, t, e, r, n) {
686
+ function z(o, s, n, e, r, t) {
687
687
  return {
688
688
  topic: o.topic,
689
689
  topicSource: o.topicSource,
@@ -697,160 +697,202 @@ function H(o, s, t, e, r, n) {
697
697
  })),
698
698
  rounds: o.rounds,
699
699
  turns: s,
700
- startedAt: t,
700
+ startedAt: n,
701
701
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
702
702
  totalTokenUsage: { input: e, output: r },
703
- ...n && Object.keys(n).length > 0 ? { roundSummaries: n } : {},
703
+ ...t && Object.keys(t).length > 0 ? { roundSummaries: t } : {},
704
704
  ...o.mode === "debate" ? { mode: "debate" } : {}
705
705
  };
706
706
  }
707
- async function ht(o, s, t, e, r) {
708
- let n;
709
- typeof o == "string" ? n = {
707
+ async function ht(o, s, n, e, r) {
708
+ let t;
709
+ typeof o == "string" ? t = {
710
710
  topic: o,
711
711
  topicSource: s,
712
- councilors: t,
712
+ councilors: n,
713
713
  rounds: e,
714
714
  onEvent: r
715
- } : n = o;
715
+ } : t = o;
716
716
  const a = (/* @__PURE__ */ new Date()).toISOString(), i = [];
717
- let l = 0, c = 0;
718
- const f = n.mode === "debate", y = {}, h = n.previousTurns?.length ? Math.max(...n.previousTurns.map((g) => g.round)) : 0;
719
- v.info("conversation", `Starting ${f ? "debate" : "freeform"} — ${n.councilors.length} councilors, ${n.rounds} rounds`, {
720
- councilors: n.councilors.map((g) => `${g.frontmatter.name} (${g.frontmatter.backend}/${g.frontmatter.model ?? "default"})`),
721
- topic: n.topic.slice(0, 200)
717
+ let c = 0, l = 0;
718
+ const m = t.mode === "debate", h = {}, y = t.previousTurns?.length ? Math.max(...t.previousTurns.map((g) => g.round)) : 0;
719
+ v.info("conversation", `Starting ${m ? "debate" : "freeform"} — ${t.councilors.length} councilors, ${t.rounds} rounds`, {
720
+ councilors: t.councilors.map((g) => `${g.frontmatter.name} (${g.frontmatter.backend}/${g.frontmatter.model ?? "default"})`),
721
+ topic: t.topic.slice(0, 200)
722
722
  });
723
- for (let g = 1; g <= n.rounds; g++) {
724
- const L = f && g > 1 ? gt(n.councilors, g) : n.councilors;
725
- for (const d of L) {
726
- if (n.signal?.aborted)
727
- return H(n, i, a, l, c, y);
728
- if (n.beforeTurn) {
729
- const m = await n.beforeTurn();
730
- m && (i.push(m), n.onEvent({ type: "turn_complete", turn: m }));
723
+ for (let g = 1; g <= t.rounds; g++) {
724
+ const j = m && g > 1 ? gt(t.councilors, g) : t.councilors;
725
+ for (const f of j) {
726
+ if (t.signal?.aborted)
727
+ return z(t, i, a, c, l, h);
728
+ if (t.beforeTurn) {
729
+ const p = await t.beforeTurn();
730
+ p && (i.push(p), t.onEvent({ type: "turn_complete", turn: p }));
731
731
  }
732
- const p = g + h;
733
- n.onEvent({ type: "turn_start", round: p, councilorName: d.frontmatter.name });
732
+ const _ = g + y;
733
+ t.onEvent({ type: "turn_start", round: _, councilorName: f.frontmatter.name });
734
734
  try {
735
- const m = await j(d.frontmatter.backend), x = d.frontmatter.model ?? m.defaultModel, Ee = f ? ft(n.topic, i, d.id, g) : pt(n.topic, i, d.id, n.previousTurns, n.previousSummary), q = {
736
- model: x,
737
- systemPrompt: d.systemPrompt,
738
- messages: Ee,
739
- temperature: d.frontmatter.temperature
735
+ const p = await D(f.frontmatter.backend), d = f.frontmatter.model ?? p.defaultModel, b = m ? ft(t.topic, i, f.id, g) : pt(t.topic, i, f.id, t.previousTurns, t.previousSummary), B = {
736
+ model: d,
737
+ systemPrompt: f.systemPrompt,
738
+ messages: b,
739
+ temperature: f.frontmatter.temperature
740
740
  };
741
- let K, N;
742
- if (m.chatStream) {
743
- K = "";
744
- for await (const I of m.chatStream(q)) {
745
- if (n.signal?.aborted) break;
746
- K += I.delta, I.delta && n.onEvent({ type: "turn_chunk", councilorName: d.frontmatter.name, delta: I.delta }), I.tokenUsage && (N = I.tokenUsage);
741
+ let M, T;
742
+ if (p.chatStream) {
743
+ M = "";
744
+ for await (const O of p.chatStream(B)) {
745
+ if (t.signal?.aborted) break;
746
+ M += O.delta, O.delta && t.onEvent({ type: "turn_chunk", councilorName: f.frontmatter.name, delta: O.delta }), O.tokenUsage && (T = O.tokenUsage);
747
747
  }
748
748
  } else {
749
- const I = await m.chat(q);
750
- K = I.content, N = I.tokenUsage;
749
+ const O = await p.chat(B);
750
+ M = O.content, T = O.tokenUsage;
751
751
  }
752
- const ee = {
753
- round: p,
754
- councilorId: d.id,
755
- councilorName: d.frontmatter.name,
756
- content: K,
752
+ const te = {
753
+ round: _,
754
+ councilorId: f.id,
755
+ councilorName: f.frontmatter.name,
756
+ content: M,
757
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
758
+ model: d,
759
+ backend: f.frontmatter.backend,
760
+ tokenUsage: T,
761
+ avatarUrl: f.avatarUrl
762
+ };
763
+ T && (c += T.input, l += T.output), i.push(te), t.onEvent({ type: "turn_complete", turn: te });
764
+ } catch (p) {
765
+ const d = p instanceof Error ? p.message : String(p);
766
+ v.error("conversation", `Turn failed for ${f.frontmatter.name} (round ${g}, model ${f.frontmatter.model ?? "default"}, backend ${f.frontmatter.backend})`, p), t.onEvent({ type: "error", councilorName: f.frontmatter.name, error: d });
767
+ const b = {
768
+ round: _,
769
+ councilorId: f.id,
770
+ councilorName: f.frontmatter.name,
771
+ content: "",
757
772
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
758
- model: x,
759
- backend: d.frontmatter.backend,
760
- tokenUsage: N,
761
- avatarUrl: d.avatarUrl
773
+ model: f.frontmatter.model ?? "default",
774
+ backend: f.frontmatter.backend,
775
+ avatarUrl: f.avatarUrl,
776
+ error: d
762
777
  };
763
- N && (l += N.input, c += N.output), i.push(ee), n.onEvent({ type: "turn_complete", turn: ee });
764
- } catch (m) {
765
- const x = m instanceof Error ? m.message : String(m);
766
- v.error("conversation", `Turn failed for ${d.frontmatter.name} (round ${g}, model ${d.frontmatter.model ?? "default"}, backend ${d.frontmatter.backend})`, m), n.onEvent({ type: "error", councilorName: d.frontmatter.name, error: x });
778
+ i.push(b), t.onEvent({ type: "turn_complete", turn: b });
767
779
  }
768
780
  }
769
- if (n.onEvent({ type: "round_complete", round: g }), f && n.config?.secretary?.backend && !n.signal?.aborted)
781
+ if (t.onEvent({ type: "round_complete", round: g }), m && t.config?.secretary?.backend && !t.signal?.aborted)
770
782
  try {
771
- const d = H(n, i, a, l, c, y);
772
- n.onEvent({ type: "round_summary_start", round: g });
773
- const p = await ct({
774
- result: d,
783
+ const f = z(t, i, a, c, l, h);
784
+ t.onEvent({ type: "round_summary_start", round: g });
785
+ const _ = await ct({
786
+ result: f,
775
787
  roundNumber: g,
776
- config: n.config,
777
- onChunk: (m) => {
778
- n.onEvent({ type: "round_summary_chunk", round: g, delta: m });
788
+ config: t.config,
789
+ onChunk: (p) => {
790
+ t.onEvent({ type: "round_summary_chunk", round: g, delta: p });
779
791
  },
780
- signal: n.signal
792
+ signal: t.signal
781
793
  });
782
- y[g] = p, n.onEvent({ type: "round_summary_complete", round: g, summary: p });
783
- } catch (d) {
784
- v.error("conversation", `Interim summary failed for round ${g}`, d);
794
+ h[g] = _, t.onEvent({ type: "round_summary_complete", round: g, summary: _ });
795
+ } catch (f) {
796
+ v.error("conversation", `Interim summary failed for round ${g}`, f);
785
797
  }
786
798
  }
787
- return H(n, i, a, l, c, y);
799
+ return z(t, i, a, c, l, h);
800
+ }
801
+ async function yt(o, s) {
802
+ const n = /* @__PURE__ */ new Map();
803
+ for (const t of o) {
804
+ const a = t.frontmatter.backend;
805
+ n.has(a) || n.set(a, []), n.get(a).push(t);
806
+ }
807
+ const e = /* @__PURE__ */ new Map();
808
+ for (const [t, a] of n) {
809
+ s?.(`Checking ${t} backend (${a.length} councilor${a.length > 1 ? "s" : ""})...`);
810
+ let i = null, c = [], l = null;
811
+ try {
812
+ i = await D(t), i.listModels && (c = (await i.listModels()).map((h) => h.id));
813
+ } catch (m) {
814
+ l = m instanceof Error ? m.message : String(m), v.error("preflight", `Backend "${t}" probe failed`, m);
815
+ }
816
+ e.set(t, { provider: i, models: c, error: l });
817
+ }
818
+ const r = [];
819
+ for (const t of o) {
820
+ const a = e.get(t.frontmatter.backend), i = [], c = t.frontmatter.model ?? a.provider?.defaultModel ?? "(unknown)";
821
+ a.error ? i.push(`Backend "${t.frontmatter.backend}" unavailable: ${a.error}`) : a.models.length > 0 && !a.models.includes(c) && i.push(
822
+ `Model "${c}" not found on ${t.frontmatter.backend}`
823
+ ), r.push({ councilor: t, ok: i.length === 0, model: c, issues: i });
824
+ }
825
+ return {
826
+ results: r,
827
+ valid: r.filter((t) => t.ok).map((t) => t.councilor),
828
+ invalid: r.filter((t) => !t.ok)
829
+ };
788
830
  }
789
- const A = u(b(), ".ai-council", "history");
790
- function yt(o) {
831
+ const I = u(k(), ".ai-council", "history");
832
+ function wt(o) {
791
833
  return o.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
792
834
  }
793
- async function wt(o) {
794
- await C(A, { recursive: !0 });
795
- const s = new Date(o.startedAt).toISOString().replace(/[:.]/g, "-").slice(0, 19), t = yt(o.topic), e = `${s}-${t}`, r = u(A, `${e}.json`);
796
- return await O(r, JSON.stringify(o, null, 2), "utf-8"), e;
835
+ async function bt(o) {
836
+ await x(I, { recursive: !0 });
837
+ const s = new Date(o.startedAt).toISOString().replace(/[:.]/g, "-").slice(0, 19), n = wt(o.topic), e = `${s}-${n}`, r = u(I, `${e}.json`);
838
+ return await C(r, JSON.stringify(o, null, 2), "utf-8"), e;
797
839
  }
798
- async function bt() {
799
- await C(A, { recursive: !0 });
800
- const o = await V(A), s = [];
801
- for (const t of o)
802
- if (t.endsWith(".json"))
840
+ async function vt() {
841
+ await x(I, { recursive: !0 });
842
+ const o = await Q(I), s = [];
843
+ for (const n of o)
844
+ if (n.endsWith(".json"))
803
845
  try {
804
- const e = await w(u(A, t), "utf-8"), r = JSON.parse(e);
846
+ const e = await w(u(I, n), "utf-8"), r = JSON.parse(e);
805
847
  s.push({
806
- id: P(t, ".json"),
848
+ id: N(n, ".json"),
807
849
  topic: r.topic,
808
850
  title: r.title,
809
- councilors: r.councilors.map((n) => n.name),
851
+ councilors: r.councilors.map((t) => t.name),
810
852
  rounds: r.rounds,
811
853
  startedAt: r.startedAt,
812
854
  completedAt: r.completedAt
813
855
  });
814
856
  } catch {
815
857
  }
816
- return s.sort((t, e) => e.startedAt.localeCompare(t.startedAt));
858
+ return s.sort((n, e) => e.startedAt.localeCompare(n.startedAt));
817
859
  }
818
- async function le(o) {
819
- const s = u(A, `${o}.json`), t = await w(s, "utf-8"), e = JSON.parse(t);
860
+ async function ue(o) {
861
+ const s = u(I, `${o}.json`), n = await w(s, "utf-8"), e = JSON.parse(n);
820
862
  return e.infographic && !e.infographics && (e.infographics = [e.infographic], delete e.infographic), e;
821
863
  }
822
- async function vt(o) {
823
- const s = u(A, `${o}.json`);
824
- await M(s);
825
- }
826
- async function kt(o, s) {
827
- const t = u(A, `${o}.json`), e = await w(t, "utf-8"), r = JSON.parse(e);
828
- r.infographics || (r.infographics = []), r.infographics.push(s), await O(t, JSON.stringify(r, null, 2), "utf-8");
864
+ async function kt(o) {
865
+ const s = u(I, `${o}.json`);
866
+ await Y(s);
829
867
  }
830
868
  async function _t(o, s) {
831
- const t = u(A, `${o}.json`), e = await w(t, "utf-8"), r = JSON.parse(e);
832
- r.infographics && s >= 0 && s < r.infographics.length && r.infographics.splice(s, 1), await O(t, JSON.stringify(r, null, 2), "utf-8");
869
+ const n = u(I, `${o}.json`), e = await w(n, "utf-8"), r = JSON.parse(e);
870
+ r.infographics || (r.infographics = []), r.infographics.push(s), await C(n, JSON.stringify(r, null, 2), "utf-8");
833
871
  }
834
- const ve = Ke(import.meta.url);
835
- function St(o) {
836
- const s = o.councilors.map((e) => e.name).join(", "), t = o.summary ?? o.turns.map((e) => `${e.councilorName}: ${e.content.slice(0, 200)}`).join(`
872
+ async function St(o, s) {
873
+ const n = u(I, `${o}.json`), e = await w(n, "utf-8"), r = JSON.parse(e);
874
+ r.infographics && s >= 0 && s < r.infographics.length && r.infographics.splice(s, 1), await C(n, JSON.stringify(r, null, 2), "utf-8");
875
+ }
876
+ const ke = Ke(import.meta.url);
877
+ function Et(o) {
878
+ const s = o.councilors.map((e) => e.name).join(", "), n = o.summary ?? o.turns.map((e) => `${e.councilorName}: ${e.content.slice(0, 200)}`).join(`
837
879
  `);
838
880
  return [
839
881
  "Create a professional infographic summarizing a panel discussion.",
840
882
  `Topic: ${o.topic.slice(0, 300)}`,
841
- `Key points: ${t.slice(0, 1500)}`,
883
+ `Key points: ${n.slice(0, 1500)}`,
842
884
  `Panelists: ${s}`,
843
885
  "Use a clean, modern design with sections for convergence points, divergence points, and key takeaways.",
844
886
  "Include relevant icons and visual hierarchy. Use a horizontal landscape layout."
845
887
  ].join(" ");
846
888
  }
847
- function Et(o) {
889
+ function $t(o) {
848
890
  if (o.infographic?.backend) return o.infographic.backend;
849
- const s = !!(o.backends.google?.apiKey || process.env.GOOGLE_API_KEY), t = !!(o.backends.openai?.apiKey || process.env.OPENAI_API_KEY);
850
- return s ? "google" : t ? "openai" : null;
891
+ const s = !!(o.backends.google?.apiKey || process.env.GOOGLE_API_KEY), n = !!(o.backends.openai?.apiKey || process.env.OPENAI_API_KEY);
892
+ return s ? "google" : n ? "openai" : null;
851
893
  }
852
894
  async function At(o, s) {
853
- const t = ve("openai").default, n = (await new t({
895
+ const n = ke("openai").default, t = (await new n({
854
896
  apiKey: s.backends.openai?.apiKey || process.env.OPENAI_API_KEY,
855
897
  ...s.backends.openai?.baseUrl ? { baseURL: s.backends.openai.baseUrl } : {}
856
898
  }).images.generate({
@@ -859,13 +901,13 @@ async function At(o, s) {
859
901
  quality: "high",
860
902
  size: "1536x1024"
861
903
  })).data?.[0]?.b64_json;
862
- if (!n) throw new Error("No image data returned from OpenAI");
863
- return n;
904
+ if (!t) throw new Error("No image data returned from OpenAI");
905
+ return t;
864
906
  }
865
907
  async function It(o, s) {
866
- const { GoogleGenAI: t } = ve("@google/genai"), e = s.backends.google?.apiKey || process.env.GOOGLE_API_KEY;
908
+ const { GoogleGenAI: n } = ke("@google/genai"), e = s.backends.google?.apiKey || process.env.GOOGLE_API_KEY;
867
909
  if (!e) throw new Error("No Google API key configured");
868
- const a = (await new t({ apiKey: e }).models.generateContent({
910
+ const a = (await new n({ apiKey: e }).models.generateContent({
869
911
  model: "gemini-3.1-flash-image-preview",
870
912
  contents: o,
871
913
  config: {
@@ -878,23 +920,23 @@ async function It(o, s) {
878
920
  return i.inlineData.data;
879
921
  throw new Error("No image data in Gemini response");
880
922
  }
881
- async function ue(o, s, t) {
882
- const e = t ?? Et(s);
923
+ async function de(o, s, n) {
924
+ const e = n ?? $t(s);
883
925
  if (!e) throw new Error("No image-capable backend configured (need OpenAI or Google API key)");
884
- const r = St(o);
926
+ const r = Et(o);
885
927
  return e === "openai" ? At(r, s) : It(r, s);
886
928
  }
887
- const $t = /https?:\/\/[^\s)<>]+/g;
888
- function Ot(o) {
889
- const s = o.match($t);
929
+ const Ot = /https?:\/\/[^\s)<>]+/g;
930
+ function Pt(o) {
931
+ const s = o.match(Ot);
890
932
  return s ? [...new Set(s)] : [];
891
933
  }
892
- async function Pt(o, s) {
893
- const t = new AbortController(), e = setTimeout(() => t.abort(), 15e3);
894
- s && s.addEventListener("abort", () => t.abort(), { once: !0 });
934
+ async function Ct(o, s) {
935
+ const n = new AbortController(), e = setTimeout(() => n.abort(), 15e3);
936
+ s && s.addEventListener("abort", () => n.abort(), { once: !0 });
895
937
  try {
896
938
  const r = await fetch(o, {
897
- signal: t.signal,
939
+ signal: n.signal,
898
940
  headers: {
899
941
  "User-Agent": "Council/1.0 (AI Discussion Tool)",
900
942
  Accept: "text/html, application/json, text/plain, */*"
@@ -903,66 +945,66 @@ async function Pt(o, s) {
903
945
  });
904
946
  if (clearTimeout(e), !r.ok)
905
947
  return { url: o, content: `[Failed to fetch: HTTP ${r.status}]` };
906
- const n = r.headers.get("content-type") || "", a = await r.text();
907
- if (n.includes("application/json"))
948
+ const t = r.headers.get("content-type") || "", a = await r.text();
949
+ if (t.includes("application/json"))
908
950
  try {
909
- const c = JSON.stringify(JSON.parse(a), null, 2);
910
- return { url: o, content: c.slice(0, 8e3) };
951
+ const l = JSON.stringify(JSON.parse(a), null, 2);
952
+ return { url: o, content: l.slice(0, 8e3) };
911
953
  } catch {
912
954
  return { url: o, content: a.slice(0, 8e3) };
913
955
  }
914
- if (n.includes("text/plain") || n.includes("text/markdown"))
956
+ if (t.includes("text/plain") || t.includes("text/markdown"))
915
957
  return { url: o, content: a.slice(0, 8e3) };
916
- const { title: i, text: l } = Ct(a);
917
- return { url: o, title: i, content: l.slice(0, 8e3) };
958
+ const { title: i, text: c } = Nt(a);
959
+ return { url: o, title: i, content: c.slice(0, 8e3) };
918
960
  } catch (r) {
919
961
  clearTimeout(e);
920
- const n = r instanceof Error ? r.message : String(r);
921
- return n.includes("abort") ? { url: o, content: "[Fetch timed out]" } : { url: o, content: `[Failed to fetch: ${n}]` };
962
+ const t = r instanceof Error ? r.message : String(r);
963
+ return t.includes("abort") ? { url: o, content: "[Fetch timed out]" } : { url: o, content: `[Failed to fetch: ${t}]` };
922
964
  }
923
965
  }
924
- function Ct(o) {
925
- const s = o.match(/<title[^>]*>([\s\S]*?)<\/title>/i), t = s ? de(s[1].trim()) : "";
966
+ function Nt(o) {
967
+ const s = o.match(/<title[^>]*>([\s\S]*?)<\/title>/i), n = s ? me(s[1].trim()) : "";
926
968
  let e = o.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<nav[\s\S]*?<\/nav>/gi, "").replace(/<header[\s\S]*?<\/header>/gi, "").replace(/<footer[\s\S]*?<\/footer>/gi, "");
927
969
  return e = e.replace(/<\/(p|div|h[1-6]|li|tr|blockquote|section|article)>/gi, `
928
970
  `), e = e.replace(/<br\s*\/?>/gi, `
929
- `), e = e.replace(/<li[^>]*>/gi, "• "), e = e.replace(/<[^>]+>/g, " "), e = de(e), e = e.split(`
971
+ `), e = e.replace(/<li[^>]*>/gi, "• "), e = e.replace(/<[^>]+>/g, " "), e = me(e), e = e.split(`
930
972
  `).map((r) => r.replace(/\s+/g, " ").trim()).filter(Boolean).join(`
931
- `), { title: t, text: e };
973
+ `), { title: n, text: e };
932
974
  }
933
- function de(o) {
934
- return o.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/&#(\d+);/g, (s, t) => String.fromCharCode(Number(t))).replace(/&[a-zA-Z]+;/g, " ");
975
+ function me(o) {
976
+ return o.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/&#(\d+);/g, (s, n) => String.fromCharCode(Number(n))).replace(/&[a-zA-Z]+;/g, " ");
935
977
  }
936
- async function xt(o, s, t) {
937
- const e = Ot(o);
978
+ async function xt(o, s, n) {
979
+ const e = Pt(o);
938
980
  if (e.length === 0) return o;
939
981
  v.info("topic-enricher", `Found ${e.length} URL(s) in topic`, { urls: e });
940
982
  const r = await Promise.all(
941
- e.map((a) => Pt(a, s))
983
+ e.map((a) => Ct(a, s))
942
984
  );
943
- let n = o;
985
+ let t = o;
944
986
  for (const a of r) {
945
987
  const i = a.title ? `Resource: ${a.title} (${a.url})` : `Resource: ${a.url}`;
946
- n += `
988
+ t += `
947
989
 
948
990
  ---
949
991
  ${i}
950
992
  ${a.content}`;
951
993
  }
952
- return v.info("topic-enricher", `Enriched topic with ${r.length} resource(s)`), n;
994
+ return v.info("topic-enricher", `Enriched topic with ${r.length} resource(s)`), t;
953
995
  }
954
- const ke = {
996
+ const _e = {
955
997
  anthropic: "https://api.anthropic.com",
956
998
  openai: "https://api.openai.com/v1",
957
999
  google: "https://generativelanguage.googleapis.com",
958
1000
  ollama: "http://localhost:11434"
959
- }, me = [
1001
+ }, pe = [
960
1002
  "claude-opus-4-20250514",
961
1003
  "claude-sonnet-4-5-20250514",
962
1004
  "claude-sonnet-4-20250514",
963
1005
  "claude-haiku-4-20250414",
964
1006
  "claude-3-5-haiku-20241022"
965
- ], B = [
1007
+ ], G = [
966
1008
  "gemini-2.5-pro",
967
1009
  "gemini-2.5-flash",
968
1010
  "gemini-2.0-flash",
@@ -970,96 +1012,96 @@ const ke = {
970
1012
  "gemini-1.5-pro",
971
1013
  "gemini-1.5-flash"
972
1014
  ];
973
- async function Nt(o, s) {
1015
+ async function Tt(o, s) {
974
1016
  try {
975
1017
  switch (o) {
976
1018
  case "ollama": {
977
- const { Ollama: t } = await import("ollama");
978
- return { connected: !0, models: (await new t({ host: s.baseUrl || ke.ollama }).list()).models.map((a) => a.name).sort() };
1019
+ const { Ollama: n } = await import("ollama");
1020
+ return { connected: !0, models: (await new n({ host: s.baseUrl || _e.ollama }).list()).models.map((a) => a.name).sort() };
979
1021
  }
980
1022
  case "openai": {
981
- const { default: t } = await import("openai");
982
- return { connected: !0, models: (await new t({
1023
+ const { default: n } = await import("openai");
1024
+ return { connected: !0, models: (await new n({
983
1025
  apiKey: s.apiKey || process.env.OPENAI_API_KEY,
984
1026
  ...s.baseUrl ? { baseURL: s.baseUrl } : {}
985
1027
  }).models.list()).data.map((a) => a.id).filter((a) => a.startsWith("gpt-") || a.startsWith("o") || a.startsWith("chatgpt-")).sort() };
986
1028
  }
987
1029
  case "anthropic": {
988
- const { default: t } = await import("@anthropic-ai/sdk"), e = new t({
1030
+ const { default: n } = await import("@anthropic-ai/sdk"), e = new n({
989
1031
  apiKey: s.apiKey || process.env.ANTHROPIC_API_KEY,
990
1032
  ...s.baseUrl ? { baseURL: s.baseUrl } : {}
991
1033
  });
992
1034
  try {
993
1035
  return { connected: !0, models: (await e.models.list({ limit: 100 })).data.map((a) => a.id).sort() };
994
1036
  } catch {
995
- return { connected: !0, models: me };
1037
+ return { connected: !0, models: pe };
996
1038
  }
997
1039
  }
998
1040
  case "google": {
999
- const t = s.apiKey || process.env.GOOGLE_API_KEY || "";
1000
- if (!t) return { connected: !1, models: B, error: "No API key" };
1041
+ const n = s.apiKey || process.env.GOOGLE_API_KEY || "";
1042
+ if (!n) return { connected: !1, models: G, error: "No API key" };
1001
1043
  const e = await fetch(
1002
- `https://generativelanguage.googleapis.com/v1beta/models?key=${t}`
1044
+ `https://generativelanguage.googleapis.com/v1beta/models?key=${n}`
1003
1045
  );
1004
1046
  if (!e.ok) {
1005
1047
  const i = (await e.json().catch(() => ({})))?.error?.message || `HTTP ${e.status}`;
1006
- return { connected: !1, models: B, error: i };
1048
+ return { connected: !1, models: G, error: i };
1007
1049
  }
1008
- const n = ((await e.json()).models || []).filter((a) => a.name.includes("gemini") && a.supportedGenerationMethods?.includes("generateContent")).map((a) => a.name.replace("models/", "")).sort();
1009
- return { connected: !0, models: n.length > 0 ? n : B };
1050
+ const t = ((await e.json()).models || []).filter((a) => a.name.includes("gemini") && a.supportedGenerationMethods?.includes("generateContent")).map((a) => a.name.replace("models/", "")).sort();
1051
+ return { connected: !0, models: t.length > 0 ? t : G };
1010
1052
  }
1011
1053
  default:
1012
1054
  return { connected: !1, models: [], error: `Unknown backend: ${o}` };
1013
1055
  }
1014
- } catch (t) {
1015
- const e = t instanceof Error ? t.message : String(t);
1016
- return { connected: !1, models: o === "anthropic" ? me : o === "google" ? B : [], error: e };
1056
+ } catch (n) {
1057
+ const e = n instanceof Error ? n.message : String(n);
1058
+ return { connected: !1, models: o === "anthropic" ? pe : o === "google" ? G : [], error: e };
1017
1059
  }
1018
1060
  }
1019
- let S = null, G = [];
1061
+ let $ = null, F = [];
1020
1062
  function Rt(o, s) {
1021
1063
  o.handle("app:getCouncilDir", async () => {
1022
- const t = process.env.COUNCIL_CWD || process.cwd();
1023
- return F(t, "council");
1024
- }), o.handle("councilors:list", async (t, e) => {
1025
- const r = u(b(), ".ai-council", "config.json");
1026
- let n = { backends: {} };
1064
+ const n = process.env.COUNCIL_CWD || process.cwd();
1065
+ return W(n, "council");
1066
+ }), o.handle("councilors:list", async (n, e) => {
1067
+ const r = u(k(), ".ai-council", "config.json");
1068
+ let t = { backends: {} };
1027
1069
  try {
1028
- const c = await w(r, "utf-8");
1029
- n = JSON.parse(c);
1070
+ const l = await w(r, "utf-8");
1071
+ t = JSON.parse(l);
1030
1072
  } catch {
1031
1073
  }
1032
- const a = ae(n), i = n.councilors ?? {};
1033
- return (await re(e, a)).map((c) => {
1034
- const f = i[c.id];
1074
+ const a = ie(t), i = t.councilors ?? {};
1075
+ return (await se(e, a)).map((l) => {
1076
+ const m = i[l.id];
1035
1077
  return {
1036
- id: c.id,
1037
- dirPath: c.dirPath,
1038
- name: c.frontmatter.name,
1039
- description: c.frontmatter.description,
1040
- backend: c.frontmatter.backend,
1041
- model: c.frontmatter.model,
1042
- temperature: c.frontmatter.temperature,
1043
- interests: c.frontmatter.interests,
1044
- avatarUrl: c.avatarUrl,
1045
- source: f?.source,
1046
- registryUrl: f?.url
1078
+ id: l.id,
1079
+ dirPath: l.dirPath,
1080
+ name: l.frontmatter.name,
1081
+ description: l.frontmatter.description,
1082
+ backend: l.frontmatter.backend,
1083
+ model: l.frontmatter.model,
1084
+ temperature: l.frontmatter.temperature,
1085
+ interests: l.frontmatter.interests,
1086
+ avatarUrl: l.avatarUrl,
1087
+ source: m?.source,
1088
+ registryUrl: m?.url
1047
1089
  };
1048
1090
  });
1049
- }), o.handle("councilors:get", async (t, e) => {
1050
- const r = u(e, "ABOUT.md"), n = await w(r, "utf-8"), { data: a, content: i } = X(n);
1051
- return { frontmatter: a, body: i.trim(), raw: n };
1052
- }), o.handle("councilors:save", async (t, e, r) => {
1053
- const n = u(e, "ABOUT.md");
1054
- return await O(n, r, "utf-8"), { success: !0 };
1055
- }), o.handle("councilors:create", async (t, e, r, n) => {
1091
+ }), o.handle("councilors:get", async (n, e) => {
1092
+ const r = u(e, "ABOUT.md"), t = await w(r, "utf-8"), { data: a, content: i } = Z(t);
1093
+ return { frontmatter: a, body: i.trim(), raw: t };
1094
+ }), o.handle("councilors:save", async (n, e, r) => {
1095
+ const t = u(e, "ABOUT.md");
1096
+ return await C(t, r, "utf-8"), { success: !0 };
1097
+ }), o.handle("councilors:create", async (n, e, r, t) => {
1056
1098
  const a = u(e, r);
1057
- return await C(a, { recursive: !0 }), await O(u(a, "ABOUT.md"), n, "utf-8"), { success: !0, dirPath: a };
1058
- }), o.handle("councilors:delete", async (t, e) => (await M(e, { recursive: !0, force: !0 }), { success: !0 })), o.handle("config:get", async () => {
1059
- const t = u(b(), ".ai-council", "config.json");
1099
+ return await x(a, { recursive: !0 }), await C(u(a, "ABOUT.md"), t, "utf-8"), { success: !0, dirPath: a };
1100
+ }), o.handle("councilors:delete", async (n, e) => (await Y(e, { recursive: !0, force: !0 }), { success: !0 })), o.handle("config:get", async () => {
1101
+ const n = u(k(), ".ai-council", "config.json");
1060
1102
  let e = { backends: {} };
1061
1103
  try {
1062
- const i = await w(t, "utf-8");
1104
+ const i = await w(n, "utf-8");
1063
1105
  e = JSON.parse(i);
1064
1106
  } catch {
1065
1107
  }
@@ -1067,134 +1109,153 @@ function Rt(o, s) {
1067
1109
  ANTHROPIC_API_KEY: !!process.env.ANTHROPIC_API_KEY,
1068
1110
  OPENAI_API_KEY: !!process.env.OPENAI_API_KEY,
1069
1111
  GOOGLE_API_KEY: !!process.env.GOOGLE_API_KEY
1070
- }, n = (i) => i ? "..." + i.slice(-4) : void 0, a = {
1071
- ANTHROPIC_API_KEY: n(process.env.ANTHROPIC_API_KEY),
1072
- OPENAI_API_KEY: n(process.env.OPENAI_API_KEY),
1073
- GOOGLE_API_KEY: n(process.env.GOOGLE_API_KEY)
1112
+ }, t = (i) => i ? "..." + i.slice(-4) : void 0, a = {
1113
+ ANTHROPIC_API_KEY: t(process.env.ANTHROPIC_API_KEY),
1114
+ OPENAI_API_KEY: t(process.env.OPENAI_API_KEY),
1115
+ GOOGLE_API_KEY: t(process.env.GOOGLE_API_KEY)
1074
1116
  };
1075
- return { config: e, envStatus: r, envKeySuffix: a, defaultUrls: ke };
1076
- }), o.handle("backend:probe", async (t, e, r) => Nt(e, r)), o.handle("backend:models", async (t, e) => {
1117
+ return { config: e, envStatus: r, envKeySuffix: a, defaultUrls: _e };
1118
+ }), o.handle("backend:probe", async (n, e, r) => Tt(e, r)), o.handle("backend:models", async (n, e) => {
1077
1119
  try {
1078
- const { getBackend: r } = await Promise.resolve().then(() => nt), n = await r(e);
1079
- return n.listModels ? { models: await n.listModels() } : { models: [], error: "Not supported" };
1120
+ const { getBackend: r } = await Promise.resolve().then(() => nt), t = await r(e);
1121
+ return t.listModels ? { models: await t.listModels() } : { models: [], error: "Not supported" };
1080
1122
  } catch (r) {
1081
1123
  return { models: [], error: r instanceof Error ? r.message : String(r) };
1082
1124
  }
1083
- }), o.handle("config:save", async (t, e) => {
1084
- const r = u(b(), ".ai-council");
1085
- return await C(r, { recursive: !0 }), await O(u(r, "config.json"), JSON.stringify(e, null, 2), "utf-8"), we(), { success: !0 };
1086
- }), o.handle("discussion:start", async (t, e) => {
1125
+ }), o.handle("config:save", async (n, e) => {
1126
+ const r = u(k(), ".ai-council");
1127
+ return await x(r, { recursive: !0 }), await C(u(r, "config.json"), JSON.stringify(e, null, 2), "utf-8"), be(), { success: !0 };
1128
+ }), o.handle("discussion:start", async (n, e) => {
1087
1129
  const r = s();
1088
1130
  if (!r) return { error: "No window" };
1089
- const n = (a) => {
1131
+ const t = (a) => {
1090
1132
  r.isDestroyed() || r.webContents.send("discussion:event", a);
1091
1133
  };
1092
1134
  try {
1093
- S && S.abort(), S = new AbortController(), G = [], v.info("ipc:discussion", "Starting discussion", { councilDir: e.councilDir, councilorIds: e.councilorIds, rounds: e.rounds, mode: e.mode });
1094
- const a = u(b(), ".ai-council", "config.json");
1135
+ $ && $.abort(), $ = new AbortController(), F = [], v.info("ipc:discussion", "Starting discussion", { councilDir: e.councilDir, councilorIds: e.councilorIds, rounds: e.rounds, mode: e.mode });
1136
+ const a = u(k(), ".ai-council", "config.json");
1095
1137
  let i = { backends: {} };
1096
1138
  try {
1097
- const p = await w(a, "utf-8");
1098
- i = JSON.parse(p);
1139
+ const d = await w(a, "utf-8");
1140
+ i = JSON.parse(d);
1099
1141
  } catch {
1100
1142
  }
1101
- const l = ae(i);
1102
- v.info("ipc:discussion", `Loading councilors from ${e.councilDir} + ${l.length} registered paths`);
1103
- const c = await re(e.councilDir, l), f = e.councilorIds?.length ? c.filter((p) => e.councilorIds.includes(p.id)) : c;
1104
- if (v.info("ipc:discussion", `Resolved ${f.length} councilors: ${f.map((p) => p.id).join(", ")}`), f.length === 0) {
1105
- n({ type: "error", councilorName: "", error: "No councilors found" });
1143
+ const c = ie(i);
1144
+ v.info("ipc:discussion", `Loading councilors from ${e.councilDir} + ${c.length} registered paths`);
1145
+ const l = await se(e.councilDir, c), m = e.councilorIds?.length ? l.filter((d) => e.councilorIds.includes(d.id)) : l;
1146
+ if (v.info("ipc:discussion", `Resolved ${m.length} councilors: ${m.map((d) => d.id).join(", ")}`), m.length === 0) {
1147
+ t({ type: "error", councilorName: "", error: "No councilors found" });
1148
+ return;
1149
+ }
1150
+ t({ type: "preflight_start" });
1151
+ const h = await yt(m, (d) => {
1152
+ t({ type: "preflight_status", message: d });
1153
+ });
1154
+ if (h.invalid.length > 0)
1155
+ for (const d of h.invalid)
1156
+ v.warn("ipc:discussion", `Preflight failed for ${d.councilor.frontmatter.name}: ${d.issues.join("; ")}`), t({
1157
+ type: "preflight_fail",
1158
+ councilorName: d.councilor.frontmatter.name,
1159
+ councilorId: d.councilor.id,
1160
+ model: d.model,
1161
+ issues: d.issues
1162
+ });
1163
+ t({ type: "preflight_complete", valid: h.valid.length, invalid: h.invalid.length });
1164
+ const y = h.valid;
1165
+ if (y.length === 0) {
1166
+ t({ type: "error", councilorName: "", error: "No councilors passed pre-flight validation. Check backend API keys and model names." });
1106
1167
  return;
1107
1168
  }
1108
- const y = async () => G.length === 0 ? null : {
1169
+ const g = async () => F.length === 0 ? null : {
1109
1170
  round: 0,
1110
1171
  councilorId: "__user__",
1111
1172
  councilorName: "You",
1112
- content: G.shift(),
1173
+ content: F.shift(),
1113
1174
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1114
1175
  model: "human",
1115
1176
  backend: "human"
1116
- }, h = await xt(e.topic, S.signal), g = !!e.previousTurns?.length, L = {
1117
- topic: h,
1177
+ }, j = await xt(e.topic, $.signal), f = !!e.previousTurns?.length, _ = {
1178
+ topic: j,
1118
1179
  topicSource: e.topicSource,
1119
- councilors: f,
1180
+ councilors: y,
1120
1181
  rounds: e.rounds,
1121
- onEvent: n,
1122
- beforeTurn: y,
1123
- signal: S.signal,
1124
- mode: g ? "freeform" : e.mode,
1182
+ onEvent: t,
1183
+ beforeTurn: g,
1184
+ signal: $.signal,
1185
+ mode: f ? "freeform" : e.mode,
1125
1186
  config: i,
1126
1187
  previousTurns: e.previousTurns,
1127
1188
  previousSummary: e.previousSummary
1128
- }, d = await ht(L);
1189
+ }, p = await ht(_);
1129
1190
  if (i.secretary?.backend)
1130
1191
  try {
1131
- n({ type: "summary_start" });
1132
- const p = await at({
1133
- result: d,
1192
+ t({ type: "summary_start" });
1193
+ const d = await at({
1194
+ result: p,
1134
1195
  config: i,
1135
- onChunk: (m) => {
1136
- n({ type: "summary_chunk", delta: m });
1196
+ onChunk: (b) => {
1197
+ t({ type: "summary_chunk", delta: b });
1137
1198
  },
1138
- signal: S?.signal
1199
+ signal: $?.signal
1139
1200
  });
1140
- d.summary = p.text, p.diagram && (d.diagram = p.diagram), n({ type: "summary_complete", summary: p.text, diagram: p.diagram });
1141
- } catch (p) {
1142
- v.error("ipc:discussion", "Secretary summary failed", p), n({ type: "error", councilorName: "Secretary", error: p instanceof Error ? p.message : String(p) });
1201
+ p.summary = d.text, d.diagram && (p.diagram = d.diagram), t({ type: "summary_complete", summary: d.text, diagram: d.diagram });
1202
+ } catch (d) {
1203
+ v.error("ipc:discussion", "Secretary summary failed", d), t({ type: "error", councilorName: "Secretary", error: d instanceof Error ? d.message : String(d) });
1143
1204
  }
1144
1205
  if (i.secretary?.backend)
1145
1206
  try {
1146
- const p = d.turns.filter((x) => x.round === 1), m = await lt({
1147
- topic: d.topic,
1148
- firstRoundTurns: p,
1207
+ const d = p.turns.filter((B) => B.round === 1), b = await lt({
1208
+ topic: p.topic,
1209
+ firstRoundTurns: d,
1149
1210
  config: i
1150
1211
  });
1151
- d.title = m, n({ type: "title_generated", title: m });
1152
- } catch (p) {
1153
- v.error("ipc:discussion", "Title generation failed", p);
1212
+ p.title = b, t({ type: "title_generated", title: b });
1213
+ } catch (d) {
1214
+ v.error("ipc:discussion", "Title generation failed", d);
1154
1215
  }
1155
1216
  if (e.infographicBackends?.length)
1156
- for (const p of e.infographicBackends)
1217
+ for (const d of e.infographicBackends)
1157
1218
  try {
1158
- n({ type: "infographic_start" });
1159
- const m = await ue(d, i, p);
1160
- d.infographics || (d.infographics = []), d.infographics.push(m), n({ type: "infographic_complete", infographic: m });
1161
- } catch (m) {
1162
- v.error("ipc:discussion", `Infographic generation failed (${p})`, m), n({ type: "infographic_error", error: m instanceof Error ? m.message : String(m) });
1219
+ t({ type: "infographic_start" });
1220
+ const b = await de(p, i, d);
1221
+ p.infographics || (p.infographics = []), p.infographics.push(b), t({ type: "infographic_complete", infographic: b });
1222
+ } catch (b) {
1223
+ v.error("ipc:discussion", `Infographic generation failed (${d})`, b), t({ type: "infographic_error", error: b instanceof Error ? b.message : String(b) });
1163
1224
  }
1164
- e.continuedFrom && (d.continuedFrom = e.continuedFrom), n({ type: "complete", result: d });
1225
+ e.continuedFrom && (p.continuedFrom = e.continuedFrom), t({ type: "complete", result: p });
1165
1226
  try {
1166
- await wt(d);
1167
- } catch (p) {
1168
- v.error("ipc:discussion", "Failed to save to history", p);
1227
+ await bt(p);
1228
+ } catch (d) {
1229
+ v.error("ipc:discussion", "Failed to save to history", d);
1169
1230
  }
1170
1231
  } catch (a) {
1171
- v.error("ipc:discussion", "Discussion failed", a), n({ type: "error", councilorName: "", error: a instanceof Error ? a.message : String(a) });
1232
+ v.error("ipc:discussion", "Discussion failed", a), t({ type: "error", councilorName: "", error: a instanceof Error ? a.message : String(a) });
1172
1233
  } finally {
1173
- S = null;
1234
+ $ = null;
1174
1235
  }
1175
- }), o.handle("discussion:stop", async () => (S && (S.abort(), S = null), { success: !0 })), o.handle("discussion:inject", async (t, e) => (G.push(e), { success: !0 })), o.handle("registry:add-local", async (t, e) => ze(e)), o.handle("registry:add-remote", async (t, e) => Ve(e)), o.handle("registry:remove", async (t, e, r) => (await Xe(e, r), { success: !0 })), o.handle("shell:open-in-finder", async (t, e) => {
1176
- te.showItemInFolder(u(e, "ABOUT.md"));
1177
- }), o.handle("shell:open-in-terminal", async (t, e) => {
1178
- await T(R)("open", ["-a", "Terminal", e]);
1179
- }), o.handle("shell:open-in-editor", async (t, e) => {
1180
- const r = T(R);
1236
+ }), o.handle("discussion:stop", async () => ($ && ($.abort(), $ = null), { success: !0 })), o.handle("discussion:inject", async (n, e) => (F.push(e), { success: !0 })), o.handle("registry:add-local", async (n, e) => ze(e)), o.handle("registry:add-remote", async (n, e) => Ve(e)), o.handle("registry:remove", async (n, e, r) => (await Xe(e, r), { success: !0 })), o.handle("shell:open-in-finder", async (n, e) => {
1237
+ ne.showItemInFolder(u(e, "ABOUT.md"));
1238
+ }), o.handle("shell:open-in-terminal", async (n, e) => {
1239
+ await U(R)("open", ["-a", "Terminal", e]);
1240
+ }), o.handle("shell:open-in-editor", async (n, e) => {
1241
+ const r = U(R);
1181
1242
  try {
1182
1243
  await r("code", [e]);
1183
1244
  } catch {
1184
- te.openPath(e);
1245
+ ne.openPath(e);
1185
1246
  }
1186
- }), o.handle("history:list", async () => bt()), o.handle("history:get", async (t, e) => le(e)), o.handle("history:delete", async (t, e) => (await vt(e), { success: !0 })), o.handle("infographic:generate", async (t, e, r) => {
1187
- const n = u(b(), ".ai-council", "config.json");
1247
+ }), o.handle("history:list", async () => vt()), o.handle("history:get", async (n, e) => ue(e)), o.handle("history:delete", async (n, e) => (await kt(e), { success: !0 })), o.handle("infographic:generate", async (n, e, r) => {
1248
+ const t = u(k(), ".ai-council", "config.json");
1188
1249
  let a = { backends: {} };
1189
1250
  try {
1190
- const c = await w(n, "utf-8");
1191
- a = JSON.parse(c);
1251
+ const l = await w(t, "utf-8");
1252
+ a = JSON.parse(l);
1192
1253
  } catch {
1193
1254
  }
1194
- const i = await le(e), l = await ue(i, a, r);
1195
- return await kt(e, l), { infographic: l };
1196
- }), o.handle("infographic:delete", async (t, e, r) => (await _t(e, r), { success: !0 })), o.handle("file:read-as-text", async (t, e) => {
1197
- const r = P(e), n = r.includes(".") ? "." + r.split(".").pop().toLowerCase() : "", a = /* @__PURE__ */ new Set([
1255
+ const i = await ue(e), c = await de(i, a, r);
1256
+ return await _t(e, c), { infographic: c };
1257
+ }), o.handle("infographic:delete", async (n, e, r) => (await St(e, r), { success: !0 })), o.handle("file:read-as-text", async (n, e) => {
1258
+ const r = N(e), t = r.includes(".") ? "." + r.split(".").pop().toLowerCase() : "", a = /* @__PURE__ */ new Set([
1198
1259
  ".txt",
1199
1260
  ".md",
1200
1261
  ".csv",
@@ -1242,43 +1303,43 @@ function Rt(o, s) {
1242
1303
  ".epub",
1243
1304
  ".rtf"
1244
1305
  ]);
1245
- if (a.has(n))
1306
+ if (a.has(t))
1246
1307
  try {
1247
- const l = await w(e, "utf-8");
1248
- return { name: r, content: l };
1249
- } catch (l) {
1250
- return { name: r, content: `[Error reading file: ${l instanceof Error ? l.message : String(l)}]` };
1308
+ const c = await w(e, "utf-8");
1309
+ return { name: r, content: c };
1310
+ } catch (c) {
1311
+ return { name: r, content: `[Error reading file: ${c instanceof Error ? c.message : String(c)}]` };
1251
1312
  }
1252
- if (i.has(n)) {
1253
- const l = T(R);
1313
+ if (i.has(t)) {
1314
+ const c = U(R);
1254
1315
  try {
1255
- const { stdout: c } = await l("markitdown", [e], {
1316
+ const { stdout: l } = await c("markitdown", [e], {
1256
1317
  timeout: 3e4,
1257
1318
  maxBuffer: 10485760
1258
1319
  // 10 MB
1259
1320
  });
1260
- return { name: r, content: c };
1261
- } catch (c) {
1262
- const f = c instanceof Error ? c.message : String(c);
1263
- return f.includes("ENOENT") ? {
1321
+ return { name: r, content: l };
1322
+ } catch (l) {
1323
+ const m = l instanceof Error ? l.message : String(l);
1324
+ return m.includes("ENOENT") ? {
1264
1325
  name: r,
1265
- content: `[Cannot convert ${n} file: markitdown is not installed. Run: pip install 'markitdown[all]']`
1266
- } : { name: r, content: `[Error converting file: ${f}]` };
1326
+ content: `[Cannot convert ${t} file: markitdown is not installed. Run: pip install 'markitdown[all]']`
1327
+ } : { name: r, content: `[Error converting file: ${m}]` };
1267
1328
  }
1268
1329
  }
1269
1330
  return { name: r, content: `[Unsupported file type: ${r}]` };
1270
1331
  }), o.handle("markitdown:check", async () => {
1271
- const t = T(R);
1332
+ const n = U(R);
1272
1333
  try {
1273
- const { stdout: e } = await t("markitdown", ["--version"], { timeout: 5e3 });
1334
+ const { stdout: e } = await n("markitdown", ["--version"], { timeout: 5e3 });
1274
1335
  return { installed: !0, version: e.trim() };
1275
1336
  } catch {
1276
1337
  return { installed: !1 };
1277
1338
  }
1278
1339
  }), o.handle("markitdown:install", async () => {
1279
- const t = T(R);
1340
+ const n = U(R);
1280
1341
  try {
1281
- return await t("pip", ["install", "markitdown[all]"], {
1342
+ return await n("pip", ["install", "markitdown[all]"], {
1282
1343
  timeout: 12e4,
1283
1344
  maxBuffer: 10 * 1024 * 1024
1284
1345
  }), { success: !0 };
@@ -1286,63 +1347,63 @@ function Rt(o, s) {
1286
1347
  return { success: !1, error: e instanceof Error ? e.message : String(e) };
1287
1348
  }
1288
1349
  }), o.handle("dialog:selectDirectory", async () => {
1289
- const t = s();
1290
- if (!t) return null;
1291
- const e = await Ae.showOpenDialog(t, {
1350
+ const n = s();
1351
+ if (!n) return null;
1352
+ const e = await $e.showOpenDialog(n, {
1292
1353
  properties: ["openDirectory"]
1293
1354
  });
1294
1355
  return e.canceled ? null : e.filePaths[0];
1295
1356
  });
1296
1357
  }
1297
- const Tt = Pe(import.meta.url), J = Oe(Tt), _e = u(b(), ".ai-council");
1298
- xe(_e, { recursive: !0 });
1299
- const Se = u(_e, "electron-debug.log");
1300
- function $(o, ...s) {
1301
- const t = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${o}] ${s.map((e) => typeof e == "string" ? e : JSON.stringify(e)).join(" ")}
1358
+ const Ut = Pe(import.meta.url), V = Oe(Ut), Se = u(k(), ".ai-council");
1359
+ Ne(Se, { recursive: !0 });
1360
+ const Ee = u(Se, "electron-debug.log");
1361
+ function P(o, ...s) {
1362
+ const n = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${o}] ${s.map((e) => typeof e == "string" ? e : JSON.stringify(e)).join(" ")}
1302
1363
  `;
1303
- Re(Se, t);
1364
+ Te(Ee, n);
1304
1365
  }
1305
- Ne(Se, `=== State Change Council Electron — started ${(/* @__PURE__ */ new Date()).toISOString()} ===
1366
+ xe(Ee, `=== State Change Council Electron — started ${(/* @__PURE__ */ new Date()).toISOString()} ===
1306
1367
  `);
1307
- D.name = "State Change Council";
1308
- let E = null;
1309
- function pe() {
1310
- $("main", "Creating BrowserWindow"), E = new ge({
1368
+ K.name = "State Change Council";
1369
+ let A = null;
1370
+ function fe() {
1371
+ P("main", "Creating BrowserWindow"), A = new he({
1311
1372
  width: 1200,
1312
1373
  height: 800,
1313
1374
  minWidth: 800,
1314
1375
  minHeight: 600,
1315
1376
  title: "State Change Council",
1316
- icon: F(J, "..", "assets", "icon.png"),
1377
+ icon: W(V, "..", "assets", "icon.png"),
1317
1378
  webPreferences: {
1318
1379
  contextIsolation: !0,
1319
1380
  nodeIntegration: !1,
1320
- preload: u(J, "preload.mjs")
1381
+ preload: u(V, "preload.mjs")
1321
1382
  }
1322
- }), E.webContents.on("console-message", (s, t, e, r, n) => {
1323
- const a = ["DEBUG", "INFO", "WARN", "ERROR"][t] || "LOG";
1324
- $(`renderer:${a}`, `${e} (${n}:${r})`);
1325
- }), E.webContents.on("render-process-gone", (s, t) => {
1326
- $("main:CRASH", "Renderer process gone:", t);
1327
- }), E.webContents.on("did-fail-load", (s, t, e) => {
1328
- $("main:LOAD_ERROR", `Failed to load: ${t} ${e}`);
1383
+ }), A.webContents.on("console-message", (s, n, e, r, t) => {
1384
+ const a = ["DEBUG", "INFO", "WARN", "ERROR"][n] || "LOG";
1385
+ P(`renderer:${a}`, `${e} (${t}:${r})`);
1386
+ }), A.webContents.on("render-process-gone", (s, n) => {
1387
+ P("main:CRASH", "Renderer process gone:", n);
1388
+ }), A.webContents.on("did-fail-load", (s, n, e) => {
1389
+ P("main:LOAD_ERROR", `Failed to load: ${n} ${e}`);
1329
1390
  });
1330
1391
  const o = process.env.VITE_DEV_SERVER_URL;
1331
1392
  if (o)
1332
- $("main", `Loading dev server URL: ${o}`), E.loadURL(o);
1393
+ P("main", `Loading dev server URL: ${o}`), A.loadURL(o);
1333
1394
  else {
1334
- const s = u(J, "../dist-renderer/index.html");
1335
- $("main", `Loading file: ${s}`), E.loadFile(s);
1395
+ const s = u(V, "../dist-renderer/index.html");
1396
+ P("main", `Loading file: ${s}`), A.loadFile(s);
1336
1397
  }
1337
- process.env.VITE_DEV_SERVER_URL && E.webContents.openDevTools(), E.on("closed", () => {
1338
- E = null;
1398
+ process.env.VITE_DEV_SERVER_URL && A.webContents.openDevTools(), A.on("closed", () => {
1399
+ A = null;
1339
1400
  });
1340
1401
  }
1341
- fe.registerSchemesAsPrivileged([
1402
+ ge.registerSchemesAsPrivileged([
1342
1403
  { scheme: "council-file", privileges: { bypassCSP: !0, supportFetchAPI: !0 } }
1343
1404
  ]);
1344
- D.whenReady().then(() => {
1345
- $("main", "App ready, registering IPC handlers");
1405
+ K.whenReady().then(() => {
1406
+ P("main", "App ready, registering IPC handlers");
1346
1407
  const o = "State Change Council", s = [
1347
1408
  {
1348
1409
  label: o,
@@ -1363,13 +1424,13 @@ D.whenReady().then(() => {
1363
1424
  { role: "viewMenu" },
1364
1425
  { role: "windowMenu" }
1365
1426
  ];
1366
- ne.setApplicationMenu(ne.buildFromTemplate(s)), fe.handle("council-file", (t) => {
1367
- const e = decodeURIComponent(t.url.replace("council-file://", ""));
1368
- return Ie.fetch(Ce(e).href);
1369
- }), Rt($e, () => E), pe(), D.on("activate", () => {
1370
- ge.getAllWindows().length === 0 && pe();
1427
+ oe.setApplicationMenu(oe.buildFromTemplate(s)), ge.handle("council-file", (n) => {
1428
+ const e = decodeURIComponent(n.url.replace("council-file://", ""));
1429
+ return Ae.fetch(Ce(e).href);
1430
+ }), Rt(Ie, () => A), fe(), K.on("activate", () => {
1431
+ he.getAllWindows().length === 0 && fe();
1371
1432
  });
1372
1433
  });
1373
- D.on("window-all-closed", () => {
1374
- process.platform !== "darwin" && D.quit();
1434
+ K.on("window-all-closed", () => {
1435
+ process.platform !== "darwin" && K.quit();
1375
1436
  });