agent-tail-core 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cli.mjs +1 -1
- package/dist/{commands-CzU-rrPM.mjs → commands-BGQ-_7t4.mjs} +37 -12
- package/dist/index.d.mts +8 -1
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
CLI and shared core for [agent-tail](https://agent-tail.vercel.app/) — pipes server output and browser console logs to log files your AI coding agents can read and `grep`.
|
|
4
4
|
|
|
5
|
+
> **Tip:** Install the umbrella [`agent-tail`](https://www.npmjs.com/package/agent-tail) package to get the CLI, Vite plugin, and Next.js plugin in one install: `npm install -D agent-tail`
|
|
6
|
+
|
|
5
7
|
## Quick start
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
npx agent-tail
|
|
10
|
+
npx agent-tail run 'fe: npm run dev' 'api: uvicorn main:app'
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
Each service gets its own log file (`fe.log`, `api.log`) plus a `combined.log` with all output interleaved. A `latest` symlink always points to the current session:
|
package/dist/cli.mjs
CHANGED
|
@@ -17,6 +17,7 @@ function should_exclude(message, excludes) {
|
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/log-manager.ts
|
|
19
19
|
const PLUGIN_PREFIX = "\x1B[36m[agent-tail]\x1B[0m";
|
|
20
|
+
const SESSION_ENV_VAR = "AGENT_TAIL_SESSION";
|
|
20
21
|
let session_counter = 0;
|
|
21
22
|
var LogManager = class {
|
|
22
23
|
constructor(options) {
|
|
@@ -49,7 +50,11 @@ var LogManager = class {
|
|
|
49
50
|
fs.unlinkSync(latest_link);
|
|
50
51
|
} catch {}
|
|
51
52
|
const relative_target = path.relative(log_dir, session_dir);
|
|
52
|
-
|
|
53
|
+
try {
|
|
54
|
+
fs.symlinkSync(relative_target, latest_link);
|
|
55
|
+
} catch {
|
|
56
|
+
fs.writeFileSync(latest_link, session_dir);
|
|
57
|
+
}
|
|
53
58
|
}
|
|
54
59
|
prune_sessions(log_dir) {
|
|
55
60
|
try {
|
|
@@ -66,6 +71,17 @@ var LogManager = class {
|
|
|
66
71
|
} catch {}
|
|
67
72
|
}
|
|
68
73
|
/**
|
|
74
|
+
* Join an existing session directory. Creates the log file if it doesn't
|
|
75
|
+
* exist. Use this when a parent process (e.g. `agent-tail run`) has
|
|
76
|
+
* already created the session and passed its path via AGENT_TAIL_SESSION.
|
|
77
|
+
*/
|
|
78
|
+
join_session(session_dir) {
|
|
79
|
+
const log_file = path.join(session_dir, this.options.logFileName);
|
|
80
|
+
if (!fs.existsSync(log_file)) fs.writeFileSync(log_file, "");
|
|
81
|
+
console.log(`${PLUGIN_PREFIX} Writing to ${log_file}`);
|
|
82
|
+
return log_file;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
69
85
|
* Resolve the current session directory. If a `latest` symlink exists and
|
|
70
86
|
* points to a valid directory, return it. Otherwise create a new session.
|
|
71
87
|
*/
|
|
@@ -73,8 +89,12 @@ var LogManager = class {
|
|
|
73
89
|
const log_dir = path.resolve(project_root, this.options.logDir);
|
|
74
90
|
const latest_link = path.join(log_dir, "latest");
|
|
75
91
|
try {
|
|
76
|
-
const
|
|
77
|
-
|
|
92
|
+
const stat = fs.lstatSync(latest_link);
|
|
93
|
+
let target;
|
|
94
|
+
if (stat.isSymbolicLink()) target = fs.realpathSync(latest_link);
|
|
95
|
+
else if (stat.isFile()) target = fs.readFileSync(latest_link, "utf-8").trim();
|
|
96
|
+
else throw new Error("unexpected latest type");
|
|
97
|
+
if (fs.existsSync(target) && fs.statSync(target).isDirectory()) return target;
|
|
78
98
|
} catch {}
|
|
79
99
|
const log_path = this.initialize(project_root);
|
|
80
100
|
return path.dirname(log_path);
|
|
@@ -82,8 +102,8 @@ var LogManager = class {
|
|
|
82
102
|
check_gitignore(project_root) {
|
|
83
103
|
const gitignore_path = path.join(project_root, ".gitignore");
|
|
84
104
|
try {
|
|
85
|
-
const lines = fs.readFileSync(gitignore_path, "utf-8").split(
|
|
86
|
-
const log_dir = this.options.logDir;
|
|
105
|
+
const lines = fs.readFileSync(gitignore_path, "utf-8").split(/\r?\n/).map((l) => l.trim());
|
|
106
|
+
const log_dir = this.options.logDir.replace(/\\/g, "/");
|
|
87
107
|
const parts = log_dir.split("/");
|
|
88
108
|
let covered = false;
|
|
89
109
|
for (let i = 1; i <= parts.length; i++) {
|
|
@@ -171,7 +191,7 @@ function parse_service_configs(args) {
|
|
|
171
191
|
* Write data to a log stream and optionally to combined.log with a prefix.
|
|
172
192
|
*/
|
|
173
193
|
function write_to_logs(chunk, name, log_stream, combined_stream, excludes = []) {
|
|
174
|
-
const lines = chunk.toString().split(
|
|
194
|
+
const lines = chunk.toString().split(/\r?\n/);
|
|
175
195
|
for (let i = 0; i < lines.length; i++) if (lines[i].length > 0) {
|
|
176
196
|
if (excludes.length && should_exclude(lines[i], excludes)) continue;
|
|
177
197
|
log_stream.write(lines[i] + "\n");
|
|
@@ -197,13 +217,14 @@ function cmd_wrap(project_root, name, command, options = DEFAULT_CLI_OPTIONS) {
|
|
|
197
217
|
combined_stream = fs.createWriteStream(combined_file, { flags: "a" });
|
|
198
218
|
}
|
|
199
219
|
console.log(`${PREFIX} ${name} → ${log_file}`);
|
|
200
|
-
const child = spawn(
|
|
220
|
+
const child = spawn(command.join(" "), {
|
|
201
221
|
stdio: [
|
|
202
222
|
"inherit",
|
|
203
223
|
"pipe",
|
|
204
224
|
"pipe"
|
|
205
225
|
],
|
|
206
|
-
env: { ...process.env }
|
|
226
|
+
env: { ...process.env },
|
|
227
|
+
shell: true
|
|
207
228
|
});
|
|
208
229
|
child.stdout?.on("data", (chunk) => {
|
|
209
230
|
process.stdout.write(chunk);
|
|
@@ -261,16 +282,20 @@ function cmd_run(project_root, service_args, options = DEFAULT_CLI_OPTIONS) {
|
|
|
261
282
|
const tag = `${COLORS[i % COLORS.length]}[${svc.name}]${RESET}`;
|
|
262
283
|
const log_file = path.join(session_dir, `${svc.name}.log`);
|
|
263
284
|
const log_stream = fs.createWriteStream(log_file, { flags: "a" });
|
|
264
|
-
const child = spawn(
|
|
285
|
+
const child = spawn(svc.command, {
|
|
265
286
|
stdio: [
|
|
266
287
|
"inherit",
|
|
267
288
|
"pipe",
|
|
268
289
|
"pipe"
|
|
269
290
|
],
|
|
270
|
-
env: {
|
|
291
|
+
env: {
|
|
292
|
+
...process.env,
|
|
293
|
+
[SESSION_ENV_VAR]: session_dir
|
|
294
|
+
},
|
|
295
|
+
shell: true
|
|
271
296
|
});
|
|
272
297
|
function handle(target, chunk) {
|
|
273
|
-
const lines = chunk.toString().split(
|
|
298
|
+
const lines = chunk.toString().split(/\r?\n/);
|
|
274
299
|
for (let j = 0; j < lines.length; j++) if (lines[j].length > 0) {
|
|
275
300
|
if (options.excludes.length && should_exclude(lines[j], options.excludes)) continue;
|
|
276
301
|
log_stream.write(lines[j] + "\n");
|
|
@@ -307,4 +332,4 @@ function cmd_run(project_root, service_args, options = DEFAULT_CLI_OPTIONS) {
|
|
|
307
332
|
}
|
|
308
333
|
|
|
309
334
|
//#endregion
|
|
310
|
-
export { resolve_session_dir as a, LogManager as c, parse_service_configs as i,
|
|
335
|
+
export { resolve_session_dir as a, LogManager as c, parse_service_configs as i, SESSION_ENV_VAR as l, cmd_run as n, DEFAULT_OPTIONS as o, cmd_wrap as r, resolve_options as s, cmd_init as t, should_exclude as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -46,6 +46,7 @@ declare function should_exclude(message: string, excludes: string[]): boolean;
|
|
|
46
46
|
declare function generate_client_script(options: ResolvedOptions): string;
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region src/log-manager.d.ts
|
|
49
|
+
declare const SESSION_ENV_VAR = "AGENT_TAIL_SESSION";
|
|
49
50
|
declare class LogManager {
|
|
50
51
|
private options;
|
|
51
52
|
constructor(options: ResolvedOptions);
|
|
@@ -53,6 +54,12 @@ declare class LogManager {
|
|
|
53
54
|
create_session_name(): string;
|
|
54
55
|
update_latest_symlink(log_dir: string, session_dir: string): void;
|
|
55
56
|
prune_sessions(log_dir: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Join an existing session directory. Creates the log file if it doesn't
|
|
59
|
+
* exist. Use this when a parent process (e.g. `agent-tail run`) has
|
|
60
|
+
* already created the session and passed its path via AGENT_TAIL_SESSION.
|
|
61
|
+
*/
|
|
62
|
+
join_session(session_dir: string): string;
|
|
56
63
|
/**
|
|
57
64
|
* Resolve the current session directory. If a `latest` symlink exists and
|
|
58
65
|
* points to a valid directory, return it. Otherwise create a new session.
|
|
@@ -92,4 +99,4 @@ declare function cmd_wrap(project_root: string, name: string, command: string[],
|
|
|
92
99
|
*/
|
|
93
100
|
declare function cmd_run(project_root: string, service_args: string[], options?: CliOptions): Promise<void>;
|
|
94
101
|
//#endregion
|
|
95
|
-
export { type BrowserLogsOptions, type CliOptions, DEFAULT_OPTIONS, type LogEntry, LogManager, type ResolvedOptions, type ServiceConfig, cmd_init, cmd_run, cmd_wrap, format_log_line, generate_client_script, parse_service_configs, resolve_options, resolve_session_dir, should_exclude };
|
|
102
|
+
export { type BrowserLogsOptions, type CliOptions, DEFAULT_OPTIONS, type LogEntry, LogManager, type ResolvedOptions, SESSION_ENV_VAR, type ServiceConfig, cmd_init, cmd_run, cmd_wrap, format_log_line, generate_client_script, parse_service_configs, resolve_options, resolve_session_dir, should_exclude };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as resolve_session_dir, c as LogManager, i as parse_service_configs, l as
|
|
1
|
+
import { a as resolve_session_dir, c as LogManager, i as parse_service_configs, l as SESSION_ENV_VAR, n as cmd_run, o as DEFAULT_OPTIONS, r as cmd_wrap, s as resolve_options, t as cmd_init, u as should_exclude } from "./commands-BGQ-_7t4.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formatter.ts
|
|
4
4
|
function format_log_line(entry) {
|
|
5
|
-
return `[${entry.timestamp}] [${entry.level.toUpperCase().padEnd(7)}] ${entry.args.join(" ")}${entry.url ? ` (${entry.url})` : ""}${entry.stack ? `\n ${entry.stack.split(
|
|
5
|
+
return `[${entry.timestamp}] [${entry.level.toUpperCase().padEnd(7)}] ${entry.args.join(" ")}${entry.url ? ` (${entry.url})` : ""}${entry.stack ? `\n ${entry.stack.split(/\r?\n/).join("\n ")}` : ""}\n`;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
//#endregion
|
|
@@ -121,4 +121,4 @@ function generate_client_script(options) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
//#endregion
|
|
124
|
-
export { DEFAULT_OPTIONS, LogManager, cmd_init, cmd_run, cmd_wrap, format_log_line, generate_client_script, parse_service_configs, resolve_options, resolve_session_dir, should_exclude };
|
|
124
|
+
export { DEFAULT_OPTIONS, LogManager, SESSION_ENV_VAR, cmd_init, cmd_run, cmd_wrap, format_log_line, generate_client_script, parse_service_configs, resolve_options, resolve_session_dir, should_exclude };
|