@cremini/skillpack 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +4 -0
  3. package/package.json +4 -3
  4. package/runtime/README.md +11 -1
  5. package/runtime/server/dist/adapters/markdown.js +74 -0
  6. package/runtime/server/dist/adapters/markdown.js.map +1 -0
  7. package/runtime/server/dist/adapters/slack.js +369 -0
  8. package/runtime/server/dist/adapters/slack.js.map +1 -0
  9. package/runtime/server/dist/adapters/telegram.js +199 -0
  10. package/runtime/server/dist/adapters/telegram.js.map +1 -0
  11. package/runtime/server/dist/adapters/types.js +2 -0
  12. package/runtime/server/dist/adapters/types.js.map +1 -0
  13. package/runtime/server/dist/adapters/web.js +201 -0
  14. package/runtime/server/dist/adapters/web.js.map +1 -0
  15. package/runtime/server/dist/agent.js +223 -0
  16. package/runtime/server/dist/agent.js.map +1 -0
  17. package/runtime/server/dist/config.js +73 -0
  18. package/runtime/server/dist/config.js.map +1 -0
  19. package/runtime/server/dist/index.js +146 -0
  20. package/runtime/server/dist/index.js.map +1 -0
  21. package/runtime/server/dist/lifecycle.js +85 -0
  22. package/runtime/server/dist/lifecycle.js.map +1 -0
  23. package/runtime/server/dist/memory.js +195 -0
  24. package/runtime/server/dist/memory.js.map +1 -0
  25. package/runtime/server/package-lock.json +4028 -244
  26. package/runtime/server/package.json +13 -3
  27. package/runtime/start.bat +40 -4
  28. package/runtime/start.sh +30 -2
  29. package/runtime/web/index.html +145 -18
  30. package/runtime/web/js/api-key-dialog.js +153 -0
  31. package/runtime/web/js/api.js +25 -0
  32. package/runtime/web/js/chat-apps-dialog.js +192 -0
  33. package/runtime/web/{app.js → js/chat.js} +112 -193
  34. package/runtime/web/js/config.js +16 -0
  35. package/runtime/web/js/main.js +56 -0
  36. package/runtime/web/js/settings.js +205 -0
  37. package/runtime/web/styles.css +301 -10
  38. package/runtime/server/chat-proxy.js +0 -229
  39. package/runtime/server/index.js +0 -63
  40. package/runtime/server/routes.js +0 -104
