Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .tps-agent.pid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
58542
2 changes: 1 addition & 1 deletion packages/cli/bin/tps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ async function main() {
action: "logs",
id: getFlag("id") ?? rest[1],
lines: cli.flags.lines as number | undefined,
follow: cli.flags.follow as boolean | undefined,
follow: (cli.flags.follow as boolean | undefined) || process.argv.includes("-f"),
});
} else if (action === "commit") {
// Inline helpers (getAuthor/getRepeatedFlags defined in else block below)
Expand Down
36 changes: 30 additions & 6 deletions packages/cli/src/commands/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,22 @@ function tailLines(content: string, count: number): string[] {

async function streamLogUpdates(logPath: string, offset: number): Promise<never> {
let position = offset;
let reading = false;
let pending = false;

const readFromPosition = (): void => {
if (reading) {
pending = true;
return;
}

const size = statSync(logPath).size;
if (size < position) {
position = 0;
}
if (size === position) return;

reading = true;
const stream = createReadStream(logPath, {
encoding: "utf-8",
start: position,
Expand All @@ -130,17 +138,33 @@ async function streamLogUpdates(logPath: string, offset: number): Promise<never>

stream.on("end", () => {
position = size;
reading = false;
if (pending) {
pending = false;
readFromPosition();
}
});
};

readFromPosition();
stream.on("error", () => {
reading = false;
});
};

await new Promise<never>((_resolve) => {
watch(logPath, { persistent: true }, (eventType) => {
await new Promise<never>(() => {
const watcher = watch(logPath, { persistent: true }, (eventType) => {
if (eventType === "change" || eventType === "rename") {
readFromPosition();
}
});

const handleSigint = (): void => {
watcher.close();
process.removeListener("SIGINT", handleSigint);
process.stdout.write("\n");
process.exit(0);
};

process.on("SIGINT", handleSigint);
});

process.exit(0);
Expand All @@ -149,12 +173,12 @@ async function streamLogUpdates(logPath: string, offset: number): Promise<never>
async function logAgentRuntime(args: AgentArgs): Promise<void> {
const agentId = args.id;
if (!agentId) {
console.error("Usage: tps agent logs --id <agent-id> [--lines <N>] [--follow]");
console.error("Usage: tps agent logs --id <agent-id> [--lines <N>] [--follow|-f]");
process.exit(1);
}

const lineCount = normalizeLogLineCount(args.lines);
const logPath = join(healthcheckHomeDir(), ".tps", "logs", `${agentId}.log`);
const logPath = join(healthcheckHomeDir(), ".tps", "agents", agentId, "session.log");
if (!existsSync(logPath)) {
console.error(`No log file found for ${agentId}`);
process.exit(1);
Expand Down
18 changes: 10 additions & 8 deletions packages/cli/test/agent-runtime-logs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ describe("tps agent logs runtime tail", () => {
let originalError: typeof console.error;
let originalExit: typeof process.exit;

function writeSessionLog(agentId: string, content: string): void {
const logDir = join(tempHome, ".tps", "agents", agentId);
mkdirSync(logDir, { recursive: true });
writeFileSync(join(logDir, "session.log"), content, "utf-8");
}

beforeEach(() => {
tempHome = mkdtempSync(join(tmpdir(), "tps-agent-runtime-logs-"));
originalHome = process.env.HOME;
Expand All @@ -35,11 +41,9 @@ describe("tps agent logs runtime tail", () => {
test("shows the last 50 lines by default", async () => {
const { runAgent } = await import("../src/commands/agent.js");
const output: string[] = [];
mkdirSync(join(tempHome, ".tps", "logs"), { recursive: true });
writeFileSync(
join(tempHome, ".tps", "logs", "ember.log"),
writeSessionLog(
"ember",
Array.from({ length: 60 }, (_, index) => `line-${index + 1}`).join("\n") + "\n",
"utf-8",
);
process.stdout.write = ((chunk: string | Uint8Array) => {
output.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8"));
Expand All @@ -56,11 +60,9 @@ describe("tps agent logs runtime tail", () => {
test("respects a custom line count", async () => {
const { runAgent } = await import("../src/commands/agent.js");
const output: string[] = [];
mkdirSync(join(tempHome, ".tps", "logs"), { recursive: true });
writeFileSync(
join(tempHome, ".tps", "logs", "ember.log"),
writeSessionLog(
"ember",
["alpha", "beta", "gamma", "delta"].join("\n"),
"utf-8",
);
process.stdout.write = ((chunk: string | Uint8Array) => {
output.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8"));
Expand Down
Loading