@cremini/skillpack 1.0.9-im.1 → 1.0.9-im.4

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.
@@ -11,6 +11,7 @@
11
11
  "@slack/bolt": "^4.6.0",
12
12
  "express": "^5.1.0",
13
13
  "node-telegram-bot-api": "^0.66.0",
14
+ "pm2": "^6.0.14",
14
15
  "ws": "^8.19.0"
15
16
  },
16
17
  "devDependencies": {
package/runtime/start.bat CHANGED
@@ -5,11 +5,14 @@ echo.
5
5
  echo Starting Skills Pack...
6
6
  echo.
7
7
 
8
- if not exist "server\node_modules" (
8
+ if not exist "server\node_modules\.bin\pm2.cmd" (
9
9
  echo Installing dependencies...
10
10
  cd server && npm ci --omit=dev && cd ..
11
11
  echo.
12
12
  )
13
13
 
14
- rem Start the server (port detection and browser launch are handled by server\dist\index.js)
15
- cd server && node dist/index.js
14
+ set "PM2_BIN=server\node_modules\.bin\pm2.cmd"
15
+
16
+ echo Launching under PM2...
17
+ echo.
18
+ "%PM2_BIN%" startOrRestart ecosystem.config.cjs --update-env
package/runtime/start.sh CHANGED
@@ -11,12 +11,15 @@ echo ""
11
11
  echo " Starting ${PACK_NAME}..."
12
12
  echo ""
13
13
 
14
- # Install dependencies
15
- if [ ! -d "server/node_modules" ]; then
14
+ # Install dependencies (including local PM2)
15
+ if [ ! -x "server/node_modules/.bin/pm2" ]; then
16
16
  echo " Installing dependencies..."
17
17
  cd server && npm install --omit=dev && cd ..
18
18
  echo ""
19
19
  fi
20
20
 
21
- # Start the server
22
- cd server && node dist/index.js
21
+ PM2_BIN="./server/node_modules/.bin/pm2"
22
+
23
+ echo " Launching under PM2..."
24
+ echo ""
25
+ "$PM2_BIN" startOrRestart ecosystem.config.cjs --update-env
@@ -104,6 +104,7 @@
104
104
  </div>
105
105
  </div>
106
106
  <div class="settings-modal-footer">
107
+ <button id="restart-service-btn" class="secondary-btn" hidden>Restart Service</button>
107
108
  <button id="save-settings-btn" class="primary-btn">Save Settings</button>
108
109
  </div>
109
110
  </dialog>
@@ -112,4 +113,4 @@
112
113
  <script type="module" src="js/main.js"></script>
113
114
  </body>
114
115
 
115
- </html>
116
+ </html>
@@ -11,3 +11,15 @@ export async function saveConfigData(updates) {
11
11
  }
12
12
  return await res.json();
13
13
  }
14
+
15
+ export async function restartRuntime() {
16
+ const res = await fetch(state.API_BASE + "/api/runtime/restart", {
17
+ method: "POST",
18
+ headers: { "Content-Type": "application/json" },
19
+ });
20
+ const payload = await res.json();
21
+ if (!res.ok) {
22
+ throw new Error(payload.message || "Restart Failed");
23
+ }
24
+ return payload;
25
+ }
@@ -1,6 +1,7 @@
1
1
  export const state = {
2
2
  config: null,
3
- API_BASE: ""
3
+ API_BASE: "",
4
+ restartRequired: false,
4
5
  };
5
6
 
6
7
  export async function loadConfig() {
@@ -1,5 +1,5 @@
1
1
  import { state } from "./config.js";
2
- import { saveConfigData } from "./api.js";
2
+ import { restartRuntime, saveConfigData } from "./api.js";
3
3
 
4
4
  // DOM Elements
5
5
  let dialog;
@@ -12,6 +12,7 @@ let telegramTokenInput;
12
12
  let slackBotTokenInput;
13
13
  let slackAppTokenInput;
14
14
  let keyStatus;
15
+ let restartBtn;
15
16
 
16
17
  export function initSettings() {
17
18
  dialog = document.getElementById("settings-dialog");
@@ -25,6 +26,7 @@ export function initSettings() {
25
26
  slackBotTokenInput = document.getElementById("slack-bot-token-input");
26
27
  slackAppTokenInput = document.getElementById("slack-app-token-input");
27
28
  keyStatus = document.getElementById("key-status");
29
+ restartBtn = document.getElementById("restart-service-btn");
28
30
 
29
31
  if (!dialog) return;
30
32
 
@@ -47,6 +49,9 @@ export function initSettings() {
47
49
  if (saveBtn) {
48
50
  saveBtn.addEventListener("click", handleSave);
49
51
  }
52
+ if (restartBtn) {
53
+ restartBtn.addEventListener("click", handleRestart);
54
+ }
50
55
 
51
56
  // Placeholder logic
52
57
  if (providerSelect) {
@@ -65,11 +70,20 @@ function populateForm() {
65
70
  const config = state.config;
66
71
  if (!config) return;
67
72
 
68
- if (config.hasApiKey) {
69
- keyStatus.textContent = "API key configured";
70
- keyStatus.className = "status-text success";
73
+ if (state.restartRequired) {
74
+ setStatus(
75
+ config.runtimeControl?.canManagedRestart
76
+ ? "Settings saved. Restart service to apply changes."
77
+ : "Settings saved. Restart the service manually to apply changes.",
78
+ "warning",
79
+ );
80
+ updateRestartButton(true);
81
+ } else if (config.hasApiKey) {
82
+ setStatus("API key configured", "success");
83
+ updateRestartButton(false);
71
84
  } else {
72
- keyStatus.textContent = "";
85
+ setStatus("", "");
86
+ updateRestartButton(false);
73
87
  }
74
88
 
75
89
  if (config.provider) {
@@ -116,17 +130,61 @@ async function handleSave() {
116
130
 
117
131
  try {
118
132
  const res = await saveConfigData(updates);
119
- keyStatus.textContent = "Settings saved";
120
- keyStatus.className = "status-text success";
121
133
  apiKeyInput.value = ""; // clear after save
122
134
 
123
135
  // Update local config
124
136
  state.config.provider = res.provider;
125
137
  state.config.adapters = res.adapters;
138
+ state.config.runtimeControl = res.runtimeControl;
126
139
  if (key) state.config.hasApiKey = true;
140
+ state.restartRequired = !!res.requiresRestart;
141
+
142
+ if (res.requiresRestart) {
143
+ setStatus(
144
+ res.runtimeControl.canManagedRestart
145
+ ? "Settings saved. Restart service to apply changes."
146
+ : "Settings saved. Restart the service manually to apply changes.",
147
+ "warning",
148
+ );
149
+ updateRestartButton(res.runtimeControl.canManagedRestart);
150
+ return;
151
+ }
152
+
153
+ setStatus("Settings saved", "success");
154
+ updateRestartButton(false);
155
+
156
+ } catch (err) {
157
+ setStatus("Save failed: " + err.message, "error");
158
+ }
159
+ }
160
+
161
+ async function handleRestart() {
162
+ if (!restartBtn) return;
127
163
 
164
+ restartBtn.disabled = true;
165
+ if (saveBtn) saveBtn.disabled = true;
166
+ setStatus("Restarting service...", "warning");
167
+
168
+ try {
169
+ await restartRuntime();
170
+ setTimeout(() => {
171
+ window.location.reload();
172
+ }, 3000);
128
173
  } catch (err) {
129
- keyStatus.textContent = "Save failed: " + err.message;
130
- keyStatus.className = "status-text error";
174
+ if (saveBtn) saveBtn.disabled = false;
175
+ restartBtn.disabled = false;
176
+ setStatus("Restart failed: " + err.message, "error");
131
177
  }
132
178
  }
179
+
180
+ function updateRestartButton(show) {
181
+ if (!restartBtn) return;
182
+ restartBtn.hidden = !show;
183
+ restartBtn.disabled = false;
184
+ }
185
+
186
+ function setStatus(message, status) {
187
+ if (!keyStatus) return;
188
+ keyStatus.textContent = message;
189
+ keyStatus.className = status ? `status-text ${status}` : "status-text";
190
+ }
@@ -198,6 +198,9 @@ body {
198
198
  .status-text.success {
199
199
  color: var(--success);
200
200
  }
201
+ .status-text.warning {
202
+ color: var(--accent);
203
+ }
201
204
  .status-text.error {
202
205
  color: var(--error);
203
206
  }
@@ -922,6 +925,22 @@ body {
922
925
  display: flex;
923
926
  justify-content: flex-end;
924
927
  align-items: center;
928
+ gap: 12px;
929
+ }
930
+ .secondary-btn {
931
+ padding: 10px 20px;
932
+ background: transparent;
933
+ color: var(--text-primary);
934
+ border: 1px solid var(--border-color);
935
+ border-radius: var(--radius-sm);
936
+ font-weight: 500;
937
+ font-size: 14px;
938
+ cursor: pointer;
939
+ transition: all 0.2s ease;
940
+ }
941
+ .secondary-btn:hover {
942
+ border-color: var(--accent);
943
+ color: var(--accent);
925
944
  }
926
945
  .primary-btn {
927
946
  padding: 10px 20px;
@@ -942,4 +961,10 @@ body {
942
961
  .primary-btn:active {
943
962
  transform: translateY(0);
944
963
  }
945
-
964
+ .primary-btn:disabled,
965
+ .secondary-btn:disabled {
966
+ opacity: 0.6;
967
+ cursor: not-allowed;
968
+ transform: none;
969
+ box-shadow: none;
970
+ }