aimeat 1.3.5 → 1.4.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 (41) hide show
  1. package/README.md +4 -2
  2. package/dist/locales/en.json +17 -7
  3. package/dist/locales/fi.json +17 -7
  4. package/dist/public/css/views/admin.css +1 -0
  5. package/dist/public/css/views/profile.css +1 -0
  6. package/dist/public/views/profile/packages-tab.js +60 -16
  7. package/dist/src/data/example-packages.d.ts +2 -0
  8. package/dist/src/data/example-packages.d.ts.map +1 -1
  9. package/dist/src/data/example-packages.js +85 -38
  10. package/dist/src/data/example-packages.js.map +1 -1
  11. package/dist/src/routes/apps.d.ts.map +1 -1
  12. package/dist/src/routes/apps.js +15 -4
  13. package/dist/src/routes/apps.js.map +1 -1
  14. package/dist/src/routes/instances.d.ts.map +1 -1
  15. package/dist/src/routes/instances.js +18 -6
  16. package/dist/src/routes/instances.js.map +1 -1
  17. package/dist/src/routes/packages.js +1 -1
  18. package/dist/src/routes/packages.js.map +1 -1
  19. package/dist/src/routes/prompts.d.ts.map +1 -1
  20. package/dist/src/routes/prompts.js +20 -1
  21. package/dist/src/routes/prompts.js.map +1 -1
  22. package/dist/src/services/component-registrar.d.ts +5 -0
  23. package/dist/src/services/component-registrar.d.ts.map +1 -1
  24. package/dist/src/services/component-registrar.js +78 -11
  25. package/dist/src/services/component-registrar.js.map +1 -1
  26. package/dist/src/services/prompt-defaults.d.ts.map +1 -1
  27. package/dist/src/services/prompt-defaults.js +303 -0
  28. package/dist/src/services/prompt-defaults.js.map +1 -1
  29. package/dist/src/services/prompt-seeder.d.ts.map +1 -1
  30. package/dist/src/services/prompt-seeder.js +3 -2
  31. package/dist/src/services/prompt-seeder.js.map +1 -1
  32. package/dist/src/storage/interface.d.ts +1 -1
  33. package/dist/src/storage/interface.d.ts.map +1 -1
  34. package/dist/src/storage/providers/mongodb/index.js +1 -1
  35. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  36. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  37. package/dist/src/storage/providers/sqlite/schema.js +3 -1
  38. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  39. package/dist/static/app-catalog.html +1 -1
  40. package/package.json +1 -1
  41. package/prisma/schema.prisma +1 -1
package/README.md CHANGED
@@ -260,10 +260,12 @@ Each node runs independently with its own identity and portal. Operators customi
260
260
 
261
261
  ### Quick start with npx
262
262
 
263
- Requires Node.js 24+. This runs the server directly without cloning:
263
+ Requires Node.js 24+. Runs without cloning the repo:
264
264
 
265
265
  ```bash
266
- npx aimeat start
266
+ npx aimeat init # interactive setup, generates .env
267
+ npx aimeat start # start the server
268
+ npx aimeat seed # seed example packages (in another terminal, server must be running)
267
269
  ```
268
270
 
269
271
  ### From source
@@ -4431,6 +4431,8 @@
4431
4431
  "copiedBtn": "Copied!"
4432
4432
  },
4433
4433
  "packages": {
4434
+ "title": "Packages",
4435
+ "desc": "Packages bundle schemas, extensions, apps, and seed data into installable units. Install ready-made packages from the gallery, browse what others have published, or create your own in the Generator.",
4434
4436
  "created": "Package created",
4435
4437
  "updated": "Package updated",
4436
4438
  "archived": "Package archived",
@@ -4445,6 +4447,8 @@
4445
4447
  "noUpdateAvailable": "No update available",
4446
4448
  "updateAvailable": "Update available",
4447
4449
  "migrationApplied": "Migration applied successfully",
4450
+ "applyUpdateConfirm": "Apply update? Your data (memory, settings) will be preserved. Apps, extensions, and schemas will be updated to the latest version.",
4451
+ "updateApplied": "Update applied successfully",
4448
4452
  "exportFailed": "Export failed",
4449
4453
  "importFailed": "Import failed",
4450
4454
  "myInstances": "My Instances",
@@ -4452,12 +4456,25 @@
4452
4456
  "gallery": "Template Gallery",
4453
4457
  "search": "Search...",
4454
4458
  "allCategories": "All Categories",
4459
+ "featured": "Featured",
4460
+ "categories": {
4461
+ "signage": "Signage",
4462
+ "marketplace": "Marketplace",
4463
+ "iot": "IoT",
4464
+ "social": "Social",
4465
+ "productivity": "Productivity",
4466
+ "communication": "Communication",
4467
+ "other": "Other"
4468
+ },
4455
4469
  "version": "Version",
4456
4470
  "components": "components",
4457
4471
  "by": "by",
4458
4472
  "install": "Install",
4459
4473
  "remove": "Remove",
4460
4474
  "checkUpdate": "Check Update",
4475
+ "createWithAi": "Create Package with AI",
4476
+ "promptCopied": "Prompt copied!",
4477
+ "createWithAiDesc": "Copy this prompt and paste it into any AI. Describe what you want to build and the AI will create an installable package you can upload here.",
4461
4478
  "noInstances": "No packages installed yet.",
4462
4479
  "noTemplates": "No templates available yet.",
4463
4480
  "labelPrompt": "Instance label (optional):",
@@ -4508,13 +4525,6 @@
4508
4525
  "sourceNode": "Source Node",
4509
4526
  "installFromRemote": "Install from Remote",
4510
4527
  "syncSuccess": "Federation sync complete"
4511
- },
4512
- "gallery": {
4513
- "install": "Install",
4514
- "downloadZip": "Download ZIP",
4515
- "components": "Components",
4516
- "rating": "Rating",
4517
- "installs": "Installs"
4518
4528
  }
