fix: clarify auth order exclusions
This commit is contained in:
@@ -25,6 +25,8 @@ Docs: https://docs.clawd.bot
|
|||||||
- CLI: render auth probe results as a table in `clawdbot models status`.
|
- CLI: render auth probe results as a table in `clawdbot models status`.
|
||||||
- CLI: suppress probe-only embedded logs unless `--verbose` is set.
|
- CLI: suppress probe-only embedded logs unless `--verbose` is set.
|
||||||
- CLI: move auth probe errors below the table to reduce wrapping.
|
- CLI: move auth probe errors below the table to reduce wrapping.
|
||||||
|
- CLI: prevent ANSI color bleed when table cells wrap.
|
||||||
|
- CLI: explain when auth profiles are excluded by auth.order in probe details.
|
||||||
- Linux: include env-configured user bin roots in systemd PATH and align PATH audits. (#1512) Thanks @robbyczgw-cla.
|
- Linux: include env-configured user bin roots in systemd PATH and align PATH audits. (#1512) Thanks @robbyczgw-cla.
|
||||||
- TUI: render Gateway slash-command replies as system output (for example, `/context`).
|
- TUI: render Gateway slash-command replies as system output (for example, `/context`).
|
||||||
- Media: preserve PNG alpha when possible; fall back to JPEG when still over size cap. (#1491) Thanks @robbyczgw-cla.
|
- Media: preserve PNG alpha when possible; fall back to JPEG when still over size cap. (#1491) Thanks @robbyczgw-cla.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ensureAuthProfileStore,
|
ensureAuthProfileStore,
|
||||||
listProfilesForProvider,
|
listProfilesForProvider,
|
||||||
resolveAuthProfileDisplayLabel,
|
resolveAuthProfileDisplayLabel,
|
||||||
|
resolveAuthProfileOrder,
|
||||||
} from "../../agents/auth-profiles.js";
|
} from "../../agents/auth-profiles.js";
|
||||||
import { runEmbeddedPiAgent } from "../../agents/pi-embedded.js";
|
import { runEmbeddedPiAgent } from "../../agents/pi-embedded.js";
|
||||||
import { describeFailoverError } from "../../agents/failover-error.js";
|
import { describeFailoverError } from "../../agents/failover-error.js";
|
||||||
@@ -143,6 +144,25 @@ function buildProbeTargets(params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const profileIds = listProfilesForProvider(store, providerKey);
|
const profileIds = listProfilesForProvider(store, providerKey);
|
||||||
|
const explicitOrder = (() => {
|
||||||
|
const order = store.order;
|
||||||
|
if (order) {
|
||||||
|
for (const [key, value] of Object.entries(order)) {
|
||||||
|
if (normalizeProviderId(key) === providerKey) return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cfgOrder = cfg?.auth?.order;
|
||||||
|
if (cfgOrder) {
|
||||||
|
for (const [key, value] of Object.entries(cfgOrder)) {
|
||||||
|
if (normalizeProviderId(key) === providerKey) return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
})();
|
||||||
|
const allowedProfiles =
|
||||||
|
explicitOrder && explicitOrder.length > 0
|
||||||
|
? new Set(resolveAuthProfileOrder({ cfg, store, provider: providerKey }))
|
||||||
|
: null;
|
||||||
const filteredProfiles = profileFilter.size
|
const filteredProfiles = profileFilter.size
|
||||||
? profileIds.filter((id) => profileFilter.has(id))
|
? profileIds.filter((id) => profileFilter.has(id))
|
||||||
: profileIds;
|
: profileIds;
|
||||||
@@ -152,6 +172,32 @@ function buildProbeTargets(params: {
|
|||||||
const profile = store.profiles[profileId];
|
const profile = store.profiles[profileId];
|
||||||
const mode = profile?.type;
|
const mode = profile?.type;
|
||||||
const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
|
const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
|
||||||
|
if (explicitOrder && !explicitOrder.includes(profileId)) {
|
||||||
|
results.push({
|
||||||
|
provider: providerKey,
|
||||||
|
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||||
|
profileId,
|
||||||
|
label,
|
||||||
|
source: "profile",
|
||||||
|
mode,
|
||||||
|
status: "unknown",
|
||||||
|
error: "Excluded by auth.order for this provider.",
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (allowedProfiles && !allowedProfiles.has(profileId)) {
|
||||||
|
results.push({
|
||||||
|
provider: providerKey,
|
||||||
|
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||||
|
profileId,
|
||||||
|
label,
|
||||||
|
source: "profile",
|
||||||
|
mode,
|
||||||
|
status: "unknown",
|
||||||
|
error: "Auth profile credentials are missing or expired.",
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!model) {
|
if (!model) {
|
||||||
results.push({
|
results.push({
|
||||||
provider: providerKey,
|
provider: providerKey,
|
||||||
|
|||||||
@@ -85,6 +85,31 @@ describe("renderTable", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("resets ANSI styling on wrapped lines", () => {
|
||||||
|
const reset = "\x1b[0m";
|
||||||
|
const out = renderTable({
|
||||||
|
width: 24,
|
||||||
|
columns: [
|
||||||
|
{ key: "K", header: "K", minWidth: 3 },
|
||||||
|
{ key: "V", header: "V", flex: true, minWidth: 10 },
|
||||||
|
],
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
K: "X",
|
||||||
|
V: `\x1b[31m${"a".repeat(80)}${reset}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = out.split("\n").filter((line) => line.includes("a"));
|
||||||
|
for (const line of lines) {
|
||||||
|
const resetIndex = line.lastIndexOf(reset);
|
||||||
|
const lastSep = line.lastIndexOf("│");
|
||||||
|
expect(resetIndex).toBeGreaterThan(-1);
|
||||||
|
expect(lastSep).toBeGreaterThan(resetIndex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("respects explicit newlines in cell values", () => {
|
it("respects explicit newlines in cell values", () => {
|
||||||
const out = renderTable({
|
const out = renderTable({
|
||||||
width: 48,
|
width: 48,
|
||||||
|
|||||||
@@ -91,6 +91,27 @@ function wrapLine(text: string, width: number): string[] {
|
|||||||
i += ch.length;
|
i += ch.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const firstCharIndex = tokens.findIndex((t) => t.kind === "char");
|
||||||
|
if (firstCharIndex < 0) return [text];
|
||||||
|
let lastCharIndex = -1;
|
||||||
|
for (let i = tokens.length - 1; i >= 0; i -= 1) {
|
||||||
|
if (tokens[i]?.kind === "char") {
|
||||||
|
lastCharIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const prefixAnsi = tokens
|
||||||
|
.slice(0, firstCharIndex)
|
||||||
|
.filter((t) => t.kind === "ansi")
|
||||||
|
.map((t) => t.value)
|
||||||
|
.join("");
|
||||||
|
const suffixAnsi = tokens
|
||||||
|
.slice(lastCharIndex + 1)
|
||||||
|
.filter((t) => t.kind === "ansi")
|
||||||
|
.map((t) => t.value)
|
||||||
|
.join("");
|
||||||
|
const coreTokens = tokens.slice(firstCharIndex, lastCharIndex + 1);
|
||||||
|
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
const isBreakChar = (ch: string) =>
|
const isBreakChar = (ch: string) =>
|
||||||
ch === " " || ch === "\t" || ch === "/" || ch === "-" || ch === "_" || ch === ".";
|
ch === " " || ch === "\t" || ch === "/" || ch === "-" || ch === "_" || ch === ".";
|
||||||
@@ -136,7 +157,7 @@ function wrapLine(text: string, width: number): string[] {
|
|||||||
lastBreakIndex = null;
|
lastBreakIndex = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const token of tokens) {
|
for (const token of coreTokens) {
|
||||||
if (token.kind === "ansi") {
|
if (token.kind === "ansi") {
|
||||||
buf.push(token);
|
buf.push(token);
|
||||||
continue;
|
continue;
|
||||||
@@ -162,7 +183,12 @@ function wrapLine(text: string, width: number): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flushAt(buf.length);
|
flushAt(buf.length);
|
||||||
return lines.length ? lines : [""];
|
if (!lines.length) return [""];
|
||||||
|
if (!prefixAnsi && !suffixAnsi) return lines;
|
||||||
|
return lines.map((line) => {
|
||||||
|
if (!line) return line;
|
||||||
|
return `${prefixAnsi}${line}${suffixAnsi}`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeWidth(n: number | undefined): number | undefined {
|
function normalizeWidth(n: number | undefined): number | undefined {
|
||||||
|
|||||||
Reference in New Issue
Block a user