zombie-vibe 0.1.6 → 0.1.7

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Zombie Pulse installs deterministic prompt-submission hooks for Codex, Claude Code, Cursor, Windsurf, and Grok. The hook records both the user's local ISO timestamp and an unambiguous UTC audit timestamp, the IANA timezone when available, the local timezone offset, the editor/AI name, the session, and prompt length. It immediately discards the prompt text.
4
4
 
5
- Events live in a private persistent queue at `~/.zombie-vibe/events.jsonl`. Each buffered event stores `occurred_at_local`, `occurred_at_utc`, timezone metadata, the machine-readable `agent`, and a display-ready `ai_name`; older events are upgraded automatically when the queue is next read. When the queue reaches 10 events, the oldest 10 are sent to the Zombie Vibe API. Failed uploads stay queued for a later prompt or manual flush.
5
+ Events live in a private persistent queue at `~/.zombie-vibe/events.jsonl`. Each buffered event stores `occurred_at_local`, `occurred_at_utc`, timezone metadata, the machine-readable `agent`, and a display-ready `ai_name`; older events are upgraded automatically when the queue is next read. Uploads use a versioned `events` array and include batch-level local/UTC send times plus the agents represented in the batch. When the queue reaches 10 events, the oldest 10 are sent to the Zombie Vibe API. Failed uploads stay queued for a later prompt or manual flush.
6
6
 
7
7
  ## Install
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zombie-vibe",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Install privacy-first prompt timing hooks for Codex, Claude Code, Cursor, Windsurf, and Grok.",
5
5
  "type": "module",
6
6
  "bin": {
package/runtime/hook.mjs CHANGED
@@ -9,6 +9,7 @@ const configPath = join(dataDir, "config.json");
9
9
  const queuePath = join(dataDir, "events.jsonl");
10
10
  const lockPath = join(dataDir, "events.lock");
11
11
  const aiNames = { codex: "Codex", claude: "Claude", cursor: "Cursor", windsurf: "Windsurf", grok: "Grok" };
12
+ const schemaVersion = 2;
12
13
 
13
14
  function localTimestamp(date, offsetMinutes = date.getTimezoneOffset()) {
14
15
  const local = new Date(date.getTime() - offsetMinutes * 60_000).toISOString().slice(0, -1);
@@ -59,6 +60,20 @@ export function eventFromPayload(payload, agent = "unknown", now = new Date()) {
59
60
  };
60
61
  }
61
62
 
63
+ export function batchPayload(events, now = new Date()) {
64
+ const timezoneOffsetMinutes = now.getTimezoneOffset();
65
+ const normalizedEvents = events.map((event) => normalizeBufferedEvent(event));
66
+ return {
67
+ schema_version: schemaVersion,
68
+ sent_at_utc: now.toISOString(),
69
+ sent_at_local: localTimestamp(now, timezoneOffsetMinutes),
70
+ timezone_offset_minutes: timezoneOffsetMinutes,
71
+ timezone_name: timezoneName(),
72
+ agents: [...new Set(normalizedEvents.map((event) => String(event.agent || "unknown")))],
73
+ events: normalizedEvents,
74
+ };
75
+ }
76
+
62
77
  async function readJson(path, fallback) {
63
78
  try { return JSON.parse(await readFile(path, "utf8")); } catch { return fallback; }
64
79
  }
@@ -96,8 +111,8 @@ async function sendBatch(config, events) {
96
111
  if (!config.apiKey || !config.apiUrl) return false;
97
112
  const response = await fetch(config.apiUrl, {
98
113
  method: "POST",
99
- headers: { authorization: `Bearer ${config.apiKey}`, "content-type": "application/json", "user-agent": "zombie-vibe-hook/0.1.4" },
100
- body: JSON.stringify({ events }),
114
+ headers: { authorization: `Bearer ${config.apiKey}`, "content-type": "application/json", "user-agent": "zombie-vibe-hook/0.1.7" },
115
+ body: JSON.stringify(batchPayload(events)),
101
116
  signal: AbortSignal.timeout(3000),
102
117
  });
103
118
  return response.ok;