openclacky 1.3.2 → 1.3.3

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/Dockerfile +3 -0
  4. data/README.md +1 -1
  5. data/README_JA.md +237 -0
  6. data/lib/clacky/agent/session_serializer.rb +49 -5
  7. data/lib/clacky/agent/time_machine.rb +247 -26
  8. data/lib/clacky/agent.rb +12 -1
  9. data/lib/clacky/agent_config.rb +14 -2
  10. data/lib/clacky/default_agents/_panels/git/panel.js +201 -0
  11. data/lib/clacky/default_agents/_panels/time_machine/panel.js +640 -0
  12. data/lib/clacky/default_agents/coding/profile.yml +3 -0
  13. data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
  14. data/lib/clacky/default_skills/cron-task-creator/SKILL.md +1 -1
  15. data/lib/clacky/default_skills/extend-openclacky/SKILL.md +6 -4
  16. data/lib/clacky/default_skills/media-gen/SKILL.md +30 -6
  17. data/lib/clacky/media/openai_compat.rb +64 -1
  18. data/lib/clacky/media/output_dir.rb +43 -0
  19. data/lib/clacky/message_history.rb +9 -0
  20. data/lib/clacky/server/channel/channel_manager.rb +26 -0
  21. data/lib/clacky/server/git_panel.rb +115 -0
  22. data/lib/clacky/server/http_server.rb +497 -12
  23. data/lib/clacky/server/server_master.rb +6 -4
  24. data/lib/clacky/version.rb +1 -1
  25. data/lib/clacky/web/app.css +473 -60
  26. data/lib/clacky/web/app.js +30 -7
  27. data/lib/clacky/web/components/code-editor.js +197 -0
  28. data/lib/clacky/web/{notify.js → components/notify.js} +1 -1
  29. data/lib/clacky/web/core/aside.js +112 -0
  30. data/lib/clacky/web/core/ext.js +387 -0
  31. data/lib/clacky/web/features/backup/store.js +92 -0
  32. data/lib/clacky/web/features/backup/view.js +94 -0
  33. data/lib/clacky/web/features/billing/store.js +163 -0
  34. data/lib/clacky/web/{billing.js → features/billing/view.js} +132 -240
  35. data/lib/clacky/web/features/brand/store.js +110 -0
  36. data/lib/clacky/web/{brand.js → features/brand/view.js} +49 -199
  37. data/lib/clacky/web/features/channels/store.js +103 -0
  38. data/lib/clacky/web/{channels.js → features/channels/view.js} +50 -127
  39. data/lib/clacky/web/features/creator/store.js +81 -0
  40. data/lib/clacky/web/{creator.js → features/creator/view.js} +53 -102
  41. data/lib/clacky/web/features/mcp/store.js +158 -0
  42. data/lib/clacky/web/{mcp.js → features/mcp/view.js} +57 -134
  43. data/lib/clacky/web/features/model-tester/store.js +77 -0
  44. data/lib/clacky/web/features/model-tester/view.js +7 -0
  45. data/lib/clacky/web/features/profile/store.js +170 -0
  46. data/lib/clacky/web/{profile.js → features/profile/view.js} +94 -144
  47. data/lib/clacky/web/features/share/store.js +145 -0
  48. data/lib/clacky/web/{share.js → features/share/view.js} +66 -202
  49. data/lib/clacky/web/features/skills/store.js +303 -0
  50. data/lib/clacky/web/features/skills/view.js +550 -0
  51. data/lib/clacky/web/features/tasks/store.js +135 -0
  52. data/lib/clacky/web/features/tasks/view.js +241 -0
  53. data/lib/clacky/web/features/trash/store.js +242 -0
  54. data/lib/clacky/web/{trash.js → features/trash/view.js} +102 -293
  55. data/lib/clacky/web/features/version/store.js +165 -0
  56. data/lib/clacky/web/features/version/view.js +323 -0
  57. data/lib/clacky/web/features/workspace/store.js +99 -0
  58. data/lib/clacky/web/features/workspace/view.js +305 -0
  59. data/lib/clacky/web/i18n.js +56 -6
  60. data/lib/clacky/web/index.html +117 -58
  61. data/lib/clacky/web/sessions.js +221 -25
  62. data/lib/clacky/web/settings.js +118 -22
  63. data/lib/clacky/web/skills.js +3 -863
  64. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +29 -0
  65. data/lib/clacky.rb +1 -0
  66. metadata +45 -20
  67. data/lib/clacky/web/backup.js +0 -119
  68. data/lib/clacky/web/model-tester.js +0 -66
  69. data/lib/clacky/web/tasks.js +0 -373
  70. data/lib/clacky/web/version.js +0 -449
  71. data/lib/clacky/web/workspace.js +0 -316
  72. /data/lib/clacky/web/{notify.mp3 → assets/notify.mp3} +0 -0
  73. /data/lib/clacky/web/{datepicker.js → components/datepicker.js} +0 -0
  74. /data/lib/clacky/web/{onboard.js → components/onboard.js} +0 -0
  75. /data/lib/clacky/web/{sidebar.js → components/sidebar.js} +0 -0
  76. /data/lib/clacky/web/{marked.min.js → vendor/marked/marked.min.js} +0 -0
