openclacky 1.3.1 → 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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -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 +65 -11
  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/brand_config.rb +1 -1
  11. data/lib/clacky/default_agents/_panels/git/panel.js +201 -0
  12. data/lib/clacky/default_agents/_panels/time_machine/panel.js +640 -0
  13. data/lib/clacky/default_agents/coding/profile.yml +3 -0
  14. data/lib/clacky/default_agents/coding/webui/.gitkeep +0 -0
  15. data/lib/clacky/default_skills/cron-task-creator/SKILL.md +1 -1
  16. data/lib/clacky/default_skills/extend-openclacky/SKILL.md +6 -4
  17. data/lib/clacky/default_skills/media-gen/SKILL.md +30 -6
  18. data/lib/clacky/media/openai_compat.rb +64 -1
  19. data/lib/clacky/media/output_dir.rb +43 -0
  20. data/lib/clacky/message_history.rb +9 -0
  21. data/lib/clacky/server/channel/channel_manager.rb +26 -0
  22. data/lib/clacky/server/git_panel.rb +115 -0
  23. data/lib/clacky/server/http_server.rb +521 -13
  24. data/lib/clacky/server/server_master.rb +6 -4
  25. data/lib/clacky/utils/environment_detector.rb +16 -0
  26. data/lib/clacky/version.rb +1 -1
  27. data/lib/clacky/web/app.css +512 -60
  28. data/lib/clacky/web/app.js +30 -7
  29. data/lib/clacky/web/components/code-editor.js +197 -0
  30. data/lib/clacky/web/{notify.js → components/notify.js} +1 -1
  31. data/lib/clacky/web/core/aside.js +112 -0
  32. data/lib/clacky/web/core/ext.js +387 -0
  33. data/lib/clacky/web/features/backup/store.js +92 -0
  34. data/lib/clacky/web/features/backup/view.js +94 -0
  35. data/lib/clacky/web/features/billing/store.js +163 -0
  36. data/lib/clacky/web/{billing.js → features/billing/view.js} +134 -242
  37. data/lib/clacky/web/features/brand/store.js +110 -0
  38. data/lib/clacky/web/{brand.js → features/brand/view.js} +49 -199
  39. data/lib/clacky/web/features/channels/store.js +103 -0
  40. data/lib/clacky/web/{channels.js → features/channels/view.js} +50 -127
  41. data/lib/clacky/web/features/creator/store.js +81 -0
  42. data/lib/clacky/web/{creator.js → features/creator/view.js} +53 -102
  43. data/lib/clacky/web/features/mcp/store.js +158 -0
  44. data/lib/clacky/web/{mcp.js → features/mcp/view.js} +57 -134
  45. data/lib/clacky/web/features/model-tester/store.js +77 -0
  46. data/lib/clacky/web/features/model-tester/view.js +7 -0
  47. data/lib/clacky/web/features/profile/store.js +170 -0
  48. data/lib/clacky/web/{profile.js → features/profile/view.js} +94 -144
  49. data/lib/clacky/web/features/share/store.js +145 -0
  50. data/lib/clacky/web/{share.js → features/share/view.js} +66 -202
  51. data/lib/clacky/web/features/skills/store.js +303 -0
  52. data/lib/clacky/web/features/skills/view.js +550 -0
  53. data/lib/clacky/web/features/tasks/store.js +135 -0
  54. data/lib/clacky/web/features/tasks/view.js +241 -0
  55. data/lib/clacky/web/features/trash/store.js +242 -0
  56. data/lib/clacky/web/{trash.js → features/trash/view.js} +102 -293
  57. data/lib/clacky/web/features/version/store.js +165 -0
  58. data/lib/clacky/web/features/version/view.js +323 -0
  59. data/lib/clacky/web/features/workspace/store.js +99 -0
  60. data/lib/clacky/web/features/workspace/view.js +305 -0
  61. data/lib/clacky/web/i18n.js +60 -6
  62. data/lib/clacky/web/index.html +117 -57
  63. data/lib/clacky/web/sessions.js +221 -25
  64. data/lib/clacky/web/settings.js +121 -25
  65. data/lib/clacky/web/skills.js +3 -821
  66. data/lib/clacky/web/vendor/codemirror/codemirror.min.js +29 -0
  67. data/lib/clacky.rb +1 -0
  68. metadata +45 -20
  69. data/lib/clacky/web/backup.js +0 -119
  70. data/lib/clacky/web/model-tester.js +0 -66
  71. data/lib/clacky/web/tasks.js +0 -365
  72. data/lib/clacky/web/version.js +0 -449
  73. data/lib/clacky/web/workspace.js +0 -212
  74. /data/lib/clacky/web/{notify.mp3 → assets/notify.mp3} +0 -0
  75. /data/lib/clacky/web/{datepicker.js → components/datepicker.js} +0 -0
  76. /data/lib/clacky/web/{onboard.js → components/onboard.js} +0 -0
  77. /data/lib/clacky/web/{sidebar.js → components/sidebar.js} +0 -0
  78. /data/lib/clacky/web/{marked.min.js → vendor/marked/marked.min.js} +0 -0
