@mycadet/assistant 0.12.11 → 0.13.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/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/openapi.yaml +2 -708
- package/package.json +2 -3
- package/scripts/sync-web-search-catalog.ts +1 -2
- package/src/__tests__/cloud-profile-guard.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +6 -38
- package/src/__tests__/conversation-queue.test.ts +45 -6
- package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
- package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +0 -51
- package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
- package/src/__tests__/run-due-schedules.test.ts +0 -4
- package/src/__tests__/schedule-store.test.ts +0 -12
- package/src/__tests__/stt-stream-session.test.ts +4 -4
- package/src/__tests__/telephony-tts-guard.test.ts +2 -50
- package/src/__tests__/voice-config-update.test.ts +12 -167
- package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
- package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
- package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
- package/src/calls/resolve-call-tts-provider.ts +6 -25
- package/src/calls/telephony-credential-preflight.ts +0 -10
- package/src/calls/telephony-tts-capability.ts +1 -17
- package/src/cli/commands/tts.ts +1 -2
- package/src/cli/index.help.ts +0 -2
- package/src/cli/program.ts +0 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
- package/src/config/schemas/__tests__/stt.test.ts +10 -14
- package/src/config/schemas/services.ts +5 -6
- package/src/config/schemas/stt.ts +1 -3
- package/src/config/schemas/tts.ts +1 -30
- package/src/daemon/daemon-readiness.ts +4 -29
- package/src/daemon/lifecycle.ts +0 -31
- package/src/daemon/providers-setup.ts +0 -8
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/heartbeat/heartbeat-service.ts +1 -66
- package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
- package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
- package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
- package/src/live-voice/live-voice-credential-preflight.ts +9 -33
- package/src/live-voice/live-voice-session.ts +10 -6
- package/src/live-voice/live-voice-tts.ts +1 -8
- package/src/plugins/defaults/memory/worker.ts +3 -3
- package/src/prompts/persona-resolver.ts +0 -35
- package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
- package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
- package/src/providers/search-provider-catalog.ts +7 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
- package/src/providers/speech-to-text/provider-catalog.ts +2 -73
- package/src/providers/speech-to-text/resolve.ts +3 -120
- package/src/runtime/http-router-types.ts +1 -3
- package/src/runtime/http-server.ts +1 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/live-voice-routes.test.ts +4 -11
- package/src/runtime/routes/live-voice-routes.ts +8 -11
- package/src/runtime/routes/secret-routes.ts +0 -6
- package/src/runtime/routes/tts-routes.ts +0 -38
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
- package/src/schedule/schedule-store.ts +0 -7
- package/src/schedule/scheduler.ts +0 -5
- package/src/schedule/worker.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
- package/src/stt/daemon-batch-transcriber.ts +4 -38
- package/src/stt/types.ts +1 -9
- package/src/tools/network/__tests__/web-search.test.ts +3 -250
- package/src/tools/network/web-search.ts +4 -165
- package/src/tts/__tests__/provider-resolution.test.ts +0 -5
- package/src/tts/provider-catalog.ts +0 -4
- package/src/tts/types.ts +0 -1
- package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
- package/src/__tests__/migration-export-http.test.ts +0 -557
- package/src/__tests__/migration-export-streaming.test.ts +0 -350
- package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
- package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
- package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
- package/src/__tests__/migration-import-from-path.test.ts +0 -324
- package/src/__tests__/migration-import-from-url.test.ts +0 -588
- package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
- package/src/__tests__/migration-jobs-status.test.ts +0 -139
- package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
- package/src/__tests__/migration-transport.test.ts +0 -1089
- package/src/__tests__/migration-validate-http.test.ts +0 -634
- package/src/__tests__/migration-wizard.test.ts +0 -1395
- package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
- package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
- package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
- package/src/__tests__/validation-results-screen.test.ts +0 -1130
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
- package/src/background-wake/background-wake-routes.test.ts +0 -906
- package/src/background-wake/cloud-client.test.ts +0 -328
- package/src/background-wake/cloud-client.ts +0 -196
- package/src/background-wake/next-wake.test.ts +0 -335
- package/src/background-wake/next-wake.ts +0 -188
- package/src/background-wake/publisher.ts +0 -93
- package/src/background-wake/wake-intent-hooks.test.ts +0 -234
- package/src/cli/commands/__tests__/backup.test.ts +0 -363
- package/src/cli/commands/backup.help.ts +0 -180
- package/src/cli/commands/backup.ts +0 -398
- package/src/cloud/cloud-speech.test.ts +0 -335
- package/src/cloud/cloud-speech.ts +0 -300
- package/src/config/cloud-speech-defaults.ts +0 -300
- package/src/config/sanitize-for-transfer.ts +0 -111
- package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
- package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
- package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
- package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
- package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
- package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
- package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
- package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
- package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
- package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
- package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
- package/src/runtime/migrations/gcs-signed-url.ts +0 -190
- package/src/runtime/migrations/job-registry.ts +0 -297
- package/src/runtime/migrations/migration-transport.ts +0 -612
- package/src/runtime/migrations/migration-wizard.ts +0 -747
- package/src/runtime/migrations/origin-mode.ts +0 -42
- package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
- package/src/runtime/migrations/staged-import-path.ts +0 -116
- package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
- package/src/runtime/migrations/validation-results-screen.ts +0 -469
- package/src/runtime/migrations/vbundle-builder.ts +0 -1382
- package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
- package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
- package/src/runtime/migrations/vbundle-importer.ts +0 -826
- package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
- package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
- package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
- package/src/runtime/migrations/vbundle-validator.ts +0 -724
- package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
- package/src/runtime/routes/background-wake-routes.ts +0 -387
- package/src/runtime/routes/migration-routes.ts +0 -2584
- package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
- package/src/tools/network/cloud-search-proxy.ts +0 -211
- package/src/tts/__tests__/cadet-provider.test.ts +0 -253
- package/src/tts/providers/cadet-provider.ts +0 -244
- package/src/types/tar-stream.d.ts +0 -66
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for the streaming vbundle export builder.
|
|
3
|
-
*
|
|
4
|
-
* Tests cover:
|
|
5
|
-
* - Format parity: streaming builder produces archives identical to sync builder
|
|
6
|
-
* - SHA-256 integrity: manifest checksums match actual file content
|
|
7
|
-
* - Temp file lifecycle: cleanup removes the temp file
|
|
8
|
-
* - Cleanup idempotency: calling cleanup twice doesn't throw
|
|
9
|
-
* - Round-trip: streamExportVBundle -> validateVBundle succeeds
|
|
10
|
-
*/
|
|
11
|
-
import { createHash } from "node:crypto";
|
|
12
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
import { gunzipSync } from "node:zlib";
|
|
15
|
-
import { beforeAll, describe, expect, test } from "bun:test";
|
|
16
|
-
|
|
17
|
-
const testDir = process.env.CADET_WORKSPACE_DIR!;
|
|
18
|
-
const testDbDir = join(testDir, "data", "db");
|
|
19
|
-
const testDbPath = join(testDbDir, "assistant.db");
|
|
20
|
-
const testConfigPath = join(testDir, "config.json");
|
|
21
|
-
|
|
22
|
-
process.env.DISABLE_HTTP_AUTH = "true";
|
|
23
|
-
|
|
24
|
-
import { defaultV1Options } from "../runtime/migrations/__tests__/v1-test-helpers.js";
|
|
25
|
-
import {
|
|
26
|
-
buildExportVBundle,
|
|
27
|
-
streamExportVBundle,
|
|
28
|
-
} from "../runtime/migrations/vbundle-builder.js";
|
|
29
|
-
import { validateVBundle } from "../runtime/migrations/vbundle-validator.js";
|
|
30
|
-
// Test fixture data: a minimal SQLite header to simulate a real database file
|
|
31
|
-
const SQLITE_HEADER = new Uint8Array([
|
|
32
|
-
0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
|
|
33
|
-
0x20, 0x33, 0x00,
|
|
34
|
-
]);
|
|
35
|
-
const TEST_CONFIG = { provider: "anthropic", model: "test-model" };
|
|
36
|
-
|
|
37
|
-
// Generate a synthetic large file (~10 MB of repeated data)
|
|
38
|
-
const LARGE_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
|
|
39
|
-
const LARGE_FILE_NAME = "large-test-data.txt";
|
|
40
|
-
|
|
41
|
-
function generateLargeFileContent(): Buffer {
|
|
42
|
-
const line =
|
|
43
|
-
"This is a line of repeated test data for streaming export verification.\n";
|
|
44
|
-
const lineBuffer = Buffer.from(line);
|
|
45
|
-
const buf = Buffer.alloc(LARGE_FILE_SIZE);
|
|
46
|
-
for (let offset = 0; offset < LARGE_FILE_SIZE; offset += lineBuffer.length) {
|
|
47
|
-
const remaining = LARGE_FILE_SIZE - offset;
|
|
48
|
-
lineBuffer.copy(buf, offset, 0, Math.min(lineBuffer.length, remaining));
|
|
49
|
-
}
|
|
50
|
-
return buf;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
beforeAll(() => {
|
|
54
|
-
// Write test fixture files so the export reads real data
|
|
55
|
-
mkdirSync(testDbDir, { recursive: true });
|
|
56
|
-
writeFileSync(testDbPath, SQLITE_HEADER);
|
|
57
|
-
writeFileSync(testConfigPath, JSON.stringify(TEST_CONFIG, null, 2));
|
|
58
|
-
writeFileSync(join(testDir, LARGE_FILE_NAME), generateLargeFileContent());
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Tar parsing helper (mirrors vbundle-validator's internal parser)
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
|
|
65
|
-
interface TarEntry {
|
|
66
|
-
name: string;
|
|
67
|
-
data: Uint8Array;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function parseTarEntries(gzippedData: Uint8Array): TarEntry[] {
|
|
71
|
-
const tarData = gunzipSync(gzippedData);
|
|
72
|
-
const entries: TarEntry[] = [];
|
|
73
|
-
let offset = 0;
|
|
74
|
-
const BLOCK_SIZE = 512;
|
|
75
|
-
|
|
76
|
-
while (offset + BLOCK_SIZE <= tarData.length) {
|
|
77
|
-
const header = tarData.subarray(offset, offset + BLOCK_SIZE);
|
|
78
|
-
if (header.every((b) => b === 0)) {
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let end = 0;
|
|
83
|
-
while (end < 100 && header[end] !== 0) {
|
|
84
|
-
end++;
|
|
85
|
-
}
|
|
86
|
-
const name = new TextDecoder().decode(header.subarray(0, end));
|
|
87
|
-
|
|
88
|
-
let sizeEnd = 124;
|
|
89
|
-
while (sizeEnd < 136 && header[sizeEnd] !== 0) {
|
|
90
|
-
sizeEnd++;
|
|
91
|
-
}
|
|
92
|
-
const sizeStr = new TextDecoder().decode(header.subarray(124, sizeEnd));
|
|
93
|
-
const size = parseInt(sizeStr, 8) || 0;
|
|
94
|
-
|
|
95
|
-
const dataStart = offset + BLOCK_SIZE;
|
|
96
|
-
const data = tarData.subarray(dataStart, dataStart + size);
|
|
97
|
-
const dataBlocks = Math.ceil(size / BLOCK_SIZE);
|
|
98
|
-
|
|
99
|
-
if (header[156] === "0".charCodeAt(0) || header[156] === 0) {
|
|
100
|
-
entries.push({ name, data: new Uint8Array(data) });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
offset = dataStart + dataBlocks * BLOCK_SIZE;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return entries;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function sha256Hex(data: Uint8Array): string {
|
|
110
|
-
return createHash("sha256").update(data).digest("hex");
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
// Streaming export tests
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
|
|
117
|
-
describe("streamExportVBundle", () => {
|
|
118
|
-
test("returns a temp file that exists on disk", async () => {
|
|
119
|
-
const result = await streamExportVBundle({
|
|
120
|
-
workspaceDir: testDir,
|
|
121
|
-
...defaultV1Options(),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
expect(existsSync(result.tempPath)).toBe(true);
|
|
126
|
-
expect(result.size).toBeGreaterThan(0);
|
|
127
|
-
} finally {
|
|
128
|
-
await result.cleanup();
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test("manifest contains correct SHA-256 checksums for all files", async () => {
|
|
133
|
-
const result = await streamExportVBundle({
|
|
134
|
-
workspaceDir: testDir,
|
|
135
|
-
...defaultV1Options(),
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
const archiveData = new Uint8Array(readFileSync(result.tempPath));
|
|
140
|
-
const entries = parseTarEntries(archiveData);
|
|
141
|
-
|
|
142
|
-
for (const fileEntry of result.manifest.contents) {
|
|
143
|
-
const tarEntry = entries.find((e) => e.name === fileEntry.path);
|
|
144
|
-
expect(tarEntry).toBeDefined();
|
|
145
|
-
expect(sha256Hex(tarEntry!.data)).toBe(fileEntry.sha256);
|
|
146
|
-
}
|
|
147
|
-
} finally {
|
|
148
|
-
await result.cleanup();
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test("decompressed archive produces same files as buildExportVBundle", async () => {
|
|
153
|
-
const streamResult = await streamExportVBundle({
|
|
154
|
-
workspaceDir: testDir,
|
|
155
|
-
...defaultV1Options(),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const syncResult = buildExportVBundle({
|
|
160
|
-
workspaceDir: testDir,
|
|
161
|
-
...defaultV1Options(),
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const streamArchiveData = new Uint8Array(
|
|
165
|
-
readFileSync(streamResult.tempPath),
|
|
166
|
-
);
|
|
167
|
-
const streamEntries = parseTarEntries(streamArchiveData);
|
|
168
|
-
const syncEntries = parseTarEntries(syncResult.archive);
|
|
169
|
-
|
|
170
|
-
// Filter out manifest.json — compare only data files
|
|
171
|
-
const streamFileEntries = streamEntries
|
|
172
|
-
.filter((e) => e.name !== "manifest.json")
|
|
173
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
174
|
-
const syncFileEntries = syncEntries
|
|
175
|
-
.filter((e) => e.name !== "manifest.json")
|
|
176
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
177
|
-
|
|
178
|
-
// Same set of files
|
|
179
|
-
expect(streamFileEntries.map((e) => e.name)).toEqual(
|
|
180
|
-
syncFileEntries.map((e) => e.name),
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
// Same content (verified via checksums)
|
|
184
|
-
for (let i = 0; i < streamFileEntries.length; i++) {
|
|
185
|
-
expect(sha256Hex(streamFileEntries[i].data)).toBe(
|
|
186
|
-
sha256Hex(syncFileEntries[i].data),
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Same manifest file entries (excluding timing fields)
|
|
191
|
-
const streamManifestFiles = streamResult.manifest.contents
|
|
192
|
-
.slice()
|
|
193
|
-
.sort((a, b) => a.path.localeCompare(b.path));
|
|
194
|
-
const syncManifestFiles = syncResult.manifest.contents
|
|
195
|
-
.slice()
|
|
196
|
-
.sort((a, b) => a.path.localeCompare(b.path));
|
|
197
|
-
|
|
198
|
-
expect(streamManifestFiles.map((f) => f.path)).toEqual(
|
|
199
|
-
syncManifestFiles.map((f) => f.path),
|
|
200
|
-
);
|
|
201
|
-
expect(streamManifestFiles.map((f) => f.sha256)).toEqual(
|
|
202
|
-
syncManifestFiles.map((f) => f.sha256),
|
|
203
|
-
);
|
|
204
|
-
expect(streamManifestFiles.map((f) => f.size_bytes)).toEqual(
|
|
205
|
-
syncManifestFiles.map((f) => f.size_bytes),
|
|
206
|
-
);
|
|
207
|
-
} finally {
|
|
208
|
-
await streamResult.cleanup();
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
test("cleanup removes the temp file", async () => {
|
|
213
|
-
const result = await streamExportVBundle({
|
|
214
|
-
workspaceDir: testDir,
|
|
215
|
-
...defaultV1Options(),
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
expect(existsSync(result.tempPath)).toBe(true);
|
|
219
|
-
await result.cleanup();
|
|
220
|
-
expect(existsSync(result.tempPath)).toBe(false);
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// ---------------------------------------------------------------------------
|
|
225
|
-
// Round-trip test
|
|
226
|
-
// ---------------------------------------------------------------------------
|
|
227
|
-
|
|
228
|
-
describe("streamExportVBundle round-trip", () => {
|
|
229
|
-
test("streaming archive passes validateVBundle with matching manifest", async () => {
|
|
230
|
-
const result = await streamExportVBundle({
|
|
231
|
-
workspaceDir: testDir,
|
|
232
|
-
...defaultV1Options(),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
const archiveData = new Uint8Array(readFileSync(result.tempPath));
|
|
237
|
-
const validationResult = validateVBundle(archiveData);
|
|
238
|
-
|
|
239
|
-
expect(validationResult.is_valid).toBe(true);
|
|
240
|
-
expect(validationResult.errors).toHaveLength(0);
|
|
241
|
-
expect(validationResult.manifest).toBeDefined();
|
|
242
|
-
|
|
243
|
-
// Verify manifest fields match
|
|
244
|
-
expect(validationResult.manifest!.schema_version).toBe(
|
|
245
|
-
result.manifest.schema_version,
|
|
246
|
-
);
|
|
247
|
-
expect(validationResult.manifest!.checksum).toBe(
|
|
248
|
-
result.manifest.checksum,
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
// Verify file entries match
|
|
252
|
-
const validatedFiles = validationResult
|
|
253
|
-
.manifest!.contents.slice()
|
|
254
|
-
.sort((a, b) => a.path.localeCompare(b.path));
|
|
255
|
-
const resultFiles = result.manifest.contents
|
|
256
|
-
.slice()
|
|
257
|
-
.sort((a, b) => a.path.localeCompare(b.path));
|
|
258
|
-
|
|
259
|
-
expect(validatedFiles).toEqual(resultFiles);
|
|
260
|
-
} finally {
|
|
261
|
-
await result.cleanup();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// ---------------------------------------------------------------------------
|
|
267
|
-
// Streaming config sanitization test
|
|
268
|
-
// ---------------------------------------------------------------------------
|
|
269
|
-
|
|
270
|
-
describe("streamExportVBundle config sanitization", () => {
|
|
271
|
-
test("exported config.json has environment-specific fields stripped", async () => {
|
|
272
|
-
// Write a config with environment-specific fields that should be stripped
|
|
273
|
-
const configWithEnvFields = {
|
|
274
|
-
provider: "anthropic",
|
|
275
|
-
model: "test-model",
|
|
276
|
-
ingress: {
|
|
277
|
-
publicBaseUrl: "https://my-tunnel.example.com",
|
|
278
|
-
enabled: true,
|
|
279
|
-
port: 8080,
|
|
280
|
-
},
|
|
281
|
-
daemon: {
|
|
282
|
-
autoStart: true,
|
|
283
|
-
logLevel: "debug",
|
|
284
|
-
},
|
|
285
|
-
skills: {
|
|
286
|
-
load: {
|
|
287
|
-
extraDirs: ["/home/user/custom-skills", "/opt/skills"],
|
|
288
|
-
autoReload: true,
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
memory: { enabled: true },
|
|
292
|
-
};
|
|
293
|
-
writeFileSync(testConfigPath, JSON.stringify(configWithEnvFields, null, 2));
|
|
294
|
-
|
|
295
|
-
const result = await streamExportVBundle({
|
|
296
|
-
workspaceDir: testDir,
|
|
297
|
-
...defaultV1Options(),
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
const archiveData = new Uint8Array(readFileSync(result.tempPath));
|
|
302
|
-
const entries = parseTarEntries(archiveData);
|
|
303
|
-
|
|
304
|
-
const configEntry = entries.find(
|
|
305
|
-
(e) => e.name === "workspace/config.json",
|
|
306
|
-
);
|
|
307
|
-
expect(configEntry).toBeDefined();
|
|
308
|
-
|
|
309
|
-
const parsedConfig = JSON.parse(
|
|
310
|
-
new TextDecoder().decode(configEntry!.data),
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
// Environment-specific fields should be stripped/reset
|
|
314
|
-
expect(parsedConfig.ingress.publicBaseUrl).toBe("");
|
|
315
|
-
expect(parsedConfig.ingress.enabled).toBeUndefined();
|
|
316
|
-
expect(parsedConfig.daemon).toBeUndefined();
|
|
317
|
-
expect(parsedConfig.skills.load.extraDirs).toEqual([]);
|
|
318
|
-
|
|
319
|
-
// Non-environment-specific fields should be preserved
|
|
320
|
-
expect(parsedConfig.provider).toBe("anthropic");
|
|
321
|
-
expect(parsedConfig.model).toBe("test-model");
|
|
322
|
-
expect(parsedConfig.ingress.port).toBe(8080);
|
|
323
|
-
expect(parsedConfig.skills.load.autoReload).toBe(true);
|
|
324
|
-
expect(parsedConfig.memory.enabled).toBe(true);
|
|
325
|
-
} finally {
|
|
326
|
-
// Restore original config for subsequent tests
|
|
327
|
-
writeFileSync(testConfigPath, JSON.stringify(TEST_CONFIG, null, 2));
|
|
328
|
-
await result.cleanup();
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
// ---------------------------------------------------------------------------
|
|
334
|
-
// Cleanup idempotency test
|
|
335
|
-
// ---------------------------------------------------------------------------
|
|
336
|
-
|
|
337
|
-
describe("streamExportVBundle cleanup", () => {
|
|
338
|
-
test("calling cleanup twice does not throw", async () => {
|
|
339
|
-
const result = await streamExportVBundle({
|
|
340
|
-
workspaceDir: testDir,
|
|
341
|
-
...defaultV1Options(),
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
await result.cleanup();
|
|
345
|
-
// Second call should not throw
|
|
346
|
-
await result.cleanup();
|
|
347
|
-
|
|
348
|
-
expect(existsSync(result.tempPath)).toBe(false);
|
|
349
|
-
});
|
|
350
|
-
});
|