@@ -1929,63 +1929,175 @@ body {
1929
1929
  #chat-panel { flex: 1; display: flex; flex-direction: row; overflow: hidden; position: relative; }
1930
1930
  #chat-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; min-width: 0; }
1931
1931
 
1932
- /* ── Workspace panel (right file browser) ───────────────────────────────── */
1933
- #workspace-panel {
1934
- --workspace-width: 280px;
1935
- width: var(--workspace-width);
1932
+ /* ── Session extension slots (agent-scoped panels mount here) ───────────────
1933
+ Each slot is laid out by the host; an empty slot collapses to zero so it
1934
+ never reserves space when no panel is mounted for the current agent. */
1935
+ /* ── Session aside — one resizable / collapsible right column with tabs ─────
1936
+ The host owns the chrome (resize handle, collapse button, floating opener);
1937
+ Clacky.ext renders the tab bar + bodies into #ext-slot-session-aside. When
1938
+ the slot has no panels for the current agent it stays empty and the whole
1939
+ column collapses to zero width. */
1940
+ #session-aside {
1941
+ --session-aside-width: 360px;
1942
+ width: var(--session-aside-width);
1936
1943
  flex-shrink: 0;
1944
+ position: relative;
1937
1945
  display: flex;
1938
1946
  flex-direction: column;
1939
- border-left: 1px solid var(--color-border-primary);
1940
- background: var(--color-bg-primary);
1941
1947
  overflow: hidden;
1948
+ border-left: 1px solid var(--color-border-primary);
1949
+ background: var(--color-bg-secondary);
1942
1950
  transition: width var(--transition-base);
1943
- position: relative;
1944
1951
  }
1945
- #workspace-panel.collapsed { width: 0; border-left: none; }
1946
- #workspace-resize-handle {
1952
+ #session-aside.collapsed { width: 0; border-left: none; }
1953
+ /* Empty slot (no panels for this agent) → collapse the whole column. */
1954
+ #session-aside:has(.session-aside-slot:empty) { width: 0; border-left: none; }
1955
+ #session-aside:has(.session-aside-slot:empty) .session-aside-resize,
1956
+ #session-aside:has(.session-aside-slot:empty) .session-aside-collapse { display: none; }
1957
+
1958
+ .session-aside-resize {
1947
1959
  position: absolute;
1948
1960
  top: 0;
1949
- left: -3px;
1961
+ left: -6px;
1950
1962
  bottom: 0;
1951
- width: 6px;
1963
+ width: 12px;
1952
1964
  cursor: col-resize;
1953
1965
  z-index: 10;
1966
+ background: transparent;
1954
1967
  }
1955
- #workspace-panel:has(#workspace-resize-handle.active) {
1968
+ .session-aside-resize::after {
1969
+ content: "";
1970
+ position: absolute;
1971
+ top: 0;
1972
+ bottom: 0;
1973
+ left: 6px;
1974
+ width: 1px;
1975
+ background: transparent;
1956
1976
  transition: background-color var(--transition-base);
1957
1977
  }