@@ -1754,6 +1754,30 @@ body {
1754
1754
  overflow: hidden;
1755
1755
  text-overflow: ellipsis;
1756
1756
  }
1757
+ .task-card-preview-expandable {
1758
+ cursor: pointer;
1759
+ }
1760
+ .task-card-preview-expandable:hover {
1761
+ color: var(--color-accent-primary);
1762
+ }
1763
+ .task-card-detail {
1764
+ margin-top: 0.625rem;
1765
+ padding: 0.625rem 0.75rem;
1766
+ background: var(--color-bg-primary);
1767
+ border: 1px solid var(--color-border-primary);
1768
+ border-radius: 6px;
1769
+ }
1770
+ .task-card-detail-content {
1771
+ margin: 0;
1772
+ font-size: 0.75rem;
1773
+ font-family: inherit;
1774
+ color: var(--color-text-secondary);
1775
+ line-height: 1.6;
1776
+ white-space: pre-wrap;
1777
+ word-break: break-word;
1778
+ max-height: 12rem;
1779
+ overflow-y: auto;
1780
+ }
1757
1781
  .task-card-actions {
1758
1782
  display: flex;
1759
1783
  align-items: center;
@@ -1905,49 +1929,175 @@ body {
1905
1929
  #chat-panel { flex: 1; display: flex; flex-direction: row; overflow: hidden; position: relative; }
1906
1930
  #chat-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; min-width: 0; }
1907
1931
 
1908
- /* ── Workspace panel (right file browser) ───────────────────────────────── */
1909
- #workspace-panel {
1910
- width: 280px;
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);
1911
1943
  flex-shrink: 0;
1944
+ position: relative;
1912
1945
  display: flex;
1913
1946
  flex-direction: column;
1914
- border-left: 1px solid var(--color-border-primary);
1915
- background: var(--color-bg-primary);
1916
1947
  overflow: hidden;
1948
+ border-left: 1px solid var(--color-border-primary);
1949
+ background: var(--color-bg-secondary);
1917
1950
  transition: width var(--transition-base);
1918
1951
  }
1919
- #workspace-panel.collapsed { width: 0; border-left: none; }
1920
- #workspace-header {
1921
- display: flex;
1922
- align-items: center;
1923
- justify-content: space-between;
1924
- height: 2.5rem;
1925
- min-height: 2.5rem;
1926
- padding: 0 0.5rem 0 0.75rem;
1927
- border-bottom: 1px solid var(--color-border-primary);
1928
- font-size: 0.8125rem;
1929
- font-weight: 600;
1930
- color: var(--color-text-primary);
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 {
1959
+ position: absolute;
1960
+ top: 0;
1961
+ left: -6px;
1962
+ bottom: 0;
1963
+ width: 12px;
1964
+ cursor: col-resize;
1965
+ z-index: 10;
1966
+ background: transparent;
1931
1967
  }
1932
- .workspace-header-actions { display: flex; gap: 0.125rem; }
1933
- .workspace-icon-btn {
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;
1976
+ transition: background-color var(--transition-base);
1977
+ }
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;
1934
1986
  display: inline-flex;
1935
1987
  align-items: center;
1936
1988
  justify-content: center;
1937
- width: 1.75rem;
1938
- height: 1.75rem;
1989
+ width: 1.625rem;
1990
+ height: 1.625rem;
1939
1991
  border: none;
1940
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;
2011
+ border-bottom: 1px solid var(--color-border-primary);
2012
+ overflow-x: auto;
2013
+ scrollbar-width: none;
2014
+ }
2015
+ .aside-tabs::-webkit-scrollbar { display: none; }
2016
+ .aside-tab {
2017
+ display: inline-flex;
2018
+ align-items: center;
2019
+ gap: 6px;
2020
+ padding: 0 12px;
2021
+ white-space: nowrap;
2022
+ cursor: pointer;
2023
+ border: none;
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);
1941
2061
  color: var(--color-text-secondary);
1942
2062
  border-radius: var(--radius-sm);
1943
2063
  cursor: pointer;
2064
+ box-shadow: var(--shadow-sm, 0 2px 8px rgba(0,0,0,0.06));
1944
2065
  transition: background-color var(--transition-base), color var(--transition-base);
1945
2066
  }
1946
- .workspace-icon-btn:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
1947
- #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 {
1948
2098
  flex: 1;
1949
2099
  overflow-y: auto;
