@bivy/bivy 0.18.3 → 0.18.4-staging.10
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/README.md +77 -25
- package/bin/codex-app-server-shim.mjs +6 -1
- package/dist/apps/gateway.js +82 -8
- package/dist/apps/inspector.js +7 -2
- package/dist/apps/preview-shell.js +81 -29
- package/dist/apps/registry.js +7 -1
- package/dist/apps/remote-preview.js +4 -2
- package/dist/apps/styles.css +40 -48
- package/dist/apps/tokens.css +58 -51
- package/dist/git-auth.js +13 -5
- package/dist/runtime/activation-readiness.js +15 -0
- package/dist/runtime/anthropic-preflight.js +1 -1
- package/dist/server.js +43 -177
- package/dist/session/prompt-attachments.js +135 -0
- package/package.json +2 -2
package/dist/apps/registry.js
CHANGED
|
@@ -15,7 +15,9 @@ const isNote = (value) => {
|
|
|
15
15
|
const note = value;
|
|
16
16
|
return !!note && typeof note.id === "string" && typeof note.at === "number" && typeof note.note === "string" && note.note.length <= 1000
|
|
17
17
|
&& typeof note.selector === "string" && typeof note.text === "string" && typeof note.path === "string"
|
|
18
|
-
&& typeof note.viewport?.width === "number" && typeof note.viewport?.height === "number"
|
|
18
|
+
&& typeof note.viewport?.width === "number" && typeof note.viewport?.height === "number"
|
|
19
|
+
&& (note.context === undefined || (typeof note.context === "string" && note.context.length <= 8000))
|
|
20
|
+
&& (note.shot === undefined || (typeof note.shot?.hash === "string" && /^[a-f0-9]{64}$/.test(note.shot.hash) && Number.isFinite(note.shot.size) && Number.isFinite(note.shot.width) && Number.isFinite(note.shot.height)));
|
|
19
21
|
};
|
|
20
22
|
const sameFiles = (a, b) => a.size === b.size && [...a].every(([key, data]) => b.get(key)?.equals(data));
|
|
21
23
|
/** Snapshot, not a live filesystem server: symlinks and hidden files are never published. */
|
|
@@ -295,6 +297,10 @@ export class AppRegistry extends EventEmitter {
|
|
|
295
297
|
this.save();
|
|
296
298
|
}
|
|
297
299
|
agentNotes(id) { return this.apps.get(id)?.agentNotes === true; }
|
|
300
|
+
/** Includes persisted apps not restored yet; unread pictures survive GC. */
|
|
301
|
+
notePictureHashes() {
|
|
302
|
+
return [...this.persisted.values()].flatMap(record => Object.values(record.notes ?? {}).flatMap(notes => Array.isArray(notes) ? notes.filter(isNote).flatMap(note => note.shot ? [note.shot.hash] : []) : []));
|
|
303
|
+
}
|
|
298
304
|
/** A reviewer's note: kept bounded, saved with the app, announced (`notes`). */
|
|
299
305
|
addNote(viewId, note) {
|
|
300
306
|
const entry = this.views.get(viewId);
|
|
@@ -9,15 +9,17 @@ export class RemotePreview {
|
|
|
9
9
|
registry;
|
|
10
10
|
returnOrigins;
|
|
11
11
|
signIn;
|
|
12
|
+
captureNote;
|
|
12
13
|
gateway;
|
|
13
14
|
origin;
|
|
14
15
|
relayUrl;
|
|
15
16
|
online = false;
|
|
16
17
|
sockets = new Set();
|
|
17
|
-
constructor(registry, returnOrigins, signIn) {
|
|
18
|
+
constructor(registry, returnOrigins, signIn, captureNote) {
|
|
18
19
|
this.registry = registry;
|
|
19
20
|
this.returnOrigins = returnOrigins;
|
|
20
21
|
this.signIn = signIn;
|
|
22
|
+
this.captureNote = captureNote;
|
|
21
23
|
}
|
|
22
24
|
get available() { return this.online && Boolean(this.gateway); }
|
|
23
25
|
ready(origin, relayUrl) {
|
|
@@ -30,7 +32,7 @@ export class RemotePreview {
|
|
|
30
32
|
return;
|
|
31
33
|
if (this.origin !== template) {
|
|
32
34
|
this.gateway?.close();
|
|
33
|
-
this.gateway = new AppGateway(this.registry, template, this.returnOrigins, this.signIn);
|
|
35
|
+
this.gateway = new AppGateway(this.registry, template, this.returnOrigins, this.signIn, this.captureNote);
|
|
34
36
|
this.origin = template;
|
|
35
37
|
}
|
|
36
38
|
this.relayUrl = relayUrl.replace(/\/$/, "") + "/preview/stream";
|
package/dist/apps/styles.css
CHANGED
|
@@ -27,13 +27,16 @@
|
|
|
27
27
|
|
|
28
28
|
* { box-sizing: border-box; }
|
|
29
29
|
html, body, #root { height: 100%; margin: 0; }
|
|
30
|
+
/* iOS samples the page and fixed shell backgrounds for its status-bar tint.
|
|
31
|
+
Paint both explicitly so the tint follows theme changes instead of sampling
|
|
32
|
+
a transparent shell. Include the loading/sign-in shell before App mounts. */
|
|
33
|
+
html, body, .app, .setup { background: var(--bg); }
|
|
30
34
|
/* Lock the shell to the viewport: no whole-page scroll or rubber-band drift on
|
|
31
35
|
iOS (the app's own panes scroll). Without this the page itself scrolls under
|
|
32
36
|
the fixed shell and the layout appears to "move around / off screen". */
|
|
33
37
|
html, body { overflow: hidden; overscroll-behavior: none; }
|
|
34
38
|
body {
|
|
35
39
|
font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
36
|
-
background: var(--bg);
|
|
37
40
|
color: var(--ink);
|
|
38
41
|
-webkit-font-smoothing: antialiased;
|
|
39
42
|
}
|
|
@@ -1094,24 +1097,25 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1094
1097
|
}
|
|
1095
1098
|
.image-viewer-img { min-width: 0; min-height: 0; max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--radius-sm); cursor: default; }
|
|
1096
1099
|
.image-viewer-close {
|
|
1097
|
-
position: absolute; top: max(
|
|
1098
|
-
border: 0; background: var(--overlay); color: var(--accent-contrast); width: 40px; height: 40px;
|
|
1099
|
-
border-radius: var(--radius-full); font-size: 26px; line-height: 1; cursor: pointer;
|
|
1100
|
+
position: absolute; top: max(var(--space-3), env(safe-area-inset-top)); right: max(var(--space-4), env(safe-area-inset-right));
|
|
1100
1101
|
}
|
|
1102
|
+
.image-viewer-close, .image-viewer-nav {
|
|
1103
|
+
border: 1px solid var(--line-strong); background: var(--surface-3); color: var(--ink);
|
|
1104
|
+
width: var(--space-7); height: var(--space-7); border-radius: var(--radius-full);
|
|
1105
|
+
font-size: var(--text-3xl); line-height: 1; cursor: pointer;
|
|
1106
|
+
display: grid; place-items: center;
|
|
1107
|
+
}
|
|
1108
|
+
.image-viewer-close:hover, .image-viewer-nav:hover { background: var(--surface-2); }
|
|
1101
1109
|
/* Prev/next page controls in the multi-image gallery — mirror the close button. */
|
|
1102
1110
|
.image-viewer-nav {
|
|
1103
1111
|
position: absolute; top: 50%; transform: translateY(-50%);
|
|
1104
|
-
border: 0; background: var(--overlay); color: var(--accent-contrast);
|
|
1105
|
-
width: 44px; height: 44px; border-radius: var(--radius-full);
|
|
1106
|
-
font-size: 30px; line-height: 1; cursor: pointer;
|
|
1107
|
-
display: grid; place-items: center;
|
|
1108
1112
|
}
|
|
1109
1113
|
.image-viewer-nav.prev { left: max(var(--space-3), env(safe-area-inset-left)); }
|
|
1110
1114
|
.image-viewer-nav.next { right: max(var(--space-4), env(safe-area-inset-right)); }
|
|
1111
1115
|
.image-viewer-count {
|
|
1112
1116
|
position: absolute; bottom: max(var(--space-4), env(safe-area-inset-bottom));
|
|
1113
1117
|
left: 50%; transform: translateX(-50%); cursor: default;
|
|
1114
|
-
background: var(--
|
|
1118
|
+
background: var(--surface-3); color: var(--ink);
|
|
1115
1119
|
padding: var(--space-1) var(--space-3); border-radius: var(--radius-full);
|
|
1116
1120
|
font-size: var(--text-sm); font-variant-numeric: tabular-nums;
|
|
1117
1121
|
}
|
|
@@ -1168,8 +1172,7 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1168
1172
|
/* Agent/model catalogs should not collapse into a tiny strip when the composer
|
|
1169
1173
|
grows. Keep their normal composer clearance, but cap that reservation and
|
|
1170
1174
|
give the scrollable catalog a stable, roomy height. */
|
|
1171
|
-
.sheet[data-size="large"] .sheet-body
|
|
1172
|
-
.sheet[data-size="mobile-full"] .sheet-body {
|
|
1175
|
+
.sheet[data-size="large"] .sheet-body {
|
|
1173
1176
|
--sheet-clear: max(
|
|
1174
1177
|
calc(env(safe-area-inset-bottom, 0px) + var(--space-2)),
|
|
1175
1178
|
min(calc(var(--composer-h, 108px) + var(--space-2) - var(--keyboard-h, 0px)), calc(var(--app-h, 100dvh) * 0.24))
|
|
@@ -1197,20 +1200,19 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1197
1200
|
page) handles a long tool list; touch scrolling + overscroll containment keep
|
|
1198
1201
|
the fling smooth on iOS and stop it chaining to the chat underneath. */
|
|
1199
1202
|
.sheet-content { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 8px; min-height: 0; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
|
|
1200
|
-
/* Embedded apps use the whole
|
|
1201
|
-
reserved for the chat composer. Keep controls clear of
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
}
|
|
1203
|
+
/* Embedded apps use the whole viewport on every screen size, including the
|
|
1204
|
+
space normally reserved for the chat composer. Keep controls clear of
|
|
1205
|
+
device safe areas. */
|
|
1206
|
+
.sheet[data-size="full"] .sheet-body {
|
|
1207
|
+
height: 100%; max-height: 100%; max-width: none; margin: 0;
|
|
1208
|
+
border: 0; border-radius: 0;
|
|
1209
|
+
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
|
1210
|
+
}
|
|
1211
|
+
.sheet[data-size="full"] .sheet-grabber { display: none; }
|
|
1212
|
+
.sheet[data-size="full"] .sheet-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1213
|
+
.sheet[data-size="full"] .sheet-head > button { flex-shrink: 0; min-height: var(--space-7); }
|
|
1214
|
+
.sheet[data-size="full"] .sheet-content { padding: 0; }
|
|
1215
|
+
.sheet[data-size="full"] .preview-peek { border-radius: 0; }
|
|
1214
1216
|
.picker-search { margin-bottom: 6px; }
|
|
1215
1217
|
/* In a picker sheet the search is a direct child of the scroll container, so pin
|
|
1216
1218
|
it to the top: the list scrolls beneath it and every option stays reachable
|
|
@@ -2136,20 +2138,6 @@ a.queue-item:hover { border-color: var(--line-strong); background: var(--surface
|
|
|
2136
2138
|
.run-sheet-recovery { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
|
|
2137
2139
|
.run-sheet-recovery .btn.sm { padding: var(--space-1) var(--space-3); }
|
|
2138
2140
|
|
|
2139
|
-
.composer-starter {
|
|
2140
|
-
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
|
|
2141
|
-
margin: 0 var(--space-3) var(--space-2); padding: var(--space-3); border: 1px solid var(--line);
|
|
2142
|
-
border-radius: var(--radius-md); background: var(--surface);
|
|
2143
|
-
}
|
|
2144
|
-
.composer-starter > div { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
|
|
2145
|
-
.composer-starter strong { font-size: var(--text-sm); color: var(--ink); }
|
|
2146
|
-
.composer-starter span { font-size: var(--text-xs); line-height: var(--lh-sm); color: var(--muted); }
|
|
2147
|
-
.composer-starter .btn { flex: none; max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
|
|
2148
|
-
@media (max-width: 520px) {
|
|
2149
|
-
.composer-starter { align-items: stretch; flex-direction: column; }
|
|
2150
|
-
.composer-starter .btn { min-height: var(--space-7); }
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
2141
|
/* Review surface (C3): state badges, checks strip, view-mode toggle, file tree,
|
|
2154
2142
|
per-file actions, and the split (side-by-side) diff layout. */
|
|
2155
2143
|
.changes-meta { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding: 6px 10px; border-bottom: 1px solid var(--line); }
|
|
@@ -3075,8 +3063,8 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3075
3063
|
.review-banner { margin: 0 var(--space-3); }
|
|
3076
3064
|
.review-note { margin: var(--space-3) var(--space-3) 0; padding-inline-start: var(--space-3); border-inline-start: 2px solid var(--line-strong); color: var(--ink); font-size: var(--text-sm); white-space: pre-wrap; }
|
|
3077
3065
|
.review-status { margin: var(--space-2) var(--space-3) 0; color: var(--muted); font-size: var(--text-sm); }
|
|
3078
|
-
.review-actions { display: flex; padding: var(--space-3); }
|
|
3079
|
-
.review-actions .btn {
|
|
3066
|
+
.review-actions { display: flex; flex-wrap: wrap; gap: var(--space-1); padding: var(--space-3); }
|
|
3067
|
+
.review-actions .btn { min-block-size: var(--space-7); }
|
|
3080
3068
|
|
|
3081
3069
|
/* Apps sheet (AppsSheet.tsx): one card per app, its views nested, one primary
|
|
3082
3070
|
action per view; secondary tools as quiet icon buttons; rare or destructive
|
|
@@ -3093,8 +3081,6 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3093
3081
|
.apps-more { position: relative; }
|
|
3094
3082
|
.apps-view-tools .apps-more { margin-inline-start: auto; }
|
|
3095
3083
|
.apps-more-menu { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: var(--z-dropdown); }
|
|
3096
|
-
.apps-notice { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 var(--space-3) var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: color-mix(in srgb, var(--ok) 12%, transparent); font-size: var(--text-sm); }
|
|
3097
|
-
.apps-notice > svg { flex: none; margin-top: 1px; color: var(--ok); }
|
|
3098
3084
|
.apps-notes { display: flex; flex-direction: column; gap: var(--space-2); margin: 0 var(--space-3) var(--space-3); padding-top: var(--space-3); border-top: 1px dashed var(--line); }
|
|
3099
3085
|
.apps-notes-head { display: flex; align-items: center; gap: var(--space-2); color: var(--muted); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; }
|
|
3100
3086
|
.apps-count { min-inline-size: 18px; padding: 0 6px; border-radius: var(--radius-full); background: var(--surface-3); color: var(--ink); text-align: center; letter-spacing: 0; }
|
|
@@ -3118,6 +3104,8 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3118
3104
|
.share-dest { display: block; inline-size: 100%; padding: 0; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); color: inherit; font: inherit; text-align: start; cursor: pointer; }
|
|
3119
3105
|
.share-dest:hover { background: var(--surface-2); }
|
|
3120
3106
|
.share-dest .app-row { min-block-size: 44px; }
|
|
3107
|
+
.preview-head-actions { display: flex; flex: none; align-items: center; gap: var(--space-1); }
|
|
3108
|
+
.preview-head-actions .btn { min-block-size: var(--space-7); }
|
|
3121
3109
|
.preview-peek-stage { position: relative; block-size: 100%; }
|
|
3122
3110
|
/* Point and speak: the recording bar floats over the top of the preview while
|
|
3123
3111
|
the finger stays on the shell's mic, so nothing under it moves. */
|
|
@@ -3166,9 +3154,8 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3166
3154
|
letter-spacing: -0.01em;
|
|
3167
3155
|
}
|
|
3168
3156
|
|
|
3169
|
-
/*
|
|
3170
|
-
|
|
3171
|
-
.readiness { margin: 10px 12px 0; }
|
|
3157
|
+
/* Setup checks and the ready-to-message confirmation. */
|
|
3158
|
+
.readiness { margin: var(--space-3) var(--space-3) 0; }
|
|
3172
3159
|
.readiness-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
|
3173
3160
|
.readiness-title { font-weight: 600; font-size: var(--text-base); letter-spacing: -0.01em; }
|
|
3174
3161
|
.readiness-dismiss {
|
|
@@ -3178,8 +3165,7 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3178
3165
|
.readiness-dismiss:hover { background: var(--surface-2); color: var(--ink); }
|
|
3179
3166
|
.readiness-passed { margin: 0 0 var(--space-2); color: var(--ok); font-size: var(--text-sm); font-weight: var(--weight-medium); }
|
|
3180
3167
|
.readiness-checks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
3181
|
-
/*
|
|
3182
|
-
already done buried the only useful state (waiting for the first answer). */
|
|
3168
|
+
/* Summarize completed checks so the next setup action stays visible. */
|
|
3183
3169
|
.readiness-check.state-passed { display: none; }
|
|
3184
3170
|
.readiness-check { display: flex; align-items: baseline; gap: 8px; font-size: var(--text-sm); }
|
|
3185
3171
|
.readiness-mark {
|
|
@@ -3368,3 +3354,9 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3368
3354
|
the composer itself, with one line of another device's draft. */
|
|
3369
3355
|
.handoff-banner { border-radius: var(--radius-md); }
|
|
3370
3356
|
.handoff-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3357
|
+
|
|
3358
|
+
/* Keep editorial type on the wordmark; session titles retain the app's sans. */
|
|
3359
|
+
.brand {
|
|
3360
|
+
font-family: var(--font-serif);
|
|
3361
|
+
font-weight: var(--weight-medium);
|
|
3362
|
+
}
|
package/dist/apps/tokens.css
CHANGED
|
@@ -30,37 +30,37 @@
|
|
|
30
30
|
/* ---- Core surfaces & text (neutral) ---- */
|
|
31
31
|
--bg: #ffffff;
|
|
32
32
|
--surface: #ffffff;
|
|
33
|
-
--surface-2: #
|
|
34
|
-
--surface-3: #
|
|
35
|
-
--ink: #
|
|
36
|
-
--muted: #
|
|
37
|
-
--line: #
|
|
38
|
-
--line-strong: #
|
|
33
|
+
--surface-2: #f5f5f5;
|
|
34
|
+
--surface-3: #ebebeb;
|
|
35
|
+
--ink: #222222;
|
|
36
|
+
--muted: #666666;
|
|
37
|
+
--line: #e5e5e5;
|
|
38
|
+
--line-strong: #c5c5c5;
|
|
39
39
|
--overlay: rgba(0, 0, 0, 0.46);
|
|
40
40
|
--overlay-strong: rgba(0, 0, 0, 0.8);
|
|
41
41
|
|
|
42
42
|
/* ---- Accent (reserved for primary actions and active status) ---- */
|
|
43
|
-
--accent: #
|
|
43
|
+
--accent: #ac4b24;
|
|
44
44
|
--accent-contrast: #ffffff;
|
|
45
|
-
--accent-hover: #
|
|
45
|
+
--accent-hover: #873b1c;
|
|
46
46
|
--accent-active: color-mix(in srgb, var(--accent), #000 22%);
|
|
47
|
-
--accent-soft:
|
|
47
|
+
--accent-soft: #f5e5d9;
|
|
48
48
|
|
|
49
49
|
/* ---- Status ---- */
|
|
50
|
-
--danger: #
|
|
51
|
-
--ok: #
|
|
52
|
-
--merged: #
|
|
50
|
+
--danger: #a63d35; --danger-soft: #f4e3dd; --danger-contrast: #ffffff;
|
|
51
|
+
--ok: #506d43;
|
|
52
|
+
--merged: #796188;
|
|
53
53
|
/* A run that finished while you weren't looking — its own signal, deliberately
|
|
54
54
|
not accent (working) / danger (needs input) / ok / merged, so
|
|
55
55
|
"something's ready" reads at a glance. */
|
|
56
|
-
--unseen: #
|
|
56
|
+
--unseen: #967021;
|
|
57
57
|
--unseen-contrast: #111111;
|
|
58
58
|
|
|
59
59
|
/* ---- Per-source hues for session/run marks (see packages/web sessionSource).
|
|
60
60
|
Kept clear of the status palette above so a source is never mistaken for an
|
|
61
61
|
outcome; app/cli stay quiet so hand-opened sessions don't shout. ---- */
|
|
62
62
|
--s-github: #24292f; --s-slack: #7c2d92; --s-linear: #5e6ad2; --s-schedule: #0e7490;
|
|
63
|
-
--s-webhook: #6d28d9; --s-manual: #b45309; --s-cli: #
|
|
63
|
+
--s-webhook: #6d28d9; --s-manual: #b45309; --s-cli: #526d3b; --s-app: #6a785a;
|
|
64
64
|
|
|
65
65
|
/* ---- Annotation: marks drawn over an app preview. The same in both themes
|
|
66
66
|
(the app underneath has its own), vivid and rare in real UIs, with a white
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
--annotate-halo: #ffffff;
|
|
70
70
|
|
|
71
71
|
/* ---- Terminal text selection ---- */
|
|
72
|
-
--term-selection: rgba(
|
|
73
|
-
--term-selection-inactive: rgba(
|
|
72
|
+
--term-selection: rgba(119, 141, 91, 0.30);
|
|
73
|
+
--term-selection-inactive: rgba(119, 141, 91, 0.18);
|
|
74
74
|
|
|
75
75
|
/* ---- Syntax highlighting ---- */
|
|
76
76
|
--syntax-comment: #6a737d; --syntax-keyword: #d73a49; --syntax-string: #032f62;
|
|
@@ -106,18 +106,18 @@
|
|
|
106
106
|
--space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px;
|
|
107
107
|
|
|
108
108
|
/* ---- Radius ---- */
|
|
109
|
-
--radius:
|
|
110
|
-
--radius-sm:
|
|
111
|
-
--radius-md:
|
|
112
|
-
--radius-lg:
|
|
113
|
-
--radius-xl:
|
|
109
|
+
--radius: 8px; /* app default — same value as --radius-md */
|
|
110
|
+
--radius-sm: 6px;
|
|
111
|
+
--radius-md: 8px;
|
|
112
|
+
--radius-lg: 12px;
|
|
113
|
+
--radius-xl: 16px;
|
|
114
114
|
--radius-full: 999px;
|
|
115
115
|
|
|
116
116
|
/* ---- Elevation ---- */
|
|
117
|
-
--shadow-sm: 0 1px
|
|
118
|
-
--shadow-md: 0 4px
|
|
119
|
-
--shadow-lg: 0 12px 32px rgba(
|
|
120
|
-
--shadow-xl: 0 24px 70px rgba(
|
|
117
|
+
--shadow-sm: 0 1px 3px rgba(40, 45, 36, 0.06);
|
|
118
|
+
--shadow-md: 0 4px 16px rgba(40, 45, 36, 0.08);
|
|
119
|
+
--shadow-lg: 0 12px 32px rgba(40, 45, 36, 0.12);
|
|
120
|
+
--shadow-xl: 0 24px 70px rgba(40, 45, 36, 0.16);
|
|
121
121
|
|
|
122
122
|
/* ---- Motion ---- */
|
|
123
123
|
--dur-fast: 120ms;
|
|
@@ -150,59 +150,66 @@
|
|
|
150
150
|
definition (they only "worked" via an inline var(--x, #fallback)). Defined
|
|
151
151
|
here so the fallback is never load-bearing and the value is consistent
|
|
152
152
|
everywhere the name appears. Prefer the canonical name on the right. ==== */
|
|
153
|
-
--warn: #
|
|
153
|
+
--warn: #967021; --warn-soft: #f0e8cf;
|
|
154
154
|
--err: var(--danger);
|
|
155
155
|
--add: var(--ok); /* diff addition */
|
|
156
156
|
--del: var(--danger); /* diff deletion */
|
|
157
157
|
--fg: var(--ink);
|
|
158
158
|
--surface-1: var(--surface);
|
|
159
159
|
--mono: var(--font-mono);
|
|
160
|
+
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
:root[data-theme="light"] { color-scheme: light; }
|
|
163
164
|
|
|
164
165
|
:root[data-theme="dark"] {
|
|
165
166
|
color-scheme: dark;
|
|
166
|
-
--bg: #000000; --surface: #
|
|
167
|
-
--ink: #
|
|
167
|
+
--bg: #000000; --surface: #080808; --surface-2: #141414; --surface-3: #202020;
|
|
168
|
+
--ink: #f3f3f3; --muted: #aaaaaa; --line: #262626; --line-strong: #484848;
|
|
168
169
|
--overlay: rgba(0, 0, 0, 0.7); --overlay-strong: rgba(0, 0, 0, 0.8);
|
|
169
|
-
--accent: #
|
|
170
|
-
--danger: #
|
|
171
|
-
--unseen: #
|
|
172
|
-
--warn: #
|
|
170
|
+
--accent: #edab7e; --accent-contrast: #271c12; --accent-hover: #f6c29f;
|
|
171
|
+
--danger: #f0a497; --danger-soft: #4a3029; --danger-contrast: #0a0a0a; --ok: #b3ce96; --merged: #cab4d4;
|
|
172
|
+
--unseen: #ddc181; --unseen-contrast: #0a0a0a;
|
|
173
|
+
--warn: #ddc181;
|
|
173
174
|
--s-github: #d7dde3; --s-slack: #d68ce6; --s-linear: #a5adf5; --s-schedule: #4bc4de;
|
|
174
|
-
--s-webhook: #b79bf7; --s-manual: #f0a45a; --s-cli: #
|
|
175
|
-
--term-selection: rgba(
|
|
175
|
+
--s-webhook: #b79bf7; --s-manual: #f0a45a; --s-cli: #adc58f; --s-app: #b2c69a;
|
|
176
|
+
--term-selection: rgba(178, 198, 154, 0.30); --term-selection-inactive: rgba(178, 198, 154, 0.18);
|
|
176
177
|
--syntax-comment: #8b949e; --syntax-keyword: #ff7b72; --syntax-string: #a5d6ff;
|
|
177
178
|
--syntax-number: #79c0ff; --syntax-title: #d2a8ff; --syntax-type: #ffa657;
|
|
178
179
|
--syntax-name: #7ee787; --syntax-deletion: #ffdcd7; --syntax-addition: #85e89d;
|
|
179
|
-
--shadow-sm: 0 1px
|
|
180
|
-
--shadow-md: 0 4px
|
|
181
|
-
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.
|
|
182
|
-
--shadow-xl: 0 24px 70px rgba(0, 0, 0, 0.
|
|
180
|
+
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.20);
|
|
181
|
+
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.24);
|
|
182
|
+
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.28);
|
|
183
|
+
--shadow-xl: 0 24px 70px rgba(0, 0, 0, 0.32);
|
|
184
|
+
|
|
185
|
+
--accent-soft: #493c2c;
|
|
186
|
+
--warn-soft: #49432b;
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
@media (prefers-color-scheme: dark) {
|
|
186
190
|
:root:not([data-theme]) {
|
|
187
191
|
color-scheme: dark;
|
|
188
|
-
--bg: #000000; --surface: #
|
|
189
|
-
--ink: #
|
|
192
|
+
--bg: #000000; --surface: #080808; --surface-2: #141414; --surface-3: #202020;
|
|
193
|
+
--ink: #f3f3f3; --muted: #aaaaaa; --line: #262626; --line-strong: #484848;
|
|
190
194
|
--overlay: rgba(0, 0, 0, 0.7); --overlay-strong: rgba(0, 0, 0, 0.8);
|
|
191
|
-
--accent: #
|
|
192
|
-
--danger: #
|
|
193
|
-
--unseen: #
|
|
194
|
-
--warn: #
|
|
195
|
+
--accent: #edab7e; --accent-contrast: #271c12; --accent-hover: #f6c29f;
|
|
196
|
+
--danger: #f0a497; --danger-soft: #4a3029; --danger-contrast: #0a0a0a; --ok: #b3ce96; --merged: #cab4d4;
|
|
197
|
+
--unseen: #ddc181; --unseen-contrast: #0a0a0a;
|
|
198
|
+
--warn: #ddc181;
|
|
195
199
|
--s-github: #d7dde3; --s-slack: #d68ce6; --s-linear: #a5adf5; --s-schedule: #4bc4de;
|
|
196
|
-
--s-webhook: #b79bf7; --s-manual: #f0a45a; --s-cli: #
|
|
197
|
-
--term-selection: rgba(
|
|
200
|
+
--s-webhook: #b79bf7; --s-manual: #f0a45a; --s-cli: #adc58f; --s-app: #b2c69a;
|
|
201
|
+
--term-selection: rgba(178, 198, 154, 0.30); --term-selection-inactive: rgba(178, 198, 154, 0.18);
|
|
198
202
|
--syntax-comment: #8b949e; --syntax-keyword: #ff7b72; --syntax-string: #a5d6ff;
|
|
199
203
|
--syntax-number: #79c0ff; --syntax-title: #d2a8ff; --syntax-type: #ffa657;
|
|
200
204
|
--syntax-name: #7ee787; --syntax-deletion: #ffdcd7; --syntax-addition: #85e89d;
|
|
201
|
-
--shadow-sm: 0 1px
|
|
202
|
-
--shadow-md: 0 4px
|
|
203
|
-
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.
|
|
204
|
-
--shadow-xl: 0 24px 70px rgba(0, 0, 0, 0.
|
|
205
|
-
|
|
205
|
+
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.20);
|
|
206
|
+
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.24);
|
|
207
|
+
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.28);
|
|
208
|
+
--shadow-xl: 0 24px 70px rgba(0, 0, 0, 0.32);
|
|
209
|
+
|
|
210
|
+
--accent-soft: #493c2c;
|
|
211
|
+
--warn-soft: #49432b;
|
|
212
|
+
}
|
|
206
213
|
}
|
|
207
214
|
|
|
208
215
|
@media (prefers-reduced-motion: reduce) {
|
package/dist/git-auth.js
CHANGED
|
@@ -148,14 +148,22 @@ export function gitNonInteractiveEnv() {
|
|
|
148
148
|
*/
|
|
149
149
|
export async function configureRepoCredentialHelper(git, dest) {
|
|
150
150
|
const helper = ensureCredentialHelper();
|
|
151
|
-
await git(["-C", dest, "config", "--local", "credential.https://github.com.useHttpPath", "true"]);
|
|
152
151
|
// Reset the helper chain for this repo, then set ONLY bivy's helper, so AGENT-run
|
|
153
152
|
// git never falls back to an inherited host helper holding the human's personal
|
|
154
|
-
// token (see credConfigArgs for the full rationale).
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
// token (see credConfigArgs for the full rationale).
|
|
154
|
+
//
|
|
155
|
+
// Git reads `credential.helper` and `credential.<url>.helper` into ONE list in
|
|
156
|
+
// FILE order, and an empty value clears everything before it. So every reset must
|
|
157
|
+
// sit above bivy's helper in .git/config — an empty `[credential] helper` written
|
|
158
|
+
// after the `[credential "https://github.com"]` section wipes bivy's helper and
|
|
159
|
+
// leaves git with none (the lazy blob fetch in `git worktree add` then dies with
|
|
160
|
+
// "could not read Username"). `--add` appends to an existing section, so drop both
|
|
161
|
+
// sections first and write them back in order; this also repairs clones written in
|
|
162
|
+
// the old order (remove-section fails harmlessly when a section is absent).
|
|
163
|
+
await git(["-C", dest, "config", "--local", "--remove-section", "credential"]).catch(() => { });
|
|
164
|
+
await git(["-C", dest, "config", "--local", "--remove-section", "credential.https://github.com"]).catch(() => { });
|
|
158
165
|
await git(["-C", dest, "config", "--local", "--add", "credential.helper", ""]);
|
|
166
|
+
await git(["-C", dest, "config", "--local", "credential.https://github.com.useHttpPath", "true"]);
|
|
159
167
|
await git(["-C", dest, "config", "--local", "--add", "credential.https://github.com.helper", ""]);
|
|
160
168
|
await git(["-C", dest, "config", "--local", "--add", "credential.https://github.com.helper", helper]);
|
|
161
169
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Use the same configured providers as the model picker, including environment
|
|
2
|
+
* credentials. An unrelated rejected key must not hide a usable provider. */
|
|
3
|
+
export async function credentialReadiness(providers, probe) {
|
|
4
|
+
const configured = providers.filter((provider) => provider.configured);
|
|
5
|
+
const results = await Promise.all(configured.map((provider) => probe(provider.id)));
|
|
6
|
+
const usable = results.find((result) => result.ok);
|
|
7
|
+
const result = usable ?? results[0];
|
|
8
|
+
return {
|
|
9
|
+
configured: configured.length > 0,
|
|
10
|
+
providers: configured.map((provider) => provider.id),
|
|
11
|
+
probed: result?.probed ?? false,
|
|
12
|
+
ok: Boolean(usable),
|
|
13
|
+
...(result?.reason ? { reason: result.reason } : {}),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -85,7 +85,7 @@ export function isAnthropicAuthError(raw) {
|
|
|
85
85
|
export async function probeAnthropicAccess(apiKey, deps = {}) {
|
|
86
86
|
const key = apiKey?.trim();
|
|
87
87
|
// Subscription/OAuth tokens are not API keys; there is no safe read probe.
|
|
88
|
-
if (!key || !key.startsWith("sk-"))
|
|
88
|
+
if (!key || !key.startsWith("sk-") || key.startsWith("sk-ant-oat"))
|
|
89
89
|
return { probed: false, ok: true, reason: "no API key to probe" };
|
|
90
90
|
const doFetch = deps.fetch ?? fetch;
|
|
91
91
|
const base = (deps.baseUrl ?? "https://api.anthropic.com").replace(/\/+$/, "");
|