@bivy/bivy 0.18.4-staging.4 → 0.18.4-staging.6
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/dist/apps/styles.css +17 -35
- 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 +19 -22
- package/package.json +1 -1
package/dist/apps/styles.css
CHANGED
|
@@ -1171,8 +1171,7 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1171
1171
|
/* Agent/model catalogs should not collapse into a tiny strip when the composer
|
|
1172
1172
|
grows. Keep their normal composer clearance, but cap that reservation and
|
|
1173
1173
|
give the scrollable catalog a stable, roomy height. */
|
|
1174
|
-
.sheet[data-size="large"] .sheet-body
|
|
1175
|
-
.sheet[data-size="mobile-full"] .sheet-body {
|
|
1174
|
+
.sheet[data-size="large"] .sheet-body {
|
|
1176
1175
|
--sheet-clear: max(
|
|
1177
1176
|
calc(env(safe-area-inset-bottom, 0px) + var(--space-2)),
|
|
1178
1177
|
min(calc(var(--composer-h, 108px) + var(--space-2) - var(--keyboard-h, 0px)), calc(var(--app-h, 100dvh) * 0.24))
|
|
@@ -1200,20 +1199,19 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1200
1199
|
page) handles a long tool list; touch scrolling + overscroll containment keep
|
|
1201
1200
|
the fling smooth on iOS and stop it chaining to the chat underneath. */
|
|
1202
1201
|
.sheet-content { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 8px; min-height: 0; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
|
|
1203
|
-
/* Embedded apps use the whole
|
|
1204
|
-
reserved for the chat composer. Keep controls clear of
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
}
|
|
1202
|
+
/* Embedded apps use the whole viewport on every screen size, including the
|
|
1203
|
+
space normally reserved for the chat composer. Keep controls clear of
|
|
1204
|
+
device safe areas. */
|
|
1205
|
+
.sheet[data-size="full"] .sheet-body {
|
|
1206
|
+
height: 100%; max-height: 100%; max-width: none; margin: 0;
|
|
1207
|
+
border: 0; border-radius: 0;
|
|
1208
|
+
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
|
1209
|
+
}
|
|
1210
|
+
.sheet[data-size="full"] .sheet-grabber { display: none; }
|
|
1211
|
+
.sheet[data-size="full"] .sheet-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1212
|
+
.sheet[data-size="full"] .sheet-head > button { flex-shrink: 0; min-height: var(--space-7); }
|
|
1213
|
+
.sheet[data-size="full"] .sheet-content { padding: 0; }
|
|
1214
|
+
.sheet[data-size="full"] .preview-peek { border-radius: 0; }
|
|
1217
1215
|
.picker-search { margin-bottom: 6px; }
|
|
1218
1216
|
/* In a picker sheet the search is a direct child of the scroll container, so pin
|
|
1219
1217
|
it to the top: the list scrolls beneath it and every option stays reachable
|
|
@@ -2139,20 +2137,6 @@ a.queue-item:hover { border-color: var(--line-strong); background: var(--surface
|
|
|
2139
2137
|
.run-sheet-recovery { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
|
|
2140
2138
|
.run-sheet-recovery .btn.sm { padding: var(--space-1) var(--space-3); }
|
|
2141
2139
|
|
|
2142
|
-
.composer-starter {
|
|
2143
|
-
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
|
|
2144
|
-
margin: 0 var(--space-3) var(--space-2); padding: var(--space-3); border: 1px solid var(--line);
|
|
2145
|
-
border-radius: var(--radius-md); background: var(--surface);
|
|
2146
|
-
}
|
|
2147
|
-
.composer-starter > div { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
|
|
2148
|
-
.composer-starter strong { font-size: var(--text-sm); color: var(--ink); }
|
|
2149
|
-
.composer-starter span { font-size: var(--text-xs); line-height: var(--lh-sm); color: var(--muted); }
|
|
2150
|
-
.composer-starter .btn { flex: none; max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
|
|
2151
|
-
@media (max-width: 520px) {
|
|
2152
|
-
.composer-starter { align-items: stretch; flex-direction: column; }
|
|
2153
|
-
.composer-starter .btn { min-height: var(--space-7); }
|
|
2154
|
-
}
|
|
2155
|
-
|
|
2156
2140
|
/* Review surface (C3): state badges, checks strip, view-mode toggle, file tree,
|
|
2157
2141
|
per-file actions, and the split (side-by-side) diff layout. */
|
|
2158
2142
|
.changes-meta { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding: 6px 10px; border-bottom: 1px solid var(--line); }
|
|
@@ -3169,9 +3153,8 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3169
3153
|
letter-spacing: -0.01em;
|
|
3170
3154
|
}
|
|
3171
3155
|
|
|
3172
|
-
/*
|
|
3173
|
-
|
|
3174
|
-
.readiness { margin: 10px 12px 0; }
|
|
3156
|
+
/* Setup checks and the ready-to-message confirmation. */
|
|
3157
|
+
.readiness { margin: var(--space-3) var(--space-3) 0; }
|
|
3175
3158
|
.readiness-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
|
3176
3159
|
.readiness-title { font-weight: 600; font-size: var(--text-base); letter-spacing: -0.01em; }
|
|
3177
3160
|
.readiness-dismiss {
|
|
@@ -3181,8 +3164,7 @@ p.setup-note .btn.link { min-height: 44px; margin-block: calc((1lh - 44px) / 2);
|
|
|
3181
3164
|
.readiness-dismiss:hover { background: var(--surface-2); color: var(--ink); }
|
|
3182
3165
|
.readiness-passed { margin: 0 0 var(--space-2); color: var(--ok); font-size: var(--text-sm); font-weight: var(--weight-medium); }
|
|
3183
3166
|
.readiness-checks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
3184
|
-
/*
|
|
3185
|
-
already done buried the only useful state (waiting for the first answer). */
|
|
3167
|
+
/* Summarize completed checks so the next setup action stays visible. */
|
|
3186
3168
|
.readiness-check.state-passed { display: none; }
|
|
3187
3169
|
.readiness-check { display: flex; align-items: baseline; gap: 8px; font-size: var(--text-sm); }
|
|
3188
3170
|
.readiness-mark {
|
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(/\/+$/, "");
|
package/dist/server.js
CHANGED
|
@@ -50,6 +50,7 @@ import { passWebhookFilter } from "./automation-filter-gate.js";
|
|
|
50
50
|
import { isModelAuthError, authProviderForSession, classifyModelAuthError } from "./runtime/auth-errors.js";
|
|
51
51
|
import { createCredentialVault, migrateVaultDir } from "./runtime/credential-store.js";
|
|
52
52
|
import { probeAnthropicAccess } from "./runtime/anthropic-preflight.js";
|
|
53
|
+
import { credentialReadiness } from "./runtime/activation-readiness.js";
|
|
53
54
|
import { createSessionNamer, fallbackSessionName } from "./session/session-namer.js";
|
|
54
55
|
import { createBranchPublish } from "./session/branch-publish.js";
|
|
55
56
|
import { createForkStandUp } from "./session/fork-standup.js";
|
|
@@ -10997,32 +10998,28 @@ app.get("/api/repos", async (_req, res) => {
|
|
|
10997
10998
|
// live. Inconclusive provider/network failures remain "unknown" instead of
|
|
10998
10999
|
// falsely blocking activation.
|
|
10999
11000
|
async function activationReadinessSnapshot() {
|
|
11000
|
-
const
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11001
|
+
const [credential, repositoryChosen, workspaceReady] = await Promise.all([
|
|
11002
|
+
listProviders(credsDir, piDir).then((providers) => credentialReadiness(providers, async (provider) => {
|
|
11003
|
+
if (provider !== "anthropic")
|
|
11004
|
+
return { probed: false, ok: true };
|
|
11005
|
+
const credential = await createCredentialVault(credsDir, piDir).read(provider);
|
|
11006
|
+
if (credential?.type === "oauth")
|
|
11007
|
+
return { probed: false, ok: true };
|
|
11008
|
+
return probeAnthropicAccess(credential?.type === "api_key" && typeof credential.key === "string"
|
|
11009
|
+
? credential.key : process.env.ANTHROPIC_API_KEY);
|
|
11010
|
+
})),
|
|
11011
|
+
gitRepoRoot(defaultWorkspace).then(Boolean),
|
|
11012
|
+
fs.promises.access(defaultWorkspace, fs.constants.R_OK | fs.constants.W_OK).then(() => true, () => false),
|
|
11013
|
+
]);
|
|
11010
11014
|
return {
|
|
11011
|
-
credential
|
|
11012
|
-
configured: configured.length > 0,
|
|
11013
|
-
providers: configured.map((entry) => entry.providerId),
|
|
11014
|
-
probed: Boolean(anthropicProbe?.probed),
|
|
11015
|
-
ok: configured.length > 0 && anthropicProbe?.ok !== false,
|
|
11016
|
-
...(anthropicProbe?.reason ? { reason: anthropicProbe.reason } : {}),
|
|
11017
|
-
},
|
|
11015
|
+
credential,
|
|
11018
11016
|
repository: {
|
|
11019
11017
|
chosen: repositoryChosen,
|
|
11020
11018
|
probed: true,
|
|
11021
|
-
//
|
|
11022
|
-
//
|
|
11023
|
-
ok:
|
|
11024
|
-
authed:
|
|
11025
|
-
...(repos.error ? { reason: repos.error } : {}),
|
|
11019
|
+
// A first message can run in the default workspace without a Git repo.
|
|
11020
|
+
// Listing remote repositories is unrelated and can take tens of seconds.
|
|
11021
|
+
ok: workspaceReady,
|
|
11022
|
+
authed: false,
|
|
11026
11023
|
},
|
|
11027
11024
|
};
|
|
11028
11025
|
}
|
package/package.json
CHANGED