crewx 0.8.1 → 0.8.2-rc.2

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 (125) hide show
  1. package/README.md +268 -268
  2. package/bin/cli-commands.js +34 -0
  3. package/bin/crewx-lib.js +213 -108
  4. package/bin/crewx-ui.js +83 -83
  5. package/bin/crewx.js +219 -147
  6. package/bin/launcher-flags.js +29 -0
  7. package/bin/package.json +1 -1
  8. package/dist/assets/MarketPage-DptjaFpT.js +36 -0
  9. package/dist/assets/{PromptTab-DVKc7hJY.js → PromptTab-DZha2_v1.js} +1 -1
  10. package/dist/assets/{_baseUniq-wjlVo2E6.js → _baseUniq-jd6NubI3.js} +1 -1
  11. package/dist/assets/{arc-BfPgRtzW.js → arc-C2te3-8P.js} +1 -1
  12. package/dist/assets/{architectureDiagram-Q4EWVU46-ewcueFAG.js → architectureDiagram-Q4EWVU46-CbIQua02.js} +1 -1
  13. package/dist/assets/{blockDiagram-DXYQGD6D-TxlbbvKn.js → blockDiagram-DXYQGD6D-Cg7qkpSM.js} +1 -1
  14. package/dist/assets/{c4Diagram-AHTNJAMY-C1lT_bl_.js → c4Diagram-AHTNJAMY-BkffDY1F.js} +1 -1
  15. package/dist/assets/channel-beae0DeI.js +1 -0
  16. package/dist/assets/chatgpt-logo-dark.svg +15 -15
  17. package/dist/assets/chatgpt-logo.svg +15 -15
  18. package/dist/assets/{chunk-4BX2VUAB-C41j2mCL.js → chunk-4BX2VUAB-BxHe9wPE.js} +1 -1
  19. package/dist/assets/{chunk-4TB4RGXK-HNNsUbz0.js → chunk-4TB4RGXK--f1tN90O.js} +1 -1
  20. package/dist/assets/{chunk-55IACEB6-qtCgO0r2.js → chunk-55IACEB6-B5QXfPXQ.js} +1 -1
  21. package/dist/assets/{chunk-EDXVE4YY-BSnDYtsd.js → chunk-EDXVE4YY-DqKhblOg.js} +1 -1
  22. package/dist/assets/{chunk-FMBD7UC4-DyHRLQqX.js → chunk-FMBD7UC4-DZ1w_G02.js} +1 -1
  23. package/dist/assets/{chunk-OYMX7WX6-CCjfi6WS.js → chunk-OYMX7WX6-BqAgQpv8.js} +1 -1
  24. package/dist/assets/{chunk-QZHKN3VN-COLty8kd.js → chunk-QZHKN3VN-DPqnGqVi.js} +1 -1
  25. package/dist/assets/{chunk-YZCP3GAM-CHUUnGeN.js → chunk-YZCP3GAM-x-ZYSQLd.js} +1 -1
  26. package/dist/assets/classDiagram-6PBFFD2Q-BquWrs1y.js +1 -0
  27. package/dist/assets/classDiagram-v2-HSJHXN6E-BquWrs1y.js +1 -0
  28. package/dist/assets/clone-C9wSPtDN.js +1 -0
  29. package/dist/assets/{cose-bilkent-S5V4N54A-CSip-V2g.js → cose-bilkent-S5V4N54A-4VCNRP-E.js} +1 -1
  30. package/dist/assets/{dagre-KV5264BT-DkdpnWhv.js → dagre-KV5264BT-DucVi1QS.js} +1 -1
  31. package/dist/assets/{diagram-5BDNPKRD-PH4qc6PV.js → diagram-5BDNPKRD-ChdRA8bE.js} +1 -1
  32. package/dist/assets/{diagram-G4DWMVQ6-Cg5xZcjx.js → diagram-G4DWMVQ6-B1-97yHr.js} +1 -1
  33. package/dist/assets/{diagram-MMDJMWI5-soKmeTCW.js → diagram-MMDJMWI5-CQs3cO7G.js} +1 -1
  34. package/dist/assets/{diagram-TYMM5635-Daq5Mihu.js → diagram-TYMM5635-CuNCxDfO.js} +1 -1
  35. package/dist/assets/{erDiagram-SMLLAGMA-kr2OtY0Y.js → erDiagram-SMLLAGMA-DdR8v8g-.js} +1 -1
  36. package/dist/assets/{flowDiagram-DWJPFMVM-DQZCb8gm.js → flowDiagram-DWJPFMVM-Dt02upId.js} +1 -1
  37. package/dist/assets/{ganttDiagram-T4ZO3ILL-BHkn485T.js → ganttDiagram-T4ZO3ILL-cG_k9VOa.js} +1 -1
  38. package/dist/assets/{gitGraphDiagram-UUTBAWPF-FaCyYFmC.js → gitGraphDiagram-UUTBAWPF-Dz1DjhKq.js} +1 -1
  39. package/dist/assets/{graph-BVJlrP6V.js → graph-CF2NtM33.js} +1 -1
  40. package/dist/assets/{infoDiagram-42DDH7IO-DJOWkKdM.js → infoDiagram-42DDH7IO-tQWKrYM6.js} +1 -1
  41. package/dist/assets/{ishikawaDiagram-UXIWVN3A-VfpvNaIf.js → ishikawaDiagram-UXIWVN3A-CLuUMkF0.js} +1 -1
  42. package/dist/assets/{journeyDiagram-VCZTEJTY-CPzsak-v.js → journeyDiagram-VCZTEJTY-a6JenLCk.js} +1 -1
  43. package/dist/assets/{kanban-definition-6JOO6SKY-DFqLDBU0.js → kanban-definition-6JOO6SKY-rqOxTzYb.js} +1 -1
  44. package/dist/assets/{layout-CCSbNPHm.js → layout-Dvic1Hpy.js} +1 -1
  45. package/dist/assets/{linear-C4T7PCKE.js → linear-CfMV1S6a.js} +1 -1
  46. package/dist/assets/main-05K4ggqd.css +10 -0
  47. package/dist/assets/main-CCM1gtr8.js +1165 -0
  48. package/dist/assets/{min-CGQNEYGh.js → min-GpF3DZux.js} +1 -1
  49. package/dist/assets/{mindmap-definition-QFDTVHPH-AuU1EqwS.js → mindmap-definition-QFDTVHPH-Cg80z0Jx.js} +1 -1
  50. package/dist/assets/{pieDiagram-DEJITSTG-CopkCZwp.js → pieDiagram-DEJITSTG-BrtK7lAq.js} +1 -1
  51. package/dist/assets/{quadrantDiagram-34T5L4WZ-lMKrSv_t.js → quadrantDiagram-34T5L4WZ-BL2txAAS.js} +1 -1
  52. package/dist/assets/{requirementDiagram-MS252O5E-dWUpHOFb.js → requirementDiagram-MS252O5E-Co3wpBnu.js} +1 -1
  53. package/dist/assets/{sankeyDiagram-XADWPNL6-C8UQx9Bb.js → sankeyDiagram-XADWPNL6-B4KJXdQ4.js} +1 -1
  54. package/dist/assets/{sequenceDiagram-FGHM5R23-CUVNIItJ.js → sequenceDiagram-FGHM5R23-xs5OuzvV.js} +1 -1
  55. package/dist/assets/{stateDiagram-FHFEXIEX-Ct0GamGl.js → stateDiagram-FHFEXIEX-bbEP20JD.js} +1 -1
  56. package/dist/assets/stateDiagram-v2-QKLJ7IA2-XYh9U1A7.js +1 -0
  57. package/dist/assets/{timeline-definition-GMOUNBTQ-ul8Po7f7.js → timeline-definition-GMOUNBTQ-CTc2wVwC.js} +1 -1
  58. package/dist/assets/{vennDiagram-DHZGUBPP-B4AOWQnP.js → vennDiagram-DHZGUBPP-oJpXott7.js} +1 -1
  59. package/dist/assets/{wardley-RL74JXVD-Dr7Wp3AJ.js → wardley-RL74JXVD-aTmOXkKh.js} +1 -1
  60. package/dist/assets/{wardleyDiagram-NUSXRM2D-Ck70faXX.js → wardleyDiagram-NUSXRM2D-C83SOkig.js} +1 -1
  61. package/dist/assets/{xychartDiagram-5P7HB3ND-Bsy5-cNt.js → xychartDiagram-5P7HB3ND-BScws0tF.js} +1 -1
  62. package/dist/index.html +13 -13
  63. package/dist-electron/main.js +153 -116
  64. package/dist-electron/overlay.js +102 -65
  65. package/dist-electron/package.json +1 -0
  66. package/dist-electron/preload.js +8 -8
  67. package/dist-server/bootstrap/crewx-server.js +19 -10
  68. package/dist-server/domain/agent/agent.service.js +12 -0
  69. package/dist-server/domain/agent/dto/update-agent.dto.js +20 -1
  70. package/dist-server/domain/mcp/crewx-tool.factory.js +44 -113
  71. package/dist-server/domain/mcp/mcp.module.js +2 -0
  72. package/dist-server/domain/mcp/mcp.service.js +37 -12
  73. package/dist-server/domain/message/message.service.js +21 -13
  74. package/dist-server/domain/skill/skill.service.js +63 -43
  75. package/dist-server/domain/task/task.module.js +2 -0
  76. package/dist-server/domain/task/task.service.js +17 -10
  77. package/dist-server/domain/thread/dto/update-thread.dto.js +23 -0
  78. package/dist-server/domain/thread/thread.controller.js +16 -0
  79. package/dist-server/domain/thread/thread.service.js +9 -0
  80. package/dist-server/main.js +1 -1
  81. package/dist-server/modules/crewx.module.js +16 -1
  82. package/dist-server/repository/box.repository.js +20 -20
  83. package/dist-server/repository/project.repository.js +13 -13
  84. package/dist-server/repository/request-log.repository.js +10 -10
  85. package/dist-server/repository/task.repository.js +72 -72
  86. package/dist-server/repository/thread.repository.js +78 -58
  87. package/package.json +6 -6
  88. package/packages/cli/dist/bootstrap/crewx-cli.js +12 -0
  89. package/packages/cli/dist/commands/agent.js +23 -23
  90. package/packages/cli/dist/commands/init.js +19 -19
  91. package/packages/cli/dist/commands/parse-common-flags.d.ts +19 -3
  92. package/packages/cli/dist/commands/parse-common-flags.js +46 -6
  93. package/packages/cli/dist/commands/registry.d.ts +13 -0
  94. package/packages/cli/dist/commands/registry.js +29 -0
  95. package/packages/cli/dist/commands/task-db.js +7 -7
  96. package/packages/cli/dist/examples/deny-secrets-plugin.d.ts +22 -0
  97. package/packages/cli/dist/examples/deny-secrets-plugin.js +40 -0
  98. package/packages/cli/dist/main.js +134 -68
  99. package/packages/cli/dist/plugins/examples/echo-hook.d.ts +24 -0
  100. package/packages/cli/dist/plugins/examples/echo-hook.js +60 -0
  101. package/packages/cli/dist/plugins/examples/verify-echo-hook.d.ts +8 -0
  102. package/packages/cli/dist/plugins/examples/verify-echo-hook.js +47 -0
  103. package/packages/cli/dist/plugins/sqlite-tracing.d.ts +11 -0
  104. package/packages/cli/dist/plugins/sqlite-tracing.js +19 -0
  105. package/packages/cli/dist/schema/tasks.d.ts +7 -0
  106. package/packages/cli/dist/schema/tasks.js +48 -0
  107. package/packages/cli/package.json +52 -52
  108. package/scripts/analyze-task-logs.mjs +569 -0
  109. package/scripts/build-manual.mjs +266 -266
  110. package/scripts/emit-dist-server-package-json.mjs +7 -7
  111. package/scripts/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  112. package/scripts/postinstall.mjs +44 -44
  113. package/scripts/smoke-tarball.mjs +285 -285
  114. package/scripts/snapshot-msg-list.sh +52 -52
  115. package/server.js +167 -164
  116. package/dist/assets/MarketPage-Dwsg6K-B.js +0 -31
  117. package/dist/assets/channel-BP4PNMmz.js +0 -1
  118. package/dist/assets/classDiagram-6PBFFD2Q-Upr3UAcM.js +0 -1
  119. package/dist/assets/classDiagram-v2-HSJHXN6E-Upr3UAcM.js +0 -1
  120. package/dist/assets/clone-B8BP7ReZ.js +0 -1
  121. package/dist/assets/main-CELBpK6r.js +0 -1166
  122. package/dist/assets/main-CmP-VosD.css +0 -10
  123. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CFBLQDEx.js +0 -1
  124. package/dist-server/domain/task/dto/project-usage.dto.js +0 -38
  125. package/dist-server/domain/thread/dto/send-message.dto.js +0 -10