4519
4529
  },
4520
4530
  "templates": {
@@ -4431,6 +4431,8 @@
4431
4431
  "copiedBtn": "Kopioitu!"
4432
4432
  },
4433
4433
  "packages": {
4434
+ "title": "Paketit",
4435
+ "desc": "Paketit kokoavat skeemoja, laajennuksia, sovelluksia ja alkuarvoja asennettaviksi kokonaisuuksiksi. Asenna valmiita paketteja galleriasta, selaa muiden julkaisuja tai luo omasi Generaattorissa.",
4434
4436
  "created": "Paketti luotu",
4435
4437
  "updated": "Paketti päivitetty",
4436
4438
  "archived": "Paketti arkistoitu",
@@ -4445,6 +4447,8 @@
4445
4447
  "noUpdateAvailable": "Ei päivitystä saatavilla",
4446
4448
  "updateAvailable": "Päivitys saatavilla",
4447
4449
  "migrationApplied": "Migraatio suoritettu onnistuneesti",
4450
+ "applyUpdateConfirm": "Paivitetaanko? Tietosi (muisti, asetukset) sailyvat. Sovellukset, laajennukset ja skeemat paivitetaan uusimpaan versioon.",
4451
+ "updateApplied": "Paivitys asennettu onnistuneesti",
4448
4452
  "exportFailed": "Vienti epäonnistui",
4449
4453
  "importFailed": "Tuonti epäonnistui",
4450
4454
  "myInstances": "Omat instanssit",
@@ -4452,12 +4456,25 @@
4452
4456
  "gallery": "Mallipohjagalleria",
4453
4457
  "search": "Hae...",
4454
4458
  "allCategories": "Kaikki kategoriat",
4459
+ "featured": "Suositeltu",
4460
+ "categories": {
4461
+ "signage": "Opasteet",
4462
+ "marketplace": "Markkinapaikka",
4463
+ "iot": "IoT",
4464
+ "social": "Sosiaalinen",
4465
+ "productivity": "Tuottavuus",
4466
+ "communication": "Viestintä",
4467
+ "other": "Muu"
4468
+ },
4455
4469
  "version": "Versio",
4456
4470
  "components": "komponenttia",
4457
4471
  "by": "tekij\u00e4",
4458
4472
  "install": "Asenna",
4459
4473
  "remove": "Poista",
4460
4474
  "checkUpdate": "Tarkista p\u00e4ivitys",
4475
+ "createWithAi": "Luo paketti tekoalylla",
4476
+ "promptCopied": "Prompt kopioitu!",
4477
+ "createWithAiDesc": "Kopioi tama prompt ja liita se mihin tahansa tekoalyyn. Kuvaile mita haluat rakentaa ja tekoaly luo asennettavan paketin.",
4461
4478
  "noInstances": "Ei asennettuja paketteja.",
4462
4479
  "noTemplates": "Ei malleja saatavilla.",
4463
4480
  "labelPrompt": "Instanssin nimi (valinnainen):",
@@ -4508,13 +4525,6 @@
4508
4525
  "sourceNode": "Lähdesolmu",
4509
4526
  "installFromRemote": "Asenna etäsolmusta",
4510
4527
  "syncSuccess": "Federaatiosynkronointi valmis"
4511
- },
4512
- "gallery": {
4513
- "install": "Asenna",
4514
- "downloadZip": "Lataa ZIP",
4515
- "components": "Komponentit",
4516
- "rating": "Arvosana",
4517
- "installs": "Asennukset"
4518
4528
  }
4519
4529
  },
