Add app diagnostic report (#1728)

* feat(diagnostics): add app diagnostic report

* fix(diagnostics): guard app diagnostic runs

* fix(diagnostics): include websocket runtime metrics

* fix(diagnostics): type websocket metric snapshot

* fix(diagnostics): include daemon shell env

* fix(loop): make stop cancellation test deterministic
This commit is contained in:
Mohamed Boudra
2026-06-25 23:20:52 +08:00
committed by GitHub
parent bdd9419189
commit 26f169866f
23 changed files with 1812 additions and 36 deletions
+30
View File
@@ -220,6 +220,36 @@ describe("provider usage list message contract", () => {
});
});
describe("diagnostics message contract", () => {
test("accepts the diagnostics request as a simple namespaced RPC", () => {
const parsed = SessionInboundMessageSchema.parse({
type: "diagnostics.request",
requestId: "diag-1",
});
expect(parsed).toEqual({
type: "diagnostics.request",
requestId: "diag-1",
});
});
test("accepts a copyable diagnostics response", () => {
const parsed = SessionOutboundMessageSchema.parse({
type: "diagnostics.response",
payload: {
requestId: "diag-2",
diagnostic: "Paseo diagnostics\n Status: ok",
},
});
expect(parsed.type).toBe("diagnostics.response");
if (parsed.type !== "diagnostics.response") {
throw new Error("Expected diagnostics.response");
}
expect(parsed.payload.diagnostic).toContain("Status: ok");
});
});
describe("agent detach RPC", () => {
test("parses the namespaced detach request", () => {
const parsed = SessionInboundMessageSchema.parse({
+20
View File
@@ -1060,6 +1060,11 @@ export const DaemonGetPairingOfferRequestSchema = z.object({
requestId: z.string(),
});
export const DiagnosticsRequestSchema = z.object({
type: z.literal("diagnostics.request"),
requestId: z.string(),
});
export const GetDaemonConfigRequestMessageSchema = z.object({
type: z.literal("get_daemon_config_request"),
requestId: z.string(),
@@ -2024,6 +2029,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
WaitForFinishRequestSchema,
DaemonGetStatusRequestSchema,
DaemonGetPairingOfferRequestSchema,
DiagnosticsRequestSchema,
GetDaemonConfigRequestMessageSchema,
SetDaemonConfigRequestMessageSchema,
ReadProjectConfigRequestMessageSchema,
@@ -2319,6 +2325,8 @@ export const ServerInfoStatusPayloadSchema = z
providerUsageList: z.boolean().optional(),
// COMPAT(agentDetach): added in v0.1.98, remove gate after 2026-12-19 once daemon floor >= v0.1.98.
agentDetach: z.boolean().optional(),
// COMPAT(daemonDiagnostics): added in v0.1.100, remove gate after 2026-12-25 once daemon floor >= v0.1.100.
daemonDiagnostics: z.boolean().optional(),
})
.optional(),
})
@@ -3033,6 +3041,16 @@ export const DaemonGetPairingOfferResponseSchema = z.object({
.passthrough(),
});
export const DiagnosticsResponseSchema = z.object({
type: z.literal("diagnostics.response"),
payload: z
.object({
requestId: z.string(),
diagnostic: z.string(),
})
.passthrough(),
});
export const SetDaemonConfigResponseMessageSchema = z.object({
type: z.literal("set_daemon_config_response"),
payload: z
@@ -4117,6 +4135,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
SetVoiceModeResponseMessageSchema,
DaemonGetStatusResponseSchema,
DaemonGetPairingOfferResponseSchema,
DiagnosticsResponseSchema,
GetDaemonConfigResponseMessageSchema,
SetDaemonConfigResponseMessageSchema,
ReadProjectConfigResponseMessageSchema,
@@ -4304,6 +4323,7 @@ export type ListProviderFeaturesResponseMessage = z.infer<
export type ListAvailableProvidersResponse = z.infer<typeof ListAvailableProvidersResponseSchema>;
export type DaemonGetStatusResponse = z.infer<typeof DaemonGetStatusResponseSchema>;
export type DaemonGetPairingOfferResponse = z.infer<typeof DaemonGetPairingOfferResponseSchema>;
export type DiagnosticsResponse = z.infer<typeof DiagnosticsResponseSchema>;
export type GetProvidersSnapshotResponseMessage = z.infer<
typeof GetProvidersSnapshotResponseMessageSchema
>;