@firstpick/pi-package-webui 0.4.0 → 0.4.1

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.
package/public/index.html CHANGED
@@ -71,8 +71,11 @@
71
71
  </div>
72
72
  </div>
73
73
  </div>
74
+ <button id="commandPaletteButton" class="terminal-command-palette-button" type="button" title="Open command palette (Ctrl/Cmd+K)" aria-label="Open command palette" data-tooltip="Command palette:&#10;• Search and run actions, slash commands, models, and tabs.&#10;• Shortcut: Ctrl/Cmd+K."><svg class="composer-icon command-palette-launcher-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 7.5h14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M5 12h9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M5 16.5h5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M17 14.5 19.5 17 17 19.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
75
+ <button id="workspaceDashboardToggleButton" class="terminal-dashboard-button" type="button" aria-controls="workspaceDashboard" aria-expanded="false" title="Show workspace overview" aria-label="Show workspace overview" data-tooltip="Workspace overview:&#10;• Shows current tab, cwd, model, context, session, and queue.&#10;• Opens common workspace/session actions from one place."><svg class="composer-icon workspace-overview-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 11.4 12 4l8 7.4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.5 10.5V20h11v-9.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M10 20v-5h4v5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
74
76
  <button id="closeAllTabsButton" class="terminal-close-all-button" type="button" title="Close all terminal tabs">Close all Tabs</button>
75
77
  </header>
78
+ <section id="workspaceDashboard" class="workspace-dashboard" aria-label="Workspace dashboard"></section>
76
79
  <div id="widgetArea" class="widget-area"></div>
77
80
  <div id="chatSearchBar" class="chat-search-bar" role="search" hidden>
78
81
  <input id="chatSearchInput" class="chat-search-input" type="search" placeholder="Search transcript…" autocomplete="off" spellcheck="false" aria-label="Search transcript" />
@@ -90,6 +93,7 @@
90
93
  </div>
91
94
  <button id="jumpToLatestButton" class="jump-to-latest-button" type="button" hidden>Latest ↓</button>
92
95
  <div id="statusBar" class="statusbar" aria-live="polite"></div>
96
+ <section id="contextMeterBar" class="context-meter-bar" aria-live="polite"></section>
93
97
  <section id="gitWorkflowPanel" class="git-workflow-panel" aria-live="polite" hidden>
94
98
  <div class="git-workflow-header">
95
99
  <div>
@@ -206,9 +210,12 @@
206
210
  aria-haspopup="menu"
207
211
  aria-expanded="false"
208
212
  aria-controls="optionsMenu"
209
- data-tooltip="Options: resume, reload, name, clone, settings, export, fork, or tree."
213
+ data-tooltip="Options: command palette, resume, reload, name, clone, settings, export, fork, or tree."
210
214
  ><svg class="composer-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 7h16M4 12h16M4 17h16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><circle cx="8" cy="7" r="1.6" fill="currentColor"/><circle cx="16" cy="12" r="1.6" fill="currentColor"/><circle cx="11" cy="17" r="1.6" fill="currentColor"/></svg></button>
211
215
  <div id="optionsMenu" class="composer-publish-menu-panel composer-options-menu-panel" role="menu" aria-label="Common Pi options">
216
+ <button id="optionsCommandPaletteButton" class="composer-publish-menu-item composer-options-menu-item" type="button" role="menuitem">
217
+ <span>Command Palette</span>
218
+ </button>
212
219
  <button id="optionsTreeButton" class="composer-publish-menu-item composer-options-menu-item" type="button" role="menuitem" data-command="/tree">
213
220
  <span>Tree</span>
214
221
  </button>
@@ -578,6 +585,35 @@
578
585
  </form>
579
586
  </dialog>
580
587
 
588
+ <dialog id="commandPaletteDialog" class="extension-dialog command-palette-dialog">
589
+ <form method="dialog">
590
+ <div class="command-palette-header">
591
+ <div>
592
+ <span class="command-palette-kicker">Quick launcher</span>
593
+ <h2>Command palette</h2>
594
+ </div>
595
+ <span class="command-palette-shortcut">Ctrl/Cmd+K</span>
596
+ </div>
597
+ <input id="commandPaletteInput" class="dialog-input command-palette-input" type="search" autocomplete="off" spellcheck="false" placeholder="Search commands, tabs, models, sessions…" aria-label="Search command palette" />
598
+ <div id="commandPaletteList" class="command-palette-list" role="listbox" aria-label="Command palette results"></div>
599
+ <p id="commandPaletteHint" class="command-palette-hint muted">Use ↑/↓ then Enter. Escape closes.</p>
600
+ </form>
601
+ </dialog>
602
+
603
+ <dialog id="editRetryDialog" class="extension-dialog edit-retry-dialog">
604
+ <form method="dialog">
605
+ <h2>Edit &amp; retry from here</h2>
606
+ <p id="editRetryMessage" class="muted">Fork the session from this user message, optionally edit it, then run the new prompt.</p>
607
+ <textarea id="editRetryText" class="dialog-editor edit-retry-text" spellcheck="true" aria-label="Edited prompt"></textarea>
608
+ <p id="editRetryStatus" class="edit-retry-status muted" role="status" aria-live="polite"></p>
609
+ <menu>
610
+ <button id="editRetryCancelButton" type="button">Cancel</button>
611
+ <button id="editRetryForkButton" type="button">Fork only</button>
612
+ <button id="editRetrySendButton" class="primary" type="button">Fork &amp; run</button>
613
+ </menu>
614
+ </form>
615
+ </dialog>
616
+
581
617
  <dialog id="nativeCommandDialog" class="extension-dialog native-command-dialog">