1950
- padding: 0.375rem 0.25rem;
2100
+ padding: 6px 8px;
1951
2101
  font-size: 0.8125rem;
1952
2102
  font-family: var(--font-mono);
1953
2103
  }
@@ -1984,26 +2134,6 @@ body {
1984
2134
  }
1985
2135
  .wt-error { color: var(--color-danger, #d23); }
1986
2136
 
1987
- /* Collapsed-state opener tab — floats at the right edge of the chat area */
1988
- #btn-workspace-open {
1989
- position: absolute;
1990
- top: 0.5rem;
1991
- right: 0.5rem;
1992
- z-index: 8;
1993
- display: inline-flex;
1994
- align-items: center;
1995
- justify-content: center;
1996
- width: 2rem;
1997
- height: 2rem;
1998
- border: 1px solid var(--color-border-primary);
1999
- background: var(--color-bg-secondary);
2000
- color: var(--color-text-secondary);
2001
- border-radius: var(--radius-sm);
2002
- cursor: pointer;
2003
- transition: background-color var(--transition-base), color var(--transition-base);
2004
- }
2005
- #btn-workspace-open:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
2006
-
2007
2137
  /* Mobile-only floating back button — replaces the old in-header back button.
2008
2138
  Hidden on desktop; mobile media query enables it. Positioned absolutely so
2009
2139
  it doesn't take layout space or add visual chrome on desktop. */
@@ -2147,13 +2277,133 @@ body {
2147
2277
  }
2148
2278
  /* Time color / alignment: anchor to the bubble's own side, let width be
2149
2279
  driven by content — prevents overflow on narrow bubbles. */
2150
- .msg-user .msg-time { color: var(--color-text-secondary); right: 0; left: auto; padding-right: 0.25rem; }
2280
+ .msg-user .msg-time { display: none; }
2151
2281
  .msg-assistant .msg-time { color: var(--color-text-secondary); left: 0; right: auto; padding-left: 0.25rem; }
2152
2282
 
2153
- .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; }
2154
2284
  [data-theme="dark"] .msg-user { background: var(--color-accent-soft); }
2155
2285
  .msg-assistant { background: var(--color-bg-tertiary); border: 1px solid var(--color-border-primary); align-self: flex-start; }
2156
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
+
2157
2407
  /* ── Copy button on assistant messages ────────────────────────────────────
2158
2408
  Hidden by default, revealed on bubble hover (same pattern as .msg-time).
2159
2409
  On touch devices (hover: none) we keep the button visible at low opacity
@@ -2187,8 +2437,8 @@ body {
2187
2437
  }
2188
2438
  .msg-copy-btn.is-copied {
2189
2439
  opacity: 1;
2190
- color: #10b981; /* success green — same across themes */
2191
- border-color: #10b981;
2440
+ color: var(--color-success);
2441
+ border-color: var(--color-success);
2192
2442
  background: var(--color-bg-primary);
2193
2443
  }
2194
2444
  .msg-copy-btn .msg-copy-icon,
@@ -2800,7 +3050,7 @@ body {
2800
3050
  display: flex;
2801
3051
  align-items: center;
2802
3052
  gap: 0.375rem;
2803
- flex-wrap: wrap;
3053
+ flex-wrap: nowrap;
2804
3054
  padding: 0.375rem 0.75rem;
2805
3055
  margin-left: 1.5rem;
2806
3056
  margin-right: 1.5rem;
@@ -2810,13 +3060,17 @@ body {
2810
3060
  color: var(--color-text-tertiary);
2811
3061
  font-family: var(--font-mono, monospace);
2812
3062
  white-space: nowrap;
2813
- overflow: hidden;
3063
+ overflow-x: auto;
3064
+ overflow-y: hidden;
3065
+ scrollbar-width: none;
2814
3066
  flex-shrink: 0;
2815
3067
  opacity: 0.95;
2816
3068
  transition: opacity 0.15s ease;
2817
3069
  cursor: default;
2818
3070
  }
2819
3071
 
3072
+ #session-info-bar::-webkit-scrollbar { display: none; }
3073
+
2820
3074
  #session-info-bar .sib-sep {
2821
3075
  opacity: 0.3;
2822
3076
  }
@@ -4059,7 +4313,6 @@ body {
4059
4313
  padding: 2rem 2rem 1.5rem;
4060
4314
  display: flex;
4061
4315
  flex-direction: column;
4062
- gap: 2rem;
4063
4316
  }
4064
4317
  .settings-section {
4065
4318
  display: flex;
@@ -4144,6 +4397,15 @@ body {
4144
4397
  }
4145
4398
 
4146
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
+ }
4147
4409
  .backup-option,
