@statechange/council 0.7.0 → 0.9.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.
- package/dist/commands/discuss.js +4 -0
- package/dist/commands/discuss.js.map +1 -1
- package/dist/core/infographic.js +2 -2
- package/dist/core/infographic.js.map +1 -1
- package/dist/core/topic-enricher.d.ts +9 -0
- package/dist/core/topic-enricher.js +129 -0
- package/dist/core/topic-enricher.js.map +1 -0
- package/dist/electron/ipc-handlers.js +4 -1
- package/dist/electron/ipc-handlers.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist-electron/main.js +565 -498
- package/dist-renderer/assets/{ar-SA-G6X2FPQ2-BgPx2ItE.js → ar-SA-G6X2FPQ2-DJTj94ZY.js} +1 -1
- package/dist-renderer/assets/{arc-uuSymAy6.js → arc-3qXpUeCd.js} +1 -1
- package/dist-renderer/assets/{az-AZ-76LH7QW2-CXxeQJ5N.js → az-AZ-76LH7QW2-1qnzBARG.js} +1 -1
- package/dist-renderer/assets/{bg-BG-XCXSNQG7-B-v6aJJk.js → bg-BG-XCXSNQG7-BIZ5IFAv.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-38ab4fdb-B2x5B_qZ.js → blockDiagram-38ab4fdb-JwSYiuLB.js} +1 -1
- package/dist-renderer/assets/{bn-BD-2XOGV67Q-CmhmKt_C.js → bn-BD-2XOGV67Q-DiYpgYAg.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-3d4e48cf-qv_cNClp.js → c4Diagram-3d4e48cf-DUCtOTzV.js} +1 -1
- package/dist-renderer/assets/{ca-ES-6MX7JW3Y-Cnypgm9v.js → ca-ES-6MX7JW3Y-CV2JFVcm.js} +1 -1
- package/dist-renderer/assets/channel-BFQOS5-A.js +1 -0
- package/dist-renderer/assets/{classDiagram-70f12bd4-DdjxeBAm.js → classDiagram-70f12bd4-DY_je9I9.js} +1 -1
- package/dist-renderer/assets/{classDiagram-v2-f2320105-DjGhSmzz.js → classDiagram-v2-f2320105-Dm2xf0kS.js} +1 -1
- package/dist-renderer/assets/clone-BdgQjyvt.js +1 -0
- package/dist-renderer/assets/{createText-2e5e7dd3-DPeQ2O5Z.js → createText-2e5e7dd3-BU4YlynJ.js} +1 -1
- package/dist-renderer/assets/{cs-CZ-2BRQDIVT-CLjGATXX.js → cs-CZ-2BRQDIVT-DgefxJv2.js} +1 -1
- package/dist-renderer/assets/{da-DK-5WZEPLOC-D5L0qoxT.js → da-DK-5WZEPLOC-CQeMoU_Y.js} +1 -1
- package/dist-renderer/assets/{de-DE-XR44H4JA-C32FRrv8.js → de-DE-XR44H4JA-Cm7XiExL.js} +1 -1
- package/dist-renderer/assets/{edges-e0da2a9e-C9UtuZtL.js → edges-e0da2a9e-DU4SF3SK.js} +1 -1
- package/dist-renderer/assets/{el-GR-BZB4AONW-DbhHCmA8.js → el-GR-BZB4AONW-BKDtOlnf.js} +1 -1
- package/dist-renderer/assets/{erDiagram-9861fffd-BkLC6VUM.js → erDiagram-9861fffd-D_cCijmv.js} +1 -1
- package/dist-renderer/assets/{es-ES-U4NZUMDT-DXQY7ys3.js → es-ES-U4NZUMDT-Blb_L7K-.js} +1 -1
- package/dist-renderer/assets/{eu-ES-A7QVB2H4-B4VgVqIF.js → eu-ES-A7QVB2H4-BZJBLMeO.js} +1 -1
- package/dist-renderer/assets/{fa-IR-HGAKTJCU-elHgBamS.js → fa-IR-HGAKTJCU-C8gu07sI.js} +1 -1
- package/dist-renderer/assets/{fi-FI-Z5N7JZ37-BQe_Oc8x.js → fi-FI-Z5N7JZ37-0j8c6s09.js} +1 -1
- package/dist-renderer/assets/{flowDb-956e92f1-DR2fF74n.js → flowDb-956e92f1-BYeD7SW0.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-66a62f08-wDDwHPpp.js → flowDiagram-66a62f08-D_7wXttk.js} +1 -1
- package/dist-renderer/assets/flowDiagram-v2-96b9c2cf-ue4yLZei.js +1 -0
- package/dist-renderer/assets/{flowchart-elk-definition-4a651766-m7cC1ndJ.js → flowchart-elk-definition-4a651766-G1tSg-iY.js} +1 -1
- package/dist-renderer/assets/{fr-FR-RHASNOE6-U8yDW4RB.js → fr-FR-RHASNOE6-_cfaQNNq.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-c361ad54-SpXIeRET.js → ganttDiagram-c361ad54-Dk5lBh7P.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-72cf32ee-CqmKGlMY.js → gitGraphDiagram-72cf32ee-BzJAQtIC.js} +1 -1
- package/dist-renderer/assets/{gl-ES-HMX3MZ6V-ti0GznU7.js → gl-ES-HMX3MZ6V-GM5nrSrW.js} +1 -1
- package/dist-renderer/assets/{graph-KjGTQ8qd.js → graph-C_xi4PaI.js} +1 -1
- package/dist-renderer/assets/{he-IL-6SHJWFNN-M5av5hFk.js → he-IL-6SHJWFNN-DvBtF7-G.js} +1 -1
- package/dist-renderer/assets/{hi-IN-IWLTKZ5I-Ci72nkHu.js → hi-IN-IWLTKZ5I-CNEB0-5K.js} +1 -1
- package/dist-renderer/assets/{hu-HU-A5ZG7DT2-CJZteS36.js → hu-HU-A5ZG7DT2-BmzYfJwp.js} +1 -1
- package/dist-renderer/assets/{id-ID-SAP4L64H-DmDvIS5c.js → id-ID-SAP4L64H-CGCjaOLU.js} +1 -1
- package/dist-renderer/assets/{index-3862675e-CCE1hBgs.js → index-3862675e-C8a4355J.js} +1 -1
- package/dist-renderer/assets/index-CYsh274_.css +1 -0
- package/dist-renderer/assets/index-Cc7m7vZn.js +51 -0
- package/dist-renderer/assets/{index-CsJIZuMr.js → index-x_yLI1Xq.js} +4 -4
- package/dist-renderer/assets/{infoDiagram-f8f76790-CcZfsGA-.js → infoDiagram-f8f76790-BsJdteru.js} +1 -1
- package/dist-renderer/assets/{it-IT-JPQ66NNP-Bzpfv7zO.js → it-IT-JPQ66NNP-vK6cBs4I.js} +1 -1
- package/dist-renderer/assets/{ja-JP-DBVTYXUO-Bybhg0KI.js → ja-JP-DBVTYXUO-oUvELdsq.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-49397b02-D5LB2Wfi.js → journeyDiagram-49397b02-BZcn-joQ.js} +1 -1
- package/dist-renderer/assets/{kaa-6HZHGXH3-n7D3u8lS.js → kaa-6HZHGXH3-39-zh5xR.js} +1 -1
- package/dist-renderer/assets/{kab-KAB-ZGHBKWFO-BsHCeWxt.js → kab-KAB-ZGHBKWFO-DIwwJSlv.js} +1 -1
- package/dist-renderer/assets/{kk-KZ-P5N5QNE5-Dvo1EL3s.js → kk-KZ-P5N5QNE5-jEG0G6v4.js} +1 -1
- package/dist-renderer/assets/{km-KH-HSX4SM5Z-Bo9Koyui.js → km-KH-HSX4SM5Z-f0MtADYu.js} +1 -1
- package/dist-renderer/assets/{ko-KR-MTYHY66A-Dqbq9Ios.js → ko-KR-MTYHY66A-D0sjNbcb.js} +1 -1
- package/dist-renderer/assets/{ku-TR-6OUDTVRD-B_bI20Zq.js → ku-TR-6OUDTVRD-D_uqAOZU.js} +1 -1
- package/dist-renderer/assets/{layout-BMJBnVbc.js → layout-Bho0HnCB.js} +1 -1
- package/dist-renderer/assets/{line-DYvIrKnf.js → line-BvfrpBJA.js} +1 -1
- package/dist-renderer/assets/{linear-CzUW4n8y.js → linear-CzjqC3F_.js} +1 -1
- package/dist-renderer/assets/{lt-LT-XHIRWOB4-DMcSSx20.js → lt-LT-XHIRWOB4-Ct0yC4CT.js} +1 -1
- package/dist-renderer/assets/{lv-LV-5QDEKY6T-WQFa3Exi.js → lv-LV-5QDEKY6T-nkNbPHg0.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-fc14e90a-CbbLnbfT.js → mindmap-definition-fc14e90a-BHot8rEp.js} +1 -1
- package/dist-renderer/assets/{mr-IN-CRQNXWMA-CeiPk7t6.js → mr-IN-CRQNXWMA-B861rik7.js} +1 -1
- package/dist-renderer/assets/{my-MM-5M5IBNSE-9E7W6sP8.js → my-MM-5M5IBNSE-SOXg7PeE.js} +1 -1
- package/dist-renderer/assets/{nb-NO-T6EIAALU-CmEniZIK.js → nb-NO-T6EIAALU-D22gGzt7.js} +1 -1
- package/dist-renderer/assets/{nl-NL-IS3SIHDZ-zXTYcbKu.js → nl-NL-IS3SIHDZ-CJxOBLb1.js} +1 -1
- package/dist-renderer/assets/{nn-NO-6E72VCQL-h3sqNMWN.js → nn-NO-6E72VCQL-FGcbdlO3.js} +1 -1
- package/dist-renderer/assets/{oc-FR-POXYY2M6-DJ0D2dhd.js → oc-FR-POXYY2M6-s7Swo1Cu.js} +1 -1
- package/dist-renderer/assets/{pa-IN-N4M65BXN-DZ6nLqLL.js → pa-IN-N4M65BXN-DFJMREPh.js} +1 -1
- package/dist-renderer/assets/{percentages-BXMCSKIN-C_WTAk1u.js → percentages-BXMCSKIN-BhceqxTM.js} +7 -7
- package/dist-renderer/assets/{pica-41wOwwIp.js → pica-ej4Z4fjh.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-8a3498a8-DbqgEWOz.js → pieDiagram-8a3498a8-CnDnQfd0.js} +1 -1
- package/dist-renderer/assets/{pl-PL-T2D74RX3-TTq9_VVs.js → pl-PL-T2D74RX3-uXVmB6im.js} +1 -1
- package/dist-renderer/assets/{pt-BR-5N22H2LF-D8eWF-rx.js → pt-BR-5N22H2LF-8kdgECeZ.js} +1 -1
- package/dist-renderer/assets/{pt-PT-UZXXM6DQ-Ck4YSJms.js → pt-PT-UZXXM6DQ-D4vr9vo6.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-120e2f19-astysE66.js → quadrantDiagram-120e2f19-DlUESmO2.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-deff3bca-BczvOV-q.js → requirementDiagram-deff3bca-CfOs9jR8.js} +1 -1
- package/dist-renderer/assets/{ro-RO-JPDTUUEW-Cix9Zgf2.js → ro-RO-JPDTUUEW-CztO0tWv.js} +1 -1
- package/dist-renderer/assets/{ru-RU-B4JR7IUQ-DOEAc_qv.js → ru-RU-B4JR7IUQ-aVURliDr.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-04a897e0-BdKNjOGj.js → sankeyDiagram-04a897e0-DRRc8FSN.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-704730f1-DmhSJhf3.js → sequenceDiagram-704730f1-BaswaqQO.js} +1 -1
- package/dist-renderer/assets/{si-LK-N5RQ5JYF-CdpuKOSp.js → si-LK-N5RQ5JYF-B2KWtx6N.js} +1 -1
- package/dist-renderer/assets/{sk-SK-C5VTKIMK-B_9Y1a-J.js → sk-SK-C5VTKIMK-DlRzLxRJ.js} +1 -1
- package/dist-renderer/assets/{sl-SI-NN7IZMDC-6_HfcMn2.js → sl-SI-NN7IZMDC-Ox8yiRTS.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-587899a1--iD3nJ-S.js → stateDiagram-587899a1-DSEEonbL.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-d93cdb3a-D_ikJOMZ.js → stateDiagram-v2-d93cdb3a-C135NgbB.js} +1 -1
- package/dist-renderer/assets/{styles-6aaf32cf-CmNrPQpM.js → styles-6aaf32cf-X5nh1pD3.js} +1 -1
- package/dist-renderer/assets/{styles-9a916d00-DF6mmpc8.js → styles-9a916d00-BCZu272E.js} +1 -1
- package/dist-renderer/assets/{styles-c10674c1-DrNd7u60.js → styles-c10674c1-C5JGHSaS.js} +1 -1
- package/dist-renderer/assets/{subset-shared.chunk-DESKTf4i.js → subset-shared.chunk-CzgdV5hf.js} +1 -1
- package/dist-renderer/assets/{subset-worker.chunk-foHYh0Wd.js → subset-worker.chunk-DfLYxc1O.js} +1 -1
- package/dist-renderer/assets/{sv-SE-XGPEYMSR-CIuCW4P8.js → sv-SE-XGPEYMSR-CizFbLCT.js} +1 -1
- package/dist-renderer/assets/{svgDrawCommon-08f97a94-z7vJpB0X.js → svgDrawCommon-08f97a94-Cv5ZIzzk.js} +1 -1
- package/dist-renderer/assets/{ta-IN-2NMHFXQM-BzAn6f_T.js → ta-IN-2NMHFXQM-B66K2LEN.js} +1 -1
- package/dist-renderer/assets/{th-TH-HPSO5L25-F8UKokOj.js → th-TH-HPSO5L25-DvHt1SBY.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-85554ec2-CqgD9A1Q.js → timeline-definition-85554ec2-C955-u4m.js} +1 -1
- package/dist-renderer/assets/{tr-TR-DEFEU3FU-Blb21beE.js → tr-TR-DEFEU3FU-u0AuqRoD.js} +1 -1
- package/dist-renderer/assets/{uk-UA-QMV73CPH-BNT7k4n6.js → uk-UA-QMV73CPH-IwAiPvJL.js} +1 -1
- package/dist-renderer/assets/{vi-VN-M7AON7JQ-Cfx0gaLT.js → vi-VN-M7AON7JQ-Dh6Aj3f5.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-e933f94c-FbPSsBHD.js → xychartDiagram-e933f94c-Bst4jMma.js} +1 -1
- package/dist-renderer/assets/{zh-CN-LNUGB5OW-CpiybZS1.js → zh-CN-LNUGB5OW-BVXMa9T3.js} +1 -1
- package/dist-renderer/assets/{zh-HK-E62DVLB3-UIQkTr8J.js → zh-HK-E62DVLB3-DYEIu92z.js} +1 -1
- package/dist-renderer/assets/{zh-TW-RAJ6MFWO-GvyNND72.js → zh-TW-RAJ6MFWO-Dm9oSthu.js} +1 -1
- package/dist-renderer/index.html +2 -2
- package/package.json +1 -1
- package/skills/council-create-councilor/SKILL.md +191 -0
- package/skills/council-discuss-idea/SKILL.md +132 -0
- package/skills/council-install-councilor/SKILL.md +122 -0
- package/dist-renderer/assets/channel-CbR4ut5U.js +0 -1
- package/dist-renderer/assets/clone-CdbunAYL.js +0 -1
- package/dist-renderer/assets/flowDiagram-v2-96b9c2cf-DYxWopzM.js +0 -1
- package/dist-renderer/assets/index-BUIE-P96.js +0 -51
- package/dist-renderer/assets/index-HXjW9ZG3.css +0 -1
package/dist-electron/main.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { shell as te, dialog as Ee, app as
|
|
2
|
-
import { join as
|
|
3
|
-
import { fileURLToPath as Oe, pathToFileURL as
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { homedir as
|
|
6
|
-
import { readFile as w, readdir as V, stat as
|
|
1
|
+
import { shell as te, dialog as Ee, app as D, protocol as fe, Menu as ne, net as Ae, BrowserWindow as he, ipcMain as Ie } from "electron";
|
|
2
|
+
import { join as u, basename as P, resolve as F, dirname as $e } from "node:path";
|
|
3
|
+
import { fileURLToPath as Oe, pathToFileURL as Pe } from "node:url";
|
|
4
|
+
import { existsSync as _, mkdirSync as Ce, writeFileSync as xe, appendFileSync as Ne } from "node:fs";
|
|
5
|
+
import { homedir as b } from "node:os";
|
|
6
|
+
import { readFile as w, readdir as V, stat as ge, mkdir as C, rm as G, writeFile as O, appendFile as Re } from "node:fs/promises";
|
|
7
7
|
import { execFile as R } from "node:child_process";
|
|
8
|
-
import { promisify as
|
|
8
|
+
import { promisify as T } from "node:util";
|
|
9
9
|
import X from "gray-matter";
|
|
10
10
|
import { z as k } from "zod";
|
|
11
|
-
import
|
|
11
|
+
import Te from "@anthropic-ai/sdk";
|
|
12
12
|
import Ue from "openai";
|
|
13
|
-
import { GoogleGenerativeAI as
|
|
14
|
-
import { Ollama as
|
|
15
|
-
import { createRequire as
|
|
13
|
+
import { GoogleGenerativeAI as Le } from "@google/generative-ai";
|
|
14
|
+
import { Ollama as De } from "ollama";
|
|
15
|
+
import { createRequire as je } from "node:module";
|
|
16
16
|
import "dotenv/config";
|
|
17
17
|
const Ke = k.object({
|
|
18
18
|
name: k.string(),
|
|
@@ -23,24 +23,24 @@ const Ke = k.object({
|
|
|
23
23
|
skills: k.array(k.string()).default([]),
|
|
24
24
|
temperature: k.number().min(0).max(2).optional(),
|
|
25
25
|
avatar: k.string().optional()
|
|
26
|
-
}),
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
}), Be = (n, s) => [
|
|
27
|
+
u(n, "skills", s, "SKILL.md"),
|
|
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")
|
|
31
31
|
];
|
|
32
|
-
async function
|
|
33
|
-
for (const t of
|
|
34
|
-
if (
|
|
32
|
+
async function Fe(n, s) {
|
|
33
|
+
for (const t of Be(s, n))
|
|
34
|
+
if (_(t)) {
|
|
35
35
|
const e = await w(t, "utf-8"), { content: r } = X(e);
|
|
36
36
|
return r.trim();
|
|
37
37
|
}
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
|
-
async function Ge(
|
|
40
|
+
async function Ge(n, s) {
|
|
41
41
|
const t = [];
|
|
42
|
-
for (const e of
|
|
43
|
-
const r = await
|
|
42
|
+
for (const e of n) {
|
|
43
|
+
const r = await Fe(e, s);
|
|
44
44
|
r && t.push(`## Skill: ${e}
|
|
45
45
|
|
|
46
46
|
${r}`);
|
|
@@ -49,149 +49,149 @@ ${r}`);
|
|
|
49
49
|
|
|
50
50
|
`);
|
|
51
51
|
}
|
|
52
|
-
function
|
|
53
|
-
return
|
|
52
|
+
function We(n, s) {
|
|
53
|
+
return n ? n.startsWith("http://") || n.startsWith("https://") ? n : `council-file://${n.startsWith("/") ? n : u(s, n)}` : void 0;
|
|
54
54
|
}
|
|
55
|
-
async function
|
|
55
|
+
async function Me(n, s) {
|
|
56
56
|
const t = /\{\{(.+?)\}\}/g;
|
|
57
|
-
let e =
|
|
58
|
-
for (const r of
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
57
|
+
let e = n;
|
|
58
|
+
for (const r of n.matchAll(t)) {
|
|
59
|
+
const o = r[1].trim(), a = u(s, o);
|
|
60
|
+
if (_(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: ${
|
|
64
|
+
e = e.replace(r[0], `[Reference not found: ${o}]`);
|
|
65
65
|
}
|
|
66
66
|
return e;
|
|
67
67
|
}
|
|
68
|
-
async function oe(
|
|
69
|
-
const s =
|
|
70
|
-
if (!
|
|
68
|
+
async function oe(n) {
|
|
69
|
+
const s = F(n), t = u(s, "ABOUT.md");
|
|
70
|
+
if (!_(t))
|
|
71
71
|
throw new Error(`No ABOUT.md found in ${s}`);
|
|
72
|
-
const e = await w(t, "utf-8"), { data: r, content:
|
|
73
|
-
let i = await
|
|
72
|
+
const e = await w(t, "utf-8"), { data: r, content: o } = X(e), a = Ke.parse(r);
|
|
73
|
+
let i = await Me(o.trim(), s);
|
|
74
74
|
if (a.skills.length > 0) {
|
|
75
|
-
const
|
|
76
|
-
|
|
75
|
+
const l = await Ge(a.skills, s);
|
|
76
|
+
l && (i += `
|
|
77
77
|
|
|
78
|
-
` +
|
|
78
|
+
` + l);
|
|
79
79
|
}
|
|
80
80
|
return {
|
|
81
|
-
id:
|
|
81
|
+
id: P(s),
|
|
82
82
|
frontmatter: a,
|
|
83
83
|
systemPrompt: i,
|
|
84
84
|
dirPath: s,
|
|
85
|
-
avatarUrl:
|
|
85
|
+
avatarUrl: We(a.avatar, s)
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
async function re(
|
|
88
|
+
async function re(n, s) {
|
|
89
89
|
const t = [], e = /* @__PURE__ */ new Set();
|
|
90
90
|
if (s?.length) {
|
|
91
91
|
for (const r of s)
|
|
92
|
-
if (
|
|
92
|
+
if (_(u(r, "ABOUT.md")))
|
|
93
93
|
try {
|
|
94
|
-
const
|
|
95
|
-
e.has(
|
|
94
|
+
const o = await oe(r);
|
|
95
|
+
e.has(o.id) || (t.push(o), e.add(o.id));
|
|
96
96
|
} catch {
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
if (
|
|
100
|
-
const r = await V(
|
|
101
|
-
for (const
|
|
102
|
-
const a =
|
|
103
|
-
(await
|
|
99
|
+
if (_(n)) {
|
|
100
|
+
const r = await V(n);
|
|
101
|
+
for (const o of r) {
|
|
102
|
+
const a = u(n, o);
|
|
103
|
+
(await ge(a)).isDirectory() && _(u(a, "ABOUT.md")) && (e.has(P(a)) || (t.push(await oe(a)), e.add(P(a))));
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
if (t.length === 0)
|
|
107
107
|
throw new Error(
|
|
108
|
-
`No councilors found. Searched ${
|
|
108
|
+
`No councilors found. Searched ${n}${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
111
|
return t;
|
|
112
112
|
}
|
|
113
|
-
const
|
|
113
|
+
const Ye = T(R), ye = u(b(), ".ai-council", "config.json"), se = u(b(), ".ai-council", "councilors");
|
|
114
114
|
async function Q() {
|
|
115
115
|
try {
|
|
116
|
-
return JSON.parse(await w(
|
|
116
|
+
return JSON.parse(await w(ye, "utf-8"));
|
|
117
117
|
} catch {
|
|
118
118
|
return { backends: {} };
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
async function Z(
|
|
122
|
-
const s =
|
|
123
|
-
await
|
|
121
|
+
async function Z(n) {
|
|
122
|
+
const s = u(b(), ".ai-council");
|
|
123
|
+
await C(s, { recursive: !0 }), await O(ye, JSON.stringify(n, null, 2), "utf-8");
|
|
124
124
|
}
|
|
125
|
-
function
|
|
126
|
-
return
|
|
125
|
+
function He(n) {
|
|
126
|
+
return n.councilors ?? n.counsellors ?? {};
|
|
127
127
|
}
|
|
128
|
-
function ae(
|
|
129
|
-
return Object.values(
|
|
128
|
+
function ae(n) {
|
|
129
|
+
return Object.values(He(n)).map((s) => s.path);
|
|
130
130
|
}
|
|
131
|
-
async function
|
|
132
|
-
const s =
|
|
133
|
-
if (!
|
|
131
|
+
async function Je(n) {
|
|
132
|
+
const s = F(n), t = u(s, "ABOUT.md");
|
|
133
|
+
if (!_(t))
|
|
134
134
|
throw new Error(`No ABOUT.md found in ${s}`);
|
|
135
|
-
const e =
|
|
136
|
-
if (
|
|
137
|
-
throw new Error(`Councilor "${e}" is already registered (path: ${
|
|
138
|
-
const
|
|
139
|
-
return
|
|
135
|
+
const e = P(s), r = await Q(), o = r.councilors ?? {};
|
|
136
|
+
if (o[e])
|
|
137
|
+
throw new Error(`Councilor "${e}" is already registered (path: ${o[e].path})`);
|
|
138
|
+
const l = (await w(t, "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? e;
|
|
139
|
+
return o[e] = {
|
|
140
140
|
path: s,
|
|
141
141
|
source: "local",
|
|
142
142
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
143
|
-
}, r.councilors =
|
|
143
|
+
}, r.councilors = o, await Z(r), { id: e, name: l };
|
|
144
144
|
}
|
|
145
|
-
async function
|
|
146
|
-
await
|
|
147
|
-
const s =
|
|
148
|
-
if (
|
|
145
|
+
async function ze(n) {
|
|
146
|
+
await C(se, { recursive: !0 });
|
|
147
|
+
const s = P(n, ".git").replace(/\.git$/, ""), t = u(se, s);
|
|
148
|
+
if (_(t))
|
|
149
149
|
throw new Error(`Directory already exists: ${t}. Remove it first or use a different URL.`);
|
|
150
|
-
await
|
|
151
|
-
const e = [], r = await Q(),
|
|
152
|
-
if (
|
|
150
|
+
await Ye("git", ["clone", "--depth", "1", n, t]);
|
|
151
|
+
const e = [], r = await Q(), o = r.councilors ?? {};
|
|
152
|
+
if (_(u(t, "ABOUT.md"))) {
|
|
153
153
|
const a = s;
|
|
154
|
-
if (
|
|
154
|
+
if (o[a])
|
|
155
155
|
throw new Error(`Councilor "${a}" is already registered`);
|
|
156
|
-
const c = (await w(
|
|
157
|
-
|
|
156
|
+
const c = (await w(u(t, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? a;
|
|
157
|
+
o[a] = {
|
|
158
158
|
path: t,
|
|
159
159
|
source: "git",
|
|
160
|
-
url:
|
|
160
|
+
url: n,
|
|
161
161
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
162
162
|
}, e.push({ id: a, name: c });
|
|
163
163
|
} else {
|
|
164
164
|
const a = await V(t);
|
|
165
165
|
for (const i of a) {
|
|
166
166
|
if (i.startsWith(".")) continue;
|
|
167
|
-
const
|
|
168
|
-
if ((await
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
path:
|
|
167
|
+
const l = u(t, i);
|
|
168
|
+
if ((await ge(l)).isDirectory() && _(u(l, "ABOUT.md"))) {
|
|
169
|
+
const f = i;
|
|
170
|
+
if (o[f]) continue;
|
|
171
|
+
const h = (await w(u(l, "ABOUT.md"), "utf-8")).match(/^name:\s*["']?(.+?)["']?\s*$/m)?.[1] ?? f;
|
|
172
|
+
o[f] = {
|
|
173
|
+
path: l,
|
|
174
174
|
source: "git",
|
|
175
|
-
url:
|
|
175
|
+
url: n,
|
|
176
176
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
177
|
-
}, e.push({ id:
|
|
177
|
+
}, e.push({ id: f, name: h });
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
if (e.length === 0)
|
|
181
|
-
throw await
|
|
181
|
+
throw await G(t, { recursive: !0, force: !0 }), new Error("No councilors found in cloned repository (no ABOUT.md files)");
|
|
182
182
|
}
|
|
183
|
-
return r.councilors =
|
|
183
|
+
return r.councilors = o, await Z(r), e;
|
|
184
184
|
}
|
|
185
|
-
async function
|
|
186
|
-
const t = await Q(), e = t.councilors ?? {}, r = e[
|
|
185
|
+
async function Ve(n, s = !1) {
|
|
186
|
+
const t = await Q(), e = t.councilors ?? {}, r = e[n];
|
|
187
187
|
if (!r)
|
|
188
|
-
throw new Error(`Councilor "${
|
|
189
|
-
s && r.source === "git" &&
|
|
188
|
+
throw new Error(`Councilor "${n}" is not registered`);
|
|
189
|
+
s && r.source === "git" && _(r.path) && await G(r.path, { recursive: !0, force: !0 }), delete e[n], t.councilors = e, await Z(t);
|
|
190
190
|
}
|
|
191
|
-
function
|
|
192
|
-
const s = new
|
|
193
|
-
apiKey:
|
|
194
|
-
...
|
|
191
|
+
function Xe(n) {
|
|
192
|
+
const s = new Te({
|
|
193
|
+
apiKey: n.apiKey ?? process.env.ANTHROPIC_API_KEY,
|
|
194
|
+
...n.baseUrl ? { baseURL: n.baseUrl } : {}
|
|
195
195
|
});
|
|
196
196
|
return {
|
|
197
197
|
name: "anthropic",
|
|
@@ -201,14 +201,14 @@ function Ve(o) {
|
|
|
201
201
|
model: t.model,
|
|
202
202
|
max_tokens: 4096,
|
|
203
203
|
system: t.systemPrompt,
|
|
204
|
-
messages: t.messages.map((
|
|
205
|
-
role:
|
|
206
|
-
content:
|
|
204
|
+
messages: t.messages.map((o) => ({
|
|
205
|
+
role: o.role,
|
|
206
|
+
content: o.content
|
|
207
207
|
})),
|
|
208
208
|
...t.temperature !== void 0 ? { temperature: t.temperature } : {}
|
|
209
209
|
});
|
|
210
210
|
return {
|
|
211
|
-
content: e.content.find((
|
|
211
|
+
content: e.content.find((o) => o.type === "text")?.text ?? "",
|
|
212
212
|
tokenUsage: {
|
|
213
213
|
input: e.usage.input_tokens,
|
|
214
214
|
output: e.usage.output_tokens
|
|
@@ -220,14 +220,14 @@ function Ve(o) {
|
|
|
220
220
|
model: t.model,
|
|
221
221
|
max_tokens: 4096,
|
|
222
222
|
system: t.systemPrompt,
|
|
223
|
-
messages: t.messages.map((
|
|
224
|
-
role:
|
|
225
|
-
content:
|
|
223
|
+
messages: t.messages.map((o) => ({
|
|
224
|
+
role: o.role,
|
|
225
|
+
content: o.content
|
|
226
226
|
})),
|
|
227
227
|
...t.temperature !== void 0 ? { temperature: t.temperature } : {}
|
|
228
228
|
});
|
|
229
|
-
for await (const
|
|
230
|
-
|
|
229
|
+
for await (const o of e)
|
|
230
|
+
o.type === "content_block_delta" && o.delta.type === "text_delta" && (yield { delta: o.delta.text });
|
|
231
231
|
const r = await e.finalMessage();
|
|
232
232
|
yield {
|
|
233
233
|
delta: "",
|
|
@@ -239,10 +239,10 @@ function Ve(o) {
|
|
|
239
239
|
}
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
-
function
|
|
242
|
+
function Qe(n) {
|
|
243
243
|
const s = new Ue({
|
|
244
|
-
apiKey:
|
|
245
|
-
...
|
|
244
|
+
apiKey: n.apiKey ?? process.env.OPENAI_API_KEY,
|
|
245
|
+
...n.baseUrl ? { baseURL: n.baseUrl } : {}
|
|
246
246
|
});
|
|
247
247
|
return {
|
|
248
248
|
name: "openai",
|
|
@@ -252,9 +252,9 @@ function Xe(o) {
|
|
|
252
252
|
model: t.model,
|
|
253
253
|
messages: [
|
|
254
254
|
{ role: "system", content: t.systemPrompt },
|
|
255
|
-
...t.messages.map((
|
|
256
|
-
role:
|
|
257
|
-
content:
|
|
255
|
+
...t.messages.map((o) => ({
|
|
256
|
+
role: o.role,
|
|
257
|
+
content: o.content
|
|
258
258
|
}))
|
|
259
259
|
],
|
|
260
260
|
...t.temperature !== void 0 ? { temperature: t.temperature } : {}
|
|
@@ -279,8 +279,8 @@ function Xe(o) {
|
|
|
279
279
|
stream_options: { include_usage: !0 }
|
|
280
280
|
});
|
|
281
281
|
for await (const r of e) {
|
|
282
|
-
const
|
|
283
|
-
|
|
282
|
+
const o = r.choices[0]?.delta?.content;
|
|
283
|
+
o && (yield { delta: o }), r.usage && (yield {
|
|
284
284
|
delta: "",
|
|
285
285
|
tokenUsage: {
|
|
286
286
|
input: r.usage.prompt_tokens,
|
|
@@ -291,8 +291,8 @@ function Xe(o) {
|
|
|
291
291
|
}
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
|
-
function
|
|
295
|
-
const s =
|
|
294
|
+
function Ze(n) {
|
|
295
|
+
const s = n.apiKey ?? process.env.GOOGLE_API_KEY ?? "", t = new Le(s);
|
|
296
296
|
return {
|
|
297
297
|
name: "google",
|
|
298
298
|
defaultModel: "gemini-2.0-flash",
|
|
@@ -303,10 +303,10 @@ function Qe(o) {
|
|
|
303
303
|
generationConfig: {
|
|
304
304
|
...e.temperature !== void 0 ? { temperature: e.temperature } : {}
|
|
305
305
|
}
|
|
306
|
-
}),
|
|
307
|
-
role:
|
|
308
|
-
parts: [{ text:
|
|
309
|
-
})), a = r.startChat({ history:
|
|
306
|
+
}), o = e.messages.slice(0, -1).map((f) => ({
|
|
307
|
+
role: f.role === "assistant" ? "model" : "user",
|
|
308
|
+
parts: [{ text: f.content }]
|
|
309
|
+
})), a = r.startChat({ history: o }), i = e.messages[e.messages.length - 1], c = (await a.sendMessage(i?.content ?? "")).response;
|
|
310
310
|
return {
|
|
311
311
|
content: c.text(),
|
|
312
312
|
tokenUsage: c.usageMetadata ? {
|
|
@@ -322,15 +322,15 @@ function Qe(o) {
|
|
|
322
322
|
generationConfig: {
|
|
323
323
|
...e.temperature !== void 0 ? { temperature: e.temperature } : {}
|
|
324
324
|
}
|
|
325
|
-
}),
|
|
326
|
-
role:
|
|
327
|
-
parts: [{ text:
|
|
328
|
-
})), a = r.startChat({ history:
|
|
329
|
-
for await (const
|
|
330
|
-
const y =
|
|
325
|
+
}), o = e.messages.slice(0, -1).map((f) => ({
|
|
326
|
+
role: f.role === "assistant" ? "model" : "user",
|
|
327
|
+
parts: [{ text: f.content }]
|
|
328
|
+
})), a = r.startChat({ history: o }), i = e.messages[e.messages.length - 1], l = await a.sendMessageStream(i?.content ?? "");
|
|
329
|
+
for await (const f of l.stream) {
|
|
330
|
+
const y = f.text();
|
|
331
331
|
y && (yield { delta: y });
|
|
332
332
|
}
|
|
333
|
-
const c = await
|
|
333
|
+
const c = await l.response;
|
|
334
334
|
yield {
|
|
335
335
|
delta: "",
|
|
336
336
|
tokenUsage: c.usageMetadata ? {
|
|
@@ -341,9 +341,9 @@ function Qe(o) {
|
|
|
341
341
|
}
|
|
342
342
|
};
|
|
343
343
|
}
|
|
344
|
-
function
|
|
345
|
-
const s = new
|
|
346
|
-
host:
|
|
344
|
+
function qe(n) {
|
|
345
|
+
const s = new De({
|
|
346
|
+
host: n.baseUrl ?? "http://localhost:11434"
|
|
347
347
|
});
|
|
348
348
|
return {
|
|
349
349
|
name: "ollama",
|
|
@@ -385,51 +385,51 @@ function Ze(o) {
|
|
|
385
385
|
},
|
|
386
386
|
stream: !0
|
|
387
387
|
});
|
|
388
|
-
let r,
|
|
388
|
+
let r, o;
|
|
389
389
|
for await (const a of e)
|
|
390
|
-
a.message.content && (yield { delta: a.message.content }), a.done && (r = a.prompt_eval_count,
|
|
390
|
+
a.message.content && (yield { delta: a.message.content }), a.done && (r = a.prompt_eval_count, o = a.eval_count);
|
|
391
391
|
yield {
|
|
392
392
|
delta: "",
|
|
393
|
-
tokenUsage: r !== void 0 ? { input: r ?? 0, output:
|
|
393
|
+
tokenUsage: r !== void 0 ? { input: r ?? 0, output: o ?? 0 } : void 0
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
396
|
};
|
|
397
397
|
}
|
|
398
398
|
const ie = {
|
|
399
|
-
anthropic:
|
|
400
|
-
openai:
|
|
401
|
-
google:
|
|
402
|
-
ollama:
|
|
399
|
+
anthropic: Xe,
|
|
400
|
+
openai: Qe,
|
|
401
|
+
google: Ze,
|
|
402
|
+
ollama: qe
|
|
403
403
|
};
|
|
404
|
-
let
|
|
405
|
-
async function
|
|
406
|
-
if (
|
|
407
|
-
const
|
|
404
|
+
let U = null;
|
|
405
|
+
async function et() {
|
|
406
|
+
if (U) return U;
|
|
407
|
+
const n = u(b(), ".ai-council", "config.json");
|
|
408
408
|
try {
|
|
409
|
-
const s = await w(
|
|
410
|
-
|
|
409
|
+
const s = await w(n, "utf-8");
|
|
410
|
+
U = JSON.parse(s);
|
|
411
411
|
} catch {
|
|
412
|
-
|
|
412
|
+
U = { backends: {} };
|
|
413
413
|
}
|
|
414
|
-
return
|
|
414
|
+
return U;
|
|
415
415
|
}
|
|
416
416
|
const z = /* @__PURE__ */ new Map();
|
|
417
|
-
function
|
|
418
|
-
|
|
417
|
+
function tt() {
|
|
418
|
+
U = null, z.clear();
|
|
419
419
|
}
|
|
420
|
-
async function W(
|
|
421
|
-
const s = z.get(
|
|
420
|
+
async function W(n) {
|
|
421
|
+
const s = z.get(n);
|
|
422
422
|
if (s) return s;
|
|
423
|
-
const t = ie[
|
|
423
|
+
const t = ie[n];
|
|
424
424
|
if (!t)
|
|
425
|
-
throw new Error(`Unknown backend: "${
|
|
426
|
-
const r = (await
|
|
427
|
-
return z.set(
|
|
425
|
+
throw new Error(`Unknown backend: "${n}". Available: ${Object.keys(ie).join(", ")}`);
|
|
426
|
+
const r = (await et()).backends[n] ?? {}, o = t(r);
|
|
427
|
+
return z.set(n, o), o;
|
|
428
428
|
}
|
|
429
|
-
function
|
|
429
|
+
function nt() {
|
|
430
430
|
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();
|
|
431
431
|
}
|
|
432
|
-
const M = "---EXCALIDRAW---",
|
|
432
|
+
const M = "---EXCALIDRAW---", ot = `You are the Secretary of a council discussion. Your job is to synthesize a clear, structured summary of the conversation that just took place.
|
|
433
433
|
|
|
434
434
|
Structure your summary with these sections:
|
|
435
435
|
|
|
@@ -446,17 +446,17 @@ Where did they disagree? What are the key tensions?
|
|
|
446
446
|
What are the most important takeaways? What would you recommend based on the full discussion?
|
|
447
447
|
|
|
448
448
|
Be concise but thorough. Use markdown formatting.`;
|
|
449
|
-
function
|
|
449
|
+
function rt(n) {
|
|
450
450
|
const s = [];
|
|
451
|
-
s.push(`Topic: ${
|
|
451
|
+
s.push(`Topic: ${n.topic}`), s.push(`Councilors: ${n.councilors.map((e) => e.name).join(", ")}`), s.push(`Rounds: ${n.rounds}`), s.push("");
|
|
452
452
|
let t = 0;
|
|
453
|
-
for (const e of
|
|
453
|
+
for (const e of n.turns)
|
|
454
454
|
e.round !== t && (t = e.round, s.push(`--- Round ${t} ---`), s.push("")), s.push(`[${e.councilorName}]:`), s.push(e.content), s.push("");
|
|
455
455
|
return s.join(`
|
|
456
456
|
`);
|
|
457
457
|
}
|
|
458
|
-
async function
|
|
459
|
-
result:
|
|
458
|
+
async function st({
|
|
459
|
+
result: n,
|
|
460
460
|
config: s,
|
|
461
461
|
onChunk: t,
|
|
462
462
|
signal: e
|
|
@@ -464,56 +464,56 @@ async function rt({
|
|
|
464
464
|
const r = s.secretary;
|
|
465
465
|
if (!r?.backend)
|
|
466
466
|
throw new Error("No secretary backend configured");
|
|
467
|
-
const
|
|
467
|
+
const o = await W(r.backend), a = r.model ?? o.defaultModel, i = r.systemPrompt || ot, l = nt(), c = `${i}
|
|
468
468
|
|
|
469
|
-
${
|
|
469
|
+
${l}
|
|
470
470
|
|
|
471
|
-
After your text summary, output \`${M}\` 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.`,
|
|
471
|
+
After your text summary, output \`${M}\` 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 = rt(n), y = {
|
|
472
472
|
model: a,
|
|
473
473
|
systemPrompt: c,
|
|
474
474
|
messages: [{ role: "user", content: `Please summarize this council discussion and create a position diagram:
|
|
475
475
|
|
|
476
|
-
${
|
|
476
|
+
${f}` }],
|
|
477
477
|
temperature: 0.5
|
|
478
478
|
};
|
|
479
|
-
let
|
|
480
|
-
if (
|
|
481
|
-
for await (const
|
|
479
|
+
let g = "";
|
|
480
|
+
if (o.chatStream)
|
|
481
|
+
for await (const m of o.chatStream(y)) {
|
|
482
482
|
if (e?.aborted) break;
|
|
483
|
-
|
|
483
|
+
g += m.delta, m.delta && t && t(m.delta);
|
|
484
484
|
}
|
|
485
485
|
else
|
|
486
|
-
|
|
487
|
-
const
|
|
488
|
-
if (
|
|
489
|
-
return { text:
|
|
490
|
-
const
|
|
491
|
-
let
|
|
486
|
+
g = (await o.chat(y)).content, t && t(g);
|
|
487
|
+
const h = g.indexOf(M);
|
|
488
|
+
if (h === -1)
|
|
489
|
+
return { text: g.trim() };
|
|
490
|
+
const L = g.slice(0, h).trim(), d = g.slice(h + M.length).trim();
|
|
491
|
+
let p;
|
|
492
492
|
try {
|
|
493
|
-
const
|
|
494
|
-
|
|
493
|
+
const m = d.match(/\[[\s\S]*\]/);
|
|
494
|
+
m && (p = JSON.parse(m[0]));
|
|
495
495
|
} catch {
|
|
496
496
|
}
|
|
497
|
-
return { text:
|
|
497
|
+
return { text: L, diagram: p };
|
|
498
498
|
}
|
|
499
|
-
const
|
|
500
|
-
async function
|
|
501
|
-
result:
|
|
499
|
+
const at = "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.";
|
|
500
|
+
async function it({
|
|
501
|
+
result: n,
|
|
502
502
|
roundNumber: s,
|
|
503
503
|
config: t,
|
|
504
504
|
onChunk: e,
|
|
505
505
|
signal: r
|
|
506
506
|
}) {
|
|
507
|
-
const
|
|
508
|
-
if (!
|
|
507
|
+
const o = t.secretary;
|
|
508
|
+
if (!o?.backend)
|
|
509
509
|
throw new Error("No secretary backend configured");
|
|
510
|
-
const a = await W(
|
|
511
|
-
c.push(`Topic: ${
|
|
512
|
-
for (const
|
|
513
|
-
c.push(`[${
|
|
514
|
-
const
|
|
510
|
+
const a = await W(o.backend), i = o.model ?? a.defaultModel, l = n.turns.filter((g) => g.round === s), c = [];
|
|
511
|
+
c.push(`Topic: ${n.topic}`), c.push(`Round ${s}${s === 1 ? " (Constructive)" : " (Rebuttal)"}`), c.push("");
|
|
512
|
+
for (const g of l)
|
|
513
|
+
c.push(`[${g.councilorName}]:`), c.push(g.content), c.push("");
|
|
514
|
+
const f = {
|
|
515
515
|
model: i,
|
|
516
|
-
systemPrompt:
|
|
516
|
+
systemPrompt: at,
|
|
517
517
|
messages: [{ role: "user", content: `Please summarize this round:
|
|
518
518
|
|
|
519
519
|
${c.join(`
|
|
@@ -522,32 +522,32 @@ ${c.join(`
|
|
|
522
522
|
};
|
|
523
523
|
let y = "";
|
|
524
524
|
if (a.chatStream)
|
|
525
|
-
for await (const
|
|
525
|
+
for await (const g of a.chatStream(f)) {
|
|
526
526
|
if (r?.aborted) break;
|
|
527
|
-
y +=
|
|
527
|
+
y += g.delta, g.delta && e && e(g.delta);
|
|
528
528
|
}
|
|
529
529
|
else
|
|
530
|
-
y = (await a.chat(
|
|
530
|
+
y = (await a.chat(f)).content, e && e(y);
|
|
531
531
|
return y.trim();
|
|
532
532
|
}
|
|
533
|
-
async function
|
|
534
|
-
topic:
|
|
533
|
+
async function ct({
|
|
534
|
+
topic: n,
|
|
535
535
|
firstRoundTurns: s,
|
|
536
536
|
config: t
|
|
537
537
|
}) {
|
|
538
538
|
const e = t.secretary;
|
|
539
539
|
if (!e?.backend)
|
|
540
540
|
throw new Error("No secretary backend configured");
|
|
541
|
-
const r = await W(e.backend),
|
|
541
|
+
const r = await W(e.backend), o = e.model ?? r.defaultModel, a = s.map((l) => `[${l.councilorName}]: ${l.content.slice(0, 300)}`).join(`
|
|
542
542
|
|
|
543
543
|
`);
|
|
544
544
|
return (await r.chat({
|
|
545
|
-
model:
|
|
545
|
+
model: o,
|
|
546
546
|
systemPrompt: "Generate a concise title (max 8 words) for this council discussion. Return only the title, no quotes or punctuation at the end.",
|
|
547
547
|
messages: [
|
|
548
548
|
{
|
|
549
549
|
role: "user",
|
|
550
|
-
content: `Topic: ${
|
|
550
|
+
content: `Topic: ${n}
|
|
551
551
|
|
|
552
552
|
First round:
|
|
553
553
|
${a}`
|
|
@@ -556,96 +556,96 @@ ${a}`
|
|
|
556
556
|
temperature: 0.3
|
|
557
557
|
})).content.trim().replace(/^["']+|["']+$/g, "").replace(/[.!?]+$/, "").trim();
|
|
558
558
|
}
|
|
559
|
-
const
|
|
559
|
+
const we = u(b(), ".ai-council"), lt = u(we, "council.log");
|
|
560
560
|
let ce = !1;
|
|
561
|
-
async function
|
|
562
|
-
ce || (await
|
|
561
|
+
async function ut() {
|
|
562
|
+
ce || (await C(we, { recursive: !0 }), ce = !0);
|
|
563
563
|
}
|
|
564
|
-
function
|
|
565
|
-
let
|
|
564
|
+
function dt(n, s, t, e) {
|
|
565
|
+
let o = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${n} [${s}] ${t}`;
|
|
566
566
|
if (e !== void 0) {
|
|
567
567
|
const a = e instanceof Error ? `${e.message}
|
|
568
568
|
${e.stack ?? ""}` : typeof e == "string" ? e : JSON.stringify(e, null, 2);
|
|
569
|
-
|
|
569
|
+
o += `
|
|
570
570
|
${a.replace(/\n/g, `
|
|
571
571
|
`)}`;
|
|
572
572
|
}
|
|
573
|
-
return
|
|
573
|
+
return o + `
|
|
574
574
|
`;
|
|
575
575
|
}
|
|
576
|
-
async function Y(
|
|
576
|
+
async function Y(n, s, t, e) {
|
|
577
577
|
try {
|
|
578
|
-
await
|
|
578
|
+
await ut(), await Re(lt, dt(n, s, t, e));
|
|
579
579
|
} catch {
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
|
-
const
|
|
583
|
-
info: (
|
|
584
|
-
warn: (
|
|
585
|
-
error: (
|
|
582
|
+
const v = {
|
|
583
|
+
info: (n, s, t) => Y("INFO", n, s, t),
|
|
584
|
+
warn: (n, s, t) => Y("WARN", n, s, t),
|
|
585
|
+
error: (n, s, t) => Y("ERROR", n, s, t)
|
|
586
586
|
};
|
|
587
|
-
function
|
|
588
|
-
const
|
|
587
|
+
function mt(n, s, t, e, r) {
|
|
588
|
+
const o = [{ role: "user", content: n }];
|
|
589
589
|
if (e?.length) {
|
|
590
590
|
for (const a of e)
|
|
591
|
-
a.councilorId === t ?
|
|
591
|
+
a.councilorId === t ? o.push({ role: "assistant", content: a.content }) : o.push({
|
|
592
592
|
role: "user",
|
|
593
593
|
content: `[${a.councilorName}, Round ${a.round}]: ${a.content}`
|
|
594
594
|
});
|
|
595
|
-
r &&
|
|
595
|
+
r && o.push({
|
|
596
596
|
role: "user",
|
|
597
597
|
content: `[Secretary Summary]: ${r}`
|
|
598
598
|
});
|
|
599
599
|
}
|
|
600
600
|
for (const a of s)
|
|
601
|
-
a.councilorId === t ?
|
|
601
|
+
a.councilorId === t ? o.push({ role: "assistant", content: a.content }) : o.push({
|
|
602
602
|
role: "user",
|
|
603
603
|
content: `[${a.councilorName}, Round ${a.round}]: ${a.content}`
|
|
604
604
|
});
|
|
605
|
-
return
|
|
605
|
+
return o;
|
|
606
606
|
}
|
|
607
|
-
function
|
|
608
|
-
const r = [{ role: "user", content:
|
|
607
|
+
function pt(n, s, t, e) {
|
|
608
|
+
const r = [{ role: "user", content: n }];
|
|
609
609
|
if (e === 1)
|
|
610
610
|
return r;
|
|
611
|
-
const
|
|
612
|
-
for (const i of
|
|
611
|
+
const o = s.filter((i) => i.round === 1);
|
|
612
|
+
for (const i of o)
|
|
613
613
|
i.councilorId === t ? r.push({ role: "assistant", content: i.content }) : r.push({
|
|
614
614
|
role: "user",
|
|
615
615
|
content: `[${i.councilorName}, Constructive]: ${i.content}`
|
|
616
616
|
});
|
|
617
617
|
const a = e - 1;
|
|
618
618
|
if (a > 1) {
|
|
619
|
-
const i = s.filter((
|
|
620
|
-
for (const
|
|
621
|
-
|
|
619
|
+
const i = s.filter((l) => l.round === a);
|
|
620
|
+
for (const l of i)
|
|
621
|
+
l.councilorId === t ? r.push({ role: "assistant", content: l.content }) : r.push({
|
|
622
622
|
role: "user",
|
|
623
|
-
content: `[${
|
|
623
|
+
content: `[${l.councilorName}, Round ${a}]: ${l.content}`
|
|
624
624
|
});
|
|
625
625
|
}
|
|
626
626
|
for (const i of s)
|
|
627
627
|
i.councilorId === t && i.round !== 1 && i.round !== a && i.round < e && r.push({ role: "assistant", content: i.content });
|
|
628
628
|
return r;
|
|
629
629
|
}
|
|
630
|
-
function
|
|
631
|
-
const t = [...
|
|
630
|
+
function ft(n, s) {
|
|
631
|
+
const t = [...n];
|
|
632
632
|
let e = s | 0;
|
|
633
633
|
const r = () => {
|
|
634
634
|
e = e + 1831565813 | 0;
|
|
635
|
-
let
|
|
636
|
-
return
|
|
635
|
+
let o = Math.imul(e ^ e >>> 15, 1 | e);
|
|
636
|
+
return o = o + Math.imul(o ^ o >>> 7, 61 | o) ^ o, ((o ^ o >>> 14) >>> 0) / 4294967296;
|
|
637
637
|
};
|
|
638
|
-
for (let
|
|
639
|
-
const a = Math.floor(r() * (
|
|
640
|
-
[t[
|
|
638
|
+
for (let o = t.length - 1; o > 0; o--) {
|
|
639
|
+
const a = Math.floor(r() * (o + 1));
|
|
640
|
+
[t[o], t[a]] = [t[a], t[o]];
|
|
641
641
|
}
|
|
642
642
|
return t;
|
|
643
643
|
}
|
|
644
|
-
function H(
|
|
644
|
+
function H(n, s, t, e, r, o) {
|
|
645
645
|
return {
|
|
646
|
-
topic:
|
|
647
|
-
topicSource:
|
|
648
|
-
councilors:
|
|
646
|
+
topic: n.topic,
|
|
647
|
+
topicSource: n.topicSource,
|
|
648
|
+
councilors: n.councilors.map((a) => ({
|
|
649
649
|
id: a.id,
|
|
650
650
|
name: a.frontmatter.name,
|
|
651
651
|
description: a.frontmatter.description,
|
|
@@ -653,118 +653,118 @@ function H(o, s, t, e, r, n) {
|
|
|
653
653
|
model: a.frontmatter.model ?? "default",
|
|
654
654
|
avatarUrl: a.avatarUrl
|
|
655
655
|
})),
|
|
656
|
-
rounds:
|
|
656
|
+
rounds: n.rounds,
|
|
657
657
|
turns: s,
|
|
658
658
|
startedAt: t,
|
|
659
659
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
660
660
|
totalTokenUsage: { input: e, output: r },
|
|
661
|
-
...
|
|
662
|
-
...
|
|
661
|
+
...o && Object.keys(o).length > 0 ? { roundSummaries: o } : {},
|
|
662
|
+
...n.mode === "debate" ? { mode: "debate" } : {}
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
|
-
async function
|
|
666
|
-
let
|
|
667
|
-
typeof
|
|
668
|
-
topic:
|
|
665
|
+
async function ht(n, s, t, e, r) {
|
|
666
|
+
let o;
|
|
667
|
+
typeof n == "string" ? o = {
|
|
668
|
+
topic: n,
|
|
669
669
|
topicSource: s,
|
|
670
670
|
councilors: t,
|
|
671
671
|
rounds: e,
|
|
672
672
|
onEvent: r
|
|
673
|
-
} :
|
|
673
|
+
} : o = n;
|
|
674
674
|
const a = (/* @__PURE__ */ new Date()).toISOString(), i = [];
|
|
675
|
-
let
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
councilors:
|
|
679
|
-
topic:
|
|
675
|
+
let l = 0, c = 0;
|
|
676
|
+
const f = o.mode === "debate", y = {}, g = o.previousTurns?.length ? Math.max(...o.previousTurns.map((h) => h.round)) : 0;
|
|
677
|
+
v.info("conversation", `Starting ${f ? "debate" : "freeform"} — ${o.councilors.length} councilors, ${o.rounds} rounds`, {
|
|
678
|
+
councilors: o.councilors.map((h) => `${h.frontmatter.name} (${h.frontmatter.backend}/${h.frontmatter.model ?? "default"})`),
|
|
679
|
+
topic: o.topic.slice(0, 200)
|
|
680
680
|
});
|
|
681
|
-
for (let
|
|
682
|
-
const
|
|
683
|
-
for (const
|
|
684
|
-
if (
|
|
685
|
-
return H(
|
|
686
|
-
if (
|
|
687
|
-
const
|
|
688
|
-
|
|
681
|
+
for (let h = 1; h <= o.rounds; h++) {
|
|
682
|
+
const L = f && h > 1 ? ft(o.councilors, h) : o.councilors;
|
|
683
|
+
for (const d of L) {
|
|
684
|
+
if (o.signal?.aborted)
|
|
685
|
+
return H(o, i, a, l, c, y);
|
|
686
|
+
if (o.beforeTurn) {
|
|
687
|
+
const m = await o.beforeTurn();
|
|
688
|
+
m && (i.push(m), o.onEvent({ type: "turn_complete", turn: m }));
|
|
689
689
|
}
|
|
690
|
-
const
|
|
691
|
-
|
|
690
|
+
const p = h + g;
|
|
691
|
+
o.onEvent({ type: "turn_start", round: p, councilorName: d.frontmatter.name });
|
|
692
692
|
try {
|
|
693
|
-
const
|
|
694
|
-
model:
|
|
695
|
-
systemPrompt:
|
|
696
|
-
messages:
|
|
697
|
-
temperature:
|
|
693
|
+
const m = await W(d.frontmatter.backend), x = d.frontmatter.model ?? m.defaultModel, Se = f ? pt(o.topic, i, d.id, h) : mt(o.topic, i, d.id, o.previousTurns, o.previousSummary), q = {
|
|
694
|
+
model: x,
|
|
695
|
+
systemPrompt: d.systemPrompt,
|
|
696
|
+
messages: Se,
|
|
697
|
+
temperature: d.frontmatter.temperature
|
|
698
698
|
};
|
|
699
|
-
let
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
for await (const
|
|
703
|
-
if (
|
|
704
|
-
|
|
699
|
+
let j, N;
|
|
700
|
+
if (m.chatStream) {
|
|
701
|
+
j = "";
|
|
702
|
+
for await (const I of m.chatStream(q)) {
|
|
703
|
+
if (o.signal?.aborted) break;
|
|
704
|
+
j += I.delta, I.delta && o.onEvent({ type: "turn_chunk", councilorName: d.frontmatter.name, delta: I.delta }), I.tokenUsage && (N = I.tokenUsage);
|
|
705
705
|
}
|
|
706
706
|
} else {
|
|
707
|
-
const
|
|
708
|
-
|
|
707
|
+
const I = await m.chat(q);
|
|
708
|
+
j = I.content, N = I.tokenUsage;
|
|
709
709
|
}
|
|
710
710
|
const ee = {
|
|
711
|
-
round:
|
|
712
|
-
councilorId:
|
|
713
|
-
councilorName:
|
|
714
|
-
content:
|
|
711
|
+
round: p,
|
|
712
|
+
councilorId: d.id,
|
|
713
|
+
councilorName: d.frontmatter.name,
|
|
714
|
+
content: j,
|
|
715
715
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
716
|
-
model:
|
|
717
|
-
backend:
|
|
718
|
-
tokenUsage:
|
|
719
|
-
avatarUrl:
|
|
716
|
+
model: x,
|
|
717
|
+
backend: d.frontmatter.backend,
|
|
718
|
+
tokenUsage: N,
|
|
719
|
+
avatarUrl: d.avatarUrl
|
|
720
720
|
};
|
|
721
|
-
|
|
722
|
-
} catch (
|
|
723
|
-
const
|
|
724
|
-
|
|
721
|
+
N && (l += N.input, c += N.output), i.push(ee), o.onEvent({ type: "turn_complete", turn: ee });
|
|
722
|
+
} catch (m) {
|
|
723
|
+
const x = m instanceof Error ? m.message : String(m);
|
|
724
|
+
v.error("conversation", `Turn failed for ${d.frontmatter.name} (round ${h}, model ${d.frontmatter.model ?? "default"}, backend ${d.frontmatter.backend})`, m), o.onEvent({ type: "error", councilorName: d.frontmatter.name, error: x });
|
|
725
725
|
}
|
|
726
726
|
}
|
|
727
|
-
if (
|
|
727
|
+
if (o.onEvent({ type: "round_complete", round: h }), f && o.config?.secretary?.backend && !o.signal?.aborted)
|
|
728
728
|
try {
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
const
|
|
732
|
-
result:
|
|
733
|
-
roundNumber:
|
|
734
|
-
config:
|
|
735
|
-
onChunk: (
|
|
736
|
-
|
|
729
|
+
const d = H(o, i, a, l, c, y);
|
|
730
|
+
o.onEvent({ type: "round_summary_start", round: h });
|
|
731
|
+
const p = await it({
|
|
732
|
+
result: d,
|
|
733
|
+
roundNumber: h,
|
|
734
|
+
config: o.config,
|
|
735
|
+
onChunk: (m) => {
|
|
736
|
+
o.onEvent({ type: "round_summary_chunk", round: h, delta: m });
|
|
737
737
|
},
|
|
738
|
-
signal:
|
|
738
|
+
signal: o.signal
|
|
739
739
|
});
|
|
740
|
-
y[
|
|
741
|
-
} catch (
|
|
742
|
-
|
|
740
|
+
y[h] = p, o.onEvent({ type: "round_summary_complete", round: h, summary: p });
|
|
741
|
+
} catch (d) {
|
|
742
|
+
v.error("conversation", `Interim summary failed for round ${h}`, d);
|
|
743
743
|
}
|
|
744
744
|
}
|
|
745
|
-
return H(
|
|
745
|
+
return H(o, i, a, l, c, y);
|
|
746
746
|
}
|
|
747
|
-
const
|
|
748
|
-
function
|
|
749
|
-
return
|
|
747
|
+
const A = u(b(), ".ai-council", "history");
|
|
748
|
+
function gt(n) {
|
|
749
|
+
return n.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
750
750
|
}
|
|
751
|
-
async function
|
|
752
|
-
await
|
|
753
|
-
const s = new Date(
|
|
754
|
-
return await
|
|
751
|
+
async function yt(n) {
|
|
752
|
+
await C(A, { recursive: !0 });
|
|
753
|
+
const s = new Date(n.startedAt).toISOString().replace(/[:.]/g, "-").slice(0, 19), t = gt(n.topic), e = `${s}-${t}`, r = u(A, `${e}.json`);
|
|
754
|
+
return await O(r, JSON.stringify(n, null, 2), "utf-8"), e;
|
|
755
755
|
}
|
|
756
|
-
async function
|
|
757
|
-
await
|
|
758
|
-
const
|
|
759
|
-
for (const t of
|
|
756
|
+
async function wt() {
|
|
757
|
+
await C(A, { recursive: !0 });
|
|
758
|
+
const n = await V(A), s = [];
|
|
759
|
+
for (const t of n)
|
|
760
760
|
if (t.endsWith(".json"))
|
|
761
761
|
try {
|
|
762
|
-
const e = await w(
|
|
762
|
+
const e = await w(u(A, t), "utf-8"), r = JSON.parse(e);
|
|
763
763
|
s.push({
|
|
764
|
-
id:
|
|
764
|
+
id: P(t, ".json"),
|
|
765
765
|
topic: r.topic,
|
|
766
766
|
title: r.title,
|
|
767
|
-
councilors: r.councilors.map((
|
|
767
|
+
councilors: r.councilors.map((o) => o.name),
|
|
768
768
|
rounds: r.rounds,
|
|
769
769
|
startedAt: r.startedAt,
|
|
770
770
|
completedAt: r.completedAt
|
|
@@ -773,59 +773,59 @@ async function yt() {
|
|
|
773
773
|
}
|
|
774
774
|
return s.sort((t, e) => e.startedAt.localeCompare(t.startedAt));
|
|
775
775
|
}
|
|
776
|
-
async function le(
|
|
777
|
-
const s =
|
|
776
|
+
async function le(n) {
|
|
777
|
+
const s = u(A, `${n}.json`), t = await w(s, "utf-8"), e = JSON.parse(t);
|
|
778
778
|
return e.infographic && !e.infographics && (e.infographics = [e.infographic], delete e.infographic), e;
|
|
779
779
|
}
|
|
780
|
-
async function
|
|
781
|
-
const s =
|
|
782
|
-
await
|
|
780
|
+
async function bt(n) {
|
|
781
|
+
const s = u(A, `${n}.json`);
|
|
782
|
+
await G(s);
|
|
783
783
|
}
|
|
784
|
-
async function
|
|
785
|
-
const t =
|
|
786
|
-
r.infographics || (r.infographics = []), r.infographics.push(s), await
|
|
784
|
+
async function vt(n, s) {
|
|
785
|
+
const t = u(A, `${n}.json`), e = await w(t, "utf-8"), r = JSON.parse(e);
|
|
786
|
+
r.infographics || (r.infographics = []), r.infographics.push(s), await O(t, JSON.stringify(r, null, 2), "utf-8");
|
|
787
787
|
}
|
|
788
|
-
async function
|
|
789
|
-
const t =
|
|
790
|
-
r.infographics && s >= 0 && s < r.infographics.length && r.infographics.splice(s, 1), await
|
|
788
|
+
async function kt(n, s) {
|
|
789
|
+
const t = u(A, `${n}.json`), e = await w(t, "utf-8"), r = JSON.parse(e);
|
|
790
|
+
r.infographics && s >= 0 && s < r.infographics.length && r.infographics.splice(s, 1), await O(t, JSON.stringify(r, null, 2), "utf-8");
|
|
791
791
|
}
|
|
792
|
-
const
|
|
793
|
-
function
|
|
794
|
-
const s =
|
|
792
|
+
const be = je(import.meta.url);
|
|
793
|
+
function _t(n) {
|
|
794
|
+
const s = n.councilors.map((e) => e.name).join(", "), t = n.summary ?? n.turns.map((e) => `${e.councilorName}: ${e.content.slice(0, 200)}`).join(`
|
|
795
795
|
`);
|
|
796
796
|
return [
|
|
797
797
|
"Create a professional infographic summarizing a panel discussion.",
|
|
798
|
-
`Topic: ${
|
|
798
|
+
`Topic: ${n.topic.slice(0, 300)}`,
|
|
799
799
|
`Key points: ${t.slice(0, 1500)}`,
|
|
800
800
|
`Panelists: ${s}`,
|
|
801
801
|
"Use a clean, modern design with sections for convergence points, divergence points, and key takeaways.",
|
|
802
802
|
"Include relevant icons and visual hierarchy. Use a horizontal landscape layout."
|
|
803
803
|
].join(" ");
|
|
804
804
|
}
|
|
805
|
-
function
|
|
806
|
-
if (
|
|
807
|
-
const s = !!(
|
|
805
|
+
function St(n) {
|
|
806
|
+
if (n.infographic?.backend) return n.infographic.backend;
|
|
807
|
+
const s = !!(n.backends.google?.apiKey || process.env.GOOGLE_API_KEY), t = !!(n.backends.openai?.apiKey || process.env.OPENAI_API_KEY);
|
|
808
808
|
return s ? "google" : t ? "openai" : null;
|
|
809
809
|
}
|
|
810
|
-
async function Et(
|
|
811
|
-
const t =
|
|
810
|
+
async function Et(n, s) {
|
|
811
|
+
const t = be("openai").default, o = (await new t({
|
|
812
812
|
apiKey: s.backends.openai?.apiKey || process.env.OPENAI_API_KEY,
|
|
813
813
|
...s.backends.openai?.baseUrl ? { baseURL: s.backends.openai.baseUrl } : {}
|
|
814
814
|
}).images.generate({
|
|
815
|
-
model: "gpt-image-1",
|
|
816
|
-
prompt:
|
|
815
|
+
model: "gpt-image-1.5",
|
|
816
|
+
prompt: n,
|
|
817
817
|
quality: "high",
|
|
818
818
|
size: "1536x1024"
|
|
819
819
|
})).data?.[0]?.b64_json;
|
|
820
|
-
if (!
|
|
821
|
-
return
|
|
820
|
+
if (!o) throw new Error("No image data returned from OpenAI");
|
|
821
|
+
return o;
|
|
822
822
|
}
|
|
823
|
-
async function
|
|
824
|
-
const { GoogleGenAI: t } =
|
|
823
|
+
async function At(n, s) {
|
|
824
|
+
const { GoogleGenAI: t } = be("@google/genai"), e = s.backends.google?.apiKey || process.env.GOOGLE_API_KEY;
|
|
825
825
|
if (!e) throw new Error("No Google API key configured");
|
|
826
826
|
const a = (await new t({ apiKey: e }).models.generateContent({
|
|
827
|
-
model: "gemini-3-
|
|
828
|
-
contents:
|
|
827
|
+
model: "gemini-3.1-flash-image-preview",
|
|
828
|
+
contents: n,
|
|
829
829
|
config: {
|
|
830
830
|
responseModalities: ["IMAGE", "TEXT"]
|
|
831
831
|
}
|
|
@@ -836,24 +836,91 @@ async function St(o, s) {
|
|
|
836
836
|
return i.inlineData.data;
|
|
837
837
|
throw new Error("No image data in Gemini response");
|
|
838
838
|
}
|
|
839
|
-
async function ue(
|
|
840
|
-
const e = t ??
|
|
839
|
+
async function ue(n, s, t) {
|
|
840
|
+
const e = t ?? St(s);
|
|
841
841
|
if (!e) throw new Error("No image-capable backend configured (need OpenAI or Google API key)");
|
|
842
|
-
const r =
|
|
843
|
-
return e === "openai" ? Et(r, s) :
|
|
842
|
+
const r = _t(n);
|
|
843
|
+
return e === "openai" ? Et(r, s) : At(r, s);
|
|
844
|
+
}
|
|
845
|
+
const It = /https?:\/\/[^\s)<>]+/g;
|
|
846
|
+
function $t(n) {
|
|
847
|
+
const s = n.match(It);
|
|
848
|
+
return s ? [...new Set(s)] : [];
|
|
849
|
+
}
|
|
850
|
+
async function Ot(n, s) {
|
|
851
|
+
const t = new AbortController(), e = setTimeout(() => t.abort(), 15e3);
|
|
852
|
+
s && s.addEventListener("abort", () => t.abort(), { once: !0 });
|
|
853
|
+
try {
|
|
854
|
+
const r = await fetch(n, {
|
|
855
|
+
signal: t.signal,
|
|
856
|
+
headers: {
|
|
857
|
+
"User-Agent": "Council/1.0 (AI Discussion Tool)",
|
|
858
|
+
Accept: "text/html, application/json, text/plain, */*"
|
|
859
|
+
},
|
|
860
|
+
redirect: "follow"
|
|
861
|
+
});
|
|
862
|
+
if (clearTimeout(e), !r.ok)
|
|
863
|
+
return { url: n, content: `[Failed to fetch: HTTP ${r.status}]` };
|
|
864
|
+
const o = r.headers.get("content-type") || "", a = await r.text();
|
|
865
|
+
if (o.includes("application/json"))
|
|
866
|
+
try {
|
|
867
|
+
const c = JSON.stringify(JSON.parse(a), null, 2);
|
|
868
|
+
return { url: n, content: c.slice(0, 8e3) };
|
|
869
|
+
} catch {
|
|
870
|
+
return { url: n, content: a.slice(0, 8e3) };
|
|
871
|
+
}
|
|
872
|
+
if (o.includes("text/plain") || o.includes("text/markdown"))
|
|
873
|
+
return { url: n, content: a.slice(0, 8e3) };
|
|
874
|
+
const { title: i, text: l } = Pt(a);
|
|
875
|
+
return { url: n, title: i, content: l.slice(0, 8e3) };
|
|
876
|
+
} catch (r) {
|
|
877
|
+
clearTimeout(e);
|
|
878
|
+
const o = r instanceof Error ? r.message : String(r);
|
|
879
|
+
return o.includes("abort") ? { url: n, content: "[Fetch timed out]" } : { url: n, content: `[Failed to fetch: ${o}]` };
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function Pt(n) {
|
|
883
|
+
const s = n.match(/<title[^>]*>([\s\S]*?)<\/title>/i), t = s ? de(s[1].trim()) : "";
|
|
884
|
+
let e = n.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, "");
|
|
885
|
+
return e = e.replace(/<\/(p|div|h[1-6]|li|tr|blockquote|section|article)>/gi, `
|
|
886
|
+
`), e = e.replace(/<br\s*\/?>/gi, `
|
|
887
|
+
`), e = e.replace(/<li[^>]*>/gi, "• "), e = e.replace(/<[^>]+>/g, " "), e = de(e), e = e.split(`
|
|
888
|
+
`).map((r) => r.replace(/\s+/g, " ").trim()).filter(Boolean).join(`
|
|
889
|
+
`), { title: t, text: e };
|
|
890
|
+
}
|
|
891
|
+
function de(n) {
|
|
892
|
+
return n.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/&#(\d+);/g, (s, t) => String.fromCharCode(Number(t))).replace(/&[a-zA-Z]+;/g, " ");
|
|
844
893
|
}
|
|
845
|
-
|
|
894
|
+
async function Ct(n, s, t) {
|
|
895
|
+
const e = $t(n);
|
|
896
|
+
if (e.length === 0) return n;
|
|
897
|
+
v.info("topic-enricher", `Found ${e.length} URL(s) in topic`, { urls: e });
|
|
898
|
+
const r = await Promise.all(
|
|
899
|
+
e.map((a) => Ot(a, s))
|
|
900
|
+
);
|
|
901
|
+
let o = n;
|
|
902
|
+
for (const a of r) {
|
|
903
|
+
const i = a.title ? `Resource: ${a.title} (${a.url})` : `Resource: ${a.url}`;
|
|
904
|
+
o += `
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
${i}
|
|
908
|
+
${a.content}`;
|
|
909
|
+
}
|
|
910
|
+
return v.info("topic-enricher", `Enriched topic with ${r.length} resource(s)`), o;
|
|
911
|
+
}
|
|
912
|
+
const ve = {
|
|
846
913
|
anthropic: "https://api.anthropic.com",
|
|
847
914
|
openai: "https://api.openai.com/v1",
|
|
848
915
|
google: "https://generativelanguage.googleapis.com",
|
|
849
916
|
ollama: "http://localhost:11434"
|
|
850
|
-
},
|
|
917
|
+
}, me = [
|
|
851
918
|
"claude-opus-4-20250514",
|
|
852
919
|
"claude-sonnet-4-5-20250514",
|
|
853
920
|
"claude-sonnet-4-20250514",
|
|
854
921
|
"claude-haiku-4-20250414",
|
|
855
922
|
"claude-3-5-haiku-20241022"
|
|
856
|
-
],
|
|
923
|
+
], K = [
|
|
857
924
|
"gemini-2.5-pro",
|
|
858
925
|
"gemini-2.5-flash",
|
|
859
926
|
"gemini-2.0-flash",
|
|
@@ -861,12 +928,12 @@ const be = {
|
|
|
861
928
|
"gemini-1.5-pro",
|
|
862
929
|
"gemini-1.5-flash"
|
|
863
930
|
];
|
|
864
|
-
async function
|
|
931
|
+
async function xt(n, s) {
|
|
865
932
|
try {
|
|
866
|
-
switch (
|
|
933
|
+
switch (n) {
|
|
867
934
|
case "ollama": {
|
|
868
935
|
const { Ollama: t } = await import("ollama");
|
|
869
|
-
return { connected: !0, models: (await new t({ host: s.baseUrl ||
|
|
936
|
+
return { connected: !0, models: (await new t({ host: s.baseUrl || ve.ollama }).list()).models.map((a) => a.name).sort() };
|
|
870
937
|
}
|
|
871
938
|
case "openai": {
|
|
872
939
|
const { default: t } = await import("openai");
|
|
@@ -883,46 +950,46 @@ async function At(o, s) {
|
|
|
883
950
|
try {
|
|
884
951
|
return { connected: !0, models: (await e.models.list({ limit: 100 })).data.map((a) => a.id).sort() };
|
|
885
952
|
} catch {
|
|
886
|
-
return { connected: !0, models:
|
|
953
|
+
return { connected: !0, models: me };
|
|
887
954
|
}
|
|
888
955
|
}
|
|
889
956
|
case "google": {
|
|
890
957
|
const t = s.apiKey || process.env.GOOGLE_API_KEY || "";
|
|
891
|
-
if (!t) return { connected: !1, models:
|
|
958
|
+
if (!t) return { connected: !1, models: K, error: "No API key" };
|
|
892
959
|
const e = await fetch(
|
|
893
960
|
`https://generativelanguage.googleapis.com/v1beta/models?key=${t}`
|
|
894
961
|
);
|
|
895
962
|
if (!e.ok) {
|
|
896
963
|
const i = (await e.json().catch(() => ({})))?.error?.message || `HTTP ${e.status}`;
|
|
897
|
-
return { connected: !1, models:
|
|
964
|
+
return { connected: !1, models: K, error: i };
|
|
898
965
|
}
|
|
899
|
-
const
|
|
900
|
-
return { connected: !0, models:
|
|
966
|
+
const o = ((await e.json()).models || []).filter((a) => a.name.includes("gemini") && a.supportedGenerationMethods?.includes("generateContent")).map((a) => a.name.replace("models/", "")).sort();
|
|
967
|
+
return { connected: !0, models: o.length > 0 ? o : K };
|
|
901
968
|
}
|
|
902
969
|
default:
|
|
903
|
-
return { connected: !1, models: [], error: `Unknown backend: ${
|
|
970
|
+
return { connected: !1, models: [], error: `Unknown backend: ${n}` };
|
|
904
971
|
}
|
|
905
972
|
} catch (t) {
|
|
906
973
|
const e = t instanceof Error ? t.message : String(t);
|
|
907
|
-
return { connected: !1, models:
|
|
974
|
+
return { connected: !1, models: n === "anthropic" ? me : n === "google" ? K : [], error: e };
|
|
908
975
|
}
|
|
909
976
|
}
|
|
910
|
-
let
|
|
911
|
-
function
|
|
912
|
-
|
|
977
|
+
let S = null, B = [];
|
|
978
|
+
function Nt(n, s) {
|
|
979
|
+
n.handle("app:getCouncilDir", async () => {
|
|
913
980
|
const t = process.env.COUNCIL_CWD || process.cwd();
|
|
914
|
-
return
|
|
915
|
-
}),
|
|
916
|
-
const r =
|
|
917
|
-
let
|
|
981
|
+
return F(t, "council");
|
|
982
|
+
}), n.handle("councilors:list", async (t, e) => {
|
|
983
|
+
const r = u(b(), ".ai-council", "config.json");
|
|
984
|
+
let o = { backends: {} };
|
|
918
985
|
try {
|
|
919
986
|
const c = await w(r, "utf-8");
|
|
920
|
-
|
|
987
|
+
o = JSON.parse(c);
|
|
921
988
|
} catch {
|
|
922
989
|
}
|
|
923
|
-
const a = ae(
|
|
990
|
+
const a = ae(o), i = o.councilors ?? {};
|
|
924
991
|
return (await re(e, a)).map((c) => {
|
|
925
|
-
const
|
|
992
|
+
const f = i[c.id];
|
|
926
993
|
return {
|
|
927
994
|
id: c.id,
|
|
928
995
|
dirPath: c.dirPath,
|
|
@@ -933,21 +1000,21 @@ function It(o, s) {
|
|
|
933
1000
|
temperature: c.frontmatter.temperature,
|
|
934
1001
|
interests: c.frontmatter.interests,
|
|
935
1002
|
avatarUrl: c.avatarUrl,
|
|
936
|
-
source:
|
|
937
|
-
registryUrl:
|
|
1003
|
+
source: f?.source,
|
|
1004
|
+
registryUrl: f?.url
|
|
938
1005
|
};
|
|
939
1006
|
});
|
|
940
|
-
}),
|
|
941
|
-
const r =
|
|
942
|
-
return { frontmatter: a, body: i.trim(), raw:
|
|
943
|
-
}),
|
|
944
|
-
const
|
|
945
|
-
return await
|
|
946
|
-
}),
|
|
947
|
-
const a =
|
|
948
|
-
return await
|
|
949
|
-
}),
|
|
950
|
-
const t =
|
|
1007
|
+
}), n.handle("councilors:get", async (t, e) => {
|
|
1008
|
+
const r = u(e, "ABOUT.md"), o = await w(r, "utf-8"), { data: a, content: i } = X(o);
|
|
1009
|
+
return { frontmatter: a, body: i.trim(), raw: o };
|
|
1010
|
+
}), n.handle("councilors:save", async (t, e, r) => {
|
|
1011
|
+
const o = u(e, "ABOUT.md");
|
|
1012
|
+
return await O(o, r, "utf-8"), { success: !0 };
|
|
1013
|
+
}), n.handle("councilors:create", async (t, e, r, o) => {
|
|
1014
|
+
const a = u(e, r);
|
|
1015
|
+
return await C(a, { recursive: !0 }), await O(u(a, "ABOUT.md"), o, "utf-8"), { success: !0, dirPath: a };
|
|
1016
|
+
}), n.handle("councilors:delete", async (t, e) => (await G(e, { recursive: !0, force: !0 }), { success: !0 })), n.handle("config:get", async () => {
|
|
1017
|
+
const t = u(b(), ".ai-council", "config.json");
|
|
951
1018
|
let e = { backends: {} };
|
|
952
1019
|
try {
|
|
953
1020
|
const i = await w(t, "utf-8");
|
|
@@ -958,35 +1025,35 @@ function It(o, s) {
|
|
|
958
1025
|
ANTHROPIC_API_KEY: !!process.env.ANTHROPIC_API_KEY,
|
|
959
1026
|
OPENAI_API_KEY: !!process.env.OPENAI_API_KEY,
|
|
960
1027
|
GOOGLE_API_KEY: !!process.env.GOOGLE_API_KEY
|
|
961
|
-
},
|
|
962
|
-
ANTHROPIC_API_KEY:
|
|
963
|
-
OPENAI_API_KEY:
|
|
964
|
-
GOOGLE_API_KEY:
|
|
1028
|
+
}, o = (i) => i ? "..." + i.slice(-4) : void 0, a = {
|
|
1029
|
+
ANTHROPIC_API_KEY: o(process.env.ANTHROPIC_API_KEY),
|
|
1030
|
+
OPENAI_API_KEY: o(process.env.OPENAI_API_KEY),
|
|
1031
|
+
GOOGLE_API_KEY: o(process.env.GOOGLE_API_KEY)
|
|
965
1032
|
};
|
|
966
|
-
return { config: e, envStatus: r, envKeySuffix: a, defaultUrls:
|
|
967
|
-
}),
|
|
968
|
-
const r =
|
|
969
|
-
return await
|
|
970
|
-
}),
|
|
1033
|
+
return { config: e, envStatus: r, envKeySuffix: a, defaultUrls: ve };
|
|
1034
|
+
}), n.handle("backend:probe", async (t, e, r) => xt(e, r)), n.handle("config:save", async (t, e) => {
|
|
1035
|
+
const r = u(b(), ".ai-council");
|
|
1036
|
+
return await C(r, { recursive: !0 }), await O(u(r, "config.json"), JSON.stringify(e, null, 2), "utf-8"), tt(), { success: !0 };
|
|
1037
|
+
}), n.handle("discussion:start", async (t, e) => {
|
|
971
1038
|
const r = s();
|
|
972
1039
|
if (!r) return { error: "No window" };
|
|
973
|
-
const
|
|
1040
|
+
const o = (a) => {
|
|
974
1041
|
r.isDestroyed() || r.webContents.send("discussion:event", a);
|
|
975
1042
|
};
|
|
976
1043
|
try {
|
|
977
|
-
|
|
978
|
-
const a =
|
|
1044
|
+
S && S.abort(), S = new AbortController(), B = [], v.info("ipc:discussion", "Starting discussion", { councilDir: e.councilDir, councilorIds: e.councilorIds, rounds: e.rounds, mode: e.mode });
|
|
1045
|
+
const a = u(b(), ".ai-council", "config.json");
|
|
979
1046
|
let i = { backends: {} };
|
|
980
1047
|
try {
|
|
981
|
-
const
|
|
982
|
-
i = JSON.parse(
|
|
1048
|
+
const p = await w(a, "utf-8");
|
|
1049
|
+
i = JSON.parse(p);
|
|
983
1050
|
} catch {
|
|
984
1051
|
}
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
const c = await re(e.councilDir,
|
|
988
|
-
if (
|
|
989
|
-
|
|
1052
|
+
const l = ae(i);
|
|
1053
|
+
v.info("ipc:discussion", `Loading councilors from ${e.councilDir} + ${l.length} registered paths`);
|
|
1054
|
+
const c = await re(e.councilDir, l), f = e.councilorIds?.length ? c.filter((p) => e.councilorIds.includes(p.id)) : c;
|
|
1055
|
+
if (v.info("ipc:discussion", `Resolved ${f.length} councilors: ${f.map((p) => p.id).join(", ")}`), f.length === 0) {
|
|
1056
|
+
o({ type: "error", councilorName: "", error: "No councilors found" });
|
|
990
1057
|
return;
|
|
991
1058
|
}
|
|
992
1059
|
const y = async () => B.length === 0 ? null : {
|
|
@@ -997,88 +1064,88 @@ function It(o, s) {
|
|
|
997
1064
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
998
1065
|
model: "human",
|
|
999
1066
|
backend: "human"
|
|
1000
|
-
}, h = !!e.previousTurns?.length,
|
|
1001
|
-
topic:
|
|
1067
|
+
}, g = await Ct(e.topic, S.signal), h = !!e.previousTurns?.length, L = {
|
|
1068
|
+
topic: g,
|
|
1002
1069
|
topicSource: e.topicSource,
|
|
1003
|
-
councilors:
|
|
1070
|
+
councilors: f,
|
|
1004
1071
|
rounds: e.rounds,
|
|
1005
|
-
onEvent:
|
|
1072
|
+
onEvent: o,
|
|
1006
1073
|
beforeTurn: y,
|
|
1007
|
-
signal:
|
|
1074
|
+
signal: S.signal,
|
|
1008
1075
|
mode: h ? "freeform" : e.mode,
|
|
1009
1076
|
config: i,
|
|
1010
1077
|
previousTurns: e.previousTurns,
|
|
1011
1078
|
previousSummary: e.previousSummary
|
|
1012
|
-
},
|
|
1079
|
+
}, d = await ht(L);
|
|
1013
1080
|
if (i.secretary?.backend)
|
|
1014
1081
|
try {
|
|
1015
|
-
|
|
1016
|
-
const
|
|
1017
|
-
result:
|
|
1082
|
+
o({ type: "summary_start" });
|
|
1083
|
+
const p = await st({
|
|
1084
|
+
result: d,
|
|
1018
1085
|
config: i,
|
|
1019
|
-
onChunk: (
|
|
1020
|
-
|
|
1086
|
+
onChunk: (m) => {
|
|
1087
|
+
o({ type: "summary_chunk", delta: m });
|
|
1021
1088
|
},
|
|
1022
|
-
signal:
|
|
1089
|
+
signal: S?.signal
|
|
1023
1090
|
});
|
|
1024
|
-
|
|
1025
|
-
} catch (
|
|
1026
|
-
|
|
1091
|
+
d.summary = p.text, p.diagram && (d.diagram = p.diagram), o({ type: "summary_complete", summary: p.text, diagram: p.diagram });
|
|
1092
|
+
} catch (p) {
|
|
1093
|
+
v.error("ipc:discussion", "Secretary summary failed", p), o({ type: "error", councilorName: "Secretary", error: p instanceof Error ? p.message : String(p) });
|
|
1027
1094
|
}
|
|
1028
1095
|
if (i.secretary?.backend)
|
|
1029
1096
|
try {
|
|
1030
|
-
const
|
|
1031
|
-
topic:
|
|
1032
|
-
firstRoundTurns:
|
|
1097
|
+
const p = d.turns.filter((x) => x.round === 1), m = await ct({
|
|
1098
|
+
topic: d.topic,
|
|
1099
|
+
firstRoundTurns: p,
|
|
1033
1100
|
config: i
|
|
1034
1101
|
});
|
|
1035
|
-
|
|
1036
|
-
} catch (
|
|
1037
|
-
|
|
1102
|
+
d.title = m, o({ type: "title_generated", title: m });
|
|
1103
|
+
} catch (p) {
|
|
1104
|
+
v.error("ipc:discussion", "Title generation failed", p);
|
|
1038
1105
|
}
|
|
1039
1106
|
if (e.infographicBackends?.length)
|
|
1040
|
-
for (const
|
|
1107
|
+
for (const p of e.infographicBackends)
|
|
1041
1108
|
try {
|
|
1042
|
-
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
} catch (
|
|
1046
|
-
|
|
1109
|
+
o({ type: "infographic_start" });
|
|
1110
|
+
const m = await ue(d, i, p);
|
|
1111
|
+
d.infographics || (d.infographics = []), d.infographics.push(m), o({ type: "infographic_complete", infographic: m });
|
|
1112
|
+
} catch (m) {
|
|
1113
|
+
v.error("ipc:discussion", `Infographic generation failed (${p})`, m), o({ type: "infographic_error", error: m instanceof Error ? m.message : String(m) });
|
|
1047
1114
|
}
|
|
1048
|
-
e.continuedFrom && (
|
|
1115
|
+
e.continuedFrom && (d.continuedFrom = e.continuedFrom), o({ type: "complete", result: d });
|
|
1049
1116
|
try {
|
|
1050
|
-
await
|
|
1051
|
-
} catch (
|
|
1052
|
-
|
|
1117
|
+
await yt(d);
|
|
1118
|
+
} catch (p) {
|
|
1119
|
+
v.error("ipc:discussion", "Failed to save to history", p);
|
|
1053
1120
|
}
|
|
1054
1121
|
} catch (a) {
|
|
1055
|
-
|
|
1122
|
+
v.error("ipc:discussion", "Discussion failed", a), o({ type: "error", councilorName: "", error: a instanceof Error ? a.message : String(a) });
|
|
1056
1123
|
} finally {
|
|
1057
|
-
|
|
1124
|
+
S = null;
|
|
1058
1125
|
}
|
|
1059
|
-
}),
|
|
1060
|
-
te.showItemInFolder(
|
|
1061
|
-
}),
|
|
1062
|
-
await
|
|
1063
|
-
}),
|
|
1064
|
-
const r =
|
|
1126
|
+
}), n.handle("discussion:stop", async () => (S && (S.abort(), S = null), { success: !0 })), n.handle("discussion:inject", async (t, e) => (B.push(e), { success: !0 })), n.handle("registry:add-local", async (t, e) => Je(e)), n.handle("registry:add-remote", async (t, e) => ze(e)), n.handle("registry:remove", async (t, e, r) => (await Ve(e, r), { success: !0 })), n.handle("shell:open-in-finder", async (t, e) => {
|
|
1127
|
+
te.showItemInFolder(u(e, "ABOUT.md"));
|
|
1128
|
+
}), n.handle("shell:open-in-terminal", async (t, e) => {
|
|
1129
|
+
await T(R)("open", ["-a", "Terminal", e]);
|
|
1130
|
+
}), n.handle("shell:open-in-editor", async (t, e) => {
|
|
1131
|
+
const r = T(R);
|
|
1065
1132
|
try {
|
|
1066
1133
|
await r("code", [e]);
|
|
1067
1134
|
} catch {
|
|
1068
1135
|
te.openPath(e);
|
|
1069
1136
|
}
|
|
1070
|
-
}),
|
|
1071
|
-
const
|
|
1137
|
+
}), n.handle("history:list", async () => wt()), n.handle("history:get", async (t, e) => le(e)), n.handle("history:delete", async (t, e) => (await bt(e), { success: !0 })), n.handle("infographic:generate", async (t, e, r) => {
|
|
1138
|
+
const o = u(b(), ".ai-council", "config.json");
|
|
1072
1139
|
let a = { backends: {} };
|
|
1073
1140
|
try {
|
|
1074
|
-
const c = await w(
|
|
1141
|
+
const c = await w(o, "utf-8");
|
|
1075
1142
|
a = JSON.parse(c);
|
|
1076
1143
|
} catch {
|
|
1077
1144
|
}
|
|
1078
|
-
const i = await le(e),
|
|
1079
|
-
return await
|
|
1080
|
-
}),
|
|
1081
|
-
const r =
|
|
1145
|
+
const i = await le(e), l = await ue(i, a, r);
|
|
1146
|
+
return await vt(e, l), { infographic: l };
|
|
1147
|
+
}), n.handle("infographic:delete", async (t, e, r) => (await kt(e, r), { success: !0 })), n.handle("file:read-as-text", async (t, e) => {
|
|
1148
|
+
const r = P(e), o = r.includes(".") ? "." + r.split(".").pop().toLowerCase() : "", a = /* @__PURE__ */ new Set([
|
|
1082
1149
|
".txt",
|
|
1083
1150
|
".md",
|
|
1084
1151
|
".csv",
|
|
@@ -1126,41 +1193,41 @@ function It(o, s) {
|
|
|
1126
1193
|
".epub",
|
|
1127
1194
|
".rtf"
|
|
1128
1195
|
]);
|
|
1129
|
-
if (a.has(
|
|
1196
|
+
if (a.has(o))
|
|
1130
1197
|
try {
|
|
1131
|
-
const
|
|
1132
|
-
return { name: r, content:
|
|
1133
|
-
} catch (
|
|
1134
|
-
return { name: r, content: `[Error reading file: ${
|
|
1198
|
+
const l = await w(e, "utf-8");
|
|
1199
|
+
return { name: r, content: l };
|
|
1200
|
+
} catch (l) {
|
|
1201
|
+
return { name: r, content: `[Error reading file: ${l instanceof Error ? l.message : String(l)}]` };
|
|
1135
1202
|
}
|
|
1136
|
-
if (i.has(
|
|
1137
|
-
const
|
|
1203
|
+
if (i.has(o)) {
|
|
1204
|
+
const l = T(R);
|
|
1138
1205
|
try {
|
|
1139
|
-
const { stdout: c } = await
|
|
1206
|
+
const { stdout: c } = await l("markitdown", [e], {
|
|
1140
1207
|
timeout: 3e4,
|
|
1141
1208
|
maxBuffer: 10485760
|
|
1142
1209
|
// 10 MB
|
|
1143
1210
|
});
|
|
1144
1211
|
return { name: r, content: c };
|
|
1145
1212
|
} catch (c) {
|
|
1146
|
-
const
|
|
1147
|
-
return
|
|
1213
|
+
const f = c instanceof Error ? c.message : String(c);
|
|
1214
|
+
return f.includes("ENOENT") ? {
|
|
1148
1215
|
name: r,
|
|
1149
|
-
content: `[Cannot convert ${
|
|
1150
|
-
} : { name: r, content: `[Error converting file: ${
|
|
1216
|
+
content: `[Cannot convert ${o} file: markitdown is not installed. Run: pip install 'markitdown[all]']`
|
|
1217
|
+
} : { name: r, content: `[Error converting file: ${f}]` };
|
|
1151
1218
|
}
|
|
1152
1219
|
}
|
|
1153
1220
|
return { name: r, content: `[Unsupported file type: ${r}]` };
|
|
1154
|
-
}),
|
|
1155
|
-
const t =
|
|
1221
|
+
}), n.handle("markitdown:check", async () => {
|
|
1222
|
+
const t = T(R);
|
|
1156
1223
|
try {
|
|
1157
1224
|
const { stdout: e } = await t("markitdown", ["--version"], { timeout: 5e3 });
|
|
1158
1225
|
return { installed: !0, version: e.trim() };
|
|
1159
1226
|
} catch {
|
|
1160
1227
|
return { installed: !1 };
|
|
1161
1228
|
}
|
|
1162
|
-
}),
|
|
1163
|
-
const t =
|
|
1229
|
+
}), n.handle("markitdown:install", async () => {
|
|
1230
|
+
const t = T(R);
|
|
1164
1231
|
try {
|
|
1165
1232
|
return await t("pip", ["install", "markitdown[all]"], {
|
|
1166
1233
|
timeout: 12e4,
|
|
@@ -1169,7 +1236,7 @@ function It(o, s) {
|
|
|
1169
1236
|
} catch (e) {
|
|
1170
1237
|
return { success: !1, error: e instanceof Error ? e.message : String(e) };
|
|
1171
1238
|
}
|
|
1172
|
-
}),
|
|
1239
|
+
}), n.handle("dialog:selectDirectory", async () => {
|
|
1173
1240
|
const t = s();
|
|
1174
1241
|
if (!t) return null;
|
|
1175
1242
|
const e = await Ee.showOpenDialog(t, {
|
|
@@ -1178,68 +1245,68 @@ function It(o, s) {
|
|
|
1178
1245
|
return e.canceled ? null : e.filePaths[0];
|
|
1179
1246
|
});
|
|
1180
1247
|
}
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
const
|
|
1184
|
-
function $(
|
|
1185
|
-
const t = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${
|
|
1248
|
+
const Rt = Oe(import.meta.url), J = $e(Rt), ke = u(b(), ".ai-council");
|
|
1249
|
+
Ce(ke, { recursive: !0 });
|
|
1250
|
+
const _e = u(ke, "electron-debug.log");
|
|
1251
|
+
function $(n, ...s) {
|
|
1252
|
+
const t = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${n}] ${s.map((e) => typeof e == "string" ? e : JSON.stringify(e)).join(" ")}
|
|
1186
1253
|
`;
|
|
1187
|
-
Ne(
|
|
1254
|
+
Ne(_e, t);
|
|
1188
1255
|
}
|
|
1189
|
-
|
|
1256
|
+
xe(_e, `=== State Change Council Electron — started ${(/* @__PURE__ */ new Date()).toISOString()} ===
|
|
1190
1257
|
`);
|
|
1191
|
-
|
|
1192
|
-
let
|
|
1193
|
-
function
|
|
1194
|
-
$("main", "Creating BrowserWindow"),
|
|
1258
|
+
D.name = "State Change Council";
|
|
1259
|
+
let E = null;
|
|
1260
|
+
function pe() {
|
|
1261
|
+
$("main", "Creating BrowserWindow"), E = new he({
|
|
1195
1262
|
width: 1200,
|
|
1196
1263
|
height: 800,
|
|
1197
1264
|
minWidth: 800,
|
|
1198
1265
|
minHeight: 600,
|
|
1199
1266
|
title: "State Change Council",
|
|
1200
|
-
icon:
|
|
1267
|
+
icon: F(J, "..", "assets", "icon.png"),
|
|
1201
1268
|
webPreferences: {
|
|
1202
1269
|
contextIsolation: !0,
|
|
1203
1270
|
nodeIntegration: !1,
|
|
1204
|
-
preload:
|
|
1271
|
+
preload: u(J, "preload.mjs")
|
|
1205
1272
|
}
|
|
1206
|
-
}),
|
|
1273
|
+
}), E.webContents.on("console-message", (s, t, e, r, o) => {
|
|
1207
1274
|
const a = ["DEBUG", "INFO", "WARN", "ERROR"][t] || "LOG";
|
|
1208
|
-
$(`renderer:${a}`, `${e} (${
|
|
1209
|
-
}),
|
|
1275
|
+
$(`renderer:${a}`, `${e} (${o}:${r})`);
|
|
1276
|
+
}), E.webContents.on("render-process-gone", (s, t) => {
|
|
1210
1277
|
$("main:CRASH", "Renderer process gone:", t);
|
|
1211
|
-
}),
|
|
1278
|
+
}), E.webContents.on("did-fail-load", (s, t, e) => {
|
|
1212
1279
|
$("main:LOAD_ERROR", `Failed to load: ${t} ${e}`);
|
|
1213
1280
|
});
|
|
1214
|
-
const
|
|
1215
|
-
if (
|
|
1216
|
-
$("main", `Loading dev server URL: ${
|
|
1281
|
+
const n = process.env.VITE_DEV_SERVER_URL;
|
|
1282
|
+
if (n)
|
|
1283
|
+
$("main", `Loading dev server URL: ${n}`), E.loadURL(n);
|
|
1217
1284
|
else {
|
|
1218
|
-
const s =
|
|
1219
|
-
$("main", `Loading file: ${s}`),
|
|
1285
|
+
const s = u(J, "../dist-renderer/index.html");
|
|
1286
|
+
$("main", `Loading file: ${s}`), E.loadFile(s);
|
|
1220
1287
|
}
|
|
1221
|
-
process.env.VITE_DEV_SERVER_URL &&
|
|
1222
|
-
|
|
1288
|
+
process.env.VITE_DEV_SERVER_URL && E.webContents.openDevTools(), E.on("closed", () => {
|
|
1289
|
+
E = null;
|
|
1223
1290
|
});
|
|
1224
1291
|
}
|
|
1225
|
-
|
|
1292
|
+
fe.registerSchemesAsPrivileged([
|
|
1226
1293
|
{ scheme: "council-file", privileges: { bypassCSP: !0, supportFetchAPI: !0 } }
|
|
1227
1294
|
]);
|
|
1228
|
-
|
|
1295
|
+
D.whenReady().then(() => {
|
|
1229
1296
|
$("main", "App ready, registering IPC handlers");
|
|
1230
|
-
const
|
|
1297
|
+
const n = "State Change Council", s = [
|
|
1231
1298
|
{
|
|
1232
|
-
label:
|
|
1299
|
+
label: n,
|
|
1233
1300
|
submenu: [
|
|
1234
|
-
{ role: "about", label: `About ${
|
|
1301
|
+
{ role: "about", label: `About ${n}` },
|
|
1235
1302
|
{ type: "separator" },
|
|
1236
1303
|
{ role: "services" },
|
|
1237
1304
|
{ type: "separator" },
|
|
1238
|
-
{ role: "hide", label: `Hide ${
|
|
1305
|
+
{ role: "hide", label: `Hide ${n}` },
|
|
1239
1306
|
{ role: "hideOthers" },
|
|
1240
1307
|
{ role: "unhide" },
|
|
1241
1308
|
{ type: "separator" },
|
|
1242
|
-
{ role: "quit", label: `Quit ${
|
|
1309
|
+
{ role: "quit", label: `Quit ${n}` }
|
|
1243
1310
|
]
|
|
1244
1311
|
},
|
|
1245
1312
|
{ role: "fileMenu" },
|
|
@@ -1247,13 +1314,13 @@ L.whenReady().then(() => {
|
|
|
1247
1314
|
{ role: "viewMenu" },
|
|
1248
1315
|
{ role: "windowMenu" }
|
|
1249
1316
|
];
|
|
1250
|
-
ne.setApplicationMenu(ne.buildFromTemplate(s)),
|
|
1317
|
+
ne.setApplicationMenu(ne.buildFromTemplate(s)), fe.handle("council-file", (t) => {
|
|
1251
1318
|
const e = decodeURIComponent(t.url.replace("council-file://", ""));
|
|
1252
|
-
return
|
|
1253
|
-
}),
|
|
1254
|
-
|
|
1319
|
+
return Ae.fetch(Pe(e).href);
|
|
1320
|
+
}), Nt(Ie, () => E), pe(), D.on("activate", () => {
|
|
1321
|
+
he.getAllWindows().length === 0 && pe();
|
|
1255
1322
|
});
|
|
1256
1323
|
});
|
|
1257
|
-
|
|
1258
|
-
process.platform !== "darwin" &&
|
|
1324
|
+
D.on("window-all-closed", () => {
|
|
1325
|
+
process.platform !== "darwin" && D.quit();
|
|
1259
1326
|
});
|