Merge remote-tracking branch 'public-gh/master' into paperclip-company-import-export

* public-gh/master:
  fix: address greptile follow-up feedback
  docs: clarify quickstart npx usage
  Add guarded dev restart handling
  Fix PAP-576 settings toggles and transcript default
  Add username log censor setting
  fix: use standard toggle component for permission controls

# Conflicts:
#	server/src/routes/agents.ts
#	ui/src/pages/AgentDetail.tsx
This commit is contained in:
dotta 2026-03-20 13:28:05 -05:00
commit 5140d7b0c4
44 changed files with 11673 additions and 208 deletions

View file

@ -721,6 +721,9 @@ function resolveNextSessionState(input: {
export function heartbeatService(db: Db) {
const instanceSettings = instanceSettingsService(db);
const getCurrentUserRedactionOptions = async () => ({
enabled: (await instanceSettings.getGeneral()).censorUsernameInLogs,
});
const runLogStore = getRunLogStore();
const secretsSvc = secretService(db);
@ -1320,8 +1323,13 @@ export function heartbeatService(db: Db) {
payload?: Record<string, unknown>;
},
) {
const sanitizedMessage = event.message ? redactCurrentUserText(event.message) : event.message;
const sanitizedPayload = event.payload ? redactCurrentUserValue(event.payload) : event.payload;
const currentUserRedactionOptions = await getCurrentUserRedactionOptions();
const sanitizedMessage = event.message
? redactCurrentUserText(event.message, currentUserRedactionOptions)
: event.message;
const sanitizedPayload = event.payload
? redactCurrentUserValue(event.payload, currentUserRedactionOptions)
: event.payload;
await db.insert(heartbeatRunEvents).values({
companyId: run.companyId,
@ -2259,8 +2267,9 @@ export function heartbeatService(db: Db) {
})
.where(eq(heartbeatRuns.id, runId));
const currentUserRedactionOptions = await getCurrentUserRedactionOptions();
const onLog = async (stream: "stdout" | "stderr", chunk: string) => {
const sanitizedChunk = redactCurrentUserText(chunk);
const sanitizedChunk = redactCurrentUserText(chunk, currentUserRedactionOptions);
if (stream === "stdout") stdoutExcerpt = appendExcerpt(stdoutExcerpt, sanitizedChunk);
if (stream === "stderr") stderrExcerpt = appendExcerpt(stderrExcerpt, sanitizedChunk);
const ts = new Date().toISOString();
@ -2510,6 +2519,7 @@ export function heartbeatService(db: Db) {
? null
: redactCurrentUserText(
adapterResult.errorMessage ?? (outcome === "timed_out" ? "Timed out" : "Adapter failed"),
currentUserRedactionOptions,
),
errorCode:
outcome === "timed_out"
@ -2577,7 +2587,10 @@ export function heartbeatService(db: Db) {
}
await finalizeAgentStatus(agent.id, outcome);
} catch (err) {
const message = redactCurrentUserText(err instanceof Error ? err.message : "Unknown adapter failure");
const message = redactCurrentUserText(
err instanceof Error ? err.message : "Unknown adapter failure",
await getCurrentUserRedactionOptions(),
);
logger.error({ err, runId }, "heartbeat execution failed");
let logSummary: { bytes: number; sha256?: string; compressed: boolean } | null = null;
@ -3615,7 +3628,7 @@ export function heartbeatService(db: Db) {
store: run.logStore,
logRef: run.logRef,
...result,
content: redactCurrentUserText(result.content),
content: redactCurrentUserText(result.content, await getCurrentUserRedactionOptions()),
};
},