syntaxmatrix 2.6.4.3__py3-none-any.whl → 3.0.0__py3-none-any.whl

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 (45) hide show
  1. syntaxmatrix/__init__.py +6 -4
  2. syntaxmatrix/agentic/agents.py +195 -15
  3. syntaxmatrix/agentic/agents_orchestrer.py +16 -10
  4. syntaxmatrix/client_docs.py +237 -0
  5. syntaxmatrix/commentary.py +96 -25
  6. syntaxmatrix/core.py +156 -54
  7. syntaxmatrix/dataset_preprocessing.py +2 -2
  8. syntaxmatrix/db.py +60 -0
  9. syntaxmatrix/db_backends/__init__.py +1 -0
  10. syntaxmatrix/db_backends/postgres_backend.py +14 -0
  11. syntaxmatrix/db_backends/sqlite_backend.py +258 -0
  12. syntaxmatrix/db_contract.py +71 -0
  13. syntaxmatrix/kernel_manager.py +174 -150
  14. syntaxmatrix/page_builder_generation.py +654 -50
  15. syntaxmatrix/page_layout_contract.py +25 -3
  16. syntaxmatrix/page_patch_publish.py +368 -15
  17. syntaxmatrix/plugins/__init__.py +0 -0
  18. syntaxmatrix/plugins/plugin_manager.py +114 -0
  19. syntaxmatrix/premium/__init__.py +18 -0
  20. syntaxmatrix/premium/catalogue/__init__.py +121 -0
  21. syntaxmatrix/premium/gate.py +119 -0
  22. syntaxmatrix/premium/state.py +507 -0
  23. syntaxmatrix/premium/verify.py +222 -0
  24. syntaxmatrix/profiles.py +1 -1
  25. syntaxmatrix/routes.py +9782 -8004
  26. syntaxmatrix/settings/model_map.py +50 -65
  27. syntaxmatrix/settings/prompts.py +1435 -380
  28. syntaxmatrix/settings/string_navbar.py +4 -4
  29. syntaxmatrix/static/icons/bot_icon.png +0 -0
  30. syntaxmatrix/static/icons/bot_icon2.png +0 -0
  31. syntaxmatrix/templates/admin_billing.html +408 -0
  32. syntaxmatrix/templates/admin_branding.html +65 -2
  33. syntaxmatrix/templates/admin_features.html +54 -0
  34. syntaxmatrix/templates/dashboard.html +285 -8
  35. syntaxmatrix/templates/edit_page.html +199 -18
  36. syntaxmatrix/themes.py +17 -17
  37. syntaxmatrix/workspace_db.py +0 -23
  38. syntaxmatrix-3.0.0.dist-info/METADATA +219 -0
  39. {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/RECORD +42 -30
  40. {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/WHEEL +1 -1
  41. syntaxmatrix/settings/default.yaml +0 -13
  42. syntaxmatrix-2.6.4.3.dist-info/METADATA +0 -539
  43. syntaxmatrix-2.6.4.3.dist-info/licenses/LICENSE.txt +0 -21
  44. /syntaxmatrix/static/icons/{logo3.png → logo2.png} +0 -0
  45. {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
-
2
1
  string_navbar_items = [
3
- "Dashboard",
4
- "Admin",
5
- ]
2
+ "Dashboard",
3
+ "Docs",
4
+ "Admin",
5
+ ]
Binary file
Binary file
@@ -0,0 +1,408 @@
1
+ <html lang="en">
2
+ <head>
3
+ <meta charset="utf-8">
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <title>Billing & plan</title>
6
+ {% if cancel_effective_at_iso %}
7
+ <div class="wrap" style="margin-bottom:12px;">
8
+ <div class="card" style="padding:12px 14px; border:1px solid rgba(251,191,36,.35); background:rgba(251,191,36,.08);">
9
+ <div style="font-weight:600; color:#fde68a;">
10
+ Cancellation scheduled.
11
+ </div>
12
+ <div style="color:rgba(226,232,240,.95); margin-top:4px;">
13
+ Access remains active until <b>{{ cancel_effective_at_iso }}</b> (UTC).
14
+ </div>
15
+ </div>
16
+ </div>
17
+ {% endif %}
18
+
19
+ <style>
20
+ body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;margin:0;background:#0b1224;color:#e5e7eb;}
21
+ .wrap{max-width:980px;margin:0 auto;padding:18px;}
22
+ .top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px;}
23
+ .top h1{margin:0;font-size:1.1rem;}
24
+ .btn{display:inline-block;padding:8px 12px;border-radius:999px;border:1px solid rgba(148,163,184,.35);color:#e5e7eb;text-decoration:none;background:transparent;cursor:pointer;font-weight:650;font-size:.85rem;}
25
+ .btn:hover{border-color:rgba(56,189,248,.6);color:#38bdf8;}
26
+ .btn-danger{border-color:rgba(244,63,94,.45);}
27
+ .btn-danger:hover{border-color:rgba(244,63,94,.75);color:#fecdd3;}
28
+ .card{background:rgba(2,6,23,.65);border:1px solid rgba(148,163,184,.25);border-radius:14px;padding:14px;box-shadow:0 18px 36px rgba(15,23,42,.6);margin-bottom:12px;}
29
+ .flash{background:rgba(34,197,94,.12);border:1px solid rgba(34,197,94,.35);padding:10px;border-radius:12px;margin-bottom:10px;color:#bbf7d0;font-size:.85rem;}
30
+ .warn{background:rgba(245,158,11,.10);border:1px solid rgba(245,158,11,.35);padding:10px;border-radius:12px;margin-bottom:10px;color:#fde68a;font-size:.85rem;}
31
+ .hint{color:#9ca3af;font-size:.78rem;line-height:1.35;margin-top:8px;}
32
+ .kvs{display:grid;grid-template-columns: 160px 1fr;gap:10px 14px;align-items:start;}
33
+ .k{color:#9ca3af;font-size:.82rem;}
34
+ .v{font-weight:700;}
35
+ textarea{width:100%;min-height:160px;padding:10px 11px;border-radius:12px;border:1px solid rgba(148,163,184,.25);background:rgba(2,6,23,.8);color:#e5e7eb;outline:none;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:.85rem;}
36
+ input[type="file"]{color:#e5e7eb;}
37
+ .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;}
38
+ code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;}
39
+ pre{background:rgba(2,6,23,.8);border:1px solid rgba(148,163,184,.18);border-radius:12px;padding:10px;overflow:auto;max-height:360px;}
40
+ .upsell{background:rgba(255,77,0,.8);}
41
+ </style>
42
+ </head>
43
+ <body>
44
+ <div class="wrap">
45
+ <div class="top">
46
+ <h1>Billing & plan</h1>
47
+ <a class="btn" href="{{ url_for('admin_panel') }}#system">Back to Admin</a>
48
+ </div>
49
+
50
+ {% with messages = get_flashed_messages(with_categories=False) %}
51
+ {% if messages %}
52
+ {% for m in messages %}
53
+ <div class="flash">{{ m }}</div>
54
+ {% endfor %}
55
+ {% endif %}
56
+ {% endwith %}
57
+
58
+ {# Payment failure grace warning (from remote licence service sync) #}
59
+ {% if premium_state.remote_status and (premium_state.remote_status | lower) == 'past_due' %}
60
+ <div class="warn">
61
+ <b>Payment failed.</b>
62
+ {% if premium_state.remote_grace_until %}
63
+ Grace period ends: <code>{{ premium_state.remote_grace_until }}</code>.
64
+ {% else %}
65
+ Your subscription is in grace period.
66
+ {% endif %}
67
+ Update billing to avoid downgrade.
68
+ {% if is_superadmin %}
69
+ <span style="margin-left:10px;">
70
+ <form method="post" style="display:inline;">
71
+ <input type="hidden" name="action" value="portal">
72
+ <button class="btn" type="submit">Manage billing</button>
73
+ </form>
74
+ </span>
75
+ {% endif %}
76
+ </div>
77
+ {% endif %}
78
+
79
+ <div class="card">
80
+ <h3 style="margin:0 0 10px 0;">Current status</h3>
81
+ <div class="kvs">
82
+ <div class="k">Plan</div>
83
+ <div class="v">{{ premium_state.plan | upper }}</div>
84
+
85
+ <div class="k">Trial</div>
86
+ <div class="v">
87
+ {% if premium_state.trial_active %}
88
+ Active ({{ premium_state.trial_days_left }} day{% if premium_state.trial_days_left != 1 %}s{% endif %} left)
89
+ {% else %}
90
+ Ended
91
+ {% endif %}
92
+
93
+ {% if (not premium_state.trial_active) and (premium_state.plan | lower == "free") %}
94
+ {% set ns = namespace(missing=[]) %}
95
+ {% for it in (ent_items or []) %}
96
+ {% if it.type == "bool" and (it.category | lower) == "features" and (not it.value) %}
97
+ {% set _ = ns.missing.append(it.name) %}
98
+ {% endif %}
99
+ {% endfor %}
100
+
101
+ <div class="warn" style="margin-top:12px;">
102
+ You're on <b>FREE</b>.
103
+
104
+ {% if ns.missing %}
105
+ <div style="margin-top:8px;">
106
+ <b>Locked on this plan:</b> {{ ns.missing | join(", ") }}.
107
+ </div>
108
+ {% endif %}
109
+
110
+ <div style="margin-top:10px;">
111
+ <b>Your current caps:</b>
112
+ <ul style="margin:6px 0 0 18px;">
113
+ {% for it in (ent_items or []) %}
114
+ {% if (it.category | lower) == "limits" %}
115
+ <li><b>{{ it.name }}:</b> {{ it.value }}{% if it.unit %} {{ it.unit }}{% endif %}</li>
116
+ {% endif %}
117
+ {% endfor %}
118
+ </ul>
119
+ </div>
120
+ {% if is_superadmin %}
121
+ <div style="margin-top:12px;display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
122
+ <a class="btn" href="{{ url_for('admin_billing') }}">Upgrade / Apply licence</a>
123
+ <span class="hint" style="margin:0;">
124
+ Quick start: paste <code>{"plan":"pro"}</code> below and click <b>Save</b>.
125
+ </span>
126
+ </div>
127
+ {% endif %}
128
+ </div>
129
+ {% endif %}
130
+ </div>
131
+
132
+ {% if is_superadmin %}
133
+ <div>
134
+ {% if last_licence_error %}
135
+ <div class="warn" style="margin-top:12px;">
136
+ <b>Last licence issue:</b> {{ last_licence_error }}
137
+ </div>
138
+ {% endif %}
139
+ </div>
140
+ {% endif %}
141
+
142
+ <div class="k">Trial started</div>
143
+ <div class="v"><code>{{ premium_state.trial_started_at or '—' }}</code></div>
144
+
145
+ {% if is_superadmin %}
146
+ <div class="k">Instance fingerprint</div>
147
+ <div class="v"><code>{{ premium_state.instance_id or '—' }}</code></div>
148
+
149
+ <div class="k">Entitlements source</div>
150
+ <div class="v"><code>{{ premium_state.source }}</code></div>
151
+
152
+ <div class="k">Licence file</div>
153
+ <div class="v">
154
+ {% if licence_exists %}
155
+ Found: <code>{{ licence_path }}</code>
156
+ {% else %}
157
+ Not found: <code>{{ licence_path }}</code>
158
+ {% endif %}
159
+ </div>
160
+ {% endif %}
161
+ </div>
162
+
163
+ {% if premium_state.trial_active %}
164
+ <div class="warn" style="margin-top:12px;">
165
+ Trial is full-access. If you upload a Pro/Enterprise licence now, it will be stored and will take over automatically after the trial ends.
166
+ </div>
167
+ {% endif %}
168
+
169
+ <div class="hint">
170
+ This is self-hosted BYOK. Upgrade is automatic: click a plan below, complete Stripe checkout.
171
+ </div>
172
+ </div>
173
+
174
+ <div class="card">
175
+ <h3 style="margin:0 0 10px 0;">Entitlements</h3>
176
+ {% set feats = [] %}
177
+ {% set lims = [] %}
178
+ {% for it in (ent_items or []) %}
179
+ {% if it.type == "bool" and (it.category | lower) == "features" %}
180
+ {% set _ = feats.append(it) %}
181
+ {% elif (it.category | lower) == "limits" %}
182
+ {% set _ = lims.append(it) %}
183
+ {% endif %}
184
+ {% endfor %}
185
+
186
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:start;">
187
+ <div>
188
+ <div class="k" style="margin-bottom:6px;">Features</div>
189
+ <ul style="margin:0 0 0 18px;">
190
+ {% for it in feats %}
191
+ <li>
192
+ {% if it.value %}✓{% else %}✕{% endif %}
193
+ {{ it.name }}
194
+ </li>
195
+ {% endfor %}
196
+ </ul>
197
+ </div>
198
+
199
+ <div>
200
+ <div class="k" style="margin-bottom:6px;">Limits</div>
201
+ <ul style="margin:0 0 0 18px;">
202
+ {% for it in lims %}
203
+ <li><b>{{ it.name }}:</b> {{ it.value }}{% if it.unit %} {{ it.unit }}{% endif %}</li>
204
+ {% endfor %}
205
+ </ul>
206
+ </div>
207
+ </div>
208
+
209
+ <details style="margin-top:10px;">
210
+ <summary class="k" style="cursor:pointer;">Show raw entitlements JSON</summary>
211
+ <pre>{{ entitlements_json }}</pre>
212
+ </details>
213
+ </div>
214
+
215
+ {% if is_superadmin %}
216
+ <div class="card">
217
+ <div class="row" style="justify-content:space-between;align-items:flex-start;">
218
+ <div>
219
+ <h3 style="margin:0 0 6px 0;">Plan actions</h3>
220
+ <div class="hint" style="margin-top:0;">Upgrade or Downgrade”.</div>
221
+ </div>
222
+ <div class="row" style="justify-content:flex-end;">
223
+ <form method="post" style="margin:0;">
224
+ <input type="hidden" name="action" value="portal">
225
+ <button class="btn" type="submit">Manage billing</button>
226
+ </form>
227
+ </div>
228
+ </div>
229
+
230
+ {% set cur = (premium_state.plan | lower) %}
231
+
232
+ <div class="row" style="margin-top:10px;">
233
+ {# FREE / TRIAL: show Pro + Enterprise #}
234
+ {% if cur in ['free','trial'] %}
235
+ <!-- Pro options -->
236
+ <form method="post">
237
+ <input type="hidden" name="action" value="checkout">
238
+ <input type="hidden" name="plan" value="pro">
239
+ <input type="hidden" name="interval" value="monthly">
240
+ <button class="btn upsell" type="submit">Pro - Monthly</button>
241
+ </form>
242
+ <form method="post">
243
+ <input type="hidden" name="action" value="checkout">
244
+ <input type="hidden" name="plan" value="pro">
245
+ <input type="hidden" name="interval" value="annual">
246
+ <button class="btn upsell" type="submit">Pro - Annual</button>
247
+ </form>
248
+
249
+ <!-- Business Monthly -->
250
+ <form method="post" action="/admin/billing" style="display:inline-block; margin-right:8px;">
251
+ <input type="hidden" name="action" value="checkout">
252
+ <input type="hidden" name="plan" value="business">
253
+ <input type="hidden" name="interval" value="monthly">
254
+ <button type="submit" class="btn upsell">Business - Monthly</button>
255
+ </form>
256
+ <form method="post" action="/admin/billing" style="display:inline-block; margin-right:8px;">
257
+ <input type="hidden" name="action" value="checkout">
258
+ <input type="hidden" name="plan" value="business">
259
+ <input type="hidden" name="interval" value="annual">
260
+ <button type="submit" class="btn upsell">Business - Annual</button>
261
+ </form>
262
+ <!-- Enterprise options -->
263
+ <form method="post">
264
+ <input type="hidden" name="action" value="checkout">
265
+ <input type="hidden" name="plan" value="enterprise">
266
+ <input type="hidden" name="interval" value="monthly">
267
+ <button class="btn upsell" type="submit">Enterprise - Monthly</button>
268
+ </form>
269
+ <form method="post">
270
+ <input type="hidden" name="action" value="checkout">
271
+ <input type="hidden" name="plan" value="enterprise">
272
+ <input type="hidden" name="interval" value="annual">
273
+ <button class="btn upsell" type="submit">Enterprise - Annual</button>
274
+ </form>
275
+ {% elif cur == 'pro' %}
276
+ {# PRO: show upgrades to Business & Enterprise #}
277
+ <form method="post">
278
+ <input type="hidden" name="action" value="checkout">
279
+ <input type="hidden" name="plan" value="business">
280
+ <input type="hidden" name="interval" value="monthly">
281
+ <button class="btn upsell" type="submit">Upgrade to Business - Monthly</button>
282
+ </form>
283
+ <form method="post">
284
+ <input type="hidden" name="action" value="checkout">
285
+ <input type="hidden" name="plan" value="business">
286
+ <input type="hidden" name="interval" value="annual">
287
+ <button class="btn upsell" type="submit">Upgrade to Business - Annual</button>
288
+ </form>
289
+
290
+ <form method="post">
291
+ <input type="hidden" name="action" value="checkout">
292
+ <input type="hidden" name="plan" value="enterprise">
293
+ <input type="hidden" name="interval" value="monthly">
294
+ <button class="btn upsell" type="submit">Upgrade to Enterprise - Monthly</button>
295
+ </form>
296
+ <form method="post">
297
+ <input type="hidden" name="action" value="checkout">
298
+ <input type="hidden" name="plan" value="enterprise">
299
+ <input type="hidden" name="interval" value="annual">
300
+ <button class="btn upsell" type="submit">Upgrade to Enterprise - Annual</button>
301
+ </form>
302
+ {% elif cur == 'business' %}
303
+ {# BUSINESS: show upgrade to Enterprise & downgrade to Pro #}
304
+ <form method="post">
305
+ <input type="hidden" name="action" value="checkout">
306
+ <input type="hidden" name="plan" value="enterprise">
307
+ <input type="hidden" name="interval" value="monthly">
308
+ <button class="btn upsell" type="submit">Upgrade to Enterprise - Monthly</button>
309
+ </form>
310
+ <form method="post">
311
+ <input type="hidden" name="action" value="checkout">
312
+ <input type="hidden" name="plan" value="enterprise">
313
+ <input type="hidden" name="interval" value="annual">
314
+ <button class="btn upsell" type="submit">Upgrade to Enterprise - Annual</button>
315
+ </form>
316
+
317
+ <form method="post">
318
+ <input type="hidden" name="action" value="checkout">
319
+ <input type="hidden" name="plan" value="pro">
320
+ <input type="hidden" name="interval" value="monthly">
321
+ <button class="btn upsell" type="submit">Downgrade to Pro - Monthly</button>
322
+ </form>
323
+ <form method="post">
324
+ <input type="hidden" name="action" value="checkout">
325
+ <input type="hidden" name="plan" value="pro">
326
+ <input type="hidden" name="interval" value="annual">
327
+ <button class="btn upsell" type="submit">Downgrade to Pro - Annual</button>
328
+ </form>
329
+ {% elif cur == 'enterprise' %}
330
+ {# ENTERPRISE: show downgrade to Business and Pro #}
331
+ <form method="post">
332
+ <input type="hidden" name="action" value="checkout">
333
+ <input type="hidden" name="plan" value="business">
334
+ <input type="hidden" name="interval" value="monthly">
335
+ <button class="btn upsell" type="submit">Downgrade to Business - Monthly</button>
336
+ </form>
337
+ <form method="post">
338
+ <input type="hidden" name="action" value="checkout">
339
+ <input type="hidden" name="plan" value="business">
340
+ <input type="hidden" name="interval" value="annual">
341
+ <button class="btn upsell" type="submit">Downgrade to Business - Annual</button>
342
+ </form>
343
+
344
+ <form method="post">
345
+ <input type="hidden" name="action" value="checkout">
346
+ <input type="hidden" name="plan" value="pro">
347
+ <input type="hidden" name="interval" value="monthly">
348
+ <button class="btn upsell" type="submit">Downgrade to Pro - Monthly</button>
349
+ </form>
350
+ <form method="post">
351
+ <input type="hidden" name="action" value="checkout">
352
+ <input type="hidden" name="plan" value="pro">
353
+ <input type="hidden" name="interval" value="annual">
354
+ <button class="btn upsell" type="submit">Downgrade to Pro - Annual</button>
355
+ </form>
356
+ {% else %}
357
+ <div class="hint">Unknown plan state.</div>
358
+ {% endif %}
359
+ </div>
360
+
361
+ <div class="hint">
362
+ Self-serve billing is via Stripe Portal (Manage billing). If you switch plans using checkout, Stripe will create a new subscription on the chosen plan.
363
+ </div>
364
+ </div>
365
+
366
+ {% if manual_licence_ui_enabled %}
367
+ <div class="card">
368
+ <h3 style="margin:0 0 10px 0;">Upload licence.json</h3>
369
+ <form method="post" enctype="multipart/form-data">
370
+ <input type="hidden" name="action" value="upload">
371
+ <div class="row">
372
+ <input type="file" name="licence_file" accept="application/json,.json">
373
+ <button class="btn" type="submit">Upload</button>
374
+ </div>
375
+ <div class="hint">Upload a JSON object. Example: <code>{"plan":"pro"}</code>.</div>
376
+ </form>
377
+ </div>
378
+
379
+ <div class="card">
380
+ <h3 style="margin:0 0 10px 0;">Paste licence JSON</h3>
381
+ <form method="post">
382
+ <input type="hidden" name="action" value="paste">
383
+ <textarea name="licence_text" placeholder='{"plan":"pro"}'></textarea>
384
+ <div style="margin-top:12px;display:flex;justify-content:flex-end;gap:10px;">
385
+ <button class="btn" type="submit">Save</button>
386
+ </div>
387
+ </form>
388
+ <div class="hint">This is intended for development/testing only. Production upgrades should use Stripe checkout.</div>
389
+ </div>
390
+ {% endif %}
391
+
392
+ <div class="card">
393
+ <h3 style="margin:0 0 10px 0;">Raw licence.json (first 8k chars)</h3>
394
+ {% if licence_raw %}
395
+ <pre>{{ licence_raw }}</pre>
396
+ {% else %}
397
+ <div class="hint">No licence file content to display.</div>
398
+ {% endif %}
399
+ <form method="post" style="margin-top:12px;">
400
+ <input type="hidden" name="action" value="clear">
401
+ <button class="btn btn-danger" type="submit" onclick="return confirm('Are you sure you want to clear the licence? This will downgrade features immediately to Free Plan.');">Clear licence</button>
402
+ </form>
403
+ </div>
404
+ {% endif %}
405
+
406
+ </div>
407
+ </body>
408
+ </html>
@@ -13,7 +13,10 @@
13
13
  .btn:hover{border-color:rgba(56,189,248,.6);color:#38bdf8;}
14
14
  .card{background:rgba(2,6,23,.65);border:1px solid rgba(148,163,184,.25);border-radius:14px;padding:14px;box-shadow:0 18px 36px rgba(15,23,42,.6);margin-bottom:12px;}
15
15
  label{display:block;font-size:.78rem;font-weight:750;margin-bottom:6px;color:#d1d5db;}
16
- input[type="file"]{width:100%;padding:10px 11px;border-radius:12px;border:1px solid rgba(148,163,184,.25);background:rgba(2,6,23,.8);color:#e5e7eb;outline:none;}
16
+ input[type="file"],
17
+ input[type="text"],
18
+ textarea{width:100%;padding:10px 11px;border-radius:12px;border:1px solid rgba(148,163,184,.25);background:rgba(2,6,23,.8);color:#e5e7eb;outline:none;}
19
+ textarea{min-height:110px;resize:vertical;}
17
20
  .row{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
18
21
  @media (max-width:760px){.row{grid-template-columns:1fr;}}
19
22
  .hint{color:#9ca3af;font-size:.78rem;line-height:1.35;margin-top:8px;}
@@ -51,6 +54,49 @@
51
54
  <div class="hint">The title displayed in the header and browser tab.</div>
52
55
  </div>
53
56
 
57
+ <hr style="border:none;border-top:1px solid rgba(148,163,184,.25);margin:16px 0;">
58
+ <h3 style="margin:0 0 8px 0;">Landing page</h3>
59
+ <p style="margin:0 0 10px 0;color:var(--muted);">
60
+ Choose what visitors see at <code>/</code>.
61
+ </p>
62
+
63
+ <div class="row" style="gap:12px;flex-wrap:wrap;">
64
+ <div style="min-width:260px;flex:1;">
65
+ <label class="label" for="landing_mode">Landing mode</label>
66
+ <select class="input" id="landing_mode" name="landing_mode">
67
+ <option value="chat" {% if (landing_mode or 'chat') == 'chat' %}selected{% endif %}>Chat (default)</option>
68
+ <option value="page" {% if landing_mode == 'page' %}selected{% endif %}>Page</option>
69
+ </select>
70
+ </div>
71
+
72
+ <div style="min-width:320px;flex:2;">
73
+ <label class="label" for="landing_page_name">Landing page name (page slug)</label>
74
+ <input class="input" id="landing_page_name" name="landing_page_name"
75
+ value="{{ landing_page_name or '' }}"
76
+ placeholder="e.g. about or services or blog">
77
+ <div style="margin-top:6px;color:var(--muted);font-size:.92rem;">
78
+ Used only when Landing mode = <b>Page</b>. This will route to:
79
+ <code>/page/&lt;name&gt;</code>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
84
+ <script>
85
+ (function(){
86
+ const mode = document.getElementById("landing_mode");
87
+ const inp = document.getElementById("landing_page_name");
88
+ if(!mode || !inp) return;
89
+
90
+ function sync(){
91
+ const isPage = (mode.value === "page");
92
+ inp.disabled = !isPage;
93
+ inp.style.opacity = isPage ? "1" : ".55";
94
+ }
95
+ mode.addEventListener("change", sync);
96
+ sync();
97
+ })();
98
+ </script>
99
+
54
100
  <div>
55
101
  <label>Project name</label>
56
102
  <input type="text" name="project_name" value="{{ project_name }}" placeholder="e.g. smxAI">
@@ -59,6 +105,23 @@
59
105
  </div>
60
106
 
61
107
  <div style="margin-top:12px;display:flex;justify-content:flex-end;gap:10px;">
108
+ <div style="margin-top:14px;">
109
+ <label>Chat identity (system profile)</label>
110
+ <textarea name="smxai_identity" placeholder="e.g. You are SyntaxMatrix AI, a helpful assistant for ...">{{ smxai_identity }}</textarea>
111
+ <div class="hint">Used as the system identity for the chat model. Leave blank to use the framework default.</div>
112
+ </div>
113
+
114
+ <div style="margin-top:12px;">
115
+ <label>Chat instructions (system rules)</label>
116
+ <textarea name="smxai_instructions" placeholder="Add extra rules for your client instance…">{{ smxai_instructions }}</textarea>
117
+ <div class="hint">Extra guardrails and tone/style instructions. Leave blank to use the framework default.</div>
118
+ </div>
119
+
120
+ <div style="margin-top:12px;">
121
+ <label>Website description (used during page generation)</label>
122
+ <textarea name="website_description" placeholder="Describe the company, services, target audience, tone, branding…">{{ website_description }}</textarea>
123
+ <div class="hint">When set, the user won’t need to retype it during page generation. Leave blank to use the framework default.</div>
124
+ </div>
62
125
  <button class="btn" type="submit">Save</button>
63
126
  </div>
64
127
  </form>
@@ -86,7 +149,7 @@
86
149
  </div>
87
150
  </form>
88
151
 
89
- <form method="post" enctype="multipart/form-data">
152
+ <form method="post" enctype="multipart/form-data">
90
153
  <input type="hidden" name="action" value="upload">
91
154
 
92
155
  <div class="row">
@@ -18,6 +18,15 @@
18
18
  .row:first-child{border-top:none;}
19
19
  .label{font-weight:750;}
20
20
  input[type="checkbox"]{transform: translateY(2px); width:16px; height:16px;}
21
+ select{
22
+ width:100%;
23
+ padding:10px 11px;
24
+ border-radius:12px;
25
+ border:1px solid rgba(148,163,184,.25);
26
+ background:rgba(2,6,23,.8);
27
+ color:#e5e7eb;
28
+ outline:none;
29
+ }
21
30
  </style>
22
31
  </head>
23
32
  <body>
@@ -53,6 +62,51 @@
53
62
  </div>
54
63
  </div>
55
64
 
65
+ <div class="row">
66
+ <input type="checkbox" id="site_documentation" name="site_documentation" {% if site_documentation %}checked{% endif %}>
67
+ <div>
68
+ <div class="label">Enable site documentation</div>
69
+ <div class="hint">Shows the Docs page in the navbar and enables /docs. Default is off to avoid errors when README.md is missing.</div>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="row">
74
+ <input type="checkbox" id="ml_lab" name="ml_lab" {% if ml_lab %}checked{% endif %}>
75
+ <div>
76
+ <div class="label">Enable ML Lab</div>
77
+ <div class="hint">Shows “MLearning” (Dashboard) in the navbar and enables /dashboard.</div>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="row">
82
+ <input type="checkbox" id="registration" name="registration" {% if registration %}checked{% endif %}>
83
+ <div>
84
+ <div class="label">Enable registration</div>
85
+ <div class="hint">Shows the Register link and enables /register for new user sign-ups.</div>
86
+ </div>
87
+ </div>
88
+
89
+ <div class="row">
90
+ <input type="checkbox" id="theme_toggle" name="theme_toggle" {% if theme_toggle %}checked{% endif %}>
91
+ <div>
92
+ <div class="label">Enable theme toggle</div>
93
+ <div class="hint">Shows the Theme toggle link in the navbar (users can switch theme per session).</div>
94
+ </div>
95
+ </div>
96
+
97
+ <div class="row">
98
+ <div style="width:16px;"></div>
99
+ <div>
100
+ <div class="label">Default theme</div>
101
+ <div class="hint" style="margin-top:-2px;margin-bottom:8px;">Applies immediately and persists across restarts.</div>
102
+ <select name="theme_name" id="theme_name">
103
+ {% for t in themes %}
104
+ <option value="{{ t }}" {% if (t|string)|lower == (theme_name|string)|lower %}selected{% endif %}>{{ t }}</option>
105
+ {% endfor %}
106
+ </select>
107
+ </div>
108
+ </div>
109
+
56
110
  <div style="margin-top:12px;display:flex;justify-content:flex-end;gap:10px;">
57
111
  <button class="btn" type="submit">Save</button>
58
112
  </div>