@zewstid/zeye-capture 0.2.0 → 0.3.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.
@@ -1,122 +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_child_process_1 = require("node:child_process");
8
- const promises_1 = require("node:fs/promises");
9
- const node_os_1 = require("node:os");
10
- const node_path_1 = require("node:path");
11
- const node_test_1 = __importDefault(require("node:test"));
12
- const localHost_1 = require("../src/localHost");
13
- function git(directory, args) {
14
- return (0, node_child_process_1.execFileSync)('git', ['-C', directory, ...args], { encoding: 'utf8' }).trim();
15
- }
16
- async function withRepository(run) {
17
- const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'zeye-capture-local-host-'));
18
- const configPath = (0, node_path_1.join)(directory, 'private-config', 'host.json');
19
- try {
20
- git(directory, ['init', '--initial-branch=main']);
21
- git(directory, ['config', 'user.email', 'capture@example.test']);
22
- git(directory, ['config', 'user.name', 'Capture Test']);
23
- await (0, promises_1.writeFile)((0, node_path_1.join)(directory, 'README.md'), 'fixture\n');
24
- git(directory, ['add', 'README.md']);
25
- git(directory, ['commit', '-m', 'fixture']);
26
- git(directory, ['remote', 'add', 'origin', 'git@github.com:zewst/zeye.git']);
27
- await run(directory, configPath);
28
- }
29
- finally {
30
- await (0, promises_1.rm)(directory, { recursive: true, force: true });
31
- }
32
- }
33
- (0, node_test_1.default)('installs and removes only Zeye-owned Claude hook groups in private local settings', async () => {
34
- await withRepository(async (repositoryRoot, configPath) => {
35
- const settingsPath = (0, node_path_1.join)(repositoryRoot, '.claude', 'settings.local.json');
36
- await (0, promises_1.mkdir)((0, node_path_1.join)(repositoryRoot, '.claude'), { recursive: true });
37
- await (0, promises_1.writeFile)(settingsPath, JSON.stringify({ hooks: { SessionStart: [{ matcher: 'existing', hooks: [{ type: 'command', command: 'existing-hook' }] }] } }));
38
- const installed = await (0, localHost_1.installClaudeHooks)({ repositoryRoot, settingsPath, configPath });
39
- strict_1.default.equal(installed.installedEvents.length, 9);
40
- const afterInstall = JSON.parse(await (0, promises_1.readFile)(settingsPath, 'utf8'));
41
- strict_1.default.equal(afterInstall.hooks.SessionStart.length, 2);
42
- strict_1.default.equal(afterInstall.hooks.PreCompact[0].hooks[0].command, 'zeye-capture claude-hook');
43
- if (process.platform !== 'win32')
44
- strict_1.default.equal((await (0, promises_1.stat)(settingsPath)).mode & 0o777, 0o600);
45
- const hostConfig = await (0, localHost_1.readLocalHostConfig)(configPath);
46
- strict_1.default.equal(hostConfig.claudeInstalls.length, 1);
47
- const removed = await (0, localHost_1.uninstallClaudeHooks)({ repositoryRoot, settingsPath, configPath });
48
- strict_1.default.equal(removed.removedEvents.length, 9);
49
- const afterRemove = JSON.parse(await (0, promises_1.readFile)(settingsPath, 'utf8'));
50
- strict_1.default.deepEqual(afterRemove.hooks.SessionStart, [{ matcher: 'existing', hooks: [{ type: 'command', command: 'existing-hook' }] }]);
51
- strict_1.default.equal(afterRemove.hooks.PreCompact, undefined);
52
- });
53
- });
54
- (0, node_test_1.default)('stores Codex tail sources in an OS-private local host config and removes them by repository', async () => {
55
- await withRepository(async (repositoryRoot, configPath) => {
56
- const jsonlPath = (0, node_path_1.join)(repositoryRoot, 'sessions', 'rollout.jsonl');
57
- await (0, localHost_1.installCodexSource)({ repositoryRoot, jsonlPath, configPath });
58
- strict_1.default.deepEqual((await (0, localHost_1.readLocalHostConfig)(configPath)).codexSources, [{ repositoryRoot, jsonlPath }]);
59
- if (process.platform !== 'win32')
60
- strict_1.default.equal((await (0, promises_1.stat)(configPath)).mode & 0o777, 0o600);
61
- strict_1.default.equal(await (0, localHost_1.uninstallCodexSource)({ repositoryRoot, jsonlPath, configPath }), 1);
62
- strict_1.default.equal((await (0, localHost_1.readLocalHostConfig)(configPath)).codexSources.length, 0);
63
- });
64
- });
65
- (0, node_test_1.default)('discovers safe Git repository identity without retaining the raw remote URL', async () => {
66
- await withRepository(async (repositoryRoot) => {
67
- const identity = await (0, localHost_1.discoverRepositoryIdentity)(repositoryRoot, { providerRepositoryId: '123' });
68
- strict_1.default.ok(identity);
69
- strict_1.default.equal(identity.fullName, 'zewst/zeye');
70
- strict_1.default.equal(identity.branch, 'main');
71
- strict_1.default.match(identity.headCommitSha || '', /^[a-f0-9]{40}$/);
72
- strict_1.default.match(identity.remoteUrlHash || '', /^[a-f0-9]{64}$/);
73
- strict_1.default.equal(JSON.stringify(identity).includes('git@github.com'), false);
74
- strict_1.default.deepEqual((0, localHost_1.captureRepositoryReference)(identity, 'repo-internal'), [{ repositoryId: 'repo-internal', providerRepositoryId: '123', canonicalName: 'zewst/zeye', remoteUrlHash: identity.remoteUrlHash, branch: 'main', headCommitSha: identity.headCommitSha, isPrimary: true }]);
75
- });
76
- });
77
- (0, node_test_1.default)('enforces a single capture process per private outbox directory', async () => {
78
- const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'zeye-capture-lock-'));
79
- try {
80
- const first = await (0, localHost_1.acquireCaptureLock)(directory);
81
- await strict_1.default.rejects((0, localHost_1.acquireCaptureLock)(directory, { maxWaitMs: 0 }), /Capture already running/);
82
- await first.release();
83
- const second = await (0, localHost_1.acquireCaptureLock)(directory);
84
- await second.release();
85
- }
86
- finally {
87
- await (0, promises_1.rm)(directory, { recursive: true, force: true });
88
- }
89
- });
90
- (0, node_test_1.default)('waits briefly for a concurrent capture lock instead of dropping a normal hook event', async () => {
91
- const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'zeye-capture-lock-wait-'));
92
- try {
93
- const first = await (0, localHost_1.acquireCaptureLock)(directory);
94
- const secondPromise = (0, localHost_1.acquireCaptureLock)(directory, { maxWaitMs: 500, initialRetryDelayMs: 5, maxRetryDelayMs: 10 });
95
- setTimeout(() => { void first.release(); }, 25);
96
- const second = await secondPromise;
97
- await second.release();
98
- }
99
- finally {
100
- await (0, promises_1.rm)(directory, { recursive: true, force: true });
101
- }
102
- });
103
- (0, node_test_1.default)('scopes an explicit outbox override to the repository rather than sharing records across checkouts', () => {
104
- const environment = { ZEYE_CAPTURE_OUTBOX_DIR: '/private/zeye-outbox' };
105
- strict_1.default.notEqual((0, localHost_1.localOutboxDirectory)('/work/repository-a', environment), (0, localHost_1.localOutboxDirectory)('/work/repository-b', environment));
106
- strict_1.default.match((0, localHost_1.localOutboxDirectory)('/work/repository-a', environment), /^\/private\/zeye-outbox\//);
107
- });
108
- (0, node_test_1.default)('sync reports a non-zero exit when a configured Codex source cannot be imported', async () => {
109
- await withRepository(async (repositoryRoot) => {
110
- const configHome = (0, node_path_1.join)(repositoryRoot, 'capture-config-home');
111
- const missingJsonl = (0, node_path_1.join)(repositoryRoot, 'missing', 'rollout.jsonl');
112
- const cli = (0, node_path_1.join)(process.cwd(), 'dist', 'src', 'cli.js');
113
- const environment = { ...process.env, XDG_CONFIG_HOME: configHome, XDG_STATE_HOME: (0, node_path_1.join)(repositoryRoot, 'capture-state-home') };
114
- for (const key of ['ZEYE_CAPTURE_ENDPOINT', 'ZEYE_CAPTURE_TOKEN', 'ZEYE_CAPTURE_ORGANIZATION_ID', 'ZEYE_CAPTURE_INSTALLATION_ID', 'ZEYE_CAPTURE_ACTOR_JSON', 'ZEYE_CAPTURE_REPOSITORY_ID', 'ZEYE_CAPTURE_PROVIDER_REPOSITORY_ID'])
115
- delete environment[key];
116
- const install = (0, node_child_process_1.spawnSync)(process.execPath, [cli, 'install', 'codex', '--jsonl', missingJsonl, '--repo', repositoryRoot], { encoding: 'utf8', env: environment });
117
- strict_1.default.equal(install.status, 0, install.stderr);
118
- const sync = (0, node_child_process_1.spawnSync)(process.execPath, [cli, 'sync', '--repo', repositoryRoot], { encoding: 'utf8', env: environment });
119
- strict_1.default.equal(sync.status, 1, sync.stderr);
120
- strict_1.default.match(sync.stdout, /configured JSONL path/);
121
- });
122
- });
@@ -1 +0,0 @@
1
- export {};
@@ -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
- });