@zewstid/zeye-capture 0.2.0 → 0.3.0
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 +55 -10
- package/dist/src/cli.js +52 -16
- package/dist/src/fileOutbox.d.ts +7 -0
- package/dist/src/fileOutbox.js +134 -5
- package/dist/src/localHost.d.ts +1 -0
- package/dist/src/localHost.js +5 -0
- package/dist/src/service.d.ts +28 -1
- package/dist/src/service.js +85 -6
- package/dist/src/transport.js +4 -1
- package/dist/src/types.d.ts +3 -0
- package/package.json +4 -3
- package/dist/test/fileOutbox.test.d.ts +0 -1
- package/dist/test/fileOutbox.test.js +0 -104
- package/dist/test/host.test.d.ts +0 -1
- package/dist/test/host.test.js +0 -58
- package/dist/test/localHost.test.d.ts +0 -1
- package/dist/test/localHost.test.js +0 -122
- package/dist/test/providers-and-transport.test.d.ts +0 -1
- package/dist/test/providers-and-transport.test.js +0 -222
- package/dist/test/transcript-and-service.test.d.ts +0 -1
- package/dist/test/transcript-and-service.test.js +0 -50
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
-
const promises_1 = require("node:fs/promises");
|
|
8
|
-
const node_os_1 = require("node:os");
|
|
9
|
-
const node_path_1 = require("node:path");
|
|
10
|
-
const node_test_1 = __importDefault(require("node:test"));
|
|
11
|
-
const fileOutbox_1 = require("../src/fileOutbox");
|
|
12
|
-
const providers_1 = require("../src/providers");
|
|
13
|
-
const redaction_1 = require("../src/redaction");
|
|
14
|
-
const transport_1 = require("../src/transport");
|
|
15
|
-
const config = {
|
|
16
|
-
endpoint: 'https://zeye.invalid/engineering-memory/ingest',
|
|
17
|
-
token: 'zem_local-test-token',
|
|
18
|
-
organizationId: 'org_fixture',
|
|
19
|
-
captureInstallationId: 'capture_fixture',
|
|
20
|
-
actor: { kind: 'HUMAN', zeyeUserId: 'user_fixture', confidence: 'VERIFIED' },
|
|
21
|
-
privacy: { classification: 'INTERNAL', contentMode: 'METADATA_ONLY', redactionApplied: true, retentionClass: 'STANDARD', visibility: 'ACTOR_ONLY' },
|
|
22
|
-
};
|
|
23
|
-
async function withOutbox(run) {
|
|
24
|
-
const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'zeye-provider-capture-'));
|
|
25
|
-
try {
|
|
26
|
-
await run(new fileOutbox_1.FileOutbox(directory, redaction_1.metadataRedactor));
|
|
27
|
-
}
|
|
28
|
-
finally {
|
|
29
|
-
await (0, promises_1.rm)(directory, { recursive: true, force: true });
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
(0, node_test_1.default)('Claude Code hook adapter records lifecycle metadata without prompt or tool input', () => {
|
|
33
|
-
const event = (0, providers_1.fromClaudeCodeHook)({
|
|
34
|
-
hook_event_name: 'PreToolUse', session_id: 'claude-session-1', event_id: 'claude-event-1',
|
|
35
|
-
timestamp: '2026-09-05T12:00:00.000Z', tool_name: 'Bash', cwd: '/private/repo', tool_input: 'cat .env',
|
|
36
|
-
});
|
|
37
|
-
strict_1.default.ok(event);
|
|
38
|
-
strict_1.default.equal(event.type, 'tool.started');
|
|
39
|
-
strict_1.default.deepEqual(event.payload, { hook: 'PreToolUse', toolName: 'Bash', workingDirectoryPresent: true, toolFailure: false });
|
|
40
|
-
strict_1.default.doesNotMatch(JSON.stringify(event.payload), /cat .env|private\/repo/);
|
|
41
|
-
});
|
|
42
|
-
(0, node_test_1.default)('Codex JSONL adapter captures known lifecycle facts and labels unknown format safely', () => {
|
|
43
|
-
const started = (0, providers_1.fromCodexJsonl)({ type: 'session_meta', session_id: 'codex-session-1', timestamp: '2026-09-05T12:00:00.000Z', payload: { type: 'session_started', instructions: 'do not persist me' } });
|
|
44
|
-
strict_1.default.ok(started);
|
|
45
|
-
strict_1.default.equal(started.type, 'session.started');
|
|
46
|
-
strict_1.default.doesNotMatch(JSON.stringify(started.payload), /instructions/);
|
|
47
|
-
const unknown = (0, providers_1.fromCodexJsonl)({ type: 'future_event', session_id: 'codex-session-1', timestamp: '2026-09-05T12:00:00.000Z', payload: { type: 'new_event' } });
|
|
48
|
-
strict_1.default.ok(unknown);
|
|
49
|
-
strict_1.default.equal(unknown.type, 'capture.warning');
|
|
50
|
-
});
|
|
51
|
-
(0, node_test_1.default)('Codex usage records expose only bounded model and token counters', () => {
|
|
52
|
-
const event = (0, providers_1.fromCodexJsonl)({ type: 'event_msg', id: 'usage-1', session_id: 'codex-session-1', timestamp: '2026-09-05T12:00:00.000Z', payload: { type: 'usage', input_tokens: 123, output_tokens: 45, model: 'gpt-5.4', prompt: 'do not persist' } });
|
|
53
|
-
strict_1.default.ok(event);
|
|
54
|
-
strict_1.default.equal(event.type, 'usage.recorded');
|
|
55
|
-
strict_1.default.deepEqual(event.payload, { recordKind: 'event_msg', eventName: 'usage', sourceFilePresent: true, inputTokens: 123, outputTokens: 45, model: 'gpt-5.4' });
|
|
56
|
-
});
|
|
57
|
-
(0, node_test_1.default)('VS Code/Copilot companion events preserve lifecycle facts but not chat or workspace content', () => {
|
|
58
|
-
const event = (0, providers_1.fromVSCodeCopilotEvent)({ event: 'tool.started', eventId: 'vscode-event-1', sessionId: 'copilot-session-1', timestamp: '2026-09-05T12:00:00.000Z', toolName: 'terminal', workspaceUri: 'file:///private/repo', chatText: 'do not persist this', toolArguments: 'cat .env' });
|
|
59
|
-
strict_1.default.ok(event);
|
|
60
|
-
strict_1.default.equal(event.provider, 'github_copilot');
|
|
61
|
-
strict_1.default.equal(event.type, 'tool.started');
|
|
62
|
-
strict_1.default.deepEqual(event.payload, { eventName: 'tool.started', toolName: 'terminal', workspacePresent: true });
|
|
63
|
-
strict_1.default.doesNotMatch(JSON.stringify(event.payload), /private\/repo|do not persist|cat .env/);
|
|
64
|
-
});
|
|
65
|
-
(0, node_test_1.default)('metadata redactor removes accidental content fields before the outbox writes them', async () => {
|
|
66
|
-
await withOutbox(async (outbox) => {
|
|
67
|
-
const observation = (0, providers_1.fromClaudeCodeHook)({ hook_event_name: 'UserPromptSubmit', session_id: 'claude-session-1', timestamp: '2026-09-05T12:00:00.000Z', prompt: 'never store this' });
|
|
68
|
-
strict_1.default.ok(observation);
|
|
69
|
-
// Simulate an adapter regression: the redaction boundary remains the final
|
|
70
|
-
// line of defence before disk and strips the content-bearing property.
|
|
71
|
-
observation.payload = { ...observation.payload, prompt: 'never store this' };
|
|
72
|
-
const queued = await outbox.enqueue(observation);
|
|
73
|
-
strict_1.default.equal(queued.record.payload.prompt, '[REDACTED]');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
(0, node_test_1.default)('metadata redactor preserves bounded numeric usage totals while redacting token values', async () => {
|
|
77
|
-
await withOutbox(async (outbox) => {
|
|
78
|
-
const queued = await outbox.enqueue({ adapter: 'codex', sessionId: 'codex-session-1', sourceEventId: 'usage-1', occurredAt: '2026-09-05T12:00:00.000Z', type: 'usage.recorded', payload: { inputTokens: 123, outputTokens: 45, token: 'secret' } });
|
|
79
|
-
strict_1.default.deepEqual(queued.record.payload, { inputTokens: 123, outputTokens: 45, token: '[REDACTED]' });
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
(0, node_test_1.default)('transport converts one durable delivery into a schema-valid ledger batch and acks only a receipt', async () => {
|
|
83
|
-
await withOutbox(async (outbox) => {
|
|
84
|
-
const observation = (0, providers_1.fromCodexJsonl)({ type: 'session_meta', id: 'codex-event-1', session_id: 'codex-session-1', timestamp: '2026-09-05T12:00:00.000Z', payload: { type: 'session_started' } });
|
|
85
|
-
strict_1.default.ok(observation);
|
|
86
|
-
const queued = await outbox.enqueue(observation);
|
|
87
|
-
const batch = (0, transport_1.deliveryToBatch)(queued.record, config);
|
|
88
|
-
strict_1.default.equal(batch.batchId, queued.record.deliveryId);
|
|
89
|
-
strict_1.default.equal(batch.events[0]?.sourceSession.provider, 'codex');
|
|
90
|
-
strict_1.default.equal(batch.events[0]?.privacy.contentMode, 'METADATA_ONLY');
|
|
91
|
-
const transport = new transport_1.CaptureHttpTransport(outbox, config, async (_url, init) => {
|
|
92
|
-
strict_1.default.equal(init.headers.authorization, 'Bearer zem_local-test-token');
|
|
93
|
-
strict_1.default.equal(JSON.parse(init.body).batchId, queued.record.deliveryId);
|
|
94
|
-
return { ok: true, status: 201, json: async () => ({ receiptId: 'receipt-1' }) };
|
|
95
|
-
});
|
|
96
|
-
strict_1.default.deepEqual(await transport.flush(), { delivered: 1, failed: 0, deferred: 0 });
|
|
97
|
-
strict_1.default.equal((await outbox.list())[0]?.status, 'ACKNOWLEDGED');
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
(0, node_test_1.default)('mixed consented sessions keep lifecycle events metadata-only and content events consented', async () => {
|
|
101
|
-
await withOutbox(async (outbox) => {
|
|
102
|
-
const queued = await outbox.enqueue({ adapter: 'codex', sessionId: 'codex-session-1', sourceEventId: 'lifecycle-1', occurredAt: '2026-09-05T12:00:00.000Z', type: 'session.started', payload: {} });
|
|
103
|
-
const lifecycle = (0, transport_1.deliveryToBatch)(queued.record, { ...config, privacy: { ...config.privacy, contentMode: 'REDACTED_CONTENT', contentConsentId: 'consent-1' } });
|
|
104
|
-
strict_1.default.equal(lifecycle.events[0].privacy.contentMode, 'METADATA_ONLY');
|
|
105
|
-
strict_1.default.equal(lifecycle.events[0].privacy.contentConsentId, undefined);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
(0, node_test_1.default)('transport preserves provider version and session lineage rather than flattening it into a root session', async () => {
|
|
109
|
-
await withOutbox(async (outbox) => {
|
|
110
|
-
const observation = (0, providers_1.fromCodexJsonl)({
|
|
111
|
-
type: 'event_msg', id: 'resume-1', session_id: 'codex-session-1', client_version: '0.42.0', timestamp: '2026-09-05T12:00:00.000Z',
|
|
112
|
-
payload: { type: 'session_resumed', source_generation_id: 'generation-2', parent_session_id: 'codex-session-parent' },
|
|
113
|
-
});
|
|
114
|
-
strict_1.default.ok(observation);
|
|
115
|
-
strict_1.default.equal(observation.relationship, 'RESUMED_FROM');
|
|
116
|
-
const queued = await outbox.enqueue(observation);
|
|
117
|
-
const event = (0, transport_1.deliveryToBatch)(queued.record, config).events[0];
|
|
118
|
-
const source = event?.sourceSession;
|
|
119
|
-
strict_1.default.equal(event?.sessionGenerationId, 'generation-2');
|
|
120
|
-
strict_1.default.deepEqual(source, {
|
|
121
|
-
provider: 'codex', clientName: 'Codex', clientVersion: '0.42.0', sourceSessionId: 'codex-session-1',
|
|
122
|
-
sourceGenerationId: 'generation-2', relationship: 'RESUMED_FROM', relatedSourceSessionId: 'codex-session-parent',
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
(0, node_test_1.default)('transport uses repository facts captured with an offline delivery, not later runtime configuration', async () => {
|
|
127
|
-
await withOutbox(async (outbox) => {
|
|
128
|
-
const queued = await outbox.enqueue({
|
|
129
|
-
adapter: 'codex', sessionId: 'offline-session', sourceEventId: 'offline-event', occurredAt: '2026-09-05T12:00:00.000Z', type: 'session.started', payload: {},
|
|
130
|
-
}, { repositories: [{ repositoryId: 'repo-original', canonicalName: 'zewst/original', branch: 'main', headCommitSha: 'a'.repeat(40), isPrimary: true }] });
|
|
131
|
-
const changedRuntime = { ...config, repositories: [{ repositoryId: 'repo-later', canonicalName: 'zewst/later', branch: 'rewrite', headCommitSha: 'b'.repeat(40), isPrimary: true }] };
|
|
132
|
-
strict_1.default.deepEqual((0, transport_1.deliveryToBatch)(queued.record, changedRuntime).events[0]?.repositories, [{ repositoryId: 'repo-original', canonicalName: 'zewst/original', branch: 'main', headCommitSha: 'a'.repeat(40), isPrimary: true }]);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
(0, node_test_1.default)('terminal-only observations remain schema-valid but honestly mark lifecycle coverage partial', async () => {
|
|
136
|
-
await withOutbox(async (outbox) => {
|
|
137
|
-
const queued = await outbox.enqueue({ adapter: 'claude-code', sessionId: 'late-session', sourceEventId: 'terminal-only', occurredAt: '2026-09-05T12:00:00.000Z', type: 'session.ended', payload: {} });
|
|
138
|
-
const event = (0, transport_1.deliveryToBatch)(queued.record, config).events[0];
|
|
139
|
-
strict_1.default.equal(event?.sequence, 0);
|
|
140
|
-
strict_1.default.equal(event?.eventType, 'session.ended');
|
|
141
|
-
strict_1.default.deepEqual(event?.completeness, [{ dimension: 'LIFECYCLE', status: 'PARTIAL', reason: 'Capture began after the session start.', observedAt: new Date(queued.record.createdAt), source: 'CLIENT' }]);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
(0, node_test_1.default)('capture endpoint rejects cleartext non-loopback collectors and an incorrect path', () => {
|
|
145
|
-
strict_1.default.throws(() => (0, transport_1.validateCaptureEndpoint)('http://capture.example/engineering-memory/ingest'), /HTTPS/);
|
|
146
|
-
strict_1.default.throws(() => (0, transport_1.validateCaptureEndpoint)('https://capture.example/ingest'), /engineering-memory\/ingest/);
|
|
147
|
-
strict_1.default.equal((0, transport_1.validateCaptureEndpoint)('http://127.0.0.1:3000/engineering-memory/ingest'), 'http://127.0.0.1:3000/engineering-memory/ingest');
|
|
148
|
-
});
|
|
149
|
-
(0, node_test_1.default)('transport leaves a retryable record untouched when the server does not issue a receipt', async () => {
|
|
150
|
-
await withOutbox(async (outbox) => {
|
|
151
|
-
const observation = (0, providers_1.fromClaudeCodeHook)({ hook_event_name: 'SessionStart', session_id: 'claude-session-1', timestamp: '2026-09-05T12:00:00.000Z' });
|
|
152
|
-
strict_1.default.ok(observation);
|
|
153
|
-
await outbox.enqueue(observation);
|
|
154
|
-
const transport = new transport_1.CaptureHttpTransport(outbox, config, async () => ({ ok: false, status: 503, json: async () => ({ error: 'unavailable' }) }));
|
|
155
|
-
strict_1.default.deepEqual(await transport.flush(), { delivered: 0, failed: 1, deferred: 0 });
|
|
156
|
-
strict_1.default.equal((await outbox.list())[0]?.status, 'RETRY');
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
(0, node_test_1.default)('outbox assigns a stable monotonic sequence so later session events do not collide at the ledger', async () => {
|
|
160
|
-
await withOutbox(async (outbox) => {
|
|
161
|
-
const started = (0, providers_1.fromClaudeCodeHook)({ hook_event_name: 'SessionStart', session_id: 'claude-session-1', timestamp: '2026-09-05T12:00:00.000Z' });
|
|
162
|
-
const ended = (0, providers_1.fromClaudeCodeHook)({ hook_event_name: 'SessionEnd', session_id: 'claude-session-1', timestamp: '2026-09-05T12:01:00.000Z' });
|
|
163
|
-
strict_1.default.ok(started);
|
|
164
|
-
strict_1.default.ok(ended);
|
|
165
|
-
const first = await outbox.enqueue(started);
|
|
166
|
-
const second = await outbox.enqueue(ended);
|
|
167
|
-
strict_1.default.equal(first.record.sequence, 0);
|
|
168
|
-
strict_1.default.equal(second.record.sequence, 1);
|
|
169
|
-
strict_1.default.equal((0, transport_1.deliveryToBatch)(second.record, config).events[0]?.sequence, 1);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
(0, node_test_1.default)('transport produces a valid GitHub Copilot ledger event from the VS Code adapter', async () => {
|
|
173
|
-
await withOutbox(async (outbox) => {
|
|
174
|
-
const event = (0, providers_1.fromVSCodeCopilotEvent)({ event: 'session.started', eventId: 'vscode-event-1', sessionId: 'copilot-session-1', timestamp: '2026-09-05T12:00:00.000Z' });
|
|
175
|
-
strict_1.default.ok(event);
|
|
176
|
-
const queued = await outbox.enqueue(event);
|
|
177
|
-
const batch = (0, transport_1.deliveryToBatch)(queued.record, config);
|
|
178
|
-
strict_1.default.equal(batch.events[0]?.sourceSession.provider, 'github_copilot');
|
|
179
|
-
strict_1.default.equal(batch.events[0]?.sourceSession.clientName, 'VS Code / GitHub Copilot');
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
(0, node_test_1.default)('transport publishes an honest adapter capability manifest to the same collector', async () => {
|
|
183
|
-
await withOutbox(async (outbox) => {
|
|
184
|
-
const transport = new transport_1.CaptureHttpTransport(outbox, config, async (url, init) => {
|
|
185
|
-
strict_1.default.equal(url, 'https://zeye.invalid/engineering-memory/manifest');
|
|
186
|
-
strict_1.default.equal(JSON.parse(init.body).provider, 'codex');
|
|
187
|
-
return { ok: true, status: 204, json: async () => ({}) };
|
|
188
|
-
});
|
|
189
|
-
await transport.publishManifest((0, transport_1.capabilityManifestForAdapter)('codex'));
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
(0, node_test_1.default)('transport sends an explicit heartbeat without serializing enrollment credentials into the body', async () => {
|
|
193
|
-
await withOutbox(async (outbox) => {
|
|
194
|
-
const transport = new transport_1.CaptureHttpTransport(outbox, config, async (url, init) => {
|
|
195
|
-
strict_1.default.equal(url, 'https://zeye.invalid/engineering-memory/heartbeat');
|
|
196
|
-
strict_1.default.equal(init.headers.authorization, 'Bearer zem_local-test-token');
|
|
197
|
-
strict_1.default.equal(init.body, '{}');
|
|
198
|
-
return { ok: true, status: 204, json: async () => ({}) };
|
|
199
|
-
});
|
|
200
|
-
await transport.heartbeat();
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
(0, node_test_1.default)('capability manifests claim only what each adapter can actually observe', () => {
|
|
204
|
-
const claude = (0, transport_1.capabilityManifestForAdapter)('claude-code');
|
|
205
|
-
strict_1.default.equal(claude.supportedEventTypes.includes('artifact.verified'), false);
|
|
206
|
-
strict_1.default.equal(claude.supportedEventTypes.includes('usage.recorded'), false);
|
|
207
|
-
strict_1.default.equal(claude.completeness.find(item => item.dimension === 'USAGE')?.maximumStatus, 'UNAVAILABLE');
|
|
208
|
-
const codex = (0, transport_1.capabilityManifestForAdapter)('codex');
|
|
209
|
-
strict_1.default.equal(codex.supportedEventTypes.includes('file.changed'), false);
|
|
210
|
-
strict_1.default.equal(codex.supportedEventTypes.includes('usage.recorded'), true);
|
|
211
|
-
strict_1.default.equal(codex.completeness.find(item => item.dimension === 'SUBAGENT_LINEAGE')?.maximumStatus, 'PARTIAL');
|
|
212
|
-
const vscode = (0, transport_1.capabilityManifestForAdapter)('vscode-copilot');
|
|
213
|
-
strict_1.default.deepEqual(vscode.transports, ['manual']);
|
|
214
|
-
strict_1.default.equal(vscode.supportedEventTypes.includes('artifact.claimed'), false);
|
|
215
|
-
});
|
|
216
|
-
(0, node_test_1.default)('advertises transcript completeness only after explicit consent enables content capture', () => {
|
|
217
|
-
const metadata = (0, transport_1.capabilityManifestForAdapter)('codex');
|
|
218
|
-
const content = (0, transport_1.capabilityManifestForAdapter)('codex', true);
|
|
219
|
-
strict_1.default.equal(metadata.completeness.find(item => item.dimension === 'MESSAGES')?.maximumStatus, 'UNAVAILABLE');
|
|
220
|
-
strict_1.default.equal(content.completeness.find(item => item.dimension === 'MESSAGES')?.maximumStatus, 'COMPLETE');
|
|
221
|
-
strict_1.default.equal(content.completeness.find(item => item.dimension === 'TOOLS')?.maximumStatus, 'COMPLETE');
|
|
222
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
-
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
-
const redaction_1 = require("../src/redaction");
|
|
9
|
-
const providers_1 = require("../src/providers");
|
|
10
|
-
const service_1 = require("../src/service");
|
|
11
|
-
(0, node_test_1.default)('redacts credentials from provider-visible transcript text before persistence', async () => {
|
|
12
|
-
const source = 'use authorization: Bearer abcdefghijklmnopqrstuvwxyz and sk-proj_abcdefghijklmnopqrstuvwxyz';
|
|
13
|
-
const redacted = (0, redaction_1.redactTranscriptText)(source);
|
|
14
|
-
strict_1.default.equal(redacted.text.includes('abcdefghijklmnopqrstuvwxyz'), false);
|
|
15
|
-
strict_1.default.ok(redacted.redactionCount >= 2);
|
|
16
|
-
const result = await redaction_1.consentedTranscriptRedactor.redact({ adapter: 'codex', sessionId: 's', sourceEventId: 'e', occurredAt: new Date().toISOString(), type: 'message.recorded', payload: {}, transcript: { kind: 'USER_MESSAGE', text: source } });
|
|
17
|
-
strict_1.default.equal(result.transcript?.text.includes('sk-proj'), false);
|
|
18
|
-
strict_1.default.equal(result.transcript?.redactionPolicyVersion, 'zeye-secrets-v1');
|
|
19
|
-
});
|
|
20
|
-
(0, node_test_1.default)('content extraction is explicit and captures only provider-visible Codex messages', () => {
|
|
21
|
-
const record = { type: 'response_item', session_id: 'session-1', id: 'message-1', payload: { type: 'message', role: 'assistant', content: [{ type: 'output_text', text: 'Visible response' }] } };
|
|
22
|
-
strict_1.default.equal((0, providers_1.fromCodexJsonl)(record)?.transcript, undefined);
|
|
23
|
-
strict_1.default.deepEqual((0, providers_1.fromCodexJsonl)(record, 'rollout.jsonl', true)?.transcript, { kind: 'ASSISTANT_MESSAGE', text: 'Visible response', providerMessageId: 'message-1' });
|
|
24
|
-
});
|
|
25
|
-
(0, node_test_1.default)('content extraction is explicit for Claude Code hook payloads', () => {
|
|
26
|
-
const record = { hook_event_name: 'UserPromptSubmit', session_id: 'session-1', event_id: 'message-1', prompt: 'Visible prompt' };
|
|
27
|
-
strict_1.default.equal((0, providers_1.fromClaudeCodeHook)(record)?.transcript, undefined);
|
|
28
|
-
strict_1.default.deepEqual((0, providers_1.fromClaudeCodeHook)(record, true)?.transcript, { kind: 'USER_MESSAGE', text: 'Visible prompt', providerMessageId: 'message-1' });
|
|
29
|
-
});
|
|
30
|
-
(0, node_test_1.default)('Claude transcript parser captures visible assistant text and tool records but excludes thinking', () => {
|
|
31
|
-
const event = (0, providers_1.fromClaudeTranscriptJsonl)({
|
|
32
|
-
type: 'assistant', sessionId: 'claude-session', uuid: 'message-1', timestamp: '2026-09-08T12:00:00.000Z',
|
|
33
|
-
message: { role: 'assistant', content: [{ type: 'thinking', thinking: 'private reasoning' }, { type: 'text', text: 'Visible answer' }, { type: 'tool_use', name: 'Bash', input: { command: 'npm test' } }] },
|
|
34
|
-
});
|
|
35
|
-
strict_1.default.equal(event?.transcript?.kind, 'ASSISTANT_MESSAGE');
|
|
36
|
-
strict_1.default.match(event?.transcript?.text || '', /Visible answer.*Tool Bash input/s);
|
|
37
|
-
strict_1.default.doesNotMatch(event?.transcript?.text || '', /private reasoning/);
|
|
38
|
-
});
|
|
39
|
-
(0, node_test_1.default)('generates restartable launchd and systemd services without embedding the token', () => {
|
|
40
|
-
const env = { XDG_CONFIG_HOME: '/safe/config' };
|
|
41
|
-
const linux = (0, service_1.serviceFiles)('/work/repo', env, 'linux');
|
|
42
|
-
const unit = (0, service_1.serviceDefinition)(linux, '/work/repo', '/usr/bin/node', '/app/zeye-capture.js');
|
|
43
|
-
strict_1.default.match(unit, /Restart=always/);
|
|
44
|
-
strict_1.default.match(unit, /service-run/);
|
|
45
|
-
strict_1.default.doesNotMatch(unit, /zem_/);
|
|
46
|
-
const mac = (0, service_1.serviceFiles)('/work/repo', env, 'darwin');
|
|
47
|
-
const plist = (0, service_1.serviceDefinition)(mac, '/work/repo', '/usr/bin/node', '/app/zeye-capture.js');
|
|
48
|
-
strict_1.default.match(plist, /KeepAlive/);
|
|
49
|
-
strict_1.default.doesNotMatch(plist, /ZEYE_CAPTURE_TOKEN/);
|
|
50
|
-
});
|