@@ -1,157 +1,194 @@
1
- import { ipcMain as u, desktopCapturer as R, app as c, globalShortcut as j, nativeImage as I, BrowserWindow as y, screen as T } from "electron";
2
- import a from "path";
3
- import k from "fs";
4
- import { spawn as g } from "child_process";
5
- import { fileURLToPath as C } from "url";
6
- const U = C(import.meta.url), m = a.dirname(U), D = a.join(m, "..");
7
- let i = null, e = null, h = 0, n = null;
8
- async function L() {
9
- return new Promise((r, t) => {
10
- var b, P;
11
- const o = a.join(m, ".."), d = a.join(o, "dist-server", "src", "server", "main.js"), x = a.join(o, "src", "server", "main.ts"), S = !k.existsSync(d), v = S ? x : d, f = {
12
- ...process.env,
13
- PORT: "0",
14
- // Random port
15
- ELECTRON_MODE: "true",
16
- // Enable static file serving
17
- SERVE_STATIC: "true"
18
- };
19
- if (S) {
20
- const s = process.platform === "win32", l = `node --import @swc-node/register/esm-register "${v}"`;
21
- if (s)
22
- n = g("cmd.exe", ["/c", l], {
23
- cwd: o,
24
- env: f,
25
- stdio: ["pipe", "pipe", "pipe"]
26
- });
27
- else {
28
- const p = process.env.SHELL || "/bin/zsh";
29
- n = g(p, ["-i", "-c", l], {
30
- cwd: o,
31
- env: f,
32
- stdio: ["pipe", "pipe", "pipe"]
33
- });
1
+ import { ipcMain, desktopCapturer, app, globalShortcut, nativeImage, BrowserWindow, screen } from "electron";
2
+ import path from "path";
3
+ import { spawn } from "child_process";
4
+ import { fileURLToPath } from "url";
5
+ const __filename$1 = fileURLToPath(import.meta.url);
6
+ const __dirname$1 = path.dirname(__filename$1);
7
+ const projectRoot = path.join(__dirname$1, "..");
8
+ let mainWindow = null;
9
+ let overlayWindow = null;
10
+ let serverPort = 0;
11
+ let serverProcess = null;
12
+ async function startNestServer() {
13
+ return new Promise((resolve, reject) => {
14
+ var _a, _b;
15
+ const isDev = process.env.NODE_ENV !== "production";
16
+ const projectRoot2 = path.join(__dirname$1, "..");
17
+ const serverScript = isDev ? path.join(projectRoot2, "src", "server", "main.ts") : path.join(projectRoot2, "dist-server", "main.js");
18
+ const nodeCmd = isDev ? `node --import @swc-node/register/esm-register "${serverScript}"` : `node "${serverScript}"`;
19
+ const shell = process.env.SHELL || "/bin/zsh";
20
+ serverProcess = spawn(shell, ["-i", "-c", nodeCmd], {
21
+ cwd: projectRoot2,
22
+ env: {
23
+ ...process.env,
24
+ PORT: "0",
25
+ // Random port
26
+ ELECTRON_MODE: "true"
27
+ // Enable static file serving
28
+ },
29
+ stdio: ["pipe", "pipe", "pipe"]
30
+ });
31
+ (_a = serverProcess.stdout) == null ? void 0 : _a.on("data", (data) => {
32
+ const output = data.toString();
33
+ console.log("[Server]", output);
34
+ const portMatch = output.match(/localhost:(\d+)|port\s*:?\s*(\d+)/i);
35
+ if (portMatch) {
36
+ const port = parseInt(portMatch[1] || portMatch[2], 10);
37
+ if (port > 0) {
38
+ serverPort = port;
39
+ resolve(port);
40
+ }
34
41
  }
35
- } else
36
- n = g(process.execPath, [v], {
37
- cwd: o,
38
- env: f,
39
- stdio: ["pipe", "pipe", "pipe"]
40
- });
41
- (b = n.stdout) == null || b.on("data", (s) => {
42
- const l = s.toString();
43
- console.log("[Server]", l);
44
- const p = l.match(/localhost:(\d+)|port\s*:?\s*(\d+)/i);
45
- if (p) {
46
- const w = parseInt(p[1] || p[2], 10);
47
- w > 0 && (h = w, r(w));
42
+ });
43
+ (_b = serverProcess.stderr) == null ? void 0 : _b.on("data", (data) => {
44
+ console.error("[Server Error]", data.toString());
45
+ });
46
+ serverProcess.on("error", (err) => {
47
+ console.error("Failed to start server:", err);
48
+ reject(err);
49
+ });
50
+ serverProcess.on("exit", (code) => {
51
+ console.log(`Server process exited with code ${code}`);
52
+ });
53
+ setTimeout(() => {
54
+ if (serverPort === 0) {
55
+ reject(new Error("Server startup timeout"));
48
56
  }
49
- }), (P = n.stderr) == null || P.on("data", (s) => {
50
- console.error("[Server Error]", s.toString());
51
- }), n.on("error", (s) => {
52
- console.error("Failed to start server:", s), t(s);
53
- }), n.on("exit", (s) => {
54
- console.log(`Server process exited with code ${s}`);
55
- }), setTimeout(() => {
56
- h === 0 && t(new Error("Server startup timeout"));
57
57
  }, 3e4);
58
58
  });
59
59
  }
60
- function E() {
61
- i = new y({
60
+ function createWindow() {
61
+ mainWindow = new BrowserWindow({
62
62
  width: 1200,
63
63
  height: 800,
64
64
  minWidth: 1e3,
65
65
  minHeight: 700,
66
- icon: a.join(D, "public", "assets", "crewx-icon-256.png"),
66
+ icon: path.join(projectRoot, "public", "assets", "crewx-icon-256.png"),
67
67
  webPreferences: {
68
- nodeIntegration: !1,
69
- contextIsolation: !0,
70
- preload: a.join(m, "preload.mjs")
68
+ nodeIntegration: false,
69
+ contextIsolation: true,
70
+ preload: path.join(__dirname$1, "preload.mjs")
71
71
  },
72
72
  titleBarStyle: "hiddenInset",
73
73
  backgroundColor: "#F9FAFB",
74
- show: !1
75
- }), i.loadURL(`http://localhost:${h}`), i.once("ready-to-show", () => {
76
- i == null || i.show();
77
- }), i.on("closed", () => {
78
- i = null;
74
+ show: false
75
+ });
76
+ mainWindow.loadURL(`http://localhost:${serverPort}`);
77
+ mainWindow.once("ready-to-show", () => {
78
+ mainWindow == null ? void 0 : mainWindow.show();
79
+ });
80
+ mainWindow.on("closed", () => {
81
+ mainWindow = null;
79
82
  });
80
83
  }
81
- function _() {
82
- const { width: r } = T.getPrimaryDisplay().workAreaSize, t = 400, o = Math.round((r - t) / 2);
83
- e = new y({
84
- width: t,
84
+ function createOverlayWindow() {
85
+ const { width: screenWidth } = screen.getPrimaryDisplay().workAreaSize;
86
+ const winWidth = 400;
87
+ const x = Math.round((screenWidth - winWidth) / 2);
88
+ overlayWindow = new BrowserWindow({
89
+ width: winWidth,
85
90
  height: 60,
86
- x: o,
91
+ x,
87
92
  y: 40,
88
- transparent: !0,
89
- alwaysOnTop: !0,
90
- frame: !1,
91
- hasShadow: !1,
92
- skipTaskbar: !0,
93
- resizable: !1,
93
+ transparent: true,
94
+ alwaysOnTop: true,
95
+ frame: false,
96
+ hasShadow: false,
97
+ skipTaskbar: true,
98
+ resizable: false,
94
99
  webPreferences: {
95
- nodeIntegration: !1,
96
- contextIsolation: !0,
97
- preload: a.join(m, "preload.mjs")
100
+ nodeIntegration: false,
101
+ contextIsolation: true,
102
+ preload: path.join(__dirname$1, "preload.mjs")
98
103
  },
99
104
  backgroundColor: "#00000000",
100
- show: !1
101
- }), e.loadURL(`http://localhost:${h}/overlay.html`), e.once("ready-to-show", () => {
102
- e == null || e.show();
103
- }), e.on("closed", () => {
104
- e = null;
105
- }), j.register("CommandOrControl+Shift+Space", () => {
106
- e && (e.isVisible() ? e.hide() : (e.show(), e.focus()));
105
+ show: false
106
+ });
107
+ overlayWindow.loadURL(`http://localhost:${serverPort}/overlay.html`);
108
+ overlayWindow.once("ready-to-show", () => {
109
+ overlayWindow == null ? void 0 : overlayWindow.show();
110
+ });
111
+ overlayWindow.on("closed", () => {
112
+ overlayWindow = null;
113
+ });
114
+ globalShortcut.register("CommandOrControl+Shift+Space", () => {
115
+ if (!overlayWindow) return;
116
+ if (overlayWindow.isVisible()) {
117
+ overlayWindow.hide();
118
+ } else {
119
+ overlayWindow.show();
120
+ overlayWindow.focus();
121
+ }
107
122
  });
108
123
  }
109
- u.on("overlay:toggle", () => {
110
- e && (e.isVisible() ? e.hide() : (e.show(), e.focus()));
124
+ ipcMain.on("overlay:toggle", () => {
125
+ if (!overlayWindow) return;
126
+ if (overlayWindow.isVisible()) {
127
+ overlayWindow.hide();
128
+ } else {
129
+ overlayWindow.show();
130
+ overlayWindow.focus();
131
+ }
111
132
  });
112
- u.on("overlay:close", () => {
113
- e == null || e.hide();
133
+ ipcMain.on("overlay:close", () => {
134
+ overlayWindow == null ? void 0 : overlayWindow.hide();
114
135
  });
115
- u.on("overlay:move", (r, { x: t, y: o }) => {
116
- e == null || e.setPosition(Math.round(t), Math.round(o));
136
+ ipcMain.on("overlay:move", (_event, { x, y }) => {
137
+ overlayWindow == null ? void 0 : overlayWindow.setPosition(Math.round(x), Math.round(y));
117
138
  });
118
- u.handle("capture-screen", async () => {
119
- const r = (e == null ? void 0 : e.isVisible()) ?? !1;
139
+ ipcMain.handle("capture-screen", async () => {
140
+ const wasVisible = (overlayWindow == null ? void 0 : overlayWindow.isVisible()) ?? false;
120
141
  try {
121
- r && (e == null || e.hide()), await new Promise((d) => setTimeout(d, 150));
122
- const t = await R.getSources({
142
+ if (wasVisible) overlayWindow == null ? void 0 : overlayWindow.hide();
143
+ await new Promise((resolve) => setTimeout(resolve, 150));
144
+ const sources = await desktopCapturer.getSources({
123
145
  types: ["screen"],
124
146
  thumbnailSize: { width: 1920, height: 1080 }
125
147
  });
126
- return t.length === 0 ? { success: !1, imageDataUrl: "", timestamp: Date.now() } : { success: !0, imageDataUrl: t[0].thumbnail.toDataURL(), timestamp: Date.now() };
127
- } catch (t) {
128
- return console.error("[capture-screen] Error:", t), { success: !1, imageDataUrl: "", timestamp: Date.now() };
148
+ if (sources.length === 0) {
149
+ return { success: false, imageDataUrl: "", timestamp: Date.now() };
150
+ }
151
+ const imageDataUrl = sources[0].thumbnail.toDataURL();
152
+ return { success: true, imageDataUrl, timestamp: Date.now() };
153
+ } catch (error) {
154
+ console.error("[capture-screen] Error:", error);
155
+ return { success: false, imageDataUrl: "", timestamp: Date.now() };
129
156
  } finally {
130
- r && (e == null || e.show());
157
+ if (wasVisible) overlayWindow == null ? void 0 : overlayWindow.show();
131
158
  }
132
159
  });
133
- async function F() {
134
- var r;
160
+ async function bootstrap() {
135
161
  try {
136
162
  if (process.platform === "darwin") {
137
- const t = a.join(D, "public", "assets", "crewx-icon-512.png"), o = I.createFromPath(t);
138
- o.isEmpty() || (r = c.dock) == null || r.setIcon(o);
163
+ const iconPath = path.join(projectRoot, "public", "assets", "crewx-icon-512.png");
164
+ const icon = nativeImage.createFromPath(iconPath);
165
+ if (!icon.isEmpty()) app.dock.setIcon(icon);
139
166
  }
140
- h = await L(), E(), _();
141
- } catch (t) {
142
- console.error("Failed to start application:", t), c.quit();
167
+ serverPort = await startNestServer();
168
+ createWindow();
169
+ createOverlayWindow();
170
+ } catch (error) {
171
+ console.error("Failed to start application:", error);
172
+ app.quit();
143
173
  }
144
174
  }
145
- c.whenReady().then(F);
146
- c.on("window-all-closed", () => {
147
- process.platform !== "darwin" && c.quit();
175
+ app.whenReady().then(bootstrap);
176
+ app.on("window-all-closed", () => {
177
+ if (process.platform !== "darwin") {
178
+ app.quit();
179
+ }
148
180
  });
149
- c.on("will-quit", () => {
150
- j.unregisterAll();
181
+ app.on("will-quit", () => {
182
+ globalShortcut.unregisterAll();
151
183
  });
152
- c.on("before-quit", () => {
153
- n && (n.kill(), n = null);
184
+ app.on("before-quit", () => {
185
+ if (serverProcess) {
186
+ serverProcess.kill();
187
+ serverProcess = null;
188
+ }
154
189
  });
155
- c.on("activate", () => {
156
- i === null && E();
190
+ app.on("activate", () => {
191
+ if (mainWindow === null) {
192
+ createWindow();
193
+ }
157
194
  });
@@ -1,92 +1,129 @@
1
- import { app as t, ipcMain as u, screen as b, BrowserWindow as E } from "electron";
2
- import l from "path";
3
- import { spawn as P } from "child_process";
4
- import { fileURLToPath as _ } from "url";
5
- const j = _(import.meta.url), w = l.dirname(j);
6
- process.platform === "darwin" && t.disableHardwareAcceleration();
7
- let e = null, c = 0, r = null;
8
- async function M() {
9
- return new Promise((n, s) => {
10
- var m, f;
11
- const i = process.env.NODE_ENV !== "production", a = l.join(w, ".."), h = i ? l.join(a, "src", "server", "main.ts") : l.join(a, "dist-server", "main.js"), g = i ? `node --import @swc-node/register/esm-register "${h}"` : `node "${h}"`, S = process.env.SHELL || "/bin/zsh";
12
- r = P(S, ["-i", "-c", g], {
13
- cwd: a,
1
+ import { app, ipcMain, screen, BrowserWindow } from "electron";
2
+ import path from "path";
3
+ import { spawn } from "child_process";
4
+ import { fileURLToPath } from "url";
5
+ const __filename$1 = fileURLToPath(import.meta.url);
6
+ const __dirname$1 = path.dirname(__filename$1);
7
+ if (process.platform === "darwin") {
8
+ app.disableHardwareAcceleration();
9
+ }
10
+ let overlayWindow = null;
11
+ let serverPort = 0;
12
+ let serverProcess = null;
13
+ async function startNestServer() {
14
+ return new Promise((resolve, reject) => {
15
+ var _a, _b;
16
+ const isDev = process.env.NODE_ENV !== "production";
17
+ const projectRoot = path.join(__dirname$1, "..");
18
+ const serverScript = isDev ? path.join(projectRoot, "src", "server", "main.ts") : path.join(projectRoot, "dist-server", "main.js");
19
+ const nodeCmd = isDev ? `node --import @swc-node/register/esm-register "${serverScript}"` : `node "${serverScript}"`;
20
+ const shell = process.env.SHELL || "/bin/zsh";
21
+ serverProcess = spawn(shell, ["-i", "-c", nodeCmd], {
22
+ cwd: projectRoot,
14
23
  env: {
15
24
  ...process.env,
16
25
  PORT: "0",
17
26
  ELECTRON_MODE: "true"
18
27
  },
19
28
  stdio: ["pipe", "pipe", "pipe"]
20
- }), (m = r.stdout) == null || m.on("data", (o) => {
21
- const v = o.toString();
22
- console.log("[Server]", v);
23
- const d = v.match(/localhost:(\d+)|port\s*:?\s*(\d+)/i);
24
- if (d) {
25
- const p = parseInt(d[1] || d[2], 10);
26
- p > 0 && (c = p, n(p));
29
+ });
30
+ (_a = serverProcess.stdout) == null ? void 0 : _a.on("data", (data) => {
31
+ const output = data.toString();
32
+ console.log("[Server]", output);
33
+ const portMatch = output.match(/localhost:(\d+)|port\s*:?\s*(\d+)/i);
34
+ if (portMatch) {
35
+ const port = parseInt(portMatch[1] || portMatch[2], 10);
36
+ if (port > 0) {
37
+ serverPort = port;
38
+ resolve(port);
39
+ }
40
+ }
41
+ });
42
+ (_b = serverProcess.stderr) == null ? void 0 : _b.on("data", (data) => {
43
+ console.error("[Server Error]", data.toString());
44
+ });
45
+ serverProcess.on("error", (err) => {
46
+ console.error("Failed to start server:", err);
47
+ reject(err);
48
+ });
49
+ serverProcess.on("exit", (code) => {
50
+ console.log(`Server process exited with code ${code}`);
51
+ });
52
+ setTimeout(() => {
53
+ if (serverPort === 0) {
54
+ reject(new Error("Server startup timeout"));
27
55
  }
28
- }), (f = r.stderr) == null || f.on("data", (o) => {
29
- console.error("[Server Error]", o.toString());
30
- }), r.on("error", (o) => {
31
- console.error("Failed to start server:", o), s(o);
32
- }), r.on("exit", (o) => {
33
- console.log(`Server process exited with code ${o}`);
34
- }), setTimeout(() => {
35
- c === 0 && s(new Error("Server startup timeout"));
36
56
  }, 3e4);
37
57
  });
38
58
  }
39
- function y() {
40
- const { width: n } = b.getPrimaryDisplay().workAreaSize, s = 400, i = Math.round((n - s) / 2);
41
- e = new E({
42
- width: s,
59
+ function createOverlay() {
60
+ const { width: screenWidth } = screen.getPrimaryDisplay().workAreaSize;
61
+ const winWidth = 400;
62
+ const x = Math.round((screenWidth - winWidth) / 2);
63
+ overlayWindow = new BrowserWindow({
64
+ width: winWidth,
43
65
  height: 60,
44
- x: i,
66
+ x,
45
67
  y: 40,
46
- transparent: !0,
47
- alwaysOnTop: !0,
48
- frame: !1,
49
- hasShadow: !1,
50
- skipTaskbar: !0,
51
- resizable: !1,
68
+ transparent: true,
69
+ alwaysOnTop: true,
70
+ frame: false,
71
+ hasShadow: false,
72
+ skipTaskbar: true,
73
+ resizable: false,
52
74
  webPreferences: {
53
- nodeIntegration: !1,
54
- contextIsolation: !0,
55
- preload: l.join(w, "preload.mjs")
75
+ nodeIntegration: false,
76
+ contextIsolation: true,
77
+ preload: path.join(__dirname$1, "preload.mjs")
56
78
  },
57
79
  backgroundColor: "#00000000",
58
- show: !1
80
+ show: false
81
+ });
82
+ const overlayUrl = `http://localhost:${serverPort}/overlay.html`;
83
+ overlayWindow.loadURL(overlayUrl);
84
+ overlayWindow.once("ready-to-show", () => {
85
+ overlayWindow == null ? void 0 : overlayWindow.show();
59
86
  });
60
- const a = `http://localhost:${c}/overlay.html`;
61
- e.loadURL(a), e.once("ready-to-show", () => {
62
- e == null || e.show();
63
- }), e.on("closed", () => {
64
- e = null;
87
+ overlayWindow.on("closed", () => {
88
+ overlayWindow = null;
65
89
  });
66
90
  }
67
- u.on("overlay:toggle", () => {
68
- e && (e.isVisible() ? e.hide() : (e.show(), e.focus()));
91
+ ipcMain.on("overlay:toggle", () => {
92
+ if (!overlayWindow) return;
93
+ if (overlayWindow.isVisible()) {
94
+ overlayWindow.hide();
95
+ } else {
96
+ overlayWindow.show();
97
+ overlayWindow.focus();
98
+ }
69
99
  });
70
- u.on("overlay:close", () => {
71
- t.quit();
100
+ ipcMain.on("overlay:close", () => {
101
+ app.quit();
72
102
  });
73
- u.on("overlay:move", (n, { x: s, y: i }) => {
74
- e == null || e.setPosition(Math.round(s), Math.round(i));
103
+ ipcMain.on("overlay:move", (_event, { x, y }) => {
104
+ overlayWindow == null ? void 0 : overlayWindow.setPosition(Math.round(x), Math.round(y));
75
105
  });
76
- async function O() {
106
+ async function bootstrap() {
77
107
  try {
78
- c = await M(), y();
79
- } catch (n) {
80
- console.error("Failed to start overlay:", n), t.quit();
108
+ serverPort = await startNestServer();
109
+ createOverlay();
110
+ } catch (error) {
111
+ console.error("Failed to start overlay:", error);
112
+ app.quit();
81
113
  }
82
114
  }
83
- t.whenReady().then(O);
84
- t.on("window-all-closed", () => {
85
- t.quit();
115
+ app.whenReady().then(bootstrap);
116
+ app.on("window-all-closed", () => {
117
+ app.quit();
86
118
  });
87
- t.on("before-quit", () => {
88
- r && (r.kill(), r = null);
119
+ app.on("before-quit", () => {
120
+ if (serverProcess) {
121
+ serverProcess.kill();
122
+ serverProcess = null;
123
+ }
89
124
  });
90
- t.on("activate", () => {
91
- e === null && c > 0 && y();
125
+ app.on("activate", () => {
126
+ if (overlayWindow === null && serverPort > 0) {
127
+ createOverlay();
128
+ }
92
129
  });
@@ -0,0 +1 @@
1
+ {"type":"module","main":"main.js"}
@@ -1,12 +1,12 @@
1
- import { contextBridge as o, ipcRenderer as e } from "electron";
2
- o.exposeInMainWorld("electron", {
1
+ import { contextBridge, ipcRenderer } from "electron";
2
+ contextBridge.exposeInMainWorld("electron", {
3
3
  platform: process.platform
4
4
  });
5
- o.exposeInMainWorld("electronOverlay", {
6
- move: (r, n) => e.send("overlay:move", { x: r, y: n }),
7
- close: () => e.send("overlay:close"),
8
- toggle: () => e.send("overlay:toggle")
5
+ contextBridge.exposeInMainWorld("electronOverlay", {
6
+ move: (x, y) => ipcRenderer.send("overlay:move", { x, y }),
7
+ close: () => ipcRenderer.send("overlay:close"),
8
+ toggle: () => ipcRenderer.send("overlay:toggle")
9
9
  });
10
- o.exposeInMainWorld("electronAPI", {
11
- captureScreen: () => e.invoke("capture-screen")
10
+ contextBridge.exposeInMainWorld("electronAPI", {
11
+ captureScreen: () => ipcRenderer.invoke("capture-screen")
12
12
  });
@@ -25,22 +25,31 @@ const SERVER_VERSION = '0.1.0';
25
25
  * workspaceRoot used by FileLoggerPlugin: directory of the yaml when present,
26
26
  * otherwise process.cwd() so logs land in the launch directory.
27
27
  */
28
- async function createServerCrewx(configPath = process.env.CREWX_CONFIG ?? 'crewx.yaml') {
29
- const absConfigPath = (0, path_1.resolve)(configPath);
30
- const isExplicitConfig = Boolean(process.env.CREWX_CONFIG);
31
- const fileExists = (0, fs_1.existsSync)(absConfigPath);
28
+ async function createServerCrewx(configPath) {
32
29
  let yamlPath;
33
30
  let workspaceRoot;
34
- if (fileExists) {
31
+ if (configPath !== undefined) {
32
+ // Caller explicitly provided a path — trust it directly without existsSync
33
+ const absConfigPath = (0, path_1.resolve)(configPath);
35
34
  yamlPath = absConfigPath;
36
35
  workspaceRoot = (0, path_1.dirname)(absConfigPath);
37
36
  }
38
- else if (isExplicitConfig) {
39
- throw new Error(`[crewx] Config file not found: ${absConfigPath} (set via CREWX_CONFIG)`);
40
- }
41
37
  else {
42
- yamlPath = undefined;
43
- workspaceRoot = process.cwd();
38
+ // No explicit path — use env/default with existsSync fallback
39
+ const defaultPath = (0, path_1.resolve)(process.env.CREWX_CONFIG ?? 'crewx.yaml');
40
+ const isExplicitConfig = Boolean(process.env.CREWX_CONFIG);
41
+ const fileExists = (0, fs_1.existsSync)(defaultPath);
42
+ if (fileExists) {
43
+ yamlPath = defaultPath;
44
+ workspaceRoot = (0, path_1.dirname)(defaultPath);
45
+ }
46
+ else if (isExplicitConfig) {
47
+ throw new Error(`[crewx] Config file not found: ${defaultPath} (set via CREWX_CONFIG)`);
48
+ }
49
+ else {
50
+ yamlPath = undefined;
51
+ workspaceRoot = process.cwd();
52
+ }
44
53
  }
45
54
  const crewx = await sdk_1.Crewx.loadYaml(yamlPath, {
46
55
  remoteFactory: createServerCrewx,
@@ -150,6 +150,9 @@ let AgentService = AgentService_1 = class AgentService {
150
150
  existing.inline = inline;
151
151
  }
152
152
  }
153
+ if (dto.skills !== undefined) {
154
+ existing.skills = { include: dto.skills.include };
155
+ }
153
156
  agents[idx] = existing;
154
157
  config.agents = agents;
155
158
  this.saveConfig(configPath, config, raw);
@@ -261,6 +264,9 @@ let AgentService = AgentService_1 = class AgentService {
261
264
  providerLocation = String(matched.location);
262
265
  }
263
266
  }
267
+ const skills = a.skills !== null && a.skills !== undefined && Array.isArray(a.skills.include)
268
+ ? { include: a.skills.include }
269
+ : undefined;
264
270
  return {
265
271
  id: String(a.id || ''),
266
272
  name: String(a.name || a.id || ''),
@@ -271,6 +277,7 @@ let AgentService = AgentService_1 = class AgentService {
271
277
  model: resolvedModel !== undefined ? String(resolvedModel) : undefined,
272
278
  providerLocation,
273
279
  prompt: resolvedPrompt,
280
+ ...(skills !== undefined && { skills }),
274
281
  };
275
282
  }
276
283
  toAgentInfo(a, providers = []) {
@@ -290,6 +297,10 @@ let AgentService = AgentService_1 = class AgentService {
290
297
  providerLocation = String(matched.location);
291
298
  }
292
299
  }
300
+ const rawSkills = a.skills;
301
+ const skills = rawSkills !== null && rawSkills !== undefined && Array.isArray(rawSkills.include)
302
+ ? { include: rawSkills.include }
303
+ : undefined;
293
304
  return {
294
305
  id: String(a.id || ''),
295
306
  name: String(a.name || a.id || ''),
@@ -300,6 +311,7 @@ let AgentService = AgentService_1 = class AgentService {
300
311
  model: resolvedModel !== undefined ? String(resolvedModel) : undefined,
301
312
  providerLocation,
302
313
  prompt: resolvedPrompt,
314
+ ...(skills !== undefined && { skills }),
303
315
  };
304
316
  }
305
317
  normalizePrompt(prompt) {