wiki-plugin-allyabase 0.0.7 → 0.0.9

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.
@@ -139,6 +139,128 @@ function emit($item, item) {
139
139
  console.log('[allyabase] Fork detected from:', forkInfo);
140
140
  }
141
141
 
142
+ // Add configuration section
143
+ const configContainer = document.createElement('div');
144
+ configContainer.style.padding = '10px';
145
+ configContainer.style.marginBottom = '15px';
146
+ configContainer.style.backgroundColor = '#f0f8ff';
147
+ configContainer.style.borderRadius = '5px';
148
+ configContainer.style.border = '1px solid #cce5ff';
149
+
150
+ const configTitle = document.createElement('div');
151
+ configTitle.style.fontWeight = 'bold';
152
+ configTitle.style.marginBottom = '10px';
153
+ configTitle.textContent = '⚙️ Configuration';
154
+ configContainer.appendChild(configTitle);
155
+
156
+ // Location Emoji Input
157
+ const locationLabel = document.createElement('div');
158
+ locationLabel.style.fontSize = '12px';
159
+ locationLabel.style.marginBottom = '4px';
160
+ locationLabel.textContent = 'Location Emoji (3 emoji):';
161
+ configContainer.appendChild(locationLabel);
162
+
163
+ const locationInput = document.createElement('input');
164
+ locationInput.type = 'text';
165
+ locationInput.id = 'location-emoji-input';
166
+ locationInput.style.width = '200px';
167
+ locationInput.style.padding = '5px';
168
+ locationInput.style.fontSize = '16px';
169
+ locationInput.style.marginBottom = '10px';
170
+ locationInput.placeholder = 'e.g., 🔥💎🌟';
171
+ configContainer.appendChild(locationInput);
172
+
173
+ // Federation Emoji Input
174
+ const federationLabel = document.createElement('div');
175
+ federationLabel.style.fontSize = '12px';
176
+ federationLabel.style.marginBottom = '4px';
177
+ federationLabel.textContent = 'Federation Emoji (1 emoji):';
178
+ configContainer.appendChild(federationLabel);
179
+
180
+ const federationInput = document.createElement('input');
181
+ federationInput.type = 'text';
182
+ federationInput.id = 'federation-emoji-input';
183
+ federationInput.style.width = '200px';
184
+ federationInput.style.padding = '5px';
185
+ federationInput.style.fontSize = '16px';
186
+ federationInput.style.marginBottom = '10px';
187
+ federationInput.placeholder = 'e.g., 💚';
188
+ federationInput.value = '💚';
189
+ configContainer.appendChild(federationInput);
190
+
191
+ // Save button
192
+ const saveConfigBtn = document.createElement('button');
193
+ saveConfigBtn.textContent = 'Save Configuration';
194
+ saveConfigBtn.style.padding = '8px 15px';
195
+ saveConfigBtn.style.fontSize = '12px';
196
+ saveConfigBtn.style.cursor = 'pointer';
197
+ saveConfigBtn.style.marginTop = '5px';
198
+ saveConfigBtn.style.backgroundColor = '#4CAF50';
199
+ saveConfigBtn.style.color = 'white';
200
+ saveConfigBtn.style.border = 'none';
201
+ saveConfigBtn.style.borderRadius = '4px';
202
+ configContainer.appendChild(saveConfigBtn);
203
+
204
+ // Config status message
205
+ const configStatus = document.createElement('div');
206
+ configStatus.id = 'config-status';
207
+ configStatus.style.fontSize = '11px';
208
+ configStatus.style.marginTop = '8px';
209
+ configStatus.style.minHeight = '16px';
210
+ configContainer.appendChild(configStatus);
211
+
212
+ container.appendChild(configContainer);
213
+
214
+ // Load current configuration
215
+ async function loadConfig() {
216
+ try {
217
+ const response = await get('/plugin/allyabase/config');
218
+ const data = await response.json();
219
+ if (data.success && data.config) {
220
+ locationInput.value = data.config.locationEmoji || '';
221
+ federationInput.value = data.config.federationEmoji || '💚';
222
+ }
223
+ } catch (err) {
224
+ console.error('[allyabase] Error loading config:', err);
225
+ }
226
+ }
227
+
228
+ // Save configuration
229
+ saveConfigBtn.addEventListener('click', async () => {
230
+ try {
231
+ configStatus.textContent = 'Saving...';
232
+ configStatus.style.color = '#666';
233
+
234
+ const response = await post('/plugin/allyabase/config', {
235
+ locationEmoji: locationInput.value.trim(),
236
+ federationEmoji: federationInput.value.trim() || '💚'
237
+ });
238
+
239
+ const result = await response.json();
240
+
241
+ if (result.success) {
242
+ configStatus.textContent = '✓ Configuration saved successfully!';
243
+ configStatus.style.color = 'green';
244
+ // Reload base emoji display
245
+ loadBaseEmoji();
246
+ } else {
247
+ configStatus.textContent = `✗ Error: ${result.error}`;
248
+ configStatus.style.color = 'red';
249
+ }
250
+
251
+ setTimeout(() => {
252
+ configStatus.textContent = '';
253
+ }, 3000);
254
+ } catch (err) {
255
+ console.error('[allyabase] Error saving config:', err);
256
+ configStatus.textContent = `✗ Error: ${err.message}`;
257
+ configStatus.style.color = 'red';
258
+ }
259
+ });
260
+
261
+ // Load config on initialization
262
+ loadConfig();
263
+
142
264
  // Add base emoji identifier section