1958
- #workspace-header {
1959
- display: flex;
1978
+ .session-aside-resize:hover::after,
1979
+ .session-aside-resize.active::after { background: var(--color-accent-primary); }
1980
+
1981
+ .session-aside-collapse {
1982
+ position: absolute;
1983
+ top: 7px;
1984
+ right: 8px;
1985
+ z-index: 11;
1986
+ display: inline-flex;
1960
1987
  align-items: center;
1961
- justify-content: space-between;
1962
- height: 2.5rem;
1963
- min-height: 2.5rem;
1964
- padding: 0 0.5rem 0 0.75rem;
1988
+ justify-content: center;
1989
+ width: 1.625rem;
1990
+ height: 1.625rem;
1991
+ border: none;
1992
+ background: transparent;
1993
+ color: var(--color-text-tertiary);
1994
+ border-radius: var(--radius-sm);
1995
+ cursor: pointer;
1996
+ transition: background-color var(--transition-base), color var(--transition-base);
1997
+ }
1998
+ .session-aside-collapse:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
1999
+
2000
+ .session-aside-slot { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
2001
+
2002
+ /* Tab bar (rendered by Clacky.ext). Leaves room on the right for the collapse
2003
+ button which is absolutely positioned over it. */
2004
+ .aside-tabs {
2005
+ flex: none;
2006
+ display: flex;
2007
+ align-items: stretch;
2008
+ height: 40px;
2009
+ padding: 0 38px 0 4px;
2010
+ gap: 2px;
1965
2011
  border-bottom: 1px solid var(--color-border-primary);
1966
- font-size: 0.8125rem;
1967
- font-weight: 600;
1968
- color: var(--color-text-primary);
2012
+ overflow-x: auto;
2013
+ scrollbar-width: none;
1969
2014
  }
1970
- .workspace-header-actions { display: flex; gap: 0.125rem; }
1971
- .workspace-icon-btn {
2015
+ .aside-tabs::-webkit-scrollbar { display: none; }
2016
+ .aside-tab {
1972
2017
  display: inline-flex;
1973
2018
  align-items: center;
1974
- justify-content: center;
1975
- width: 1.75rem;
1976
- height: 1.75rem;
2019
+ gap: 6px;
2020
+ padding: 0 12px;
2021
+ white-space: nowrap;
2022
+ cursor: pointer;
1977
2023
  border: none;
1978
- background: transparent;
2024
+ background: none;
2025
+ font-size: 12.5px;
2026
+ color: var(--color-text-tertiary);
2027
+ border-bottom: 2px solid transparent;
2028
+ }
2029
+ .aside-tab:hover { color: var(--color-text-secondary); }
2030
+ .aside-tab.active { color: var(--color-text-primary); border-bottom-color: var(--color-accent-primary); font-weight: 600; }
2031
+ .aside-tab-badge {
2032
+ font-size: 10px;
2033
+ min-width: 16px;
2034
+ height: 16px;
2035
+ padding: 0 4px;
2036
+ border-radius: var(--radius-pill);
2037
+ background: var(--color-accent-primary);
2038
+ color: var(--color-text-inverse);
2039
+ display: inline-flex;
2040
+ align-items: center;
2041
+ justify-content: center;
2042
+ }
2043
+
2044
+ .aside-bodies { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
2045
+ .aside-panel { flex: 1; min-height: 0; overflow: auto; display: none; flex-direction: column; }
2046
+ .aside-panel.active { display: flex; }
2047
+
2048
+ /* Floating opener shown when the column is collapsed. */
2049
+ .session-aside-opener {
2050
+ position: absolute;
2051
+ top: 0.5rem;
2052
+ right: 0.5rem;
2053
+ z-index: 8;
2054
+ display: inline-flex;
2055
+ align-items: center;
2056
+ justify-content: center;
2057
+ width: 2rem;
2058
+ height: 2rem;
2059
+ border: 1px solid var(--color-border-primary);
2060
+ background: var(--color-bg-secondary);
1979
2061
  color: var(--color-text-secondary);
1980
2062
  border-radius: var(--radius-sm);
1981
2063
  cursor: pointer;
2064
+ box-shadow: var(--shadow-sm, 0 2px 8px rgba(0,0,0,0.06));
1982
2065
  transition: background-color var(--transition-base), color var(--transition-base);
1983
2066
  }
1984
- .workspace-icon-btn:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
1985
- #workspace-tree {
2067
+ .session-aside-opener:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
2068
+
2069
+ .session-banner:empty,
2070
+ .session-composer:empty { display: none; }
2071
+ .session-banner { flex-shrink: 0; }
2072
+ .session-composer { flex-shrink: 0; }
2073
+
2074
+ /* ── File tree (used inside the Files tab) ──────────────────────────────── */
2075
+ .wt-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; }
2076
+ .wt-bar {
2077
+ flex: none;
2078
+ display: flex;
2079
+ align-items: center;
2080
+ justify-content: space-between;
2081
+ gap: 8px;
2082
+ padding: 8px 12px;
2083
+ border-bottom: 1px solid var(--color-border-secondary);
2084
+ }
2085
+ .wt-bar-hint { font-size: 11px; color: var(--color-text-tertiary); }
2086
+ .wt-bar-btn {
2087
+ flex: none;
2088
+ padding: 3px 10px;
2089
+ border: 1px solid var(--color-border-primary);
2090
+ border-radius: var(--radius-sm);
2091
+ background: var(--color-bg-secondary);
2092
+ color: var(--color-text-secondary);
2093
+ font-size: 11px;
2094
+ cursor: pointer;
2095
+ }
2096
+ .wt-bar-btn:hover { background: var(--color-bg-hover); }
2097
+ .wt-tree {
1986
2098
  flex: 1;
1987
2099
  overflow-y: auto;
1988
- padding: 0.375rem 0.25rem;
2100
+ padding: 6px 8px;
1989
2101
  font-size: 0.8125rem;
1990
2102
  font-family: var(--font-mono);
1991
2103
  }
@@ -2022,26 +2134,6 @@ body {
2022
2134
  }
2023
2135
  .wt-error { color: var(--color-danger, #d23); }
2024
2136
 
2025
- /* Collapsed-state opener tab — floats at the right edge of the chat area */
2026
- #btn-workspace-open {
2027
- position: absolute;
2028
- top: 0.5rem;
2029
- right: 0.5rem;
2030
- z-index: 8;
2031
- display: inline-flex;
2032
- align-items: center;
2033
- justify-content: center;
2034
- width: 2rem;
2035
- height: 2rem;
2036
- border: 1px solid var(--color-border-primary);
2037
- background: var(--color-bg-secondary);
2038
- color: var(--color-text-secondary);
2039
- border-radius: var(--radius-sm);
2040
- cursor: pointer;
2041
- transition: background-color var(--transition-base), color var(--transition-base);
2042
- }
2043
- #btn-workspace-open:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
2044
-
2045
2137
  /* Mobile-only floating back button — replaces the old in-header back button.
2046
2138
  Hidden on desktop; mobile media query enables it. Positioned absolutely so
2047
2139
  it doesn't take layout space or add visual chrome on desktop. */
@@ -2185,13 +2277,133 @@ body {
2185
2277
  }
2186
2278
  /* Time color / alignment: anchor to the bubble's own side, let width be
2187
2279
  driven by content — prevents overflow on narrow bubbles. */
2188
- .msg-user .msg-time { color: var(--color-text-secondary); right: 0; left: auto; padding-right: 0.25rem; }
2280
+ .msg-user .msg-time { display: none; }
2189
2281
  .msg-assistant .msg-time { color: var(--color-text-secondary); left: 0; right: auto; padding-left: 0.25rem; }
2190
2282
 
2191
- .msg-user { background: var(--color-accent-soft); color: var(--color-text-primary); align-self: flex-end; white-space: pre-wrap; }
2283
+ .msg-user { background: var(--color-accent-soft); color: var(--color-text-primary); white-space: pre-wrap; }
2192
2284
  [data-theme="dark"] .msg-user { background: var(--color-accent-soft); }
2193
2285
  .msg-assistant { background: var(--color-bg-tertiary); border: 1px solid var(--color-border-primary); align-self: flex-start; }
2194
2286
 
2287
+ /* ── User message action bar (copy + edit) ─────────────────────────────── */
2288
+ .msg-user-wrap {
2289
+ position: relative;
2290
+ display: flex;
2291
+ justify-content: flex-end;
2292
+ padding-bottom: 1.8rem;
2293
+ }
2294
+ .msg-user-actions {
2295
+ position: absolute;
2296
+ top: calc(100% - 1.5rem + 2px);
2297
+ right: 0;
2298
+ display: flex;
2299
+ gap: 0.125rem;
2300
+ opacity: 0;
2301
+ transition: opacity 0.15s ease;
2302
+ pointer-events: none;
2303
+ z-index: 3;
2304
+ }
2305
+ .msg-user-wrap:hover .msg-user-actions { opacity: 1; pointer-events: auto; }
2306
+ .msg-user-wrap:has(.msg-user.editing) { padding-bottom: 0; }
2307
+ .msg-user-wrap:has(.msg-user.editing) .msg-user-actions { display: none; }
2308
+
2309
+ .msg-user-action-btn {
2310
+ display: inline-flex;
2311
+ align-items: center;
2312
+ justify-content: center;
2313
+ width: 1.625rem;
2314
+ height: 1.625rem;
2315
+ padding: 0;
2316
+ border: 1px solid var(--color-border-primary);
2317
+ border-radius: 5px;
2318
+ background: var(--color-bg-primary);
2319
+ color: var(--color-text-secondary);
2320
+ cursor: pointer;
2321
+ transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
2322
+ }
2323
+ .msg-user-action-btn:hover {
2324
+ color: var(--color-text-primary);
2325
+ background: var(--color-bg-tertiary);
2326
+ }
2327
+ .msg-user-action-btn:active { transform: translateY(1px); }
2328
+ .msg-user-action-btn.is-copied {
2329
+ color: var(--color-success);
2330
+ border-color: var(--color-success);
2331
+ }
2332
+ .msg-user-copy-icon-check { display: none; }
2333
+ .msg-user-action-btn.is-copied .msg-user-copy-icon { display: none; }
2334
+ .msg-user-action-btn.is-copied .msg-user-copy-icon-check { display: inline; }
2335
+
2336
+ /* Keep the buttons reachable without hover on touch / narrow viewports. */
2337
+ @media (hover: none) {
2338
+ .msg-user-actions { opacity: 0.65; pointer-events: auto; }
2339
+ }
2340
+
2341
+ /* ── Edit mode ─────────────────────────────────────────────────────────── */
2342
+ .msg-user.editing {
2343
+ background: var(--color-bg-primary);
2344
+ padding: 0.625rem 0.75rem 0.5rem;
2345
+ overflow: visible;
2346
+ border-radius: 8px;
2347
+ border: 1px solid var(--color-border-primary);
2348
+ max-width: min(42rem, 90%);
2349
+ width: min(42rem, 90%);
2350
+ }
2351
+ .msg-user-edit-wrap {
2352
+ display: flex;
2353
+ flex-direction: column;
2354
+ gap: 0.5rem;
2355
+ width: 100%;
2356
+ }
2357
+ .msg-user-edit-textarea {
2358
+ width: 100%;
2359
+ min-height: 1.5rem;
2360
+ padding: 0;
2361
+ border: none;
2362
+ border-radius: 0;
2363
+ background: transparent;
2364
+ color: var(--color-text-primary);
2365
+ font-family: inherit;
2366
+ font-size: 0.875rem;
2367
+ line-height: 1.6;
2368
+ resize: none;
2369
+ overflow: hidden;
2370
+ outline: none;
2371
+ white-space: pre-wrap;
2372
+ }
2373
+ .msg-user-edit-actions {
2374
+ display: flex;
2375
+ justify-content: flex-end;
2376
+ gap: 0.375rem;
2377
+ }
2378
+ .msg-user-edit-cancel {
2379
+ padding: 0.25rem 0.625rem;
2380
+ border: 1px solid var(--color-border-primary);
2381
+ border-radius: 5px;
2382
+ background: transparent;
2383
+ color: var(--color-text-secondary);
2384
+ font-size: 0.75rem;
2385
+ font-weight: 500;
2386
+ cursor: pointer;
2387
+ transition: background 0.15s ease, color 0.15s ease;
2388
+ }
2389
+ .msg-user-edit-cancel:hover {
2390
+ background: var(--color-bg-hover);
2391
+ color: var(--color-text-primary);
2392
+ }
2393
+ .msg-user-edit-send {
2394
+ padding: 0.25rem 0.75rem;
2395
+ border: none;
2396
+ border-radius: 5px;
2397
+ background: var(--color-button-primary);
2398
+ color: var(--color-button-primary-text);
2399
+ font-size: 0.75rem;
2400
+ font-weight: 500;
2401
+ cursor: pointer;
2402
+ transition: opacity 0.15s ease;
2403
+ }
2404
+ .msg-user-edit-send:hover { opacity: 0.88; }
2405
+ .msg-user-edit-send:active { opacity: 0.76; }
2406
+
2195
2407
  /* ── Copy button on assistant messages ────────────────────────────────────
2196
2408
  Hidden by default, revealed on bubble hover (same pattern as .msg-time).
2197
2409
  On touch devices (hover: none) we keep the button visible at low opacity
@@ -2225,8 +2437,8 @@ body {
2225
2437
  }
2226
2438
  .msg-copy-btn.is-copied {
2227
2439
  opacity: 1;
2228
- color: #10b981; /* success green — same across themes */
2229
- border-color: #10b981;
2440
+ color: var(--color-success);
2441
+ border-color: var(--color-success);
2230
2442
  background: var(--color-bg-primary);
2231
2443
  }
2232
2444
  .msg-copy-btn .msg-copy-icon,
@@ -2838,7 +3050,7 @@ body {
2838
3050
  display: flex;
2839
3051
  align-items: center;
2840
3052
  gap: 0.375rem;
2841
- flex-wrap: wrap;
3053
+ flex-wrap: nowrap;
2842
3054
  padding: 0.375rem 0.75rem;
2843
3055
  margin-left: 1.5rem;
2844
3056
  margin-right: 1.5rem;
@@ -2848,13 +3060,17 @@ body {
2848
3060
  color: var(--color-text-tertiary);
2849
3061
  font-family: var(--font-mono, monospace);
2850
3062
  white-space: nowrap;
2851
- overflow: hidden;
3063
+ overflow-x: auto;
3064
+ overflow-y: hidden;
3065
+ scrollbar-width: none;
2852
3066
  flex-shrink: 0;
2853
3067
  opacity: 0.95;
2854
3068
  transition: opacity 0.15s ease;
2855
3069
  cursor: default;
2856
3070
  }
2857
3071
 
3072
+ #session-info-bar::-webkit-scrollbar { display: none; }
3073
+
2858
3074
  #session-info-bar .sib-sep {
2859
3075
  opacity: 0.3;
2860
3076
  }
@@ -4097,7 +4313,6 @@ body {
4097
4313
  padding: 2rem 2rem 1.5rem;
4098
4314
  display: flex;
4099
4315
  flex-direction: column;
4100
- gap: 2rem;
4101
4316
  }
4102
4317
  .settings-section {
4103
4318
  display: flex;
@@ -4182,6 +4397,15 @@ body {
4182
4397
  }
4183
4398
 
4184
4399
  /* ── Backup section ── */
4400
+ .backup-auto-card {
4401
+ border: 1px solid var(--color-border-primary);
4402
+ border-radius: 10px;
4403
+ padding: 0.625rem 0.875rem;
4404
+ background: var(--color-bg-secondary);
4405
+ }
4406
+ .backup-auto-card .backup-auto-row {
4407
+ margin: 0.25rem 0;
4408
+ }
4185
4409
  .backup-option,
4186
4410
  .backup-auto-label {
4187
4411
  font-size: 0.8125rem;
@@ -4193,6 +4417,11 @@ body {
4193
4417
  .backup-option {
4194
4418
  margin: 0.75rem 0;
4195
4419
  }
4420
+ .backup-option-nested {
4421
+ margin: 0.5rem 0 0.25rem 2.75rem;
4422
+ font-size: 0.78125rem;
4423
+ color: var(--color-text-secondary);
4424
+ }
4196
4425
  .backup-auto-row {
4197
4426
  display: flex;
4198
4427
  align-items: center;
@@ -4208,7 +4437,6 @@ body {
4208
4437
  display: flex;
4209
4438
  align-items: center;
4210
4439
  gap: 0.75rem;
4211
- margin: 0.75rem 0;
4212
4440
  flex-wrap: wrap;
4213
4441
  }
4214
4442
 
@@ -4609,7 +4837,6 @@ body {
4609
4837
  color: var(--color-text-secondary);
4610
4838
  font-family: var(--font-mono, monospace);
4611
4839
  background: var(--color-bg-tertiary);
4612
- padding: 0.125rem 0.375rem;
4613
4840
  border-radius: 4px;
4614
4841
  display: inline-block;
4615
4842
  max-width: 100%;
@@ -6620,6 +6847,123 @@ body {
6620
6847
  background: var(--color-error-bg, #fff0f0);
6621
6848
  }
6622
6849
 
6850
+
6851
+ /* ── CodeEditor (CodeMirror 6) Modal ────────────────────────────────────── */
6852
+ .code-editor-modal {
6853
+ background: var(--color-bg-secondary);
6854
+ border-radius: 12px;
6855
+ border: 1px solid var(--color-border-primary);
6856
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
6857
+ width: 92%;
6858
+ max-width: 820px;
6859
+ height: 82vh;
6860
+ max-height: 860px;
6861
+ display: flex;
6862
+ flex-direction: column;
6863
+ overflow: hidden;
6864
+ }
6865
+ .code-editor-header {
6866
+ display: flex;
6867
+ align-items: center;
6868
+ justify-content: space-between;
6869
+ padding: 0.75rem 1.25rem;
6870
+ border-bottom: 1px solid var(--color-border);
6871
+ }
6872
+ .code-editor-header h3 {
6873
+ margin: 0;
6874
+ font-size: 0.875rem;
6875
+ font-weight: 600;
6876
+ font-family: var(--font-mono, 'SF Mono', 'Fira Code', monospace);
6877
+ color: var(--color-text-primary);
6878
+ }
6879
+ .code-editor-close {
6880
+ background: none;
6881
+ border: none;
6882
+ font-size: 1.25rem;
6883
+ line-height: 1;
6884
+ color: var(--color-text-tertiary);
6885
+ cursor: pointer;
6886
+ width: 2rem;
6887
+ height: 2rem;
6888
+ display: flex;
6889
+ align-items: center;
6890
+ justify-content: center;
6891
+ border-radius: 6px;
6892
+ padding: 0;
6893
+ }
6894
+ .code-editor-close:hover {
6895
+ color: var(--color-text-primary);
6896
+ background: var(--color-bg-hover);
6897
+ }
6898
+ .code-editor-body {
6899
+ flex: 1;
6900
+ overflow: hidden;
6901
+ position: relative;
6902
+ }
6903
+ .code-editor-body .cm-editor {
6904
+ height: 100%;
6905
+ font-size: 0.8125rem;
6906
+ line-height: 1.6;
6907
+ background: transparent;
6908
+ }
6909
+ .code-editor-body .cm-editor .cm-content {
6910
+ background: transparent;
6911
+ }
6912
+ .code-editor-body .cm-editor.cm-focused {
6913
+ outline: none;
6914
+ }
6915
+ .code-editor-body .cm-scroller {
6916
+ overflow: auto;
6917
+ font-family: var(--font-mono, 'SF Mono', 'Fira Code', monospace);
6918
+ }
6919
+ .code-editor-body .cm-gutters {
6920
+ background: transparent;
6921
+ border-right: 1px solid var(--color-border-primary);
6922
+ color: var(--color-text-tertiary);
6923
+ }
6924
+
6925
+ .code-editor-body .cm-activeLineGutter {
6926
+ background: var(--color-bg-hover);
6927
+ }
6928
+ .code-editor-body .cm-activeLine {
6929
+ background: var(--color-bg-hover);
6930
+ }
6931
+ .code-editor-body .cm-selectionBackground {
6932
+ background: color-mix(in srgb, var(--color-accent-primary) 20%, transparent) !important;
6933
+ }
6934
+ .code-editor-footer {
6935
+ display: flex;
6936
+ align-items: center;
6937
+ justify-content: space-between;
6938
+ padding: 0.625rem 1.25rem;
6939
+ border-top: 1px solid var(--color-border);
6940
+ gap: 0.75rem;
6941
+ }
6942
+ .code-editor-status {
6943
+ font-size: 0.8125rem;
6944
+ color: var(--color-text-secondary);
6945
+ }
6946
+ .code-editor-status-error {
6947
+ color: var(--color-error, #c0392b);
6948
+ }
6949
+ .code-editor-actions {
6950
+ display: flex;
6951
+ gap: 0.5rem;
6952
+ }
6953
+ .code-editor-modal--image .code-editor-body {
6954
+ display: flex;
6955
+ align-items: center;
6956
+ justify-content: center;
6957
+ background: var(--color-bg-primary);
6958
+ overflow: auto;
6959
+ }
6960
+ .code-editor-img-preview {
6961
+ max-width: 100%;
6962
+ max-height: 100%;
6963
+ object-fit: contain;
6964
+ border-radius: 4px;
6965
+ }
6966
+
6623
6967
  /* ── Skills sidebar section ──────────────────────────────────────────────── */
6624
6968
  #skill-list-items { padding: 0 0.5rem 0.5rem; display: flex; flex-direction: column; gap: 2px; }
6625
6969
 
@@ -8690,6 +9034,29 @@ body.setup-mode[data-theme="dark"] {
8690
9034
  cursor: wait;
8691
9035
  }
8692
9036
 
9037
+ .profile-pane-footer-actions {
9038
+ display: flex;
9039
+ gap: 0.5rem;
9040
+ align-items: center;
9041
+ }
9042
+
9043
+ .btn-profile-edit {
9044
+ padding: 0.5rem 1.125rem;
9045
+ border-radius: 8px;
9046
+ border: 1px solid var(--color-border-primary);
9047
+ background: transparent;
9048
+ color: var(--color-text-primary);
9049
+ font-size: 0.8125rem;
9050
+ font-weight: 500;
9051
+ cursor: pointer;
9052
+ transition: border-color 0.15s, color 0.15s;
9053
+ }
9054
+
9055
+ .btn-profile-edit:hover {
9056
+ border-color: var(--color-button-primary);
9057
+ color: var(--color-button-primary);
9058
+ }
9059
+
8693
9060
  /* ── Minimal-Markdown rendered body ───────────────────────────────────── */
8694
9061
  .profile-markdown {
8695
9062
  font-size: 0.8438rem;
@@ -8830,6 +9197,7 @@ body.setup-mode[data-theme="dark"] {
8830
9197
 
8831
9198
  /* Shared base for per-card buttons. */
8832
9199
  .btn-memory-curate,
9200
+ .btn-memory-edit,
8833
9201
  .btn-memory-delete,
8834
9202
  .btn-memory-expand {
8835
9203
  padding: 0.3125rem 0.625rem;
@@ -8845,7 +9213,8 @@ body.setup-mode[data-theme="dark"] {
8845
9213
  transition: background 0.15s, border-color 0.15s, color 0.15s;
8846
9214
  }
8847
9215
 
8848
- .btn-memory-curate:hover {
9216
+ .btn-memory-curate:hover,
9217
+ .btn-memory-edit:hover {
8849
9218
  border-color: var(--color-text-primary);
8850
9219
  background: var(--color-bg-hover);
8851
9220
  }
@@ -11712,4 +12081,48 @@ body.setup-mode[data-theme="dark"] {
11712
12081
  font-size: 0.7rem;
11713
12082
  color: var(--color-text-tertiary);
11714
12083
  }
12084
+
12085
+ /* Session aside: fixed overlay on mobile */
12086
+ #session-aside {
12087
+ position: fixed;
12088
+ top: 0;
12089
+ right: 0;
12090
+ height: 100%;
12091
+ z-index: 200;
12092
+ box-shadow: -4px 0 24px rgba(0,0,0,0.18);
12093
+ transition: transform 0.3s ease, background-color 0.3s ease;
12094
+ transform: translateX(0);
12095
+ width: var(--session-aside-width);
12096
+ }
12097
+ #session-aside.collapsed {
12098
+ transform: translateX(100%);
12099
+ width: var(--session-aside-width);
12100
+ border-left: 1px solid var(--color-border-primary);
12101
+ }
12102
+ #session-aside-resize { display: none; }
12103
+
12104
+ #workspace-overlay {
12105
+ display: none;
12106
+ position: fixed;
12107
+ inset: 0;
12108
+ z-index: 199;
12109
+ background: rgba(0,0,0,0.4);
12110
+ }
12111
+ #workspace-overlay.active {
12112
+ display: block;
12113
+ }
12114
+ }
12115
+
12116
+ /* ════ Media output directory subsection (nested under #media-section) ════ */
12117
+ #media-output-dir-section.settings-subsection {
12118
+ display: flex;
12119
+ flex-direction: column;
12120
+ gap: 0.5rem;
12121
+ max-width: 48rem;
12122
+ }
12123
+ #media-output-dir-section .settings-subsection-desc {
12124
+ font-size: 0.8125rem;
12125
+ color: var(--color-text-secondary);
12126
+ line-height: 1.5;
12127
+ margin: 0;
11715
12128
  }