@@ -0,0 +1,205 @@
1
+ import { state } from "./config.js";
2
+ import { restartRuntime, saveConfigData } from "./api.js";
3
+
4
+ // DOM Elements
5
+ let dialog;
6
+ let settingsBtn;
7
+ let closeBtn;
8
+ let saveBtn;
9
+ let providerSelect;
10
+ let apiKeyInput;
11
+ let telegramTokenInput;
12
+ let slackBotTokenInput;
13
+ let slackAppTokenInput;
14
+ let keyStatus;
15
+ let restartBtn;
16
+
17
+ export function initSettings() {
18
+ dialog = document.getElementById("settings-dialog");
19
+ settingsBtn = document.getElementById("open-settings-btn");
20
+ closeBtn = document.getElementById("close-settings-btn");
21
+ saveBtn = document.getElementById("save-settings-btn");
22
+
23
+ providerSelect = document.getElementById("provider-select");
24
+ apiKeyInput = document.getElementById("api-key-input");
25
+ telegramTokenInput = document.getElementById("telegram-token-input");
26
+ slackBotTokenInput = document.getElementById("slack-bot-token-input");
27
+ slackAppTokenInput = document.getElementById("slack-app-token-input");
28
+ keyStatus = document.getElementById("key-status");
29
+ restartBtn = document.getElementById("restart-service-btn");
30
+
31
+ if (!dialog) return;
32
+
33
+ // Open/Close dialog
34
+ if (settingsBtn) {
35
+ settingsBtn.addEventListener("click", () => {
36
+ populateForm();
37
+ dialog.showModal();
38
+ });
39
+ }
40
+
41
+ if (closeBtn) {
42
+ closeBtn.addEventListener("click", () => {
43
+ dialog.close();
44
+ keyStatus.textContent = ""; // clear status on close
45
+ });
46
+ }
47
+
48
+ // Save Settings
49
+ if (saveBtn) {
50
+ saveBtn.addEventListener("click", handleSave);
51
+ }
52
+ if (restartBtn) {
53
+ restartBtn.addEventListener("click", handleRestart);
54
+ }
55
+
56
+ // Placeholder logic
57
+ if (providerSelect) {
58
+ providerSelect.addEventListener("change", updatePlaceholder);
59
+ }
60
+ }
61
+
62
+ function updatePlaceholder() {
63
+ const p = providerSelect.value;
64
+ if (p === "openai") apiKeyInput.placeholder = "sk-proj-...";
65
+ else if (p === "anthropic") apiKeyInput.placeholder = "sk-ant-api03-...";
66
+ else apiKeyInput.placeholder = "sk-...";
67
+ }
68
+
69
+ function populateForm() {
70
+ const config = state.config;
71
+ if (!config) return;
72
+
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 {
82
+ setStatus("", "");
83
+ updateRestartButton(false);
84
+ }
85
+
86
+ if (config.hasApiKey && config.apiKey) {
87
+ apiKeyInput.value = config.apiKey;
88
+ } else if (config.hasApiKey) {
89
+ apiKeyInput.value = "***************************************************";
90
+ } else {
91
+ apiKeyInput.value = "";
92
+ }
93
+
94
+ if (config.provider) {
95
+ providerSelect.value = config.provider;
96
+ }
97
+ updatePlaceholder();
98
+
99
+ const adapters = config.adapters || {};
100
+ if (adapters.telegram && adapters.telegram.token) {
101
+ telegramTokenInput.value = adapters.telegram.token;
102
+ } else {
103
+ telegramTokenInput.value = "";
104
+ }
105
+
106
+ if (adapters.slack) {
107
+ slackBotTokenInput.value = adapters.slack.botToken || "";
108
+ slackAppTokenInput.value = adapters.slack.appToken || "";
109
+ } else {
110
+ slackBotTokenInput.value = "";
111
+ slackAppTokenInput.value = "";
112
+ }
113
+ }
114
+
115
+ async function handleSave() {
116
+ const key = apiKeyInput.value.trim();
117
+ const provider = providerSelect.value;
118
+ const telegramToken = telegramTokenInput.value.trim();
119
+ const slackBotToken = slackBotTokenInput.value.trim();
120
+ const slackAppToken = slackAppTokenInput.value.trim();
121
+
122
+ const adapters = {};
123
+ if (telegramToken) adapters.telegram = { token: telegramToken };
124
+ if (slackBotToken || slackAppToken) {
125
+ adapters.slack = {
126
+ botToken: slackBotToken || undefined,
127
+ appToken: slackAppToken || undefined
128
+ };
129
+ }
130
+
131
+ const updates = { provider, adapters };
132
+ if (key && key !== "***************************************************" && key !== state.config.apiKey) {
133
+ updates.key = key;
134
+ }
135
+
136
+ try {
137
+ const res = await saveConfigData(updates);
138
+
139
+ // Update local config
140
+ state.config.provider = res.provider;
141
+ state.config.adapters = res.adapters;
142
+ state.config.runtimeControl = res.runtimeControl;
143
+ if (updates.key) {
144
+ state.config.hasApiKey = true;
145
+ state.config.apiKey = updates.key;
146
+ }
147
+
148
+ if (state.config.hasApiKey && state.config.apiKey) {
149
+ apiKeyInput.value = state.config.apiKey;
150
+ } else if (state.config.hasApiKey) {
151
+ apiKeyInput.value = "***************************************************";
152
+ } else {
153
+ apiKeyInput.value = "";
154
+ }
155
+ state.restartRequired = !!res.requiresRestart;
156
+
157
+ if (res.requiresRestart) {
158
+ setStatus(
159
+ res.runtimeControl.canManagedRestart
160
+ ? "Settings saved. Restart service to apply changes."
161
+ : "Settings saved. Restart the service manually to apply changes.",
162
+ "warning",
163
+ );
164
+ updateRestartButton(res.runtimeControl.canManagedRestart);
165
+ return;
166
+ }
167
+
168
+ setStatus("Settings saved", "success");
169
+ updateRestartButton(false);
170
+
171
+ } catch (err) {
172
+ setStatus("Save failed: " + err.message, "error");
173
+ }
174
+ }
175
+
176
+ async function handleRestart() {
177
+ if (!restartBtn) return;
178
+
179
+ restartBtn.disabled = true;
180
+ if (saveBtn) saveBtn.disabled = true;
181
+ setStatus("Restarting service...", "warning");
182
+
183
+ try {
184
+ await restartRuntime();
185
+ setTimeout(() => {
186
+ window.location.reload();
187
+ }, 6000);
188
+ } catch (err) {
189
+ if (saveBtn) saveBtn.disabled = false;
190
+ restartBtn.disabled = false;
191
+ setStatus("Restart failed: " + err.message, "error");
192
+ }
193
+ }
194
+
195
+ function updateRestartButton(show) {
196
+ if (!restartBtn) return;
197
+ restartBtn.hidden = !show;
198
+ restartBtn.disabled = false;
199
+ }
200
+
201
+ function setStatus(message, status) {
202
+ if (!keyStatus) return;
203
+ keyStatus.textContent = message;
204
+ keyStatus.className = status ? `status-text ${status}` : "status-text";
205
+ }
@@ -55,7 +55,8 @@ body {
55
55
  .sidebar-header {
56
56
  padding: 24px 20px;
57
57
  border-bottom: 1px solid var(--border-color);
58
- background: var(--bg-primary);
58
+ background: transparent;
59
+ flex-shrink: 0;
59
60
  }
60
61
 
61
62
  .sidebar-header h1 {
@@ -71,12 +72,20 @@ body {
71
72
  line-height: 1.4;
72
73
  }
73
74
 
74
- .sidebar-section {
75
+ .sidebar-settings-section {
75
76
  padding: 16px 20px;
76
- border-bottom: 1px solid var(--border-color);
77
+ border-top: 1px solid var(--border-color);
78
+ background: var(--bg-secondary);
79
+ flex-shrink: 0;
80
+ }
81
+
82
+ .sidebar-skills-section {
83
+ padding: 16px 20px;
84
+ flex: 1;
85
+ overflow-y: auto;
77
86
  }
78
87
 
79
- .sidebar-section h3 {
88
+ .sidebar-skills-section h3 {
80
89
  font-size: 11px;
81
90
  font-weight: 600;
82
91
  text-transform: uppercase;
@@ -85,23 +94,26 @@ body {
85
94
  margin-bottom: 10px;
86
95
  }
87
96
 
88
- .sidebar-section ul {
97
+ .sidebar-skills-section ul {
89
98
  list-style: none;
90
99
  }
91
100
 
92
- .sidebar-section li {
93
- padding: 8px 12px;
101
+ .sidebar-skills-section li {
102
+ padding: 12px;
94
103
  font-size: 13px;
95
104
  color: var(--text-primary);
96
105
  background: var(--bg-tertiary);
106
+ border: 1px solid transparent;
97
107
  border-radius: var(--radius-sm);
98
- margin-bottom: 6px;
108
+ margin-bottom: 8px;
99
109
  cursor: default;
100
110
  transition: all 0.2s;
101
111
  }
102
112
 
103
- .sidebar-section li:hover {
104
- background: var(--border-color);
113
+ .sidebar-skills-section li:hover {
114
+ background: var(--bg-secondary);
115
+ border-color: var(--border-color);
116
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
105
117
  }
106
118
 
107
119
  .skill-name {
@@ -198,6 +210,9 @@ body {
198
210
  .status-text.success {
199
211
  color: var(--success);
200
212
  }
213
+ .status-text.warning {
214
+ color: var(--accent);
215
+ }
201
216
  .status-text.error {
202
217
  color: var(--error);
203
218
  }
@@ -772,3 +787,279 @@ body {
772
787
  .thinking-content p:last-child {
773
788
  margin-bottom: 0;
774
789
  }
790
+
791
+ /* ---- Sidebar Action Buttons ---- */
792
+ .sidebar-actions-group {
793
+ padding: 24px 20px;
794
+ border-bottom: 1px solid var(--border-color);
795
+ display: flex;
796
+ flex-direction: column;
797
+ gap: 12px;
798
+ flex-shrink: 0;
799
+ }
800
+
801
+ .action-btn {
802
+ display: flex;
803
+ align-items: center;
804
+ justify-content: center;
805
+ gap: 8px;
806
+ width: 100%;
807
+ padding: 9px 16px;
808
+ border-radius: var(--radius-sm);
809
+ font-size: 14px;
810
+ font-weight: 500;
811
+ cursor: pointer;
812
+ transition: all 0.25s ease;
813
+ font-family: inherit;
814
+ }
815
+
816
+ /* Default (not connected) state — outline style */
817
+ .action-btn.chatapps-btn {
818
+ background: var(--bg-tertiary);
819
+ border: 1px solid var(--border-color);
820
+ color: var(--text-primary);
821
+ }
822
+ .action-btn.chatapps-btn:hover {
823
+ border-color: var(--accent);
824
+ background: var(--bg-secondary);
825
+ box-shadow: 0 4px 12px rgba(0,0,0,0.04);
826
+ transform: translateY(-1px);
827
+ }
828
+
829
+ /* Connected state — green filled */
830
+ .action-btn.chatapps-btn.connected {
831
+ background: var(--accent);
832
+ border: 1px solid var(--accent);
833
+ color: #fff;
834
+ opacity: 0.85;
835
+ }
836
+ .action-btn.chatapps-btn.connected:hover {
837
+ opacity: 1;
838
+ box-shadow: 0 4px 16px var(--accent-glow);
839
+ transform: translateY(-1px);
840
+ }
841
+ .action-btn.chatapps-btn.connected .action-btn-icon {
842
+ stroke: #fff;
843
+ }
844
+
845
+ /* API Key button — always outline style */
846
+ .action-btn.apikey-btn {
847
+ background: var(--bg-tertiary);
848
+ border: 1px solid var(--border-color);
849
+ color: var(--text-primary);
850
+ }
851
+ .action-btn.apikey-btn:hover {
852
+ border-color: var(--accent);
853
+ background: var(--bg-secondary);
854
+ box-shadow: 0 4px 12px rgba(0,0,0,0.04);
855
+ transform: translateY(-1px);
856
+ }
857
+
858
+ /* API Key configured state */
859
+ .action-btn.apikey-btn.connected {
860
+ border-color: var(--accent);
861
+ color: var(--accent);
862
+ background: var(--bg-secondary);
863
+ }
864
+ .action-btn.apikey-btn.connected .action-btn-icon {
865
+ stroke: var(--accent);
866
+ }
867
+
868
+ .action-btn-icon {
869
+ flex-shrink: 0;
870
+ }
871
+
872
+ /* ---- Compact Modal Variant ---- */
873
+ .compact-modal {
874
+ width: 440px;
875
+ }
876
+
877
+ /* ---- Settings Modal ---- */
878
+ .settings-trigger-btn {
879
+ display: flex;
880
+ align-items: center;
881
+ justify-content: center;
882
+ gap: 8px;
883
+ width: 100%;
884
+ padding: 12px;
885
+ background: var(--bg-tertiary);
886
+ border: 1px solid var(--border-color);
887
+ border-radius: var(--radius-sm);
888
+ color: var(--text-primary);
889
+ font-weight: 500;
890
+ cursor: pointer;
891
+ transition: all 0.2s ease;
892
+ }
893
+ .settings-trigger-btn:hover {
894
+ background: #ebebeb;
895
+ }
896
+
897
+ .settings-modal {
898
+ margin: auto;
899
+ padding: 0;
900
+ border: 1px solid rgba(255, 255, 255, 0.1);
901
+ border-radius: 16px;
902
+ background: var(--bg-secondary);
903
+ width: 520px;
904
+ max-width: 90vw;
905
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1), 0 0 0 1px var(--border-color);
906
+ font-family: inherit;
907
+ color: var(--text-primary);
908
+ opacity: 0;
909
+ transform: scale(0.95) translateY(10px);
910
+ transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
911
+ }
912
+ .settings-modal[open] {
913
+ opacity: 1;
914
+ transform: scale(1) translateY(0);
915
+ }
916
+ .settings-modal::backdrop {
917
+ background: rgba(0, 0, 0, 0.2);
918
+ backdrop-filter: blur(4px);
919
+ -webkit-backdrop-filter: blur(4px);
920
+ opacity: 0;
921
+ transition: opacity 0.3s ease;
922
+ }
923
+ .settings-modal[open]::backdrop {
924
+ opacity: 1;
925
+ }
926
+
927
+ .settings-modal-header {
928
+ display: flex;
929
+ justify-content: space-between;
930
+ align-items: center;
931
+ padding: 24px 24px 12px 24px;
932
+ background: transparent;
933
+ border-top-left-radius: 16px;
934
+ border-top-right-radius: 16px;
935
+ }
936
+ .settings-modal-header h2 { font-size: 18px; font-weight: 600; margin: 0; color: var(--text-primary); letter-spacing: -0.01em; }
937
+ .close-btn {
938
+ background: var(--bg-tertiary);
939
+ border: 1px solid var(--border-color);
940
+ border-radius: 8px;
941
+ width: 32px;
942
+ height: 32px;
943
+ display: flex;
944
+ align-items: center;
945
+ justify-content: center;
946
+ font-size: 18px;
947
+ cursor: pointer;
948
+ color: var(--text-secondary);
949
+ transition: all 0.2s ease;
950
+ }
951
+ .close-btn:hover {
952
+ background: var(--bg-primary);
953
+ color: var(--text-primary);
954
+ border-color: var(--text-secondary);
955
+ }
956
+
957
+ .settings-sections {
958
+ padding: 24px;
959
+ max-height: calc(85vh - 140px);
960
+ overflow-y: auto;
961
+ }
962
+ .settings-section {
963
+ margin-bottom: 28px;
964
+ padding-bottom: 28px;
965
+ border-bottom: 1px solid var(--border-color);
966
+ }
967
+ .settings-section:last-child {
968
+ margin-bottom: 0;
969
+ padding-bottom: 0;
970
+ border-bottom: none;
971
+ }
972
+ .section-title {
973
+ font-size: 14px;
974
+ font-weight: 600;
975
+ color: var(--text-primary);
976
+ margin-top: 0;
977
+ margin-bottom: 16px;
978
+ text-transform: uppercase;
979
+ letter-spacing: 0.5px;
980
+ opacity: 0.8;
981
+ }
982
+
983
+ .form-group { margin-bottom: 16px; }
984
+ .form-group:last-child { margin-bottom: 0; }
985
+ .form-group label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 8px; color: var(--text-primary); }
986
+ .form-input {
987
+ width: 100%;
988
+ padding: 12px 14px;
989
+ background: var(--bg-tertiary);
990
+ border: 1px solid var(--border-color);
991
+ border-radius: var(--radius-sm);
992
+ font-size: 14px;
993
+ outline: none;
994
+ color: var(--text-primary);
995
+ transition: all 0.2s ease;
996
+ }
997
+ .form-input:focus {
998
+ border-color: var(--accent);
999
+ background: var(--bg-secondary);
1000
+ box-shadow: 0 0 0 3px var(--accent-glow);
1001
+ }
1002
+
1003
+ /* Specific to provider-select in Settings Modal to match form-input */
1004
+ .settings-modal .provider-select-wrapper select {
1005
+ padding: 12px 14px;
1006
+ font-size: 14px;
1007
+ transition: all 0.2s ease;
1008
+ }
1009
+ .settings-modal .provider-select-wrapper select:focus {
1010
+ border-color: var(--accent);
1011
+ background: var(--bg-secondary);
1012
+ box-shadow: 0 0 0 3px var(--accent-glow);
1013
+ }
1014
+
1015
+ .settings-modal-footer {
1016
+ padding: 16px 24px 24px 24px;
1017
+ background: transparent;
1018
+ border-bottom-left-radius: 16px;
1019
+ border-bottom-right-radius: 16px;
1020
+ display: flex;
1021
+ justify-content: flex-end;
1022
+ align-items: center;
1023
+ gap: 12px;
1024
+ }
1025
+ .secondary-btn {
1026
+ padding: 10px 20px;
1027
+ background: transparent;
1028
+ color: var(--text-primary);
1029
+ border: 1px solid var(--border-color);
1030
+ border-radius: var(--radius-sm);
1031
+ font-weight: 500;
1032
+ font-size: 14px;
1033
+ cursor: pointer;
1034
+ transition: all 0.2s ease;
1035
+ }
1036
+ .secondary-btn:hover {
1037
+ border-color: var(--accent);
1038
+ color: var(--accent);
1039
+ }
1040
+ .primary-btn {
1041
+ padding: 10px 20px;
1042
+ background: var(--accent);
1043
+ color: #fff;
1044
+ border: none;
1045
+ border-radius: var(--radius-sm);
1046
+ font-weight: 500;
1047
+ font-size: 14px;
1048
+ cursor: pointer;
1049
+ transition: all 0.2s ease;
1050
+ }
1051
+ .primary-btn:hover {
1052
+ background: var(--accent-hover);
1053
+ box-shadow: 0 4px 12px var(--accent-glow);
1054
+ transform: translateY(-1px);
1055
+ }
1056
+ .primary-btn:active {
1057
+ transform: translateY(0);
1058
+ }
1059
+ .primary-btn:disabled,
1060
+ .secondary-btn:disabled {
1061
+ opacity: 0.6;
1062
+ cursor: not-allowed;
1063
+ transform: none;
1064
+ box-shadow: none;
1065
+ }