143
265
  const baseEmojiContainer = document.createElement('div');
144
266
  baseEmojiContainer.style.padding = '10px';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-allyabase",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Allyabase management plugin for the federated wiki",
5
5
  "keywords": [
6
6
  "wiki",
package/server/server.js CHANGED
@@ -29,6 +29,9 @@ const SERVICE_PORTS = {
29
29
  // PID file for tracking PM2 process
30
30
  const PM2_PID_FILE = path.join(__dirname, 'allyabase-pm2.pid');
31
31
 
32
+ // Plugin configuration file (stores locationEmoji, federationEmoji, etc.)
33
+ const CONFIG_FILE = path.join(__dirname, 'plugin-config.json');
34
+
32
35
  let baseStatus = {
33
36
  running: false,
34
37
  services: {},
@@ -37,7 +40,38 @@ let baseStatus = {
37
40
 
38
41
  let allyabaseProcess = null;
39
42
 
40
- // Function to load wiki's owner.json for keypair and location emoji
43
+ // Load plugin configuration (locationEmoji, federationEmoji, etc.)
44
+ function loadPluginConfig() {
45
+ try {
46
+ if (fs.existsSync(CONFIG_FILE)) {
47
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
48
+ }
49
+ // Return defaults if no config file exists
50
+ return {
51
+ locationEmoji: null,
52
+ federationEmoji: '💚'
53
+ };
54
+ } catch (err) {
55
+ console.error('[wiki-plugin-allyabase] Error loading plugin config:', err);
56
+ return {
57
+ locationEmoji: null,
58
+ federationEmoji: '💚'
59
+ };
60
+ }
61
+ }
62
+
63
+ // Save plugin configuration
64
+ function savePluginConfig(config) {
65
+ try {
66
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
67
+ return true;
68
+ } catch (err) {
69
+ console.error('[wiki-plugin-allyabase] Error saving plugin config:', err);
70
+ return false;
71
+ }
72
+ }
73
+
74
+ // Function to load wiki's sessionless keys from owner.json (authentication only)
41
75
  function loadWikiKeypair() {
42
76
  try {
43
77
  const ownerPath = path.join(process.env.HOME || '/root', '.wiki/status/owner.json');
@@ -46,9 +80,7 @@ function loadWikiKeypair() {
46
80
  if (ownerData.sessionlessKeys) {
47
81
  return {
48
82
  pubKey: ownerData.sessionlessKeys.pubKey,
49
- privateKey: ownerData.sessionlessKeys.privateKey,
50
- locationEmoji: ownerData.locationEmoji,
51
- federationEmoji: ownerData.federationEmoji
83
+ privateKey: ownerData.sessionlessKeys.privateKey
52
84
  };
53
85
  }
54
86
  }
@@ -121,17 +153,17 @@ function killProcessByPort(port) {
121
153
  });
122
154
  }
123
155
 
124
- // Function to stop PM2 and all managed services
156
+ // Function to stop PM2-managed allyabase services (not the daemon itself,
157
+ // since wiki may also be running under PM2)
125
158
  async function stopPM2() {
126
- console.log('[wiki-plugin-allyabase] Stopping PM2 and all services...');
159
+ console.log('[wiki-plugin-allyabase] Stopping allyabase services...');
127
160
 
128
161
  return new Promise((resolve) => {
129
- // Try to stop PM2 gracefully using pm2 kill
130
- exec('pm2 kill', (err, stdout, stderr) => {
162
+ exec('pm2 stop all', (err, stdout, stderr) => {
131
163
  if (err) {
132
- console.log(`[wiki-plugin-allyabase] PM2 kill failed (might not be running): ${err.message}`);
164
+ console.log(`[wiki-plugin-allyabase] pm2 stop all failed (might not be running): ${err.message}`);
133
165
  } else {
134
- console.log(`[wiki-plugin-allyabase] PM2 killed successfully`);
166
+ console.log(`[wiki-plugin-allyabase] Allyabase services stopped`);
135
167
  }
136
168
 
137
169
  // Clean up PID file
@@ -521,8 +553,8 @@ async function startServer(params) {
521
553
  if (targetWikiUrls && targetWikiUrls.length > 0) {
522
554
  // This is a cross-wiki request - try all registered URLs
523
555
  const currentWikiUrl = `http://localhost:${req.socket.localPort}`;
524
- const wikiInfo = loadWikiKeypair();
525
- const thisWikiLocationEmoji = wikiInfo ? wikiInfo.locationEmoji : null;
556
+ const config = loadPluginConfig();
557
+ const thisWikiLocationEmoji = config.locationEmoji;
526
558
 
527
559
  console.log('[BDO EMOJI] Cross-wiki request detected');
528
560
  console.log('[BDO EMOJI] Target wikis (${targetWikiUrls.length}): ${targetWikiUrls.join(', ')}');
@@ -751,58 +783,122 @@ async function startServer(params) {
751
783
  res.send(baseStatus);
752
784
  });
753
785
 
754
- // Endpoint to get wiki's base emoji identifier
786
+ // Endpoint to get wiki's base emoji identifier (from plugin config)
755
787
  app.get('/plugin/allyabase/base-emoji', function(req, res) {
756
788
  try {
757
- const ownerPath = path.join(process.env.HOME || '/root', '.wiki/status/owner.json');
758
- if (fs.existsSync(ownerPath)) {
759
- const ownerData = JSON.parse(fs.readFileSync(ownerPath, 'utf8'));
760
-
761
- const response = {
762
- federationEmoji: ownerData.federationEmoji || '💚',
763
- locationEmoji: ownerData.locationEmoji || null,
764
- baseEmoji: (ownerData.federationEmoji || '💚') + (ownerData.locationEmoji || ''),
765
- warnings: []
766
- };
789
+ const config = loadPluginConfig();
790
+ const keypair = loadWikiKeypair();
767
791
 
768
- // Validation warnings
769
- if (!ownerData.locationEmoji) {
770
- response.warnings.push({
771
- severity: 'error',
772
- message: 'Missing locationEmoji in owner.json',
773
- fix: 'Add "locationEmoji": "🔥💎🌟" (3 emoji) to your owner.json'
774
- });
775
- } else if (!ownerData.federationEmoji) {
776
- response.warnings.push({
777
- severity: 'warning',
778
- message: 'Missing federationEmoji in owner.json, using default 💚',
779
- fix: 'Add "federationEmoji": "💚" to your owner.json'
792
+ const response = {
793
+ federationEmoji: config.federationEmoji || '💚',
794
+ locationEmoji: config.locationEmoji || null,
795
+ baseEmoji: (config.federationEmoji || '💚') + (config.locationEmoji || ''),
796
+ warnings: []
797
+ };
798
+
799
+ // Validation warnings
800
+ if (!config.locationEmoji) {
801
+ response.warnings.push({
802
+ severity: 'error',
803
+ message: 'Location emoji not configured',
804
+ fix: 'Set your 3-emoji location identifier in the plugin settings'
805
+ });
806
+ }
807
+
808
+ if (!keypair || !keypair.pubKey) {
809
+ response.warnings.push({
810
+ severity: 'error',
811
+ message: 'Missing sessionless keys in owner.json',
812
+ fix: 'BDO operations will fail without sessionless keys in ~/.wiki/status/owner.json'
813
+ });
814
+ }
815
+
816
+ res.send(response);
817
+ } catch (err) {
818
+ console.error('Error reading base emoji config:', err);
819
+ res.status(500).send({
820
+ error: 'Failed to load base emoji',
821
+ message: err.message
822
+ });
823
+ }
824
+ });
825
+
826
+ // Endpoint to get plugin configuration
827
+ app.get('/plugin/allyabase/config', function(req, res) {
828
+ try {
829
+ const config = loadPluginConfig();
830
+ res.send({
831
+ success: true,
832
+ config: config
833
+ });
834
+ } catch (err) {
835
+ console.error('Error loading plugin config:', err);
836
+ res.status(500).send({
837
+ success: false,
838
+ error: 'Failed to load configuration',
839
+ message: err.message
840
+ });
841
+ }
842
+ });
843
+
844
+ // Endpoint to save plugin configuration (requires owner auth)
845
+ app.post('/plugin/allyabase/config', owner, function(req, res) {
846
+ try {
847
+ const { locationEmoji, federationEmoji } = req.body;
848
+
849
+ // Validate locationEmoji (should be exactly 3 emoji)
850
+ if (locationEmoji) {
851
+ const emojiRegex = /[\u{1F1E6}-\u{1F1FF}]{2}|(?:[\u{1F3F4}\u{1F3F3}][\u{FE0F}]?(?:\u{200D}[\u{2620}\u{2695}\u{2696}\u{2708}\u{1F308}][\u{FE0F}]?)?)|(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\u{200D}(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F))*/gu;
852
+ const emojis = locationEmoji.match(emojiRegex) || [];
853
+
854
+ if (emojis.length !== 3) {
855
+ return res.status(400).send({
856
+ success: false,
857
+ error: 'Location emoji must be exactly 3 emoji characters',
858
+ got: emojis.length
780
859
  });
781
860
  }
861
+ }
862
+
863
+ // Validate federationEmoji (should be exactly 1 emoji)
864
+ if (federationEmoji) {
865
+ const emojiRegex = /[\u{1F1E6}-\u{1F1FF}]{2}|(?:[\u{1F3F4}\u{1F3F3}][\u{FE0F}]?(?:\u{200D}[\u{2620}\u{2695}\u{2696}\u{2708}\u{1F308}][\u{FE0F}]?)?)|(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\u{200D}(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F))*/gu;
866
+ const emojis = federationEmoji.match(emojiRegex) || [];
782
867
 
783
- if (!ownerData.sessionlessKeys) {
784
- response.warnings.push({
785
- severity: 'error',
786
- message: 'Missing sessionlessKeys in owner.json',
787
- fix: 'BDO operations will fail without sessionless keys'
868
+ if (emojis.length !== 1) {
869
+ return res.status(400).send({
870
+ success: false,
871
+ error: 'Federation emoji must be exactly 1 emoji character',
872
+ got: emojis.length
788
873
  });
789
874
  }
875
+ }
876
+
877
+ const config = loadPluginConfig();
878
+
879
+ // Update config with provided values
880
+ if (locationEmoji !== undefined) config.locationEmoji = locationEmoji;
881
+ if (federationEmoji !== undefined) config.federationEmoji = federationEmoji;
790
882
 
791
- res.send(response);
883
+ const saved = savePluginConfig(config);
884
+
885
+ if (saved) {
886
+ res.send({
887
+ success: true,
888
+ config: config,
889
+ message: 'Configuration saved successfully'
890
+ });
792
891
  } else {
793
- res.status(404).send({
794
- error: 'Owner configuration not found',
795
- warnings: [{
796
- severity: 'error',
797
- message: 'owner.json file not found',
798
- fix: 'Create ~/.wiki/status/owner.json with locationEmoji and sessionlessKeys'
799
- }]
892
+ res.status(500).send({
893
+ success: false,
894
+ error: 'Failed to save configuration'
800
895
  });
801
896
  }
802
897
  } catch (err) {
803
- console.error('Error reading owner.json:', err);
898
+ console.error('Error saving plugin config:', err);
804
899
  res.status(500).send({
805
- error: 'Failed to load base emoji',
900
+ success: false,
901
+ error: 'Failed to save configuration',
806
902
  message: err.message
807
903
  });
808
904
  }