| author | |
| committer | |
| log | 7c901a37c4e8f35c408a27dbd1bd2efea06a74f5 |
| tree | 0066e6bdf1d8a10f7a70358796a1fb499d2963e8 |
| parent | 20885cecf77e205b8931ca1b29f0a2832836a157 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>8 files changed, 23 insertions(+), 14 deletions(-)
.github/triage/PLAYBOOK.md+3-2| ... | @@ -59,8 +59,9 @@ different code depending on it: | ... | @@ -59,8 +59,9 @@ different code depending on it: |
| 59 | 59 | ||
| 60 | Then work from evidence, not assumption. In rough order of value: | 60 | Then work from evidence, not assumption. In rough order of value: |
| 61 | 61 | ||
| 62 | - The server log and the trace file (`server.trace.ndjson`) around the time of the | 62 | - The trace file (`server.trace.ndjson`) around the time of the problem, plus the |
| 63 | problem. Recent failures usually leave a trail here. | 63 | service log or desktop backend logs from the context file if they exist. Recent |
| 64 | failures usually leave a trail here. | ||
| 64 | - The provider event log, for problems with claude/codex/cursor sessions. | 65 | - The provider event log, for problems with claude/codex/cursor sessions. |
| 65 | - The SQLite database. Read it freely, but only write when a write is necessary | 66 | - The SQLite database. Read it freely, but only write when a write is necessary |
| 66 | to fix the problem the user described, and get their explicit permission | 67 | to fix the problem the user described, and get their explicit permission |
apps/server/src/cli/config.test.ts-1| ... | @@ -508,7 +508,6 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { | ... | @@ -508,7 +508,6 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 508 | resolved.terminalLogsDir, | 508 | resolved.terminalLogsDir, |
| 509 | resolved.attachmentsDir, | 509 | resolved.attachmentsDir, |
| 510 | resolved.worktreesDir, | 510 | resolved.worktreesDir, |
| 511 | path.dirname(resolved.serverLogPath), | ||
| 512 | path.dirname(resolved.serverTracePath), | 511 | path.dirname(resolved.serverTracePath), |
| 513 | ]) { | 512 | ]) { |
| 514 | expect(yield* fs.exists(directory)).toBe(true); | 513 | expect(yield* fs.exists(directory)).toBe(true); |
apps/server/src/cli/triage.ts+6-1| ... | @@ -27,6 +27,7 @@ import * as Schema from "effect/Schema"; | ... | @@ -27,6 +27,7 @@ import * as Schema from "effect/Schema"; |
| 27 | import { Command, Flag } from "effect/unstable/cli"; | 27 | import { Command, Flag } from "effect/unstable/cli"; |
| 28 | 28 | ||
| 29 | import packageJson from "../../package.json" with { type: "json" }; | 29 | import packageJson from "../../package.json" with { type: "json" }; |
| 30 | import * as BootService from "../cloud/bootService.ts"; | ||
| 30 | import * as ServerConfig from "../config.ts"; | 31 | import * as ServerConfig from "../config.ts"; |
| 31 | import { resolveBaseDir } from "../os-jank.ts"; | 32 | import { resolveBaseDir } from "../os-jank.ts"; |
| 32 | import { isProcessAlive, readPersistedServerRuntimeState } from "../serverRuntimeState.ts"; | 33 | import { isProcessAlive, readPersistedServerRuntimeState } from "../serverRuntimeState.ts"; |
| ... | @@ -201,7 +202,11 @@ export const triageCommand = Command.make("triage", { | ... | @@ -201,7 +202,11 @@ export const triageCommand = Command.make("triage", { |
| 201 | dbPath: paths.dbPath, | 202 | dbPath: paths.dbPath, |
| 202 | settingsPath: paths.settingsPath, | 203 | settingsPath: paths.settingsPath, |
| 203 | logsDir: paths.logsDir, | 204 | logsDir: paths.logsDir, |
| 204 | serverLogPath: paths.serverLogPath, | 205 | // The server writes no log file of its own. Service installs and the |
| 206 | // desktop app capture its output. The glob covers every desktop backend | ||
| 207 | // (such as WSL) and rotated copies; names come from DesktopObservability.ts. | ||
| 208 | serviceLogPath: path.join(paths.logsDir, BootService.BOOT_SERVICE_LOG_FILE), | ||
| 209 | desktopBackendLogGlob: path.join(paths.logsDir, "server-child*.log*"), | ||
| 205 | serverTracePath: paths.serverTracePath, | 210 | serverTracePath: paths.serverTracePath, |
| 206 | providerEventLogPath: paths.providerEventLogPath, | 211 | providerEventLogPath: paths.providerEventLogPath, |
| 207 | terminalLogsDir: paths.terminalLogsDir, | 212 | terminalLogsDir: paths.terminalLogsDir, |
apps/server/src/cli/triagePrompt.test.ts+4-1| ... | @@ -52,7 +52,8 @@ it("context file carries every path the playbook depends on", () => { | ... | @@ -52,7 +52,8 @@ it("context file carries every path the playbook depends on", () => { |
| 52 | dbPath: "/home/u/.t3/userdata/state.sqlite", | 52 | dbPath: "/home/u/.t3/userdata/state.sqlite", |
| 53 | settingsPath: "/home/u/.t3/userdata/settings.json", | 53 | settingsPath: "/home/u/.t3/userdata/settings.json", |
| 54 | logsDir: "/home/u/.t3/userdata/logs", | 54 | logsDir: "/home/u/.t3/userdata/logs", |
| 55 | serverLogPath: "/home/u/.t3/userdata/logs/server.log", | 55 | serviceLogPath: "/home/u/.t3/userdata/logs/boot-service.log", |
| 56 | desktopBackendLogGlob: "/home/u/.t3/userdata/logs/server-child*.log*", | ||
| 56 | serverTracePath: "/home/u/.t3/userdata/logs/server.trace.ndjson", | 57 | serverTracePath: "/home/u/.t3/userdata/logs/server.trace.ndjson", |
| 57 | providerEventLogPath: "/home/u/.t3/userdata/logs/provider/events.log", | 58 | providerEventLogPath: "/home/u/.t3/userdata/logs/provider/events.log", |
| 58 | terminalLogsDir: "/home/u/.t3/userdata/logs/terminals", | 59 | terminalLogsDir: "/home/u/.t3/userdata/logs/terminals", |
| ... | @@ -63,6 +64,8 @@ it("context file carries every path the playbook depends on", () => { | ... | @@ -63,6 +64,8 @@ it("context file carries every path the playbook depends on", () => { |
| 63 | }); | 64 | }); |
| 64 | assert.include(context, "/home/u/.t3/userdata/state.sqlite"); | 65 | assert.include(context, "/home/u/.t3/userdata/state.sqlite"); |
| 65 | assert.include(context, "/home/u/.t3/userdata/logs/server.trace.ndjson"); | 66 | assert.include(context, "/home/u/.t3/userdata/logs/server.trace.ndjson"); |
| 67 | assert.include(context, "/home/u/.t3/userdata/logs/boot-service.log"); | ||
| 68 | assert.include(context, "/home/u/.t3/userdata/logs/server-child*.log*"); | ||
| 66 | assert.include(context, "/home/u/.t3/userdata/logs/provider/events.log"); | 69 | assert.include(context, "/home/u/.t3/userdata/logs/provider/events.log"); |
| 67 | assert.include(context, "/home/u/.t3/userdata/secrets"); | 70 | assert.include(context, "/home/u/.t3/userdata/secrets"); |
| 68 | assert.include(context, "/home/u/.t3/source"); | 71 | assert.include(context, "/home/u/.t3/source"); |
apps/server/src/cli/triagePrompt.ts+7-4| ... | @@ -71,8 +71,9 @@ different code depending on it: | ... | @@ -71,8 +71,9 @@ different code depending on it: |
| 71 | 71 | ||
| 72 | Then work from evidence, not assumption. In rough order of value: | 72 | Then work from evidence, not assumption. In rough order of value: |
| 73 | 73 | ||
| 74 | - The server log and the trace file (\`server.trace.ndjson\`) around the time of the | 74 | - The trace file (\`server.trace.ndjson\`) around the time of the problem, plus the |
| 75 | problem. Recent failures usually leave a trail here. | 75 | service log or desktop backend logs from the context file if they exist. Recent |
| 76 | failures usually leave a trail here. | ||
| 76 | - The provider event log, for problems with claude/codex/cursor sessions. | 77 | - The provider event log, for problems with claude/codex/cursor sessions. |
| 77 | - The SQLite database. Read it freely, but only write when a write is necessary | 78 | - The SQLite database. Read it freely, but only write when a write is necessary |
| 78 | to fix the problem the user described, and get their explicit permission | 79 | to fix the problem the user described, and get their explicit permission |
| ... | @@ -176,7 +177,8 @@ export interface TriageContextInput { | ... | @@ -176,7 +177,8 @@ export interface TriageContextInput { |
| 176 | readonly dbPath: string; | 177 | readonly dbPath: string; |
| 177 | readonly settingsPath: string; | 178 | readonly settingsPath: string; |
| 178 | readonly logsDir: string; | 179 | readonly logsDir: string; |
| 179 | readonly serverLogPath: string; | 180 | readonly serviceLogPath: string; |
| 181 | readonly desktopBackendLogGlob: string; | ||
| 180 | readonly serverTracePath: string; | 182 | readonly serverTracePath: string; |
| 181 | readonly providerEventLogPath: string; | 183 | readonly providerEventLogPath: string; |
| 182 | readonly terminalLogsDir: string; | 184 | readonly terminalLogsDir: string; |
| ... | @@ -205,7 +207,8 @@ Generated by \`t3 triage\` at ${input.generatedAt}. | ... | @@ -205,7 +207,8 @@ Generated by \`t3 triage\` at ${input.generatedAt}. |
| 205 | - Database (SQLite; write only with the user's explicit permission): ${input.paths.dbPath} | 207 | - Database (SQLite; write only with the user's explicit permission): ${input.paths.dbPath} |
| 206 | - Settings: ${input.paths.settingsPath} | 208 | - Settings: ${input.paths.settingsPath} |
| 207 | - Logs dir: ${input.paths.logsDir} | 209 | - Logs dir: ${input.paths.logsDir} |
| 208 | - Server log: ${input.paths.serverLogPath} | 210 | - Service log (systemd/launchd service installs only): ${input.paths.serviceLogPath} |
| 211 | - Desktop backend logs (glob; one file per backend plus rotated copies; written only when a backend crashes or fails to start): ${input.paths.desktopBackendLogGlob} | ||
| 209 | - Server trace (ndjson): ${input.paths.serverTracePath} | 212 | - Server trace (ndjson): ${input.paths.serverTracePath} |
| 210 | - Provider event log: ${input.paths.providerEventLogPath} | 213 | - Provider event log: ${input.paths.providerEventLogPath} |
| 211 | - Terminal logs: ${input.paths.terminalLogsDir} | 214 | - Terminal logs: ${input.paths.terminalLogsDir} |
apps/server/src/cloud/bootService.ts+3-1| ... | @@ -43,6 +43,8 @@ const BOOT_SERVICE_UNIT_FILE = `${BOOT_SERVICE_NAME}.service`; | ... | @@ -43,6 +43,8 @@ const BOOT_SERVICE_UNIT_FILE = `${BOOT_SERVICE_NAME}.service`; |
| 43 | const BOOT_SERVICE_LAUNCHD_LABEL = "com.t3tools.t3code.service"; | 43 | const BOOT_SERVICE_LAUNCHD_LABEL = "com.t3tools.t3code.service"; |
| 44 | const BOOT_SERVICE_PLIST_FILE = `${BOOT_SERVICE_LAUNCHD_LABEL}.plist`; | 44 | const BOOT_SERVICE_PLIST_FILE = `${BOOT_SERVICE_LAUNCHD_LABEL}.plist`; |
| 45 | const BOOT_SERVICE_UNIT_ENV = "T3_BOOT_SERVICE_UNIT"; | 45 | const BOOT_SERVICE_UNIT_ENV = "T3_BOOT_SERVICE_UNIT"; |
| 46 | /** File in the logs dir that receives the service's stdout and stderr. `t3 triage` points agents at it. */ | ||
| 47 | export const BOOT_SERVICE_LOG_FILE = "boot-service.log"; | ||
| 46 | 48 | ||
| 47 | /** systemd expands `%` specifiers, including in unquoted append-log paths. */ | 49 | /** systemd expands `%` specifiers, including in unquoted append-log paths. */ |
| 48 | function escapeSystemdSpecifiers(value: string): string { | 50 | function escapeSystemdSpecifiers(value: string): string { |
| ... | @@ -599,7 +601,7 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: { | ... | @@ -599,7 +601,7 @@ export const make = Effect.fn("cloud.boot_service.make")(function* (input: { |
| 599 | environmentPath, | 601 | environmentPath, |
| 600 | }); | 602 | }); |
| 601 | const unitPath = detectedManager?.unitPath ?? ""; | 603 | const unitPath = detectedManager?.unitPath ?? ""; |
| 602 | const logPath = path.join(input.logsDir, "boot-service.log"); | 604 | const logPath = path.join(input.logsDir, BOOT_SERVICE_LOG_FILE); |
| 603 | const statePath = path.join(input.baseDir, "runtime", SERVICE_STATE_FILE); | 605 | const statePath = path.join(input.baseDir, "runtime", SERVICE_STATE_FILE); |
| 604 | const restartPendingPath = path.join(input.baseDir, "runtime", SERVICE_RESTART_PENDING_FILE); | 606 | const restartPendingPath = path.join(input.baseDir, "runtime", SERVICE_RESTART_PENDING_FILE); |
| 605 | const runtimePaths = pinnedRuntimePaths(path, input.baseDir, input.cliVersion, platform); | 607 | const runtimePaths = pinnedRuntimePaths(path, input.baseDir, input.cliVersion, platform); |
apps/server/src/config.ts-2| ... | @@ -44,7 +44,6 @@ export interface ServerDerivedPaths { | ... | @@ -44,7 +44,6 @@ export interface ServerDerivedPaths { |
| 44 | /** Screenshots the agent asks the collaborative browser to keep for the user. */ | 44 | /** Screenshots the agent asks the collaborative browser to keep for the user. */ |
| 45 | readonly browserArtifactsDir: string; | 45 | readonly browserArtifactsDir: string; |
| 46 | readonly logsDir: string; | 46 | readonly logsDir: string; |
| 47 | readonly serverLogPath: string; | ||
| 48 | readonly serverTracePath: string; | 47 | readonly serverTracePath: string; |
| 49 | readonly providerLogsDir: string; | 48 | readonly providerLogsDir: string; |
| 50 | readonly providerEventLogPath: string; | 49 | readonly providerEventLogPath: string; |
| ... | @@ -154,7 +153,6 @@ export const deriveServerPaths = Effect.fn(function* ( | ... | @@ -154,7 +153,6 @@ export const deriveServerPaths = Effect.fn(function* ( |
| 154 | attachmentsDir, | 153 | attachmentsDir, |
| 155 | browserArtifactsDir: join(stateDir, "browser-artifacts"), | 154 | browserArtifactsDir: join(stateDir, "browser-artifacts"), |
| 156 | logsDir, | 155 | logsDir, |
| 157 | serverLogPath: join(logsDir, "server.log"), | ||
| 158 | serverTracePath: join(logsDir, "server.trace.ndjson"), | 156 | serverTracePath: join(logsDir, "server.trace.ndjson"), |
| 159 | providerLogsDir, | 157 | providerLogsDir, |
| 160 | providerEventLogPath: join(providerLogsDir, "events.log"), | 158 | providerEventLogPath: join(providerLogsDir, "events.log"), |
docs/operations/observability.md-2| ... | @@ -603,5 +603,3 @@ Current high-value span and metric boundaries include: | ... | @@ -603,5 +603,3 @@ Current high-value span and metric boundaries include: |
| 603 | - logs outside spans are not persisted in the trace file; SSH-managed launch stdout/stderr is still | 603 | - logs outside spans are not persisted in the trace file; SSH-managed launch stdout/stderr is still |
| 604 | captured in its launcher log | 604 | captured in its launcher log |
| 605 | - metrics are not snapshotted locally | 605 | - metrics are not snapshotted locally |
| 606 | - the old `serverLogPath` still exists in config for compatibility, but the trace file is the primary | ||
| 607 | structured persisted artifact |