elepha 0.1.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/LICENSE.md +375 -0
- package/README.md +135 -0
- package/bin/elepha.js +2 -0
- package/dist/adapters/base.js +600 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude-code.js +260 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.js +499 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/discriminators.js +39 -0
- package/dist/adapters/discriminators.js.map +1 -0
- package/dist/adapters/index.js +6 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/internal-command.js +3 -0
- package/dist/adapters/internal-command.js.map +1 -0
- package/dist/cli/backup-wizard.js +97 -0
- package/dist/cli/backup-wizard.js.map +1 -0
- package/dist/cli/capture-service.js +80 -0
- package/dist/cli/capture-service.js.map +1 -0
- package/dist/cli/commands/backfills.js +336 -0
- package/dist/cli/commands/backfills.js.map +1 -0
- package/dist/cli/commands/backup.js +234 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/config.js +66 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/consent.js +237 -0
- package/dist/cli/commands/consent.js.map +1 -0
- package/dist/cli/commands/daemon-control.js +76 -0
- package/dist/cli/commands/daemon-control.js.map +1 -0
- package/dist/cli/commands/doctor.js +31 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/hook.js +24 -0
- package/dist/cli/commands/hook.js.map +1 -0
- package/dist/cli/commands/import.js +611 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/init.js +19 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/inspect.js +54 -0
- package/dist/cli/commands/inspect.js.map +1 -0
- package/dist/cli/commands/install.js +49 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/internal.js +16 -0
- package/dist/cli/commands/internal.js.map +1 -0
- package/dist/cli/commands/mcp.js +12 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/projects.js +26 -0
- package/dist/cli/commands/projects.js.map +1 -0
- package/dist/cli/commands/purge.js +216 -0
- package/dist/cli/commands/purge.js.map +1 -0
- package/dist/cli/commands/reingest.js +80 -0
- package/dist/cli/commands/reingest.js.map +1 -0
- package/dist/cli/commands/rekey.js +58 -0
- package/dist/cli/commands/rekey.js.map +1 -0
- package/dist/cli/commands/restore.js +376 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/rollup.js +130 -0
- package/dist/cli/commands/rollup.js.map +1 -0
- package/dist/cli/commands/sanitize.js +72 -0
- package/dist/cli/commands/sanitize.js.map +1 -0
- package/dist/cli/commands/segment.js +153 -0
- package/dist/cli/commands/segment.js.map +1 -0
- package/dist/cli/commands/self-update.js +26 -0
- package/dist/cli/commands/self-update.js.map +1 -0
- package/dist/cli/commands/start.js +53 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/stats.js +42 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/commands/status.js +73 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/uninstall.js +23 -0
- package/dist/cli/commands/uninstall.js.map +1 -0
- package/dist/cli/config-wizard.js +104 -0
- package/dist/cli/config-wizard.js.map +1 -0
- package/dist/cli/destructive-op.js +32 -0
- package/dist/cli/destructive-op.js.map +1 -0
- package/dist/cli/import-wizard.js +89 -0
- package/dist/cli/import-wizard.js.map +1 -0
- package/dist/cli/index.js +74 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-wizard.js +80 -0
- package/dist/cli/init-wizard.js.map +1 -0
- package/dist/cli/init.js +159 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/launcher-probe.js +71 -0
- package/dist/cli/launcher-probe.js.map +1 -0
- package/dist/cli/project-path.js +16 -0
- package/dist/cli/project-path.js.map +1 -0
- package/dist/cli/purge-wizard.js +200 -0
- package/dist/cli/purge-wizard.js.map +1 -0
- package/dist/cli/restore-wizard.js +101 -0
- package/dist/cli/restore-wizard.js.map +1 -0
- package/dist/cli/shared.js +128 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli/status.js +22 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/wordmark.js +15 -0
- package/dist/cli/wordmark.js.map +1 -0
- package/dist/config/constants.js +115 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/env.js +168 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/memory-config.js +63 -0
- package/dist/config/memory-config.js.map +1 -0
- package/dist/config/paths.js +343 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/settings.js +132 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/config/version.js +12 -0
- package/dist/config/version.js.map +1 -0
- package/dist/daemon/failure-window.js +38 -0
- package/dist/daemon/failure-window.js.map +1 -0
- package/dist/daemon/heartbeat.js +40 -0
- package/dist/daemon/heartbeat.js.map +1 -0
- package/dist/daemon/index.js +873 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/log-rotation.js +27 -0
- package/dist/daemon/log-rotation.js.map +1 -0
- package/dist/daemon/readability-guard.js +89 -0
- package/dist/daemon/readability-guard.js.map +1 -0
- package/dist/daemon/rollup-service.js +239 -0
- package/dist/daemon/rollup-service.js.map +1 -0
- package/dist/daemon/update-check.js +87 -0
- package/dist/daemon/update-check.js.map +1 -0
- package/dist/daemon/work-queue.js +28 -0
- package/dist/daemon/work-queue.js.map +1 -0
- package/dist/discovery/session-projects.js +242 -0
- package/dist/discovery/session-projects.js.map +1 -0
- package/dist/hooks/codex-trust.js +80 -0
- package/dist/hooks/codex-trust.js.map +1 -0
- package/dist/hooks/common.js +81 -0
- package/dist/hooks/common.js.map +1 -0
- package/dist/hooks/hook-log.js +38 -0
- package/dist/hooks/hook-log.js.map +1 -0
- package/dist/hooks/installer.js +200 -0
- package/dist/hooks/installer.js.map +1 -0
- package/dist/hooks/session-start.js +321 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/user-prompt-submit.js +248 -0
- package/dist/hooks/user-prompt-submit.js.map +1 -0
- package/dist/install/binary.js +72 -0
- package/dist/install/binary.js.map +1 -0
- package/dist/install/config-file.js +119 -0
- package/dist/install/config-file.js.map +1 -0
- package/dist/install/daemon-health.js +48 -0
- package/dist/install/daemon-health.js.map +1 -0
- package/dist/install/daemon-service.js +309 -0
- package/dist/install/daemon-service.js.map +1 -0
- package/dist/install/doctor.js +180 -0
- package/dist/install/doctor.js.map +1 -0
- package/dist/install/health-checks.js +90 -0
- package/dist/install/health-checks.js.map +1 -0
- package/dist/install/installer.js +411 -0
- package/dist/install/installer.js.map +1 -0
- package/dist/install/launchd-backend.js +261 -0
- package/dist/install/launchd-backend.js.map +1 -0
- package/dist/install/launcher.js +224 -0
- package/dist/install/launcher.js.map +1 -0
- package/dist/install/markers.js +14 -0
- package/dist/install/markers.js.map +1 -0
- package/dist/install/platform.js +29 -0
- package/dist/install/platform.js.map +1 -0
- package/dist/install/present-tools.js +16 -0
- package/dist/install/present-tools.js.map +1 -0
- package/dist/install/self-update.js +120 -0
- package/dist/install/self-update.js.map +1 -0
- package/dist/install/service-backend.js +36 -0
- package/dist/install/service-backend.js.map +1 -0
- package/dist/install/service-manifest.js +36 -0
- package/dist/install/service-manifest.js.map +1 -0
- package/dist/install/status.js +58 -0
- package/dist/install/status.js.map +1 -0
- package/dist/install/systemd-backend.js +225 -0
- package/dist/install/systemd-backend.js.map +1 -0
- package/dist/markers.js +5 -0
- package/dist/markers.js.map +1 -0
- package/dist/mcp/installer.js +131 -0
- package/dist/mcp/installer.js.map +1 -0
- package/dist/mcp/server.js +81 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/get-context.js +3 -0
- package/dist/mcp/tools/get-context.js.map +1 -0
- package/dist/mcp/tools/list-projects.js +3 -0
- package/dist/mcp/tools/list-projects.js.map +1 -0
- package/dist/mcp/tools/save-memory.js +3 -0
- package/dist/mcp/tools/save-memory.js.map +1 -0
- package/dist/mcp/tools.js +288 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/rendering/raw-turn-renderer.js +85 -0
- package/dist/rendering/raw-turn-renderer.js.map +1 -0
- package/dist/security/file-permissions.js +15 -0
- package/dist/security/file-permissions.js.map +1 -0
- package/dist/security/provider-transcript.js +74 -0
- package/dist/security/provider-transcript.js.map +1 -0
- package/dist/security/sanitize.js +210 -0
- package/dist/security/sanitize.js.map +1 -0
- package/dist/security/self-ingestion.js +47 -0
- package/dist/security/self-ingestion.js.map +1 -0
- package/dist/security/sentinel.js +19 -0
- package/dist/security/sentinel.js.map +1 -0
- package/dist/security/subprocess-allowlist.js +421 -0
- package/dist/security/subprocess-allowlist.js.map +1 -0
- package/dist/serving/instructions.js +33 -0
- package/dist/serving/instructions.js.map +1 -0
- package/dist/serving/lexical-recall.js +249 -0
- package/dist/serving/lexical-recall.js.map +1 -0
- package/dist/serving/session-reader.js +302 -0
- package/dist/serving/session-reader.js.map +1 -0
- package/dist/storage/backfill-runner.js +34 -0
- package/dist/storage/backfill-runner.js.map +1 -0
- package/dist/storage/backup.js +46 -0
- package/dist/storage/backup.js.map +1 -0
- package/dist/storage/candidate-validator.js +77 -0
- package/dist/storage/candidate-validator.js.map +1 -0
- package/dist/storage/consent-store.js +198 -0
- package/dist/storage/consent-store.js.map +1 -0
- package/dist/storage/custom-title-backfill.js +68 -0
- package/dist/storage/custom-title-backfill.js.map +1 -0
- package/dist/storage/db.js +312 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/external-agent-import-purge.js +182 -0
- package/dist/storage/external-agent-import-purge.js.map +1 -0
- package/dist/storage/first-prompt-search-backfill.js +76 -0
- package/dist/storage/first-prompt-search-backfill.js.map +1 -0
- package/dist/storage/first-prompt-search.js +7 -0
- package/dist/storage/first-prompt-search.js.map +1 -0
- package/dist/storage/injection-store.js +37 -0
- package/dist/storage/injection-store.js.map +1 -0
- package/dist/storage/memory-store.js +428 -0
- package/dist/storage/memory-store.js.map +1 -0
- package/dist/storage/project-resolver.js +294 -0
- package/dist/storage/project-resolver.js.map +1 -0
- package/dist/storage/project-store.js +104 -0
- package/dist/storage/project-store.js.map +1 -0
- package/dist/storage/rendered-chars-backfill.js +85 -0
- package/dist/storage/rendered-chars-backfill.js.map +1 -0
- package/dist/storage/resegmentation.js +582 -0
- package/dist/storage/resegmentation.js.map +1 -0
- package/dist/storage/rollup-store.js +246 -0
- package/dist/storage/rollup-store.js.map +1 -0
- package/dist/storage/root-commit-backfill.js +32 -0
- package/dist/storage/root-commit-backfill.js.map +1 -0
- package/dist/storage/sanitize-backfill.js +184 -0
- package/dist/storage/sanitize-backfill.js.map +1 -0
- package/dist/storage/segmentation.js +87 -0
- package/dist/storage/segmentation.js.map +1 -0
- package/dist/storage/session-fields-backfill.js +196 -0
- package/dist/storage/session-fields-backfill.js.map +1 -0
- package/dist/storage/session-read-model.js +130 -0
- package/dist/storage/session-read-model.js.map +1 -0
- package/dist/storage/session-store.js +200 -0
- package/dist/storage/session-store.js.map +1 -0
- package/dist/storage/session-title-backfill.js +75 -0
- package/dist/storage/session-title-backfill.js.map +1 -0
- package/dist/storage/session-title.js +71 -0
- package/dist/storage/session-title.js.map +1 -0
- package/dist/storage/shown-session-list-store.js +33 -0
- package/dist/storage/shown-session-list-store.js.map +1 -0
- package/dist/storage/stats.js +30 -0
- package/dist/storage/stats.js.map +1 -0
- package/dist/storage/turn-store.js +202 -0
- package/dist/storage/turn-store.js.map +1 -0
- package/dist/storage/ulid.js +17 -0
- package/dist/storage/ulid.js.map +1 -0
- package/dist/summarizer/anthropic-call.js +76 -0
- package/dist/summarizer/anthropic-call.js.map +1 -0
- package/dist/summarizer/call-log.js +120 -0
- package/dist/summarizer/call-log.js.map +1 -0
- package/dist/summarizer/haiku-provider.js +136 -0
- package/dist/summarizer/haiku-provider.js.map +1 -0
- package/dist/summarizer/pricing.js +8 -0
- package/dist/summarizer/pricing.js.map +1 -0
- package/dist/summarizer/prompt-cache.js +6 -0
- package/dist/summarizer/prompt-cache.js.map +1 -0
- package/dist/summarizer/prompt.js +47 -0
- package/dist/summarizer/prompt.js.map +1 -0
- package/dist/summarizer/provider-config.js +25 -0
- package/dist/summarizer/provider-config.js.map +1 -0
- package/dist/summarizer/rollup-prompt.js +225 -0
- package/dist/summarizer/rollup-prompt.js.map +1 -0
- package/dist/summarizer/rollup-provider.js +224 -0
- package/dist/summarizer/rollup-provider.js.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util/error.js +5 -0
- package/dist/util/error.js.map +1 -0
- package/dist/util/fs.js +97 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/relative-time.js +12 -0
- package/dist/util/relative-time.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Backups of the DB file, written before any destructive operation
|
|
2
|
+
// (purge, rekey). Two gaps closed here: backups inherited the process umask
|
|
3
|
+
// (world-readable, same as the DB itself before the file-permissions fix),
|
|
4
|
+
// and nothing ever pruned them - each is a full snapshot of exactly the data
|
|
5
|
+
// the user asked to erase, so an unbounded pile of them undercuts
|
|
6
|
+
// "revocation = deletion" as badly as skipping the delete would.
|
|
7
|
+
import { chmodSync, copyFileSync, readdirSync, unlinkSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { BACKUP_KEEP, PRIVATE_FILE_MODE } from '../config/constants.js';
|
|
10
|
+
const BACKUP_MARKER = '.bak-';
|
|
11
|
+
/** Checkpoints the live database, then copies it to a timestamped sibling, mode 0600. */
|
|
12
|
+
export function writeBackup(db, dbPath) {
|
|
13
|
+
const backupPath = `${dbPath}${BACKUP_MARKER}${new Date().toISOString().replace(/[:.]/g, '-')}`;
|
|
14
|
+
const [checkpoint] = db.pragma('wal_checkpoint(TRUNCATE)');
|
|
15
|
+
if (checkpoint?.busy !== 0) {
|
|
16
|
+
throw new Error(`Backup aborted: WAL checkpoint did not complete (busy=${String(checkpoint?.busy)}); no backup was written.`);
|
|
17
|
+
}
|
|
18
|
+
copyFileSync(dbPath, backupPath);
|
|
19
|
+
chmodSync(backupPath, PRIVATE_FILE_MODE);
|
|
20
|
+
return backupPath;
|
|
21
|
+
}
|
|
22
|
+
/** Deletes every backup for dbPath except the `keep` most recent (by filename, which sorts chronologically for the ISO-derived suffix). Returns the paths deleted. */
|
|
23
|
+
export function pruneBackups(dbPath, keep) {
|
|
24
|
+
const dir = path.dirname(dbPath);
|
|
25
|
+
const prefix = `${path.basename(dbPath)}${BACKUP_MARKER}`;
|
|
26
|
+
const backups = readdirSync(dir)
|
|
27
|
+
.filter((f) => f.startsWith(prefix))
|
|
28
|
+
.map((f) => path.join(dir, f))
|
|
29
|
+
.sort();
|
|
30
|
+
const toDelete = backups.length > keep ? backups.slice(0, backups.length - keep) : [];
|
|
31
|
+
for (const p of toDelete) {
|
|
32
|
+
unlinkSync(p);
|
|
33
|
+
}
|
|
34
|
+
return toDelete;
|
|
35
|
+
}
|
|
36
|
+
/** Writes a backup, retains the configured number of snapshots, and reports both actions. */
|
|
37
|
+
export function backupDatabaseAndReport(db, dbPath, log = console.log) {
|
|
38
|
+
const backupPath = writeBackup(db, dbPath);
|
|
39
|
+
log(`\nBacked up ${dbPath} to ${backupPath}.`);
|
|
40
|
+
const pruned = pruneBackups(dbPath, BACKUP_KEEP);
|
|
41
|
+
if (pruned.length > 0) {
|
|
42
|
+
log(`Pruned ${pruned.length} older backup(s), keeping the ${BACKUP_KEEP} most recent.`);
|
|
43
|
+
}
|
|
44
|
+
return backupPath;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/storage/backup.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,4EAA4E;AAC5E,2EAA2E;AAC3E,6EAA6E;AAC7E,kEAAkE;AAClE,iEAAiE;AAEjE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAExE,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B,yFAAyF;AACzF,MAAM,UAAU,WAAW,CAAC,EAAqB,EAAE,MAAc;IAC7D,MAAM,UAAU,GAAG,GAAG,MAAM,GAAG,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;IAChG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,0BAA0B,CAA8B,CAAC;IACxF,IAAI,UAAU,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,yDAAyD,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAClI,CAAC;IACD,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACjC,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IACzC,OAAO,UAAU,CAAC;AACtB,CAAC;AAED,sKAAsK;AACtK,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,aAAa,EAAE,CAAC;IAC1D,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC;SAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;SACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;SAC7B,IAAI,EAAE,CAAC;IAEZ,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACvB,UAAU,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,uBAAuB,CAAC,EAAqB,EAAE,MAAc,EAAE,GAAG,GAA8B,OAAO,CAAC,GAAG;IACvH,MAAM,UAAU,GAAG,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3C,GAAG,CAAC,eAAe,MAAM,OAAO,UAAU,GAAG,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,GAAG,CAAC,UAAU,MAAM,CAAC,MAAM,iCAAiC,WAAW,eAAe,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,UAAU,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { SUPPORTED_TOOLS } from '../types/index.js';
|
|
2
|
+
export const CANDIDATE_SEMANTIC_TABLES = ['sessions', 'memories', 'session_rollups', 'consent_roots'];
|
|
3
|
+
const MAX_REPORTED_VIOLATIONS = 20;
|
|
4
|
+
const RULES = {
|
|
5
|
+
sessions: {
|
|
6
|
+
jsonStringArrays: [{ column: 'trailing_files' }],
|
|
7
|
+
enums: [
|
|
8
|
+
{ column: 'tool', values: SUPPORTED_TOOLS },
|
|
9
|
+
{ column: 'surface', values: ['cli', 'desktop'], nullable: true },
|
|
10
|
+
{ column: 'kind', values: ['main', 'subagent', 'fork', 'adjudicator'], nullable: true },
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
memories: {
|
|
14
|
+
jsonStringArrays: [{ column: 'files_touched' }],
|
|
15
|
+
enums: [{ column: 'has_external_content', values: [0, 1] }],
|
|
16
|
+
},
|
|
17
|
+
session_rollups: {
|
|
18
|
+
jsonStringArrays: [{ column: 'files_touched' }],
|
|
19
|
+
enums: [
|
|
20
|
+
{ column: 'kind', values: ['primary', 'subagent'] },
|
|
21
|
+
{ column: 'rollup_state', values: ['live', 'final'] },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
consent_roots: {
|
|
25
|
+
enums: [
|
|
26
|
+
{ column: 'state', values: ['approved', 'denied', 'pending'] },
|
|
27
|
+
{ column: 'source', values: ['discovery', 'cli', 'grandfathered'] },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
function isJsonStringArray(value) {
|
|
32
|
+
if (typeof value !== 'string') {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(value);
|
|
37
|
+
return Array.isArray(parsed) && parsed.every((item) => typeof item === 'string');
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function selectedColumns(rules) {
|
|
44
|
+
return [...(rules.jsonStringArrays ?? []), ...(rules.enums ?? [])].map((rule) => `"${rule.column}"`);
|
|
45
|
+
}
|
|
46
|
+
/** Validates untrusted backup values without materializing candidate tables in memory. */
|
|
47
|
+
export function validateCandidateSemantics(db, tables) {
|
|
48
|
+
const violations = [];
|
|
49
|
+
const addViolation = (violation) => {
|
|
50
|
+
if (violations.length < MAX_REPORTED_VIOLATIONS) {
|
|
51
|
+
violations.push(violation);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
violations.push(`candidate: additional violations omitted after the first ${MAX_REPORTED_VIOLATIONS}`);
|
|
55
|
+
return true;
|
|
56
|
+
};
|
|
57
|
+
for (const table of tables) {
|
|
58
|
+
const rules = RULES[table];
|
|
59
|
+
const rows = db.prepare(`SELECT ${selectedColumns(rules).join(', ')} FROM "${table}"`).iterate();
|
|
60
|
+
for (const row of rows) {
|
|
61
|
+
for (const rule of rules.jsonStringArrays ?? []) {
|
|
62
|
+
if (!isJsonStringArray(row[rule.column]) && addViolation(`${table}.${rule.column}: must be a JSON array of strings`)) {
|
|
63
|
+
return violations;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const rule of rules.enums ?? []) {
|
|
67
|
+
const value = row[rule.column];
|
|
68
|
+
const valid = (value === null && rule.nullable === true) || rule.values.includes(value);
|
|
69
|
+
if (!valid && addViolation(`${table}.${rule.column}: must be one of ${rule.values.join(', ')}`)) {
|
|
70
|
+
return violations;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return violations;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=candidate-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candidate-validator.js","sourceRoot":"","sources":["../../src/storage/candidate-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Consent roots are the ingestion boundary. They are deliberately separate
|
|
2
|
+
// from project rows: a project row is historical capture, while consent is a
|
|
3
|
+
// user decision that can cover a whole ProjectSet and later be withdrawn.
|
|
4
|
+
import { canonicalizeExisting, isRefusedProjectRoot, isWithin, normalizeForCompare, samePath } from '../config/paths.js';
|
|
5
|
+
import { ProjectResolver } from './project-resolver.js';
|
|
6
|
+
import { newUlid } from './ulid.js';
|
|
7
|
+
export const CONSENT_GRANDFATHERED_AT_KEY = 'consent_grandfathered_at';
|
|
8
|
+
function storedPathKey(rootPath) {
|
|
9
|
+
const normalized = normalizeForCompare(rootPath);
|
|
10
|
+
return normalized.length > 1 ? normalized.replace(/\/+$/, '') : normalized;
|
|
11
|
+
}
|
|
12
|
+
function prefersConsentRow(candidate, incumbent) {
|
|
13
|
+
const cs = candidate.source === 'cli' ? 1 : 0;
|
|
14
|
+
const is = incumbent.source === 'cli' ? 1 : 0;
|
|
15
|
+
if (cs !== is) {
|
|
16
|
+
return cs > is;
|
|
17
|
+
}
|
|
18
|
+
const ct = Date.parse(candidate.decided_at) || 0;
|
|
19
|
+
const it = Date.parse(incumbent.decided_at) || 0;
|
|
20
|
+
if (ct !== it) {
|
|
21
|
+
return ct > it;
|
|
22
|
+
}
|
|
23
|
+
return candidate.ulid > incumbent.ulid;
|
|
24
|
+
}
|
|
25
|
+
function canonicalPath(projectPath) {
|
|
26
|
+
return canonicalizeExisting(projectPath);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* First-open migration for pre-consent databases. It is intentionally
|
|
30
|
+
* additive: existing memories are evidence captured before consent existed,
|
|
31
|
+
* so grandfathering never deletes or rewrites them.
|
|
32
|
+
*/
|
|
33
|
+
export function grandfatherConsentRoots(db) {
|
|
34
|
+
const inserted = [];
|
|
35
|
+
const grandfather = db.transaction(() => {
|
|
36
|
+
const marker = db.prepare('SELECT 1 FROM meta WHERE key = ?').get(CONSENT_GRANDFATHERED_AT_KEY);
|
|
37
|
+
if (marker !== undefined) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const roots = new ProjectResolver(db)
|
|
41
|
+
.list()
|
|
42
|
+
.map((set) => set.gitRoot ?? set.paths[0])
|
|
43
|
+
.filter((root) => root !== undefined)
|
|
44
|
+
.map(canonicalPath);
|
|
45
|
+
const distinctRoots = [...new Map(roots.map((root) => [normalizeForCompare(root), root])).values()];
|
|
46
|
+
const now = new Date().toISOString();
|
|
47
|
+
const insert = db.prepare(`INSERT INTO consent_roots (ulid, path, state, decided_at, source)
|
|
48
|
+
VALUES (@ulid, @path, @state, @decided_at, 'grandfathered')`);
|
|
49
|
+
for (const root of distinctRoots) {
|
|
50
|
+
const state = isRefusedProjectRoot(root) ? 'denied' : 'approved';
|
|
51
|
+
const row = { ulid: newUlid(), path: root, state, decided_at: now, source: 'grandfathered' };
|
|
52
|
+
insert.run(row);
|
|
53
|
+
inserted.push(row);
|
|
54
|
+
}
|
|
55
|
+
db.prepare('INSERT INTO meta (key, value) VALUES (?, ?)').run(CONSENT_GRANDFATHERED_AT_KEY, now);
|
|
56
|
+
});
|
|
57
|
+
grandfather.immediate();
|
|
58
|
+
return inserted;
|
|
59
|
+
}
|
|
60
|
+
export function canonicalizeConsentRoots(db) {
|
|
61
|
+
const columns = new Set(db.pragma('table_info(consent_roots)').map((column) => column.name));
|
|
62
|
+
if (!['ulid', 'path', 'state', 'decided_at', 'source'].every((column) => columns.has(column))) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const rows = db.prepare('SELECT ulid, path, state, decided_at, source FROM consent_roots').all();
|
|
66
|
+
if (rows.length === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const groups = new Map();
|
|
70
|
+
for (const root of rows) {
|
|
71
|
+
const key = storedPathKey(root.path);
|
|
72
|
+
const group = groups.get(key) ?? [];
|
|
73
|
+
group.push(root);
|
|
74
|
+
groups.set(key, group);
|
|
75
|
+
}
|
|
76
|
+
const deleteRoot = db.prepare('DELETE FROM consent_roots WHERE ulid = ?');
|
|
77
|
+
db.transaction(() => {
|
|
78
|
+
for (const group of groups.values()) {
|
|
79
|
+
const winner = group.reduce((incumbent, candidate) => (prefersConsentRow(candidate, incumbent) ? candidate : incumbent));
|
|
80
|
+
for (const candidate of group) {
|
|
81
|
+
if (candidate.ulid !== winner.ulid) {
|
|
82
|
+
deleteRoot.run(candidate.ulid);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
}
|
|
88
|
+
export class ConsentStore {
|
|
89
|
+
db;
|
|
90
|
+
constructor(db) {
|
|
91
|
+
this.db = db;
|
|
92
|
+
}
|
|
93
|
+
countApproved() {
|
|
94
|
+
return this.db.prepare("SELECT COUNT(*) AS count FROM consent_roots WHERE state = 'approved'").get().count;
|
|
95
|
+
}
|
|
96
|
+
list(state) {
|
|
97
|
+
return (state === undefined
|
|
98
|
+
? this.db.prepare('SELECT ulid, path, state, decided_at, source FROM consent_roots ORDER BY path').all()
|
|
99
|
+
: this.db
|
|
100
|
+
.prepare('SELECT ulid, path, state, decided_at, source FROM consent_roots WHERE state = ? ORDER BY path')
|
|
101
|
+
.all(state));
|
|
102
|
+
}
|
|
103
|
+
remove(ulid) {
|
|
104
|
+
return this.db.prepare('DELETE FROM consent_roots WHERE ulid = ?').run(ulid).changes > 0;
|
|
105
|
+
}
|
|
106
|
+
/** An approved root covers itself and its descendants, case-insensitively on macOS. */
|
|
107
|
+
isConsented(projectPath) {
|
|
108
|
+
return this.consentState(projectPath) === 'approved';
|
|
109
|
+
}
|
|
110
|
+
isRevoked(projectPath) {
|
|
111
|
+
return this.consentState(projectPath) === 'denied';
|
|
112
|
+
}
|
|
113
|
+
isRevokedProjectSet(projectPaths) {
|
|
114
|
+
return (!projectPaths.some((projectPath) => this.isConsented(projectPath)) &&
|
|
115
|
+
projectPaths.some((projectPath) => this.isRevoked(projectPath)));
|
|
116
|
+
}
|
|
117
|
+
consentState(projectPath) {
|
|
118
|
+
return this.explicitConsentDecision(projectPath)?.state ?? 'pending';
|
|
119
|
+
}
|
|
120
|
+
explicitConsentDecision(projectPath) {
|
|
121
|
+
const canonicalProjectPath = canonicalPath(projectPath);
|
|
122
|
+
return this.list()
|
|
123
|
+
.filter((root) => root.state !== 'pending' && isWithin(root.path, canonicalProjectPath))
|
|
124
|
+
.reduce((closest, candidate) => {
|
|
125
|
+
if (closest === undefined) {
|
|
126
|
+
return candidate;
|
|
127
|
+
}
|
|
128
|
+
const candidateLength = storedPathKey(candidate.path).length;
|
|
129
|
+
const closestLength = storedPathKey(closest.path).length;
|
|
130
|
+
if (candidateLength > closestLength) {
|
|
131
|
+
return candidate;
|
|
132
|
+
}
|
|
133
|
+
// Equal depth means duplicate rows for one physical root, so the newest explicit decision must win.
|
|
134
|
+
if (candidateLength === closestLength && prefersConsentRow(candidate, closest)) {
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
return closest;
|
|
138
|
+
}, undefined);
|
|
139
|
+
}
|
|
140
|
+
/** Records an unseen root once; a pending decision must be visible, never a quiet drop. */
|
|
141
|
+
recordPending(projectPath) {
|
|
142
|
+
const canonical = canonicalPath(projectPath);
|
|
143
|
+
const current = this.list().find((root) => samePath(root.path, canonical));
|
|
144
|
+
if (current) {
|
|
145
|
+
return current;
|
|
146
|
+
}
|
|
147
|
+
const row = {
|
|
148
|
+
ulid: newUlid(),
|
|
149
|
+
path: canonical,
|
|
150
|
+
state: 'pending',
|
|
151
|
+
decided_at: new Date().toISOString(),
|
|
152
|
+
source: 'discovery',
|
|
153
|
+
};
|
|
154
|
+
this.db
|
|
155
|
+
.prepare('INSERT INTO consent_roots (ulid, path, state, decided_at, source) VALUES (@ulid, @path, @state, @decided_at, @source)')
|
|
156
|
+
.run(row);
|
|
157
|
+
return row;
|
|
158
|
+
}
|
|
159
|
+
/** Returns the effective capture-off state, recording only grantable unseen roots as pending. */
|
|
160
|
+
captureOffNudge(projectPath) {
|
|
161
|
+
const decision = this.explicitConsentDecision(projectPath);
|
|
162
|
+
if (decision?.state === 'approved') {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
if (decision) {
|
|
166
|
+
return decision;
|
|
167
|
+
}
|
|
168
|
+
return isRefusedProjectRoot(projectPath) ? 'refused' : this.recordPending(projectPath);
|
|
169
|
+
}
|
|
170
|
+
grant(projectPath) {
|
|
171
|
+
const canonical = canonicalPath(projectPath);
|
|
172
|
+
if (isRefusedProjectRoot(projectPath) || isRefusedProjectRoot(canonical)) {
|
|
173
|
+
throw new Error(`${canonical} is a refused project root and cannot be granted.`);
|
|
174
|
+
}
|
|
175
|
+
return this.setState(projectPath, 'approved', 'cli');
|
|
176
|
+
}
|
|
177
|
+
revoke(projectPath) {
|
|
178
|
+
return this.setState(projectPath, 'denied', 'cli');
|
|
179
|
+
}
|
|
180
|
+
setState(projectPath, state, source) {
|
|
181
|
+
const canonical = canonicalPath(projectPath);
|
|
182
|
+
const existing = this.list().find((root) => samePath(root.path, canonical));
|
|
183
|
+
const row = {
|
|
184
|
+
ulid: existing?.ulid ?? newUlid(),
|
|
185
|
+
path: existing?.path ?? canonical,
|
|
186
|
+
state,
|
|
187
|
+
decided_at: new Date().toISOString(),
|
|
188
|
+
source,
|
|
189
|
+
};
|
|
190
|
+
this.db
|
|
191
|
+
.prepare(`INSERT INTO consent_roots (ulid, path, state, decided_at, source)
|
|
192
|
+
VALUES (@ulid, @path, @state, @decided_at, @source)
|
|
193
|
+
ON CONFLICT(path) DO UPDATE SET state = excluded.state, decided_at = excluded.decided_at, source = excluded.source`)
|
|
194
|
+
.run(row);
|
|
195
|
+
return row;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=consent-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-store.js","sourceRoot":"","sources":["../../src/storage/consent-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Backfill Claude Code's standalone custom-title UI event into
|
|
2
|
+
// sessions.custom_title. It never parses or rewrites turns, memories, rollups,
|
|
3
|
+
// rendered output, or rendered_chars.
|
|
4
|
+
import { isReadableProviderSource } from '../config/paths.js';
|
|
5
|
+
import { applyBackfill, planBackfill } from './backfill-runner.js';
|
|
6
|
+
const deriver = {
|
|
7
|
+
load(db) {
|
|
8
|
+
return {
|
|
9
|
+
sessions: db.prepare('SELECT id, tool, native_id, source_path, custom_title FROM sessions').all(),
|
|
10
|
+
state: undefined,
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
async derive({ adapters, session }) {
|
|
14
|
+
if (!isReadableProviderSource(session.tool, session.source_path)) {
|
|
15
|
+
return {
|
|
16
|
+
sessionId: session.id,
|
|
17
|
+
nativeId: session.native_id,
|
|
18
|
+
tool: session.tool,
|
|
19
|
+
sourcePath: session.source_path,
|
|
20
|
+
before: session.custom_title,
|
|
21
|
+
after: session.custom_title,
|
|
22
|
+
transcriptMissing: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
let title;
|
|
26
|
+
try {
|
|
27
|
+
title = (await adapters[session.tool].readCustomTitle?.(session.source_path))?.customTitle;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {
|
|
31
|
+
sessionId: session.id,
|
|
32
|
+
nativeId: session.native_id,
|
|
33
|
+
tool: session.tool,
|
|
34
|
+
sourcePath: session.source_path,
|
|
35
|
+
before: session.custom_title,
|
|
36
|
+
after: session.custom_title,
|
|
37
|
+
transcriptMissing: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const after = title ?? null;
|
|
41
|
+
if (session.custom_title === after) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
sessionId: session.id,
|
|
46
|
+
nativeId: session.native_id,
|
|
47
|
+
tool: session.tool,
|
|
48
|
+
sourcePath: session.source_path,
|
|
49
|
+
before: session.custom_title,
|
|
50
|
+
after,
|
|
51
|
+
transcriptMissing: false,
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
shouldWrite: (change) => !change.transcriptMissing,
|
|
55
|
+
write(db, change) {
|
|
56
|
+
db.prepare('UPDATE sessions SET custom_title = ? WHERE id = ?').run(change.after, change.sessionId);
|
|
57
|
+
return {};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
/** Reports the exact rows a custom-title backfill would touch, without writing. */
|
|
61
|
+
export async function planCustomTitleBackfill(db, adapters) {
|
|
62
|
+
return planBackfill(db, adapters, deriver);
|
|
63
|
+
}
|
|
64
|
+
/** Applies only planned custom_title changes in one transaction. */
|
|
65
|
+
export async function applyCustomTitleBackfill(db, adapters) {
|
|
66
|
+
return applyBackfill(db, adapters, deriver);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=custom-title-backfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-title-backfill.js","sourceRoot":"","sources":["../../src/storage/custom-title-backfill.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+EAA+E;AAC/E,sCAAsC;AAGtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAwB,YAAY,EAAE,MAAM,sBAAsB,CAAC;AA0BzF,MAAM,OAAO,GAAoD;IAC7D,IAAI,CAAC,EAAE;QACH,OAAO;YACH,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,qEAAqE,CAAC,CAAC,GAAG,EAAmB;YAClH,KAAK,EAAE,SAAS;SACnB,CAAC;IACN,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE;QAC9B,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/D,OAAO;gBACH,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,QAAQ,EAAE,OAAO,CAAC,SAAS;gBAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,WAAW;gBAC/B,MAAM,EAAE,OAAO,CAAC,YAAY;gBAC5B,KAAK,EAAE,OAAO,CAAC,YAAY;gBAC3B,iBAAiB,EAAE,IAAI;aAC1B,CAAC;QACN,CAAC;QAED,IAAI,KAAyB,CAAC;QAC9B,IAAI,CAAC;YACD,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC;QAC/F,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,QAAQ,EAAE,OAAO,CAAC,SAAS;gBAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,WAAW;gBAC/B,MAAM,EAAE,OAAO,CAAC,YAAY;gBAC5B,KAAK,EAAE,OAAO,CAAC,YAAY;gBAC3B,iBAAiB,EAAE,IAAI;aAC1B,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,IAAI,IAAI,CAAC;QAC5B,IAAI,OAAO,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;YACjC,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,OAAO;YACH,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,WAAW;YAC/B,MAAM,EAAE,OAAO,CAAC,YAAY;YAC5B,KAAK;YACL,iBAAiB,EAAE,KAAK;SAC3B,CAAC;IACN,CAAC;IACD,WAAW,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,iBAAiB;IAClD,KAAK,CAAC,EAAE,EAAE,MAAM;QACZ,EAAE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACpG,OAAO,EAAE,CAAC;IACd,CAAC;CACJ,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAAY,EAAE,QAA0C;IAClG,OAAO,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,EAAY,EAAE,QAA0C;IACnG,OAAO,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC"}
|