4148
4410
  .backup-auto-label {
4149
4411
  font-size: 0.8125rem;
@@ -4155,6 +4417,11 @@ body {
4155
4417
  .backup-option {
4156
4418
  margin: 0.75rem 0;
4157
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
+ }
4158
4425
  .backup-auto-row {
4159
4426
  display: flex;
4160
4427
  align-items: center;
@@ -4170,7 +4437,6 @@ body {
4170
4437
  display: flex;
4171
4438
  align-items: center;
4172
4439
  gap: 0.75rem;
4173
- margin: 0.75rem 0;
4174
4440
  flex-wrap: wrap;
4175
4441
  }
4176
4442
 
@@ -4571,7 +4837,6 @@ body {
4571
4837
  color: var(--color-text-secondary);
4572
4838
  font-family: var(--font-mono, monospace);
4573
4839
  background: var(--color-bg-tertiary);
4574
- padding: 0.125rem 0.375rem;
4575
4840
  border-radius: 4px;
4576
4841
  display: inline-block;
4577
4842
  max-width: 100%;
@@ -4633,14 +4898,15 @@ body {
4633
4898
  }
4634
4899
  .model-card-grid-toolbar {
4635
4900
  display: flex;
4636
- flex-wrap: wrap;
4901
+ flex-wrap: nowrap;
4637
4902
  gap: 0.375rem;
4638
4903
  margin-left: auto;
4639
4904
  justify-content: flex-end;
4640
4905
  }
4641
4906
  .model-card-grid-footer {
4642
4907
  display: flex;
4643
- justify-content: flex-end;
4908
+ justify-content: space-between;
4909
+ align-items: center;
4644
4910
  margin-top: 0.25rem;
4645
4911
  }
4646
4912
  .model-card-grid-link {
@@ -6581,6 +6847,123 @@ body {
6581
6847
  background: var(--color-error-bg, #fff0f0);
6582
6848
  }
6583
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
+
6584
6967
  /* ── Skills sidebar section ──────────────────────────────────────────────── */
6585
6968
  #skill-list-items { padding: 0 0.5rem 0.5rem; display: flex; flex-direction: column; gap: 2px; }
6586
6969
 
@@ -8651,6 +9034,29 @@ body.setup-mode[data-theme="dark"] {
8651
9034
  cursor: wait;
8652
9035
  }
8653
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
+
8654
9060
  /* ── Minimal-Markdown rendered body ───────────────────────────────────── */
8655
9061
  .profile-markdown {
8656
9062
  font-size: 0.8438rem;
@@ -8791,6 +9197,7 @@ body.setup-mode[data-theme="dark"] {
8791
9197
 
8792
9198
  /* Shared base for per-card buttons. */
8793
9199
  .btn-memory-curate,
9200
+ .btn-memory-edit,
8794
9201
  .btn-memory-delete,
8795
9202
  .btn-memory-expand {
8796
9203
  padding: 0.3125rem 0.625rem;
@@ -8806,7 +9213,8 @@ body.setup-mode[data-theme="dark"] {
8806
9213
  transition: background 0.15s, border-color 0.15s, color 0.15s;
8807
9214
  }
8808
9215
 
8809
- .btn-memory-curate:hover {
9216
+ .btn-memory-curate:hover,
9217
+ .btn-memory-edit:hover {
8810
9218
  border-color: var(--color-text-primary);
8811
9219
  background: var(--color-bg-hover);
8812
9220
  }
@@ -11442,7 +11850,7 @@ body.setup-mode[data-theme="dark"] {
11442
11850
  min-height: 0;
11443
11851
  }
11444
11852
  #skills-body {
11445
- padding: 1rem 1rem 5rem;
11853
+ padding: 1rem 1rem 1rem;
11446
11854
  gap: 0.75rem;
11447
11855
  overflow-y: auto;
11448
11856
  -webkit-overflow-scrolling: touch;
@@ -11543,9 +11951,9 @@ body.setup-mode[data-theme="dark"] {
11543
11951
  }
11544
11952
 
11545
11953
  /* ── Billing / Trash / Creator pages ── */
11546
- #billing-body { padding: 1rem 1rem 5rem; }
11547
- #trash-body { padding: 1rem 1rem 5rem; }
11548
- #creator-body { padding: 1rem 1rem 5rem; }
11954
+ #billing-body { padding: 1rem 1rem 1rem; }
11955
+ #trash-body { padding: 1rem 1rem 1rem; }
11956
+ #creator-body { padding: 1rem 1rem 1rem; }
11549
11957
 
11550
11958
  .billing-heatmap-row { grid-template-columns: 1fr; }
11551
11959
 
@@ -11673,4 +12081,48 @@ body.setup-mode[data-theme="dark"] {
11673
12081
  font-size: 0.7rem;
11674
12082
  color: var(--color-text-tertiary);
11675
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;
11676
12128
  }