4520
4530
  "templates": {
@@ -555,6 +555,7 @@
555
555
  .adm-badge-suspended { background: #FEF3C7; color: #B45309; }
556
556
  .adm-badge-published { background: #D1FAE5; color: #047857; }
557
557
  .adm-badge-active { background: #D1FAE5; color: #047857; }
558
+ .adm-badge-installed { background: #D1FAE5; color: #047857; }
558
559
 
559
560
  /* ── Board Members ── */
560
561
  .adm-board-detail { border-top: 1px solid var(--card-border, var(--glass-border)); padding-top: 8px; }
@@ -371,6 +371,7 @@
371
371
  .pf .pkg-tag{font-size:.7rem;padding:2px 8px;border-radius:6px;background:var(--bg-dim,#F3F4F6);color:var(--text-dim,#6B7280)}
372
372
  .pf .pkg-badge{display:inline-block;padding:2px 8px;border-radius:6px;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.3px}
373
373
  .pf .pkg-badge-active{background:rgba(74,222,128,0.15);color:#4ade80}
374
+ .pf .pkg-badge-installed{background:rgba(74,222,128,0.15);color:#4ade80}
374
375
  .pf .pkg-badge-inactive{background:rgba(156,163,175,0.15);color:#9ca3af}
375
376
  .pf .pkg-badge-error{background:rgba(239,68,68,0.15);color:#f87171}
376
377
  .pf .pkg-badge-featured{background:rgba(251,191,36,0.15);color:#fbbf24}
@@ -16,13 +16,14 @@
16
16
  * importing packages into generator projects (fork vs edit detection)
17
17
  * v1.3.0 — 2026-03-20 — add ZIP upload/download and template proposal buttons
18
18
  * v1.4.0 — 2026-03-20 — add remote templates section with federation sync
19
+ * v1.5.0 — 2026-05-05 — add intro section, i18n for categories/featured, fix status badge label
19
20
  */
20
21
  import { h } from 'preact';
21
22
  import { useState, useEffect, useCallback } from 'preact/hooks';
22
23
  import htm from 'htm';
23
24
  const html = htm.bind(h);
24
25
  import { t } from '/js/i18n.js';
25
- import { escHtml } from '/js/utils.js';
26
+ import { escHtml, copyToClipboard } from '/js/utils.js';
26
27
  import { Spinner } from './shared.js';
27
28
  import { useConfirm } from '/components/Modal.js';
28
29
  import * as pkgService from '/js/services/packages.js';
@@ -44,8 +45,8 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
44
45
  setLoading(true);
45
46
  try {
46
47
  const [instRes, pkgRes, tplRes] = await Promise.all([
47
- pkgService.listInstances({ status: 'active' }),
48
- pkgService.listPackages({ status: 'published', author: session?.owner }),
48
+ pkgService.listInstances({ status: 'installed' }),
49
+ pkgService.listPackages({ author: session?.owner }),
49
50
  pkgService.listTemplates({ sort: 'newest' }),
50
51
  ]);
51
52
  if (instRes.ok) setInstances(instRes.data?.instances ?? []);
@@ -83,7 +84,7 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
83
84
 
84
85
  const handleRemove = async (id) => {
85
86
  confirm(t('packages.confirmRemove') || 'Remove this instance?', async () => {
86
- const res = await pkgService.removeInstance(id, false);
87
+ const res = await pkgService.removeInstance(id, true);
87
88
  if (res.ok) {
88
89
  showToast(t('packages.instanceRemoved'));
89
90
  loadData();
@@ -97,7 +98,27 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
97
98
  const res = await pkgService.checkUpdate(id);
98
99
  if (res.ok && res.data) {
99
100
  if (res.data.updateAvailable) {
100
- showToast(`${t('packages.updateAvailable')}: ${res.data.latestVersion}`);
101
+ confirm(
102
+ `${t('packages.updateAvailable')}: ${res.data.latestVersion}\n\n${t('packages.applyUpdateConfirm') || 'Apply update? Your data (memory, settings) will be preserved. Apps, extensions, and schemas will be updated to the latest version.'}`,
103
+ async () => {
104
+ const instRes = await pkgService.getInstance(id);
105
+ const installed = instRes.data?.installedComponents || [];
106
+ const components = installed.map(c => ({
107
+ componentId: c.componentId,
108
+ action: (c.type === 'memory' || c.type === 'translation') ? 'skip' : 'replace',
109
+ }));
110
+ const applyRes = await pkgService.applyMigration(id, {
111
+ targetVersion: res.data.latestVersion,
112
+ components,
113
+ });
114
+ if (applyRes.ok) {
115
+ showToast(t('packages.updateApplied') || 'Update applied successfully');
116
+ loadData();
117
+ } else {
118
+ showToast(applyRes.error?.message || 'Update failed', true);
119
+ }
120
+ },
121
+ );
101
122
  } else {
102
123
  showToast(t('packages.noUpdateAvailable'));
103
124
  }
@@ -183,6 +204,21 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
183
204
 
184
205
  const isOperator = session?.roles?.includes('operator');
185
206
 
207
+ const copyPackagePrompt = async () => {
208
+ try {
209
+ const res = await fetch('/v1/prompts/package-builder');
210
+ const json = await res.json();
211
+ if (json.ok && json.data?.content) {
212
+ copyToClipboard(json.data.content);
213
+ showToast(t('packages.promptCopied') || 'Prompt copied! Paste it into AI Chat.');
214
+ } else {
215
+ showToast('Failed to load prompt', true);
216
+ }
217
+ } catch (e) {
218
+ showToast('Failed to load prompt', true);
219
+ }
220
+ };
221
+
186
222
  if (loading) return html`<${Spinner} />`;
187
223
 
188
224
  const filtered = packages.filter(p => {
@@ -193,6 +229,14 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
193
229
 
194
230
  return html`
195
231
  <div class="pkg-tab">
232
+ <div class="section-title">${t('packages.title')}</div>
233
+ <div class="section-desc">${t('packages.desc')}</div>
234
+ <div style="display:flex;gap:.75rem;flex-wrap:wrap;margin-bottom:1.25rem;align-items:center">
235
+ <button class="btn-primary" onClick=${copyPackagePrompt}>
236
+ ${'\u{1F916}'} ${t('packages.createWithAi') || 'Create Package with AI'}
237
+ </button>
238
+ <span style="font-size:.8rem;color:var(--text-dim,#6B7280);max-width:420px">${t('packages.createWithAiDesc') || 'Copy this prompt and paste it into any AI. Describe what you want to build and the AI will create an installable package.'}</span>
239
+ </div>
196
240
  <div class="pkg-nav">
197
241
  <button class=${view === 'instances' ? 'active' : ''} onClick=${() => setView('instances')}>
198
242
  \u{1F4E6} ${t('packages.myInstances') || 'My Instances'} (${instances.length})
@@ -239,23 +283,23 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
239
283
  <div class="pkg-section">
240
284
  <div class="pkg-section-header">
241
285
  <h3>${t('packages.browse') || 'Available Packages'}</h3>
242
- <label class="btn-outline pkg-upload-btn">
286
+ <input type="file" id="pkg-zip-file" accept=".zip" style="display:none" onChange=${handleUploadZip} />
287
+ <button class="btn-outline" onClick=${() => document.getElementById('pkg-zip-file')?.click()}>
243
288
  ${t('packages.uploadZip') || 'Upload ZIP'}
244
- <input type="file" accept=".zip" class="pkg-hidden-input" onChange=${handleUploadZip} />
245
- </label>
289
+ </button>
246
290
  </div>
247
291
  <div class="pkg-filters">
248
292
  <input type="text" placeholder=${t('packages.search') || 'Search...'}
249
293
  value=${search} onInput=${e => setSearch(e.target.value)} />
250
294
  <select value=${category} onChange=${e => setCategory(e.target.value)}>
251
295
  <option value="">${t('packages.allCategories') || 'All Categories'}</option>
252
- <option value="signage">Signage</option>
253
- <option value="marketplace">Marketplace</option>
254
- <option value="iot">IoT</option>
255
- <option value="social">Social</option>
256
- <option value="productivity">Productivity</option>
257
- <option value="communication">Communication</option>
258
- <option value="other">Other</option>
296
+ <option value="signage">${t('packages.categories.signage') || 'Signage'}</option>
297
+ <option value="marketplace">${t('packages.categories.marketplace') || 'Marketplace'}</option>
298
+ <option value="iot">${t('packages.categories.iot') || 'IoT'}</option>
299
+ <option value="social">${t('packages.categories.social') || 'Social'}</option>
300
+ <option value="productivity">${t('packages.categories.productivity') || 'Productivity'}</option>
301
+ <option value="communication">${t('packages.categories.communication') || 'Communication'}</option>
302
+ <option value="other">${t('packages.categories.other') || 'Other'}</option>
259
303
  </select>
260
304
  </div>
261
305
  ${filtered.length === 0 ? html`
@@ -317,7 +361,7 @@ export default function PackagesTab({ session, showToast, navigate, locale }) {
317
361
  <div class="pkg-card" key=${tpl.id}>
318
362
  <div class="pkg-card-header">
319
363
  <span class="pkg-card-name">${escHtml(tpl.title)}</span>
320
- ${tpl.featured && html`<span class="pkg-badge pkg-badge-featured">\u2B50 Featured</span>`}
364
+ ${tpl.featured && html`<span class="pkg-badge pkg-badge-featured">\u2B50 ${t('packages.featured') || 'Featured'}</span>`}
321
365
  </div>
322
366
  <div class="pkg-card-desc">${escHtml(tpl.description || '')}</div>
323
367
  <div class="pkg-card-meta">
@@ -14,6 +14,8 @@
14
14
  * v1.2.0 — 2026-03-17 — rename Ad Slots to Rotated Views; add edit capability;
15
15
  * support image/HTML/URL content types; layout modes (fullscreen/header/full);
16
16
  * light+dark themes with accent colour; AI prompt helper for HTML views
17
+ * v1.3.0 — 2026-05-05 — rewrite cortex manifest with proper components array,
18
+ * .js lib filenames, tags, exports, and api_surface metadata
17
19
  */
18
20
  import type { PackageRecord, TemplateListingRecord } from '../storage/interface.js';
19
21
  export interface ExamplePackageDef {
@@ -1 +1 @@
1
- {"version":3,"file":"example-packages.d.ts","sourceRoot":"","sources":["../../../src/data/example-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAoB,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAItG,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACnG,eAAe,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CACH;AAgBD,2CAA2C;AAC3C,wBAAgB,kBAAkB,IAAI,iBAAiB,EAAE,CAExD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IACxF,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,qBAAqB,CAAC;CAChC,CAwDA"}
1
+ {"version":3,"file":"example-packages.d.ts","sourceRoot":"","sources":["../../../src/data/example-packages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAoB,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAItG,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IACnG,eAAe,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CACH;AAgBD,2CAA2C;AAC3C,wBAAgB,kBAAkB,IAAI,iBAAiB,EAAE,CAExD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IACxF,GAAG,EAAE,aAAa,CAAC;IACnB,OAAO,EAAE,qBAAqB,CAAC;CAChC,CAwDA"}
@@ -14,6 +14,8 @@
14
14
  * v1.2.0 — 2026-03-17 — rename Ad Slots to Rotated Views; add edit capability;
15
15
  * support image/HTML/URL content types; layout modes (fullscreen/header/full);
16
16
  * light+dark themes with accent colour; AI prompt helper for HTML views
17
+ * v1.3.0 — 2026-05-05 — rewrite cortex manifest with proper components array,
18
+ * .js lib filenames, tags, exports, and api_surface metadata
17
19
  */
18
20
  import { createHash, randomUUID } from 'node:crypto';
19
21
  // ── Helpers ──────────────────────────────────────────────────────────
@@ -152,7 +154,8 @@ function memoryInit() {
152
154
  {
153
155
  key: 'signage:config',
154
156
  value: {
155
- rotationIntervalMs: 8000, emergencyOverride: true, theme: 'dark',
157
+ rotationEnabled: true, rotationIntervalSec: 8,
158
+ emergencyOverride: true, theme: 'dark',
156
159
  layout: 'full', accentColor: '#1a1a2e',
157
160
  locale: 'en', buildingName: 'Sunrise Residences', floors: 12, timezone: 'Europe/Helsinki',
158
161
  },
@@ -181,10 +184,36 @@ function memoryInit() {
181
184
  }, null, 2);
182
185
  }
183
186
  const CORTEX_SIGNAGE = JSON.stringify({
184
- manifest: `name: signage-cortex\nversion: 1.0.0\ndescription: AI agent for managing digital signage content\ncapabilities: [memory_read, memory_write, consent_check]\ntriggers:\n - { event: schedule, cron: "0 8 * * *", action: rotate_daily_content }\n - { event: memory_change, key: "signage:announcements", action: notify_kiosk_refresh }`,
187
+ manifest: [
188
+ 'name: signage-cortex',
189
+ 'version: 1.0.0',
190
+ 'description: Content management cortex for digital signage -- schedules content rotation, prunes expired announcements, and provides helper libraries for kiosk apps.',
191
+ 'tags: [signage, kiosk, content-management, scheduling]',
192
+ 'capabilities: [memory_read, memory_write, consent_check]',
193
+ 'triggers:',
194
+ ' - { event: schedule, cron: "0 8 * * *", action: rotate_daily_content }',
195
+ ' - { event: memory_change, key: "signage:announcements", action: notify_kiosk_refresh }',
196
+ 'components:',
197
+ ' - type: lib',
198
+ ' name: contentRotation',
199
+ ' filename: contentRotation.js',
200
+ ' exports: [selectActiveAnnouncements]',
201
+ ' api_surface: |',
202
+ ' selectActiveAnnouncements(announcements, now)',
203
+ ' Filters expired announcements and sorts by priority (emergency > urgent > normal).',
204
+ ' Returns: filtered, sorted array.',
205
+ ' - type: lib',
206
+ ' name: scheduling',
207
+ ' filename: scheduling.js',
208
+ ' exports: [rotateDailyContent]',
209
+ ' api_surface: |',
210
+ ' rotateDailyContent(api)',
211
+ ' Reads signage:announcements, removes expired entries, writes back.',
212
+ ' Called by the daily cron trigger.',
213
+ ].join('\n'),
185
214
  libs: {
186
- contentRotation: 'function selectActiveAnnouncements(a,now){return a.filter(x=>!x.expiresAt||new Date(x.expiresAt)>now).sort((a,b)=>({emergency:0,urgent:1,normal:2}[a.priority]??2)-({emergency:0,urgent:1,normal:2}[b.priority]??2));}',
187
- scheduling: 'async function rotateDailyContent(api){const a=await api.get("signage:announcements");const now=new Date();const active=a.filter(x=>!x.expiresAt||new Date(x.expiresAt)>now);if(active.length!==a.length)await api.set("signage:announcements",active);}',
215
+ 'contentRotation.js': 'function selectActiveAnnouncements(a,now){return a.filter(x=>!x.expiresAt||new Date(x.expiresAt)>now).sort((a,b)=>({emergency:0,urgent:1,normal:2}[a.priority]??2)-({emergency:0,urgent:1,normal:2}[b.priority]??2));}',
216
+ 'scheduling.js': 'async function rotateDailyContent(api){const a=await api.get("signage:announcements");const now=new Date();const active=a.filter(x=>!x.expiresAt||new Date(x.expiresAt)>now);if(active.length!==a.length)await api.set("signage:announcements",active);}',
188
217
  },
189
218
  }, null, 2);
190
219
  // ── Admin Panel App ──────────────────────────────────────────────────
@@ -286,7 +315,11 @@ button.outline{background:#fff;color:#0066cc;border:1px solid #0066cc;padding:.3
286
315
  <div id="tab-config" class="panel" style="display:none">
287
316
  <h2>Display Settings</h2>
288
317
  <div class="form-group"><label>Building Name</label><input id="cfg-building" placeholder="Building name"></div>
289
- <div class="form-group"><label>Rotation Interval (ms)</label><input id="cfg-interval" type="number" value="8000" min="2000" max="60000"></div>
318
+ <div class="form-group">
319
+ <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer"><input id="cfg-rotation" type="checkbox" checked> Rotate views automatically</label>
320
+ <small style="color:#666">When off, only the first active view is shown</small>
321
+ </div>
322
+ <div class="form-group" id="cfg-interval-group"><label>Rotation Speed (seconds)</label><input id="cfg-interval" type="number" value="8" min="2" max="120"><small style="color:#666">How many seconds each view is shown before switching to the next</small></div>
290
323
  <div class="form-group">
291
324
  <label>Layout</label>
292
325
  <div class="layout-options">
@@ -390,32 +423,32 @@ document.getElementById("ai-prompt-box").textContent=AI_CHAT_PROMPT;
390
423
  el.innerHTML='<div class="type-fields"><div class="form-group"><label>Webpage URL</label><input id="view-content" placeholder="https://example.com"></div></div>';
391
424
  }}
392
425
 
393
- var AI_CHAT_PROMPT='You are a Digital Signage View Designer. Your job is to interview the user step by step and then produce a single self-contained HTML file (HTML + CSS + JS all in one file) that will be displayed on a digital signage kiosk screen.\n\n'
394
- +'## Interview Process\n\n'
395
- +'Ask these questions ONE AT A TIME. Wait for the user to answer before asking the next one. Be friendly and enthusiastic.\n\n'
396
- +'1. **Purpose**: "What do you want to show on the signage screen? For example: weather, clock, company info, event schedule, welcome message, menu, news feed, social media, custom animation, or something else?"\n\n'
397
- +'2. **Style**: "What visual style do you prefer? Options:\n - Clean & minimal (lots of whitespace, simple fonts)\n - Bold & colorful (gradients, vibrant colors, shadows)\n - Corporate & professional (muted colors, structured layout)\n - Playful & animated (movement, transitions, fun elements)\n - Futuristic / tech (dark background, glowing effects, particle animations)\n - Or describe your own style!"\n\n'
398
- +'3. **Colors**: "Any specific brand colors? Or should I pick colors that match your chosen style? You can say things like: dark background with blue accents, or use our brand colors #FF5733 and #333333"\n\n'
399
- +'4. **Content details**: Based on what they chose in step 1, ask relevant follow-up questions. For example:\n - Weather: "Which city? Celsius or Fahrenheit?"\n - Clock: "12h or 24h format? Show date too?"\n - Welcome message: "What should the text say? Any logo URL?"\n - Menu/schedule: "List the items you want to display"\n - Custom: "Describe in detail what should appear on screen"\n\n'
400
- +'5. **Animations**: "Do you want any animations or movement? Options:\n - None (static page)\n - Subtle (gentle fades, slow floating elements)\n - Dynamic (sliding text, rotating elements, particle effects)\n - Eye-catching (bold transitions, attention-grabbing movement)"\n\n'
401
- +'6. **Size & layout**: "This will be displayed on a screen section. Should the content:\n - Fill the entire area (full bleed)\n - Be centered with padding\n - Use a specific layout (sidebar, header+content, grid)?"\n\n'
402
- +'## Output Rules\n\n'
403
- +'After the interview, produce the HTML file following these rules:\n\n'
404
- +'- Single self-contained HTML file with inline CSS and JS (no external dependencies unless from CDN)\n'
405
- +'- Use <!DOCTYPE html> and proper structure\n'
406
- +'- The page should look great at any screen size (use vh/vw units, flexbox/grid)\n'
407
- +'- Background should fill the viewport (no white edges)\n'
408
- +'- Use system-ui font stack unless a specific font is requested\n'
409
- +'- If using animations, use CSS animations or requestAnimationFrame for smooth 60fps\n'
410
- +'- If showing live data (time, weather), update it automatically\n'
411
- +'- For weather, use a free API like wttr.in or open-meteo.com\n'
412
- +'- Make text large and readable from a distance (this is for a wall-mounted screen)\n'
413
- +'- High contrast between text and background\n'
414
- +'- No scrollbars, no overflow\n\n'
415
- +'## Final delivery\n\n'
416
- +'When you output the HTML, say:\n\n'
417
- +'"Here is your signage view! Copy ALL the code below and paste it into the **HTML Code** field in your Digital Signage Admin panel (Rotated Views tab, select HTML type)."\n\n'
418
- +'Then output the complete HTML in a code block.\n\n'
426
+ var AI_CHAT_PROMPT='You are a Digital Signage View Designer. Your job is to interview the user step by step and then produce a single self-contained HTML file (HTML + CSS + JS all in one file) that will be displayed on a digital signage kiosk screen.\\n\\n'
427
+ +'## Interview Process\\n\\n'
428
+ +'Ask these questions ONE AT A TIME. Wait for the user to answer before asking the next one. Be friendly and enthusiastic.\\n\\n'
429
+ +'1. **Purpose**: "What do you want to show on the signage screen? For example: weather, clock, company info, event schedule, welcome message, menu, news feed, social media, custom animation, or something else?"\\n\\n'
430
+ +'2. **Style**: "What visual style do you prefer? Options:\\n - Clean & minimal (lots of whitespace, simple fonts)\\n - Bold & colorful (gradients, vibrant colors, shadows)\\n - Corporate & professional (muted colors, structured layout)\\n - Playful & animated (movement, transitions, fun elements)\\n - Futuristic / tech (dark background, glowing effects, particle animations)\\n - Or describe your own style!"\\n\\n'
431
+ +'3. **Colors**: "Any specific brand colors? Or should I pick colors that match your chosen style? You can say things like: dark background with blue accents, or use our brand colors #FF5733 and #333333"\\n\\n'
432
+ +'4. **Content details**: Based on what they chose in step 1, ask relevant follow-up questions. For example:\\n - Weather: "Which city? Celsius or Fahrenheit?"\\n - Clock: "12h or 24h format? Show date too?"\\n - Welcome message: "What should the text say? Any logo URL?"\\n - Menu/schedule: "List the items you want to display"\\n - Custom: "Describe in detail what should appear on screen"\\n\\n'
433
+ +'5. **Animations**: "Do you want any animations or movement? Options:\\n - None (static page)\\n - Subtle (gentle fades, slow floating elements)\\n - Dynamic (sliding text, rotating elements, particle effects)\\n - Eye-catching (bold transitions, attention-grabbing movement)"\\n\\n'
434
+ +'6. **Size & layout**: "This will be displayed on a screen section. Should the content:\\n - Fill the entire area (full bleed)\\n - Be centered with padding\\n - Use a specific layout (sidebar, header+content, grid)?"\\n\\n'
435
+ +'## Output Rules\\n\\n'
436
+ +'After the interview, produce the HTML file following these rules:\\n\\n'
437
+ +'- Single self-contained HTML file with inline CSS and JS (no external dependencies unless from CDN)\\n'
438
+ +'- Use <!DOCTYPE html> and proper structure\\n'
439
+ +'- The page should look great at any screen size (use vh/vw units, flexbox/grid)\\n'
440
+ +'- Background should fill the viewport (no white edges)\\n'
441
+ +'- Use system-ui font stack unless a specific font is requested\\n'
442
+ +'- If using animations, use CSS animations or requestAnimationFrame for smooth 60fps\\n'
443
+ +'- If showing live data (time, weather), update it automatically\\n'
444
+ +'- For weather, use a free API like wttr.in or open-meteo.com\\n'
445
+ +'- Make text large and readable from a distance (this is for a wall-mounted screen)\\n'
446
+ +'- High contrast between text and background\\n'
447
+ +'- No scrollbars, no overflow\\n\\n'
448
+ +'## Final delivery\\n\\n'
449
+ +'When you output the HTML, say:\\n\\n'
450
+ +'"Here is your signage view! Copy ALL the code below and paste it into the **HTML Code** field in your Digital Signage Admin panel (Rotated Views tab, select HTML type)."\\n\\n'
451
+ +'Then output the complete HTML in a code block.\\n\\n'
419
452
  +'After the code, add: "You can preview it in the admin panel and edit it anytime. Want me to make any changes?"';
420
453
 
421
454
  function copyAiPrompt(){
@@ -510,7 +543,11 @@ function loadConfig(){
510
543
  memGet('signage:config').then(function(_r){
511
544
  var c=_r?_r.value:{};
512
545
  document.getElementById('cfg-building').value=c.buildingName||'';
513
- document.getElementById('cfg-interval').value=c.rotationIntervalMs||8000;
546
+ var rotEnabled=c.rotationEnabled!==false;
547
+ document.getElementById('cfg-rotation').checked=rotEnabled;
548
+ document.getElementById('cfg-interval-group').style.display=rotEnabled?'':'none';
549
+ var sec=c.rotationIntervalSec||Math.round((c.rotationIntervalMs||8000)/1000);
550
+ document.getElementById('cfg-interval').value=sec;
514
551
  document.getElementById('cfg-theme').value=c.theme||'dark';
515
552
  document.getElementById('cfg-accent').value=c.accentColor||'#1a1a2e';
516
553
  var layout=c.layout||'full';
@@ -521,11 +558,17 @@ if(o.getAttribute('data-layout')===layout)o.classList.add('selected');
521
558
  });
522
559
  })}
523
560
 
561
+ document.getElementById('cfg-rotation').addEventListener('change',function(){
562
+ document.getElementById('cfg-interval-group').style.display=this.checked?'':'none';
563
+ });
564
+
524
565
  function saveConfig(){
525
566
  memGet('signage:config').then(function(_r){
526
567
  var c=_r?_r.value:{};
527
568
  c.buildingName=document.getElementById('cfg-building').value.trim();
528
- c.rotationIntervalMs=parseInt(document.getElementById('cfg-interval').value)||8000;
569
+ c.rotationEnabled=document.getElementById('cfg-rotation').checked;
570
+ c.rotationIntervalSec=parseInt(document.getElementById('cfg-interval').value)||8;
571
+ delete c.rotationIntervalMs;
529
572
  c.theme=document.getElementById('cfg-theme').value;
530
573
  c.layout=document.getElementById('cfg-layout').value;
531
574
  c.accentColor=document.getElementById('cfg-accent').value;
@@ -653,7 +696,7 @@ body{background:var(--bg);color:var(--text)}
653
696
 
654
697
  <script>
655
698
  var session=null;
656
- var cfg={rotationIntervalMs:8000,buildingName:'Digital Signage',theme:'dark',layout:'full',accentColor:'#1a1a2e'};
699
+ var cfg={rotationEnabled:true,rotationIntervalSec:8,buildingName:'Digital Signage',theme:'dark',layout:'full',accentColor:'#1a1a2e'};
657
700
  var anns=[],views=[],viewIdx=0,rotTimer=null;
658
701
 
659
702
  function getHeaders(){var h={'Content-Type':'application/json'};if(session&&session.jwt)h['Authorization']='Bearer '+session.jwt;return h}
@@ -724,9 +767,12 @@ viewIdx++;
724
767
  }
725
768
 
726
769
  function startRotation(){
727
- if(rotTimer)clearInterval(rotTimer);
770
+ if(rotTimer){clearInterval(rotTimer);rotTimer=null}
728
771
  renderView();
729
- rotTimer=setInterval(function(){renderView()},cfg.rotationIntervalMs||8000);
772
+ if(cfg.rotationEnabled!==false){
773
+ var ms=(cfg.rotationIntervalSec||cfg.rotationIntervalMs/1000||8)*1000;
774
+ rotTimer=setInterval(function(){renderView()},ms);
775
+ }
730
776
  }
731
777
 
732
778
  /* ── Data loading ── */
@@ -735,10 +781,11 @@ Promise.all([memGet('signage:config'),memGet('signage:announcements'),memGet('si
735
781
  .then(function(res){
736
782
  var c=res[0],a=res[1],v=res[2];
737
783
  if(c){
738
- var oldInterval=cfg.rotationIntervalMs;
784
+ var oldSec=cfg.rotationIntervalSec;
785
+ var oldEnabled=cfg.rotationEnabled;
739
786
  cfg=Object.assign({},cfg,c);
740
787
  applyTheme();
741
- if(c.rotationIntervalMs!==oldInterval)startRotation();
788
+ if(c.rotationIntervalSec!==oldSec||c.rotationEnabled!==oldEnabled)startRotation();
742
789
  }
743
790
  anns=Array.isArray(a)?a:[];
744
791
  views=Array.isArray(v)?v:[];
@@ -1 +1 @@
1
- {"version":3,"file":"example-packages.js","sourceRoot":"","sources":["../../../src/data/example-packages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"example-packages.js","sourceRoot":"","sources":["../../../src/data/example-packages.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/apps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAQ1D;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,CAqcvG"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/apps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,yBAAyB,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAQ1D;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,CA8cvG"}
@@ -358,7 +358,9 @@ export function appsRouter(config, storage, peers) {
358
358
  router.patch('/v1/apps/:filename', requireAuth(), async (req, res) => {
359
359
  const gaii = resolveIdentity(req.auth, config.nodeId);
360
360
  const filename = req.params.filename;
361
- const app = await storage.getApp(gaii, filename);
361
+ let app = await storage.getApp(gaii, filename);
362
+ if (!app)
363
+ app = await storage.getApp(req.auth.owner, filename);
362
364
  if (!app) {
363
365
  res.status(404).json(error(config.nodeId, 'NOT_FOUND', `App "${filename}" not found in your uploads`));
364
366
  return;
@@ -387,15 +389,24 @@ export function appsRouter(config, storage, peers) {
387
389
  const filename = req.params.filename;
388
390
  const versionParam = req.query.version;
389
391
  const version = versionParam ? parseInt(versionParam, 10) : undefined;
390
- const app = await storage.getApp(gaii, filename, version);
392
+ // Try full GHII first, fall back to bare owner name (backward compat for
393
+ // apps created before the ownerGaii fix in the package install flow)
394
+ let app = await storage.getApp(gaii, filename, version);
395
+ let effectiveGaii = gaii;
396
+ if (!app) {
397
+ const bareOwner = req.auth.owner;
398
+ app = await storage.getApp(bareOwner, filename, version);
399
+ if (app)
400
+ effectiveGaii = bareOwner;
401
+ }
391
402
  if (!app) {
392
403
  res.status(404).json(error(config.nodeId, 'NOT_FOUND', `App "${filename}" not found in your uploads${version ? ` (version ${version})` : ''}`));
393
404
  return;
394
405
  }
395
- await storage.deleteApp(gaii, filename, version);
406
+ await storage.deleteApp(effectiveGaii, filename, version);
396
407
  if (!version) {
397
408
  // Full delete — also remove screenshot
398
- await storage.deleteStorageFile(gaii, `apps/screenshots/${filename}`);
409
+ await storage.deleteStorageFile(effectiveGaii, `apps/screenshots/${filename}`);
399
410
  }
400
411
  const owner = req.auth.owner;
401
412
  await storage.addSiteChangeLog({