@p4r4d0xb0x/opencode-provider-logger 1.0.1 → 1.1.1
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/dist/index.js +419 -5
- package/package.json +5 -6
- package/dist/adapters/claude-code/hook.d.ts +0 -2
- package/dist/adapters/claude-code/hook.js +0 -48
- package/dist/adapters/claude-code/install.d.ts +0 -2
- package/dist/adapters/claude-code/install.js +0 -106
- package/dist/adapters/claude-code/transform.d.ts +0 -26
- package/dist/adapters/claude-code/transform.js +0 -66
- package/dist/adapters/codex-cli/hook.d.ts +0 -2
- package/dist/adapters/codex-cli/hook.js +0 -48
- package/dist/adapters/codex-cli/install.d.ts +0 -2
- package/dist/adapters/codex-cli/install.js +0 -118
- package/dist/adapters/codex-cli/transform.d.ts +0 -26
- package/dist/adapters/codex-cli/transform.js +0 -35
- package/dist/adapters/opencode/hooks.js +0 -87
- package/dist/adapters/opencode/index.js +0 -63
- package/dist/buffer.d.ts +0 -13
- package/dist/buffer.js +0 -45
- package/dist/core/buffer.d.ts +0 -13
- package/dist/core/buffer.js +0 -45
- package/dist/core/entry.d.ts +0 -5
- package/dist/core/entry.js +0 -19
- package/dist/core/index.d.ts +0 -8
- package/dist/core/index.js +0 -5
- package/dist/core/logger.d.ts +0 -21
- package/dist/core/logger.js +0 -107
- package/dist/core/types.d.ts +0 -42
- package/dist/core/types.js +0 -27
- package/dist/core/uploader.d.ts +0 -12
- package/dist/core/uploader.js +0 -45
- package/dist/hooks.d.ts +0 -7
- package/dist/hooks.js +0 -72
- package/dist/logger.d.ts +0 -17
- package/dist/logger.js +0 -97
- package/dist/types.d.ts +0 -21
- package/dist/types.js +0 -14
- package/dist/uploader.d.ts +0 -13
- package/dist/uploader.js +0 -45
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { makeEntry } from "../../core/entry.js";
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Claude Code hook event → normalised category mapping
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
const HOOK_CATEGORY_MAP = {
|
|
6
|
-
// Session lifecycle
|
|
7
|
-
SessionStart: "session.start",
|
|
8
|
-
SessionEnd: "session.end",
|
|
9
|
-
PreCompact: "session.compact",
|
|
10
|
-
PostCompact: "session.compact",
|
|
11
|
-
// Prompt / message
|
|
12
|
-
UserPromptSubmit: "prompt.user",
|
|
13
|
-
InstructionsLoaded: "instructions.loaded",
|
|
14
|
-
Stop: "message.assistant",
|
|
15
|
-
StopFailure: "message.assistant",
|
|
16
|
-
// Tool execution
|
|
17
|
-
PreToolUse: "tool.pre",
|
|
18
|
-
PostToolUse: "tool.post",
|
|
19
|
-
PostToolUseFailure: "tool.error",
|
|
20
|
-
// Permission
|
|
21
|
-
PermissionRequest: "permission.request",
|
|
22
|
-
PermissionDenied: "permission.denied",
|
|
23
|
-
// Subagent / task
|
|
24
|
-
SubagentStart: "subagent.start",
|
|
25
|
-
SubagentStop: "subagent.stop",
|
|
26
|
-
TaskCreated: "task.created",
|
|
27
|
-
TaskCompleted: "task.completed",
|
|
28
|
-
// Environment
|
|
29
|
-
ConfigChange: "config.change",
|
|
30
|
-
CwdChanged: "cwd.change",
|
|
31
|
-
FileChanged: "file.change",
|
|
32
|
-
WorktreeCreate: "file.change",
|
|
33
|
-
WorktreeRemove: "file.change",
|
|
34
|
-
// Misc
|
|
35
|
-
Notification: "notification",
|
|
36
|
-
Elicitation: "elicitation",
|
|
37
|
-
ElicitationResult: "elicitation.result",
|
|
38
|
-
TeammateIdle: "session.idle",
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Transform a Claude Code hook stdin payload into a ProviderLogEntry.
|
|
42
|
-
*/
|
|
43
|
-
export function transformClaudeEvent(input) {
|
|
44
|
-
const hookName = input.hook_event_name;
|
|
45
|
-
const category = HOOK_CATEGORY_MAP[hookName] ?? "raw";
|
|
46
|
-
const sessionID = input.session_id ?? "unknown";
|
|
47
|
-
// Build output based on event type
|
|
48
|
-
let output = null;
|
|
49
|
-
if (hookName === "PostToolUse" || hookName === "PostToolUseFailure") {
|
|
50
|
-
output = input.tool_response ?? null;
|
|
51
|
-
}
|
|
52
|
-
else if (hookName === "Stop" || hookName === "StopFailure") {
|
|
53
|
-
output = input.last_assistant_message ?? null;
|
|
54
|
-
}
|
|
55
|
-
return makeEntry("claude-code", sessionID, category, hookName, input, output, {
|
|
56
|
-
model: input.model ?? undefined,
|
|
57
|
-
toolName: input.tool_name ?? undefined,
|
|
58
|
-
turnID: input.turn_id ?? undefined,
|
|
59
|
-
agentID: input.agent_id ?? undefined,
|
|
60
|
-
agentType: input.agent_type ?? undefined,
|
|
61
|
-
transcriptPath: input.transcript_path ?? undefined,
|
|
62
|
-
cwd: input.cwd ?? undefined,
|
|
63
|
-
userID: process.env.USER ?? process.env.USERNAME ?? undefined,
|
|
64
|
-
permissionMode: input.permission_mode ?? undefined,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Codex CLI hook script — receives JSON on stdin, logs to JSONL
|
|
4
|
-
// Usage: Set as a "command" hook in ~/.codex/hooks.json
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
import { LocalWriter } from "../../core/logger.js";
|
|
7
|
-
import { R2Uploader } from "../../core/uploader.js";
|
|
8
|
-
import { defaultConfig } from "../../core/types.js";
|
|
9
|
-
import { transformCodexEvent } from "./transform.js";
|
|
10
|
-
const UPLOAD_ON_EVENTS = new Set(["Stop"]);
|
|
11
|
-
async function main() {
|
|
12
|
-
// Read JSON from stdin
|
|
13
|
-
const chunks = [];
|
|
14
|
-
for await (const chunk of process.stdin) {
|
|
15
|
-
chunks.push(chunk);
|
|
16
|
-
}
|
|
17
|
-
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
18
|
-
if (!raw)
|
|
19
|
-
return;
|
|
20
|
-
let input;
|
|
21
|
-
try {
|
|
22
|
-
input = JSON.parse(raw);
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
process.stderr.write(`provider-logger: invalid JSON on stdin\n`);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const config = defaultConfig("codex-cli");
|
|
29
|
-
const writer = new LocalWriter(config);
|
|
30
|
-
const entry = transformCodexEvent(input);
|
|
31
|
-
// Append to session-scoped JSONL file
|
|
32
|
-
await writer.append(entry.sessionID, entry);
|
|
33
|
-
// On stop, trigger upload of pending files
|
|
34
|
-
if (UPLOAD_ON_EVENTS.has(input.hook_event_name)) {
|
|
35
|
-
const log = (level, msg, extra) => {
|
|
36
|
-
if (level === "error" || level === "warn") {
|
|
37
|
-
process.stderr.write(`provider-logger [${level}]: ${msg}\n`);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
const uploader = new R2Uploader(config, writer, log);
|
|
41
|
-
await uploader.retryPending().catch(() => { });
|
|
42
|
-
await uploader.cleanup().catch(() => { });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
main().catch((err) => {
|
|
46
|
-
process.stderr.write(`provider-logger: ${err}\n`);
|
|
47
|
-
process.exit(1);
|
|
48
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Generate / merge Codex CLI hook configuration into hooks.json
|
|
4
|
-
// Usage: node dist/adapters/codex-cli/install.js [--global | --project]
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
7
|
-
import { join, dirname } from "node:path";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
/** Resolve the compiled hook.js path relative to this install script */
|
|
11
|
-
function hookCommand() {
|
|
12
|
-
const hookPath = join(__dirname, "hook.js");
|
|
13
|
-
return `node "${hookPath}"`;
|
|
14
|
-
}
|
|
15
|
-
function generateHooksConfig() {
|
|
16
|
-
const cmd = hookCommand();
|
|
17
|
-
return {
|
|
18
|
-
SessionStart: [
|
|
19
|
-
{
|
|
20
|
-
matcher: "startup|resume",
|
|
21
|
-
hooks: [
|
|
22
|
-
{
|
|
23
|
-
type: "command",
|
|
24
|
-
command: cmd,
|
|
25
|
-
timeout: 10,
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
PreToolUse: [
|
|
31
|
-
{
|
|
32
|
-
matcher: ".*",
|
|
33
|
-
hooks: [
|
|
34
|
-
{
|
|
35
|
-
type: "command",
|
|
36
|
-
command: cmd,
|
|
37
|
-
timeout: 10,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
PostToolUse: [
|
|
43
|
-
{
|
|
44
|
-
matcher: ".*",
|
|
45
|
-
hooks: [
|
|
46
|
-
{
|
|
47
|
-
type: "command",
|
|
48
|
-
command: cmd,
|
|
49
|
-
timeout: 10,
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
UserPromptSubmit: [
|
|
55
|
-
{
|
|
56
|
-
hooks: [
|
|
57
|
-
{
|
|
58
|
-
type: "command",
|
|
59
|
-
command: cmd,
|
|
60
|
-
timeout: 10,
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
Stop: [
|
|
66
|
-
{
|
|
67
|
-
hooks: [
|
|
68
|
-
{
|
|
69
|
-
type: "command",
|
|
70
|
-
command: cmd,
|
|
71
|
-
timeout: 30,
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async function install(mode) {
|
|
79
|
-
const home = process.env.HOME ?? require("node:os").homedir();
|
|
80
|
-
const hooksPath = mode === "global"
|
|
81
|
-
? join(home, ".codex", "hooks.json")
|
|
82
|
-
: join(process.cwd(), ".codex", "hooks.json");
|
|
83
|
-
// Read existing hooks or start fresh
|
|
84
|
-
let existing = {};
|
|
85
|
-
try {
|
|
86
|
-
const raw = await readFile(hooksPath, "utf-8");
|
|
87
|
-
existing = JSON.parse(raw);
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
// file doesn't exist yet
|
|
91
|
-
}
|
|
92
|
-
const existingHooks = (existing.hooks ?? {});
|
|
93
|
-
const newHooks = generateHooksConfig();
|
|
94
|
-
for (const [event, matchers] of Object.entries(newHooks)) {
|
|
95
|
-
if (!existingHooks[event]) {
|
|
96
|
-
existingHooks[event] = matchers;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
const cmd = hookCommand();
|
|
100
|
-
const alreadyInstalled = existingHooks[event].some((m) => m?.hooks?.some((h) => h?.command?.includes(cmd)));
|
|
101
|
-
if (!alreadyInstalled) {
|
|
102
|
-
existingHooks[event].push(...matchers);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
existing.hooks = existingHooks;
|
|
107
|
-
await mkdir(dirname(hooksPath), { recursive: true });
|
|
108
|
-
await writeFile(hooksPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
109
|
-
console.log(`✓ Provider logger hooks installed → ${hooksPath}`);
|
|
110
|
-
console.log(` Events: SessionStart, PreToolUse, PostToolUse, UserPromptSubmit, Stop`);
|
|
111
|
-
console.log(` Note: Codex hooks require [features] codex_hooks = true in config.toml`);
|
|
112
|
-
}
|
|
113
|
-
// CLI
|
|
114
|
-
const mode = process.argv.includes("--project") ? "project" : "global";
|
|
115
|
-
install(mode).catch((err) => {
|
|
116
|
-
console.error(`Install failed: ${err}`);
|
|
117
|
-
process.exit(1);
|
|
118
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { ProviderLogEntry } from "../../core/types.js";
|
|
2
|
-
/** Common fields present in every Codex CLI hook stdin payload */
|
|
3
|
-
export interface CodexHookInput {
|
|
4
|
-
session_id: string;
|
|
5
|
-
hook_event_name: string;
|
|
6
|
-
transcript_path?: string | null;
|
|
7
|
-
cwd?: string;
|
|
8
|
-
model?: string;
|
|
9
|
-
source?: string;
|
|
10
|
-
turn_id?: string;
|
|
11
|
-
tool_name?: string;
|
|
12
|
-
tool_use_id?: string;
|
|
13
|
-
tool_input?: {
|
|
14
|
-
command?: string;
|
|
15
|
-
[key: string]: unknown;
|
|
16
|
-
};
|
|
17
|
-
tool_response?: unknown;
|
|
18
|
-
prompt?: string;
|
|
19
|
-
stop_hook_active?: boolean;
|
|
20
|
-
last_assistant_message?: string | null;
|
|
21
|
-
[key: string]: unknown;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Transform a Codex CLI hook stdin payload into a ProviderLogEntry.
|
|
25
|
-
*/
|
|
26
|
-
export declare function transformCodexEvent(input: CodexHookInput): ProviderLogEntry;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { makeEntry } from "../../core/entry.js";
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Codex CLI hook event → normalised category mapping
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
const HOOK_CATEGORY_MAP = {
|
|
6
|
-
SessionStart: "session.start",
|
|
7
|
-
PreToolUse: "tool.pre",
|
|
8
|
-
PostToolUse: "tool.post",
|
|
9
|
-
UserPromptSubmit: "prompt.user",
|
|
10
|
-
Stop: "message.assistant",
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Transform a Codex CLI hook stdin payload into a ProviderLogEntry.
|
|
14
|
-
*/
|
|
15
|
-
export function transformCodexEvent(input) {
|
|
16
|
-
const hookName = input.hook_event_name;
|
|
17
|
-
const category = HOOK_CATEGORY_MAP[hookName] ?? "raw";
|
|
18
|
-
const sessionID = input.session_id ?? "unknown";
|
|
19
|
-
// Build output based on event type
|
|
20
|
-
let output = null;
|
|
21
|
-
if (hookName === "PostToolUse") {
|
|
22
|
-
output = input.tool_response ?? null;
|
|
23
|
-
}
|
|
24
|
-
else if (hookName === "Stop") {
|
|
25
|
-
output = input.last_assistant_message ?? null;
|
|
26
|
-
}
|
|
27
|
-
return makeEntry("codex-cli", sessionID, category, hookName, input, output, {
|
|
28
|
-
model: input.model ?? undefined,
|
|
29
|
-
toolName: input.tool_name ?? undefined,
|
|
30
|
-
turnID: input.turn_id ?? undefined,
|
|
31
|
-
transcriptPath: input.transcript_path ?? undefined,
|
|
32
|
-
cwd: input.cwd ?? undefined,
|
|
33
|
-
userID: process.env.USER ?? process.env.USERNAME ?? undefined,
|
|
34
|
-
});
|
|
35
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { makeEntry } from "@p4r4d0xb0x/provider-logger-core";
|
|
2
|
-
/** OpenCode event types worth logging */
|
|
3
|
-
const LOG_EVENT_TYPES = new Set([
|
|
4
|
-
"message.updated",
|
|
5
|
-
"session.idle",
|
|
6
|
-
"session.status",
|
|
7
|
-
"session.created",
|
|
8
|
-
"session.compacted",
|
|
9
|
-
]);
|
|
10
|
-
/** Map OpenCode hook names to normalised event categories */
|
|
11
|
-
const HOOK_CATEGORY_MAP = {
|
|
12
|
-
"chat.message": "message.updated",
|
|
13
|
-
"chat.params": "prompt.params",
|
|
14
|
-
"experimental.chat.system.transform": "prompt.system",
|
|
15
|
-
"experimental.chat.messages.transform": "prompt.system",
|
|
16
|
-
"experimental.text.complete": "message.assistant",
|
|
17
|
-
"tool.execute.before": "tool.pre",
|
|
18
|
-
"tool.execute.after": "tool.post",
|
|
19
|
-
event: "raw",
|
|
20
|
-
};
|
|
21
|
-
/** Map OpenCode event types to normalised categories */
|
|
22
|
-
const EVENT_TYPE_CATEGORY_MAP = {
|
|
23
|
-
"message.updated": "message.updated",
|
|
24
|
-
"session.idle": "session.idle",
|
|
25
|
-
"session.status": "session.status",
|
|
26
|
-
"session.created": "session.created",
|
|
27
|
-
"session.compacted": "session.compact",
|
|
28
|
-
};
|
|
29
|
-
export function createHooks(buffer, config, flush, log) {
|
|
30
|
-
const safeRecord = (sessionID, hook, input, output, categoryOverride) => {
|
|
31
|
-
try {
|
|
32
|
-
const category = categoryOverride ?? HOOK_CATEGORY_MAP[hook];
|
|
33
|
-
const entry = makeEntry("opencode", sessionID, category, hook, input, output);
|
|
34
|
-
buffer.append(entry);
|
|
35
|
-
if (buffer.sizeOf(sessionID) >= config.flushThresholdBytes) {
|
|
36
|
-
flush(sessionID).catch(() => { });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
log?.("error", `Hook record failed [${hook}]`, { error: String(err) });
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
return {
|
|
44
|
-
"chat.message": async (input, output) => {
|
|
45
|
-
safeRecord(input.sessionID, "chat.message", input, output);
|
|
46
|
-
},
|
|
47
|
-
"chat.params": async (input, output) => {
|
|
48
|
-
safeRecord(input.sessionID, "chat.params", input, output);
|
|
49
|
-
},
|
|
50
|
-
"experimental.chat.system.transform": async (input, output) => {
|
|
51
|
-
const sessionID = input.sessionID ?? "unknown";
|
|
52
|
-
safeRecord(sessionID, "experimental.chat.system.transform", input, output);
|
|
53
|
-
},
|
|
54
|
-
"experimental.chat.messages.transform": async (input, output) => {
|
|
55
|
-
const firstMsg = output.messages?.[0]?.info;
|
|
56
|
-
const sessionID = firstMsg?.sessionID ?? "unknown";
|
|
57
|
-
safeRecord(sessionID, "experimental.chat.messages.transform", input, output);
|
|
58
|
-
},
|
|
59
|
-
"experimental.text.complete": async (input, output) => {
|
|
60
|
-
safeRecord(input.sessionID, "experimental.text.complete", input, output);
|
|
61
|
-
},
|
|
62
|
-
"tool.execute.before": async (input, output) => {
|
|
63
|
-
safeRecord(input.sessionID, "tool.execute.before", input, output);
|
|
64
|
-
},
|
|
65
|
-
"tool.execute.after": async (input, output) => {
|
|
66
|
-
safeRecord(input.sessionID, "tool.execute.after", input, output);
|
|
67
|
-
},
|
|
68
|
-
event: async ({ event }) => {
|
|
69
|
-
try {
|
|
70
|
-
const ev = event;
|
|
71
|
-
if (!LOG_EVENT_TYPES.has(ev.type))
|
|
72
|
-
return;
|
|
73
|
-
const sessionID = ev.properties?.sessionID ?? ev.properties?.info?.sessionID;
|
|
74
|
-
if (!sessionID)
|
|
75
|
-
return;
|
|
76
|
-
const category = EVENT_TYPE_CATEGORY_MAP[ev.type] ?? "raw";
|
|
77
|
-
safeRecord(sessionID, "event", { type: ev.type }, ev.properties, category);
|
|
78
|
-
if (ev.type === "session.idle") {
|
|
79
|
-
await flush(sessionID);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
log?.("error", "Event hook failed", { error: String(err) });
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { SessionBuffer, LocalWriter, WorkerUploader, defaultConfig, } from "@p4r4d0xb0x/provider-logger-core";
|
|
2
|
-
import { createHooks } from "./hooks.js";
|
|
3
|
-
import { basename } from "node:path";
|
|
4
|
-
const providerLogger = async ({ client }) => {
|
|
5
|
-
const config = defaultConfig("opencode");
|
|
6
|
-
const buffer = new SessionBuffer();
|
|
7
|
-
const writer = new LocalWriter(config);
|
|
8
|
-
const log = (level, message, extra) => {
|
|
9
|
-
client.app.log({
|
|
10
|
-
body: { service: "provider-logger", level, message, extra },
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
const uploader = new WorkerUploader(config, writer, log);
|
|
14
|
-
// Retry any pending uploads from previous sessions
|
|
15
|
-
uploader.retryPending().catch((err) => {
|
|
16
|
-
log("warn", "Failed to retry pending uploads", { error: String(err) });
|
|
17
|
-
});
|
|
18
|
-
// Cleanup local files older than retention period
|
|
19
|
-
uploader.cleanup().catch((err) => {
|
|
20
|
-
log("warn", "Failed to cleanup old files", { error: String(err) });
|
|
21
|
-
});
|
|
22
|
-
const flush = async (sessionID) => {
|
|
23
|
-
if (!buffer.has(sessionID))
|
|
24
|
-
return;
|
|
25
|
-
const entries = buffer.flush(sessionID);
|
|
26
|
-
try {
|
|
27
|
-
const filepath = await writer.write(sessionID, entries);
|
|
28
|
-
if (filepath) {
|
|
29
|
-
const tsNanos = basename(filepath, ".jsonl");
|
|
30
|
-
await uploader.upload({ path: filepath, sessionID, tsNanos });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
log("error", `Flush failed for session ${sessionID}`, {
|
|
35
|
-
error: String(err),
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
// Flush remaining buffers on process exit
|
|
40
|
-
const flushAll = async () => {
|
|
41
|
-
const all = buffer.flushAll();
|
|
42
|
-
const writes = [];
|
|
43
|
-
for (const [sessionID, entries] of all) {
|
|
44
|
-
if (entries.length === 0)
|
|
45
|
-
continue;
|
|
46
|
-
writes.push(writer.write(sessionID, entries).then(async (filepath) => {
|
|
47
|
-
if (filepath) {
|
|
48
|
-
const tsNanos = basename(filepath, ".jsonl");
|
|
49
|
-
await uploader.upload({ path: filepath, sessionID, tsNanos });
|
|
50
|
-
}
|
|
51
|
-
}).catch((err) => {
|
|
52
|
-
log("error", `Shutdown flush failed for ${sessionID}`, { error: String(err) });
|
|
53
|
-
}));
|
|
54
|
-
}
|
|
55
|
-
await Promise.allSettled(writes);
|
|
56
|
-
};
|
|
57
|
-
process.on("beforeExit", () => {
|
|
58
|
-
flushAll().catch(() => { });
|
|
59
|
-
});
|
|
60
|
-
log("info", "Provider logger initialized");
|
|
61
|
-
return createHooks(buffer, config, flush, log);
|
|
62
|
-
};
|
|
63
|
-
export default providerLogger;
|
package/dist/buffer.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { LogEntry } from "./types.js";
|
|
2
|
-
/** Rough byte estimate without JSON.stringify overhead */
|
|
3
|
-
export declare function estimateEntrySize(entry: LogEntry): number;
|
|
4
|
-
export declare class SessionBuffer {
|
|
5
|
-
private buffers;
|
|
6
|
-
private sizes;
|
|
7
|
-
append(entry: LogEntry): void;
|
|
8
|
-
sizeOf(sessionID: string): number;
|
|
9
|
-
flush(sessionID: string): LogEntry[];
|
|
10
|
-
flushAll(): Map<string, LogEntry[]>;
|
|
11
|
-
has(sessionID: string): boolean;
|
|
12
|
-
sessionIDs(): string[];
|
|
13
|
-
}
|
package/dist/buffer.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** Rough byte estimate without JSON.stringify overhead */
|
|
2
|
-
export function estimateEntrySize(entry) {
|
|
3
|
-
// Fixed overhead: id(36) + timestamp(24) + timestampNanos(19) + hook(~30) + JSON structure(~80)
|
|
4
|
-
const FIXED = 190;
|
|
5
|
-
const dataStr = typeof entry.data.input === "string" ? entry.data.input.length : 200;
|
|
6
|
-
const dataOut = typeof entry.data.output === "string" ? entry.data.output.length : 200;
|
|
7
|
-
return FIXED + entry.sessionID.length + dataStr + dataOut;
|
|
8
|
-
}
|
|
9
|
-
export class SessionBuffer {
|
|
10
|
-
buffers = new Map();
|
|
11
|
-
sizes = new Map();
|
|
12
|
-
append(entry) {
|
|
13
|
-
const { sessionID } = entry;
|
|
14
|
-
if (!this.buffers.has(sessionID)) {
|
|
15
|
-
this.buffers.set(sessionID, []);
|
|
16
|
-
this.sizes.set(sessionID, 0);
|
|
17
|
-
}
|
|
18
|
-
this.buffers.get(sessionID).push(entry);
|
|
19
|
-
// Approximate size: avoid double JSON.stringify (once here, once on write)
|
|
20
|
-
const approx = estimateEntrySize(entry);
|
|
21
|
-
this.sizes.set(sessionID, (this.sizes.get(sessionID) ?? 0) + approx);
|
|
22
|
-
}
|
|
23
|
-
sizeOf(sessionID) {
|
|
24
|
-
return this.sizes.get(sessionID) ?? 0;
|
|
25
|
-
}
|
|
26
|
-
flush(sessionID) {
|
|
27
|
-
const entries = this.buffers.get(sessionID) ?? [];
|
|
28
|
-
this.buffers.delete(sessionID);
|
|
29
|
-
this.sizes.delete(sessionID);
|
|
30
|
-
return entries;
|
|
31
|
-
}
|
|
32
|
-
flushAll() {
|
|
33
|
-
const all = new Map(this.buffers);
|
|
34
|
-
this.buffers.clear();
|
|
35
|
-
this.sizes.clear();
|
|
36
|
-
return all;
|
|
37
|
-
}
|
|
38
|
-
has(sessionID) {
|
|
39
|
-
const buf = this.buffers.get(sessionID);
|
|
40
|
-
return buf !== undefined && buf.length > 0;
|
|
41
|
-
}
|
|
42
|
-
sessionIDs() {
|
|
43
|
-
return [...this.buffers.keys()];
|
|
44
|
-
}
|
|
45
|
-
}
|
package/dist/core/buffer.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ProviderLogEntry } from "./types.js";
|
|
2
|
-
/** Rough byte estimate without JSON.stringify overhead */
|
|
3
|
-
export declare function estimateEntrySize(entry: ProviderLogEntry): number;
|
|
4
|
-
export declare class SessionBuffer {
|
|
5
|
-
private buffers;
|
|
6
|
-
private sizes;
|
|
7
|
-
append(entry: ProviderLogEntry): void;
|
|
8
|
-
sizeOf(sessionID: string): number;
|
|
9
|
-
flush(sessionID: string): ProviderLogEntry[];
|
|
10
|
-
flushAll(): Map<string, ProviderLogEntry[]>;
|
|
11
|
-
has(sessionID: string): boolean;
|
|
12
|
-
sessionIDs(): string[];
|
|
13
|
-
}
|
package/dist/core/buffer.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** Rough byte estimate without JSON.stringify overhead */
|
|
2
|
-
export function estimateEntrySize(entry) {
|
|
3
|
-
// Fixed overhead: id(36) + timestamp(24) + timestampNanos(19) + hookName(~30)
|
|
4
|
-
// + platform(~12) + category(~20) + JSON structure(~100)
|
|
5
|
-
const FIXED = 240;
|
|
6
|
-
const dataStr = typeof entry.data.input === "string" ? entry.data.input.length : 200;
|
|
7
|
-
const dataOut = typeof entry.data.output === "string" ? entry.data.output.length : 200;
|
|
8
|
-
return FIXED + entry.sessionID.length + dataStr + dataOut;
|
|
9
|
-
}
|
|
10
|
-
export class SessionBuffer {
|
|
11
|
-
buffers = new Map();
|
|
12
|
-
sizes = new Map();
|
|
13
|
-
append(entry) {
|
|
14
|
-
const { sessionID } = entry;
|
|
15
|
-
if (!this.buffers.has(sessionID)) {
|
|
16
|
-
this.buffers.set(sessionID, []);
|
|
17
|
-
this.sizes.set(sessionID, 0);
|
|
18
|
-
}
|
|
19
|
-
this.buffers.get(sessionID).push(entry);
|
|
20
|
-
const approx = estimateEntrySize(entry);
|
|
21
|
-
this.sizes.set(sessionID, (this.sizes.get(sessionID) ?? 0) + approx);
|
|
22
|
-
}
|
|
23
|
-
sizeOf(sessionID) {
|
|
24
|
-
return this.sizes.get(sessionID) ?? 0;
|
|
25
|
-
}
|
|
26
|
-
flush(sessionID) {
|
|
27
|
-
const entries = this.buffers.get(sessionID) ?? [];
|
|
28
|
-
this.buffers.delete(sessionID);
|
|
29
|
-
this.sizes.delete(sessionID);
|
|
30
|
-
return entries;
|
|
31
|
-
}
|
|
32
|
-
flushAll() {
|
|
33
|
-
const all = new Map(this.buffers);
|
|
34
|
-
this.buffers.clear();
|
|
35
|
-
this.sizes.clear();
|
|
36
|
-
return all;
|
|
37
|
-
}
|
|
38
|
-
has(sessionID) {
|
|
39
|
-
const buf = this.buffers.get(sessionID);
|
|
40
|
-
return buf !== undefined && buf.length > 0;
|
|
41
|
-
}
|
|
42
|
-
sessionIDs() {
|
|
43
|
-
return [...this.buffers.keys()];
|
|
44
|
-
}
|
|
45
|
-
}
|
package/dist/core/entry.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ProviderLogEntry, Platform, EventCategory } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Create a ProviderLogEntry with auto-generated id, timestamp, and nanos.
|
|
4
|
-
*/
|
|
5
|
-
export declare function makeEntry(platform: Platform, sessionID: string, category: EventCategory, hookName: string, input: unknown, output: unknown, meta?: ProviderLogEntry["meta"]): ProviderLogEntry;
|
package/dist/core/entry.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
/**
|
|
3
|
-
* Create a ProviderLogEntry with auto-generated id, timestamp, and nanos.
|
|
4
|
-
*/
|
|
5
|
-
export function makeEntry(platform, sessionID, category, hookName, input, output, meta) {
|
|
6
|
-
const now = Date.now();
|
|
7
|
-
const micro = Math.floor(Math.random() * 1_000_000);
|
|
8
|
-
return {
|
|
9
|
-
id: randomUUID(),
|
|
10
|
-
timestamp: new Date(now).toISOString(),
|
|
11
|
-
timestampNanos: `${now}${String(micro).padStart(6, "0")}`,
|
|
12
|
-
sessionID,
|
|
13
|
-
platform,
|
|
14
|
-
category,
|
|
15
|
-
hookName,
|
|
16
|
-
data: { input, output },
|
|
17
|
-
...(meta ? { meta } : {}),
|
|
18
|
-
};
|
|
19
|
-
}
|
package/dist/core/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export type { ProviderLogEntry, Platform, EventCategory, OpenCodeHookName, PluginConfig, } from "./types.js";
|
|
2
|
-
export { defaultConfig, DEFAULT_CONFIG, LOG_EVENT_TYPES } from "./types.js";
|
|
3
|
-
export { SessionBuffer, estimateEntrySize } from "./buffer.js";
|
|
4
|
-
export { LocalWriter, makeTimestampNanos, _resetCounter } from "./logger.js";
|
|
5
|
-
export type { PendingFile } from "./logger.js";
|
|
6
|
-
export { R2Uploader } from "./uploader.js";
|
|
7
|
-
export type { LogFn } from "./uploader.js";
|
|
8
|
-
export { makeEntry } from "./entry.js";
|
package/dist/core/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { defaultConfig, DEFAULT_CONFIG, LOG_EVENT_TYPES } from "./types.js";
|
|
2
|
-
export { SessionBuffer, estimateEntrySize } from "./buffer.js";
|
|
3
|
-
export { LocalWriter, makeTimestampNanos, _resetCounter } from "./logger.js";
|
|
4
|
-
export { R2Uploader } from "./uploader.js";
|
|
5
|
-
export { makeEntry } from "./entry.js";
|
package/dist/core/logger.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ProviderLogEntry, PluginConfig } from "./types.js";
|
|
2
|
-
export interface PendingFile {
|
|
3
|
-
path: string;
|
|
4
|
-
sessionID: string;
|
|
5
|
-
tsNanos: string;
|
|
6
|
-
}
|
|
7
|
-
export declare class LocalWriter {
|
|
8
|
-
private config;
|
|
9
|
-
constructor(config: PluginConfig);
|
|
10
|
-
private sessionDir;
|
|
11
|
-
/** Write a batch of entries to a new JSONL file (used by buffered mode) */
|
|
12
|
-
write(sessionID: string, entries: ProviderLogEntry[]): Promise<string>;
|
|
13
|
-
/** Append a single entry to a session-scoped JSONL file (used by hook scripts) */
|
|
14
|
-
append(sessionID: string, entry: ProviderLogEntry): Promise<string>;
|
|
15
|
-
getPending(): Promise<PendingFile[]>;
|
|
16
|
-
markUploaded(filepath: string): Promise<void>;
|
|
17
|
-
cleanup(): Promise<void>;
|
|
18
|
-
}
|
|
19
|
-
export declare function makeTimestampNanos(): string;
|
|
20
|
-
/** @internal — exposed for testing */
|
|
21
|
-
export declare function _resetCounter(): void;
|