582
618
  <form method="dialog">
583
619
  <h2 id="nativeCommandTitle">Pi command</h2>
package/public/styles.css CHANGED
@@ -1109,6 +1109,12 @@ body.side-panel-collapsed .terminal-tabs-shell {
1109
1109
  .optional-feature-row.disabled {
1110
1110
  border-color: rgba(249, 226, 175, 0.28);
1111
1111
  }
1112
+ .optional-feature-row.installed {
1113
+ border-color: rgba(137, 180, 250, 0.26);
1114
+ }
1115
+ .optional-feature-row.updating {
1116
+ border-color: rgba(250, 179, 135, 0.32);
1117
+ }
1112
1118
  .optional-feature-row.missing {
1113
1119
  border-color: rgba(243, 139, 168, 0.25);
1114
1120
  }
@@ -1150,6 +1156,14 @@ body.side-panel-collapsed .terminal-tabs-shell {
1150
1156
  color: var(--ctp-yellow);
1151
1157
  border-color: rgba(249, 226, 175, 0.32);
1152
1158
  }
1159
+ .optional-feature-pill.installed {
1160
+ color: var(--ctp-blue);
1161
+ border-color: rgba(137, 180, 250, 0.32);
1162
+ }
1163
+ .optional-feature-pill.updating {
1164
+ color: var(--ctp-peach);
1165
+ border-color: rgba(250, 179, 135, 0.34);
1166
+ }
1153
1167
  .optional-feature-pill.missing {
1154
1168
  color: var(--ctp-red);
1155
1169
  border-color: rgba(243, 139, 168, 0.32);
@@ -1180,11 +1194,17 @@ body.side-panel-collapsed .terminal-tabs-shell {
1180
1194
  color: var(--ctp-teal);
1181
1195
  border-color: rgba(148, 226, 213, 0.32);
1182
1196
  }
1183
- .optional-feature-action.install {
1197
+ .optional-feature-action.install,
1198
+ .optional-feature-action.update {
1184
1199
  color: var(--ctp-yellow);
1185
1200
  border-color: rgba(249, 226, 175, 0.32);
1186
1201
  }
1187
- .optional-feature-action.install:not(:disabled):hover {
1202
+ .optional-feature-action.update {
1203
+ color: var(--ctp-peach);
1204
+ border-color: rgba(250, 179, 135, 0.34);
1205
+ }
1206
+ .optional-feature-action.install:not(:disabled):hover,
1207
+ .optional-feature-action.update:not(:disabled):hover {
1188
1208
  color: #11111b;
1189
1209
  border-color: transparent;
1190
1210
  background: linear-gradient(120deg, var(--ctp-yellow), var(--ctp-peach));
@@ -4420,7 +4440,7 @@ button.composer-skill-tag:focus-visible {
4420
4440
  display: flex;
4421
4441
  }
4422
4442
  .composer-options-menu-panel {
4423
- max-height: min(88vh, 36rem);
4443
+ max-height: min(calc(var(--visual-viewport-height, 100dvh) - 2rem), 44rem);
4424
4444
  }
4425
4445
  .composer-publish-menu.open .composer-publish-button {
4426
4446
  border-color: rgba(250, 179, 135, 0.58);
@@ -4468,6 +4488,7 @@ button.composer-skill-tag:focus-visible {
4468
4488
  width: min(22rem, calc(100vw - 2rem));
4469
4489
  min-width: min(18rem, calc(100vw - 2rem));
4470
4490
  max-width: min(22rem, calc(100vw - 2rem));
4491
+ max-height: min(calc(var(--visual-viewport-height, 100dvh) - 2rem), 44rem);
4471
4492
  overflow-x: hidden;
4472
4493
  }
4473
4494
  .composer-app-runner-menu-item {
@@ -6769,7 +6790,11 @@ button.composer-skill-tag:focus-visible {
6769
6790
  }
6770
6791
  .composer-actions-panel > .composer-options-menu .composer-publish-menu-panel {
6771
6792
  inset-inline: auto 0;
6772
- max-height: min(76dvh, 34rem);
6793
+ max-height: min(calc(var(--visual-viewport-height, 100dvh) - 2rem), 44rem);
6794
+ }
6795
+ .composer-actions-panel > .composer-app-runner-menu .composer-publish-menu-panel {
6796
+ inset-inline: auto 0;
6797
+ max-height: min(calc(var(--visual-viewport-height, 100dvh) - 2rem), 44rem);
6773
6798
  }
6774
6799
  .composer-actions-panel > .composer-publish-menu .composer-publish-menu-item {
6775
6800
  width: 100%;
@@ -6999,3 +7024,490 @@ button.composer-skill-tag:focus-visible {
6999
7024
  outline: 2px solid var(--accent-2);
7000
7025
  outline-offset: 2px;
7001
7026
  }
7027
+
7028
+ /* Broad usability MVPs: dashboard, command palette, context meter, edit/retry */
7029
+ .terminal-command-palette-button,
7030
+ .terminal-dashboard-button {
7031
+ position: relative;
7032
+ flex: 0 0 auto;
7033
+ min-height: 2.35rem;
7034
+ padding: 0.38rem 0.7rem;
7035
+ white-space: nowrap;
7036
+ color: var(--ctp-teal);
7037
+ border-color: rgba(148, 226, 213, 0.32);
7038
+ background:
7039
+ linear-gradient(120deg, rgba(148, 226, 213, 0.12), rgba(137, 180, 250, 0.08)),
7040
+ rgba(var(--ctp-crust-rgb), 0.58);
7041
+ }
7042
+ .terminal-command-palette-button,
7043
+ .terminal-dashboard-button {
7044
+ display: inline-grid;
7045
+ place-items: center;
7046
+ width: 2.35rem;
7047
+ min-width: 2.35rem;
7048
+ padding-inline: 0;
7049
+ font-size: 1.05rem;
7050
+ line-height: 1;
7051
+ }
7052
+ .terminal-command-palette-button .command-palette-launcher-icon,
7053
+ .terminal-dashboard-button .workspace-overview-icon {
7054
+ width: 1.18rem;
7055
+ height: 1.18rem;
7056
+ stroke-width: 2.1;
7057
+ filter: drop-shadow(0 0 0.45rem rgba(148, 226, 213, 0.22));
7058
+ }
7059
+ .terminal-dashboard-button[aria-expanded="true"] {
7060
+ color: #11111b;
7061
+ border-color: transparent;
7062
+ background: linear-gradient(120deg, var(--ctp-teal), var(--ctp-blue));
7063
+ }
7064
+ .terminal-command-palette-button[data-tooltip]::before,
7065
+ .terminal-command-palette-button[data-tooltip]::after,
7066
+ .terminal-dashboard-button[data-tooltip]::before,
7067
+ .terminal-dashboard-button[data-tooltip]::after {
7068
+ position: absolute;
7069
+ right: 0;
7070
+ pointer-events: none;
7071
+ opacity: 0;
7072
+ transition: opacity 140ms ease, transform 140ms ease;
7073
+ }
7074
+ .terminal-command-palette-button[data-tooltip]::before,
7075
+ .terminal-dashboard-button[data-tooltip]::before {
7076
+ content: "";
7077
+ top: calc(100% + 0.42rem);
7078
+ right: 0.78rem;
7079
+ z-index: 119;
7080
+ width: 0.72rem;
7081
+ height: 0.72rem;
7082
+ background: rgba(var(--ctp-crust-rgb), 0.96);
7083
+ border-left: 1px solid rgba(166, 227, 161, 0.28);
7084
+ border-top: 1px solid rgba(166, 227, 161, 0.28);
7085
+ transform: translateY(-0.2rem) rotate(45deg);
7086
+ }
7087
+ .terminal-command-palette-button[data-tooltip]::after,
7088
+ .terminal-dashboard-button[data-tooltip]::after {
7089
+ content: attr(data-tooltip);
7090
+ top: calc(100% + 0.72rem);
7091
+ z-index: 120;
7092
+ width: max-content;
7093
+ max-width: min(25rem, calc(100vw - 2rem));
7094
+ padding: 0.78rem 0.9rem;
7095
+ color: var(--ctp-text);
7096
+ text-align: left;
7097
+ white-space: pre-line;
7098
+ line-height: 1.45;
7099
+ border: 1px solid rgba(166, 227, 161, 0.30);
7100
+ border-radius: 0.86rem;
7101
+ background:
7102
+ radial-gradient(circle at 8% 0%, rgba(166, 227, 161, 0.13), transparent 12rem),
7103
+ linear-gradient(145deg, rgba(var(--ctp-crust-rgb), 0.98), rgba(var(--ctp-base-rgb), 0.94));
7104
+ box-shadow: 0 1rem 2.4rem rgba(var(--ctp-crust-rgb), 0.58), 0 0 1.2rem rgba(166, 227, 161, 0.16), inset 0 1px 0 rgba(255,255,255,0.055);
7105
+ font-size: 0.82rem;
7106
+ font-weight: 650;
7107
+ text-transform: none;
7108
+ letter-spacing: 0;
7109
+ transform: translateY(-0.2rem);
7110
+ }
7111
+ .terminal-command-palette-button[data-tooltip]:hover::before,
7112
+ .terminal-command-palette-button[data-tooltip]:hover::after,
7113
+ .terminal-command-palette-button[data-tooltip]:focus-visible::before,
7114
+ .terminal-command-palette-button[data-tooltip]:focus-visible::after,
7115
+ .terminal-dashboard-button[data-tooltip]:hover::before,
7116
+ .terminal-dashboard-button[data-tooltip]:hover::after,
7117
+ .terminal-dashboard-button[data-tooltip]:focus-visible::before,
7118
+ .terminal-dashboard-button[data-tooltip]:focus-visible::after {
7119
+ opacity: 1;
7120
+ transform: translateY(0);
7121
+ }
7122
+ .terminal-command-palette-button[data-tooltip]:hover::before,
7123
+ .terminal-command-palette-button[data-tooltip]:focus-visible::before,
7124
+ .terminal-dashboard-button[data-tooltip]:hover::before,
7125
+ .terminal-dashboard-button[data-tooltip]:focus-visible::before {
7126
+ transform: translateY(0) rotate(45deg);
7127
+ }
7128
+ .workspace-dashboard[hidden],
7129
+ .context-meter-bar[hidden] { display: none; }
7130
+ .workspace-dashboard {
7131
+ display: grid;
7132
+ gap: 0.72rem;
7133
+ padding: 0.78rem 0.95rem;
7134
+ border-bottom: 1px solid rgba(180, 190, 254, 0.16);
7135
+ background:
7136
+ radial-gradient(circle at 8% 0, rgba(148, 226, 213, 0.13), transparent 18rem),
7137
+ linear-gradient(135deg, rgba(var(--ctp-crust-rgb), 0.66), rgba(var(--ctp-base-rgb), 0.54));
7138
+ }
7139
+ .workspace-dashboard-header {
7140
+ display: flex;
7141
+ align-items: start;
7142
+ justify-content: space-between;
7143
+ gap: 0.8rem;
7144
+ }
7145
+ .workspace-dashboard-title {
7146
+ min-width: 0;
7147
+ }
7148
+ .workspace-dashboard-kicker,
7149
+ .command-palette-kicker {
7150
+ color: var(--ctp-pink);
7151
+ font-size: 0.68rem;
7152
+ font-weight: 900;
7153
+ letter-spacing: 0.14em;
7154
+ text-transform: uppercase;
7155
+ }
7156
+ .workspace-dashboard-title h2,
7157
+ .command-palette-header h2 {
7158
+ margin: 0.12rem 0 0.22rem;
7159
+ font-size: 1.05rem;
7160
+ }
7161
+ .workspace-dashboard-title p {
7162
+ margin: 0;
7163
+ overflow-wrap: anywhere;
7164
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
7165
+ font-size: 0.72rem;
7166
+ }
7167
+ .workspace-dashboard-actions {
7168
+ display: flex;
7169
+ flex-wrap: wrap;
7170
+ justify-content: flex-end;
7171
+ gap: 0.42rem;
7172
+ }
7173
+ .workspace-dashboard-action {
7174
+ min-height: 2.15rem;
7175
+ padding: 0.32rem 0.58rem;
7176
+ font-size: 0.72rem;
7177
+ font-weight: 850;
7178
+ }
7179
+ .workspace-dashboard-action.primary {
7180
+ color: var(--button-primary-text);
7181
+ border-color: transparent;
7182
+ background: var(--neon-gradient);
7183
+ }
7184
+ .workspace-dashboard-metrics {
7185
+ display: grid;
7186
+ grid-template-columns: repeat(4, minmax(0, 1fr));
7187
+ gap: 0.58rem;
7188
+ }
7189
+ .workspace-dashboard-metric {
7190
+ min-width: 0;
7191
+ padding: 0.62rem;
7192
+ border: 1px solid rgba(180, 190, 254, 0.16);
7193
+ border-radius: 0.76rem;
7194
+ background: rgba(var(--ctp-crust-rgb), 0.48);
7195
+ }
7196
+ .workspace-dashboard-metric-label,
7197
+ .workspace-dashboard-metric-detail,
7198
+ .workspace-dashboard-tabs-title,
7199
+ .command-palette-item-kind,
7200
+ .command-palette-item-description {
7201
+ display: block;
7202
+ color: rgba(var(--ctp-subtext-rgb), 0.72);
7203
+ font-size: 0.68rem;
7204
+ line-height: 1.35;
7205
+ }
7206
+ .workspace-dashboard-metric-label {
7207
+ font-weight: 900;
7208
+ letter-spacing: 0.08em;
7209
+ text-transform: uppercase;
7210
+ }
7211
+ .workspace-dashboard-metric strong {
7212
+ display: block;
7213
+ margin-top: 0.18rem;
7214
+ overflow: hidden;
7215
+ color: var(--ctp-text);
7216
+ text-overflow: ellipsis;
7217
+ white-space: nowrap;
7218
+ }
7219
+ .workspace-dashboard-tabs {
7220
+ display: grid;
7221
+ gap: 0.42rem;
7222
+ }
7223
+ .workspace-dashboard-tab-list {
7224
+ display: flex;
7225
+ flex-wrap: wrap;
7226
+ gap: 0.38rem;
7227
+ }
7228
+ .workspace-dashboard-tab {
7229
+ display: inline-flex;
7230
+ align-items: center;
7231
+ gap: 0.32rem;
7232
+ min-height: 2rem;
7233
+ padding: 0.28rem 0.52rem;
7234
+ color: rgba(var(--ctp-text-rgb), 0.84);
7235
+ font-size: 0.72rem;
7236
+ }
7237
+ .workspace-dashboard-tab.active {
7238
+ color: #11111b;
7239
+ border-color: transparent;
7240
+ background: linear-gradient(120deg, var(--ctp-teal), var(--ctp-blue));
7241
+ }
7242
+ .workspace-dashboard-tab-dot {
7243
+ color: var(--ctp-teal);
7244
+ font-size: 0.72rem;
7245
+ }
7246
+ .workspace-dashboard-tab-more {
7247
+ align-self: center;
7248
+ color: rgba(var(--ctp-subtext-rgb), 0.72);
7249
+ font-size: 0.72rem;
7250
+ }
7251
+ .context-meter-bar {
7252
+ display: grid;
7253
+ grid-template-columns: minmax(0, 1.2fr) minmax(8rem, 1fr) auto;
7254
+ gap: 0.68rem;
7255
+ align-items: center;
7256
+ padding: 0.56rem 0.95rem;
7257
+ border-top: 1px solid rgba(180, 190, 254, 0.12);
7258
+ border-bottom: 1px solid rgba(180, 190, 254, 0.14);
7259
+ background: linear-gradient(90deg, rgba(166, 227, 161, 0.09), rgba(249, 226, 175, 0.08), rgba(137, 180, 250, 0.08));
7260
+ }
7261
+ .context-meter-summary {
7262
+ display: grid;
7263
+ gap: 0.12rem;
7264
+ min-width: 0;
7265
+ }
7266
+ .context-meter-summary strong,
7267
+ .context-meter-summary span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
7268
+ .context-meter {
7269
+ position: relative;
7270
+ height: 0.72rem;
7271
+ overflow: hidden;
7272
+ border: 1px solid rgba(180, 190, 254, 0.16);
7273
+ border-radius: 999px;
7274
+ background: rgba(var(--ctp-crust-rgb), 0.62);
7275
+ }
7276
+ .context-meter-fill {
7277
+ display: block;
7278
+ height: 100%;
7279
+ border-radius: inherit;
7280
+ background: linear-gradient(90deg, var(--ctp-green), var(--context-active-color, var(--ctp-teal)));
7281
+ box-shadow: 0 0 0.85rem var(--context-active-glow, rgba(148, 226, 213, 0.24));
7282
+ transition: width 180ms ease;
7283
+ }
7284
+ .context-meter.unknown .context-meter-fill {
7285
+ width: 100% !important;
7286
+ background: repeating-linear-gradient(90deg, rgba(148, 226, 213, 0.22) 0 0.8rem, rgba(203, 166, 247, 0.18) 0.8rem 1.6rem);
7287
+ }
7288
+ .context-meter-actions {
7289
+ display: flex;
7290
+ gap: 0.42rem;
7291
+ justify-content: flex-end;
7292
+ }
7293
+ .context-meter-actions button {
7294
+ min-height: 2.1rem;
7295
+ padding: 0.28rem 0.56rem;
7296
+ font-size: 0.72rem;
7297
+ font-weight: 850;
7298
+ }
7299
+ .context-meter-auto[aria-pressed="true"] {
7300
+ color: #11111b;
7301
+ border-color: transparent;
7302
+ background: linear-gradient(120deg, var(--ctp-green), var(--ctp-teal));
7303
+ }
7304
+ .command-palette-dialog {
7305
+ width: min(42rem, calc(100vw - 1.5rem));
7306
+ max-height: min(44rem, calc(var(--visual-viewport-height, 100dvh) - 2rem));
7307
+ padding: 0;
7308
+ overflow: hidden;
7309
+ }
7310
+ .command-palette-dialog form {
7311
+ display: grid;
7312
+ grid-template-rows: auto auto minmax(0, 1fr) auto;
7313
+ gap: 0;
7314
+ width: 100%;
7315
+ max-height: inherit;
7316
+ min-height: 0;
7317
+ }
7318
+ .edit-retry-dialog form {
7319
+ width: min(44rem, calc(100vw - 2rem));
7320
+ }
7321
+ .command-palette-header {
7322
+ display: flex;
7323
+ align-items: start;
7324
+ justify-content: space-between;
7325
+ gap: 0.9rem;
7326
+ min-width: 0;
7327
+ padding: 1rem 1rem 0.72rem;
7328
+ }
7329
+ .command-palette-header > div {
7330
+ min-width: 0;
7331
+ }
7332
+ .command-palette-shortcut {
7333
+ flex: 0 0 auto;
7334
+ max-width: 9rem;
7335
+ padding: 0.18rem 0.52rem;
7336
+ overflow: hidden;
7337
+ border: 1px solid rgba(180, 190, 254, 0.22);
7338
+ border-radius: 999px;
7339
+ color: rgba(var(--ctp-subtext-rgb), 0.78);
7340
+ background: rgba(var(--ctp-crust-rgb), 0.46);
7341
+ font-size: 0.68rem;
7342
+ font-weight: 850;
7343
+ text-overflow: ellipsis;
7344
+ white-space: nowrap;
7345
+ }
7346
+ .command-palette-input {
7347
+ width: calc(100% - 2rem);
7348
+ min-width: 0;
7349
+ margin: 0 1rem 0.72rem;
7350
+ padding: 0.86rem 0.9rem;
7351
+ border-radius: 0.82rem;
7352
+ background:
7353
+ radial-gradient(circle at 0 0, rgba(203, 166, 247, 0.12), transparent 14rem),
7354
+ rgba(var(--ctp-crust-rgb), 0.50);
7355
+ }
7356
+ .command-palette-list {
7357
+ display: grid;
7358
+ gap: 0.42rem;
7359
+ min-height: 0;
7360
+ max-height: none;
7361
+ overflow-x: hidden;
7362
+ overflow-y: auto;
7363
+ padding: 0 1rem 0.7rem;
7364
+ scrollbar-gutter: stable;
7365
+ }
7366
+ .command-palette-item {
7367
+ display: grid;
7368
+ grid-template-columns: 4.8rem minmax(0, 1fr);
7369
+ gap: 0.1rem 0.7rem;
7370
+ width: 100%;
7371
+ min-width: 0;
7372
+ min-height: 3.4rem;
7373
+ padding: 0.62rem 0.74rem;
7374
+ overflow: hidden;
7375
+ text-align: left;
7376
+ border-radius: 0.82rem;
7377
+ background:
7378
+ linear-gradient(120deg, rgba(203, 166, 247, 0.06), rgba(148, 226, 213, 0.04)),
7379
+ rgba(var(--ctp-crust-rgb), 0.46);
7380
+ }
7381
+ .command-palette-item:hover,
7382
+ .command-palette-item:focus-visible {
7383
+ transform: none;
7384
+ }
7385
+ .command-palette-item-kind {
7386
+ grid-row: 1 / span 2;
7387
+ align-self: center;
7388
+ min-width: 0;
7389
+ overflow: hidden;
7390
+ color: var(--ctp-teal);
7391
+ font-size: 0.68rem;
7392
+ font-weight: 900;
7393
+ letter-spacing: 0.08em;
7394
+ text-overflow: ellipsis;
7395
+ text-transform: uppercase;
7396
+ white-space: nowrap;
7397
+ }
7398
+ .command-palette-item-label {
7399
+ min-width: 0;
7400
+ overflow: hidden;
7401
+ color: var(--ctp-text);
7402
+ font-weight: 900;
7403
+ text-overflow: ellipsis;
7404
+ white-space: nowrap;
7405
+ }
7406
+ .command-palette-item-description {
7407
+ min-width: 0;
7408
+ overflow: hidden;
7409
+ text-overflow: ellipsis;
7410
+ white-space: nowrap;
7411
+ }
7412
+ .command-palette-item.active,
7413
+ .command-palette-item:focus-visible {
7414
+ color: var(--ctp-text);
7415
+ border-color: rgba(148, 226, 213, 0.66);
7416
+ background:
7417
+ linear-gradient(90deg, rgba(245, 194, 231, 0.20), rgba(137, 180, 250, 0.14), rgba(148, 226, 213, 0.16)),
7418
+ rgba(var(--ctp-surface-rgb), 0.70);
7419
+ box-shadow: inset 3px 0 0 var(--ctp-teal), 0 0 1rem rgba(148, 226, 213, 0.16);
7420
+ }
7421
+ .command-palette-item.active .command-palette-item-kind,
7422
+ .command-palette-item.active .command-palette-item-label { color: var(--ctp-text); }
7423
+ .command-palette-item.active .command-palette-item-description { color: rgba(var(--ctp-subtext-rgb), 0.84); }
7424
+ .command-palette-empty {
7425
+ padding: 1rem;
7426
+ text-align: center;
7427
+ }
7428
+ .command-palette-hint {
7429
+ margin: 0;
7430
+ padding: 0.62rem 1rem 0.82rem;
7431
+ border-top: 1px solid rgba(180, 190, 254, 0.14);
7432
+ background: rgba(var(--ctp-crust-rgb), 0.50);
7433
+ }
7434
+ .edit-retry-text {
7435
+ width: 100%;
7436
+ min-height: 12rem;
7437
+ margin-top: 0.65rem;
7438
+ }
7439
+ .edit-retry-status.error { color: var(--ctp-red); }
7440
+ .edit-retry-status.info { color: var(--ctp-subtext); }
7441
+ .message.has-edit-retry-action:not(.toolResult):not(.bashExecution):not(.compactionSummary) > .message-header,
7442
+ .message.has-edit-retry-action:not(.toolResult):not(.bashExecution):not(.compactionSummary) > .message-body {
7443
+ padding-right: 5.65rem;
7444
+ }
7445
+ .message-edit-retry-button {
7446
+ position: absolute;
7447
+ top: 0.48rem;
7448
+ right: 2.95rem;
7449
+ z-index: 9;
7450
+ display: inline-flex;
7451
+ align-items: center;
7452
+ justify-content: center;
7453
+ width: 2.15rem;
7454
+ min-width: 2.15rem;
7455
+ min-height: 2.05rem;
7456
+ padding: 0;
7457
+ border-radius: 0.64rem;
7458
+ color: rgba(var(--ctp-text-rgb), 0.82);
7459
+ background: linear-gradient(180deg, rgba(var(--ctp-surface-rgb), 0.82), rgba(var(--ctp-crust-rgb), 0.90));
7460
+ border-color: rgba(203, 166, 247, 0.28);
7461
+ box-shadow: 0 0.45rem 1rem rgba(var(--ctp-crust-rgb), 0.30), inset 0 1px 0 rgba(255,255,255,0.055);
7462
+ font-size: 1rem;
7463
+ line-height: 1;
7464
+ opacity: 0.72;
7465
+ }
7466
+ .message-edit-retry-button:hover,
7467
+ .message-edit-retry-button:focus-visible {
7468
+ color: #11111b;
7469
+ border-color: transparent;
7470
+ background: linear-gradient(120deg, var(--ctp-pink), var(--ctp-mauve));
7471
+ opacity: 1;
7472
+ }
7473
+ @media (max-width: 900px) {
7474
+ .workspace-dashboard-header,
7475
+ .context-meter-bar { grid-template-columns: 1fr; }
7476
+ .workspace-dashboard-header { display: grid; }
7477
+ .workspace-dashboard-actions { justify-content: stretch; }
7478
+ .workspace-dashboard-action { flex: 1 1 8rem; }
7479
+ .workspace-dashboard-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
7480
+ .context-meter-actions { justify-content: stretch; }
7481
+ .context-meter-actions button { flex: 1 1 auto; }
7482
+ }
7483
+ @media (max-width: 720px) {
7484
+ .terminal-command-palette-button { display: none; }
7485
+ .workspace-dashboard { padding: 0.62rem 0.7rem; }
7486
+ .workspace-dashboard-metrics { grid-template-columns: 1fr; }
7487
+ .command-palette-dialog {
7488
+ inset: calc(0.5rem + env(safe-area-inset-top)) 0 auto 0;
7489
+ width: min(100vw - 1rem, 42rem);
7490
+ max-height: calc(var(--visual-viewport-height, 100dvh) - 1rem - env(safe-area-inset-top));
7491
+ margin-inline: auto;
7492
+ border-radius: 1rem;
7493
+ }
7494
+ .command-palette-header { padding: 0.85rem 0.85rem 0.62rem; }
7495
+ .command-palette-input {
7496
+ width: calc(100% - 1.7rem);
7497
+ margin-inline: 0.85rem;
7498
+ }
7499
+ .command-palette-list { padding-inline: 0.85rem; }
7500
+ .command-palette-item { grid-template-columns: 1fr; }
7501
+ .command-palette-item-kind { grid-row: auto; }
7502
+ .message-edit-retry-button {
7503
+ top: 0.38rem;
7504
+ right: 2.8rem;
7505
+ width: 2rem;
7506
+ min-width: 2rem;
7507
+ min-height: 1.92rem;
7508
+ }
7509
+ .message.has-edit-retry-action:not(.toolResult):not(.bashExecution):not(.compactionSummary) > .message-header,
7510
+ .message.has-edit-retry-action:not(.toolResult):not(.bashExecution):not(.compactionSummary) > .message-body {
7511
+ padding-right: 5rem;
7512
+ }
7513
+ }
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { spawn, spawnSync } from "node:child_process";
3
- import { chmod, mkdtemp, rm, stat } from "node:fs/promises";
3
+ import { chmod, mkdtemp, rm, stat, writeFile } from "node:fs/promises";
4
4
  import { networkInterfaces, tmpdir } from "node:os";
5
5
  import path from "node:path";
6
6
  import { setTimeout as delay } from "node:timers/promises";
@@ -154,6 +154,47 @@ try {
154
154
  assert.equal(gitRemote.status, 200);
155
155
  assert.equal(gitRemote.body?.ok, true, "remote endpoint should add origin without pushing");
156
156
  assert.equal(gitRemote.body?.data?.remoteUrl, "https://github.com/Firstp1ck/pi-webui-http-harness.git");
157
+
158
+ await writeFile(path.join(cwd, "single.txt"), "created\n");
159
+ const gitAddCreated = await request("127.0.0.1", "/api/git-workflow/add", { method: "POST", body: { tab: tabId } });
160
+ assert.equal(gitAddCreated.status, 200);
161
+ assert.equal(gitAddCreated.body?.ok, true, "git add endpoint should stage a new single file");
162
+ const createdDefault = await request("127.0.0.1", `/api/git-workflow/default-commit-message?tab=${encodeURIComponent(tabId)}`);
163
+ assert.equal(createdDefault.status, 200);
164
+ assert.equal(createdDefault.body?.ok, true, "default commit message endpoint should return ok for a staged single file");
165
+ assert.equal(createdDefault.body?.data?.message, "created single.txt");
166
+ const createdCommit = await request("127.0.0.1", "/api/git-workflow/commit", { method: "POST", body: { variant: "input", message: createdDefault.body?.data?.message, tab: tabId } });
167
+ assert.equal(createdCommit.status, 200);
168
+ assert.equal(createdCommit.body?.ok, true, "input commit endpoint should accept the generated single-file default");
169
+
170
+ await writeFile(path.join(cwd, "single.txt"), "updated\n");
171
+ const gitAddUpdated = await request("127.0.0.1", "/api/git-workflow/add", { method: "POST", body: { tab: tabId } });
172
+ assert.equal(gitAddUpdated.status, 200);
173
+ assert.equal(gitAddUpdated.body?.ok, true, "git add endpoint should stage a single-file update");
174
+ const updatedDefault = await request("127.0.0.1", `/api/git-workflow/default-commit-message?tab=${encodeURIComponent(tabId)}`);
175
+ assert.equal(updatedDefault.status, 200);
176
+ assert.equal(updatedDefault.body?.data?.message, "updated single.txt");
177
+ const updatedCommit = await request("127.0.0.1", "/api/git-workflow/commit", { method: "POST", body: { variant: "input", message: updatedDefault.body?.data?.message, tab: tabId } });
178
+ assert.equal(updatedCommit.status, 200);
179
+ assert.equal(updatedCommit.body?.ok, true, "input commit endpoint should accept the update default");
180
+
181
+ await rm(path.join(cwd, "single.txt"));
182
+ const gitAddDeleted = await request("127.0.0.1", "/api/git-workflow/add", { method: "POST", body: { tab: tabId } });
183
+ assert.equal(gitAddDeleted.status, 200);
184
+ assert.equal(gitAddDeleted.body?.ok, true, "git add endpoint should stage a single-file deletion");
185
+ const deletedDefault = await request("127.0.0.1", `/api/git-workflow/default-commit-message?tab=${encodeURIComponent(tabId)}`);
186
+ assert.equal(deletedDefault.status, 200);
187
+ assert.equal(deletedDefault.body?.data?.message, "deleted single.txt");
188
+
189
+ await writeFile(path.join(cwd, "multi-a.txt"), "a\n");
190
+ await writeFile(path.join(cwd, "multi-b.txt"), "b\n");
191
+ const gitAddMultiple = await request("127.0.0.1", "/api/git-workflow/add", { method: "POST", body: { tab: tabId } });
192
+ assert.equal(gitAddMultiple.status, 200);
193
+ assert.equal(gitAddMultiple.body?.ok, true, "git add endpoint should stage multiple files");
194
+ const multipleDefault = await request("127.0.0.1", `/api/git-workflow/default-commit-message?tab=${encodeURIComponent(tabId)}`);
195
+ assert.equal(multipleDefault.status, 200);
196
+ assert.equal(multipleDefault.body?.ok, true, "default commit message endpoint should still return ok when no default is available");
197
+ assert.equal(multipleDefault.body?.data?.message, "", "multiple staged files should not get a default commit message");
157
198
  } else {
158
199
  console.log("http-endpoints-harness: git not available; skipping git init workflow endpoint checks");
159
200
  }