@hasna/contacts 0.6.3 → 0.6.4

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/dist/cli/index.js CHANGED
@@ -4813,6 +4813,25 @@ async function handleExport(req) {
4813
4813
  }
4814
4814
  });
4815
4815
  }
4816
+ function handleDocumentFiles(req, segments) {
4817
+ const docId = segments[2];
4818
+ const sub = segments[3];
4819
+ if (!docId)
4820
+ return apiError("Document ID required");
4821
+ if (req.method !== "GET")
4822
+ return apiError("Method not allowed", 405);
4823
+ if (sub === "file") {
4824
+ const db = getDatabase();
4825
+ const row = db.query(`SELECT encrypted_file_path FROM contact_documents WHERE id = ?`).get(docId);
4826
+ if (!row?.encrypted_file_path || !existsSync4(row.encrypted_file_path)) {
4827
+ return new Response("No file attachment", { status: 404 });
4828
+ }
4829
+ return new Response(Bun.file(row.encrypted_file_path), {
4830
+ headers: { "Cache-Control": "public, max-age=3600" }
4831
+ });
4832
+ }
4833
+ return apiError("Use /api/documents/:id/file to get the attachment", 400);
4834
+ }
4816
4835
  async function handleImages(req, _url, segments) {
4817
4836
  const entityId = segments[2];
4818
4837
  if (!entityId)
@@ -4909,6 +4928,9 @@ function startServer(port) {
4909
4928
  case "images":
4910
4929
  response = await handleImages(req, url, segments);
4911
4930
  break;
4931
+ case "documents":
4932
+ response = handleDocumentFiles(req, segments);
4933
+ break;
4912
4934
  default:
4913
4935
  response = apiError("Not found", 404);
4914
4936
  }
@@ -6052,13 +6074,14 @@ var init_org_chart = __esm(() => {
6052
6074
  var exports_vault = {};
6053
6075
  __export(exports_vault, {
6054
6076
  unlockVault: () => unlockVault,
6077
+ storeFile: () => storeFile,
6055
6078
  requireVault: () => requireVault,
6056
6079
  lockVault: () => lockVault,
6057
6080
  isVaultUnlocked: () => isVaultUnlocked,
6058
6081
  isVaultInitialized: () => isVaultInitialized,
6059
6082
  initVault: () => initVault,
6060
6083
  getDocumentsDir: () => getDocumentsDir,
6061
- encryptFile: () => encryptFile,
6084
+ getDocumentFilePath: () => getDocumentFilePath,
6062
6085
  encrypt: () => encrypt,
6063
6086
  decryptFile: () => decryptFile,
6064
6087
  decrypt: () => decrypt
@@ -6171,20 +6194,23 @@ function decrypt(ciphertext, iv) {
6171
6194
  decrypted += decipher.final("utf8");
6172
6195
  return decrypted;
6173
6196
  }
6174
- function encryptFile(sourcePath, entityId) {
6175
- const key = requireVault();
6197
+ function storeFile(sourcePath, entityId) {
6176
6198
  if (!existsSync5(DOCUMENTS_DIR))
6177
6199
  mkdirSync4(DOCUMENTS_DIR, { recursive: true });
6200
+ const ext = sourcePath.split(".").pop() || "bin";
6201
+ const destPath = join5(DOCUMENTS_DIR, `${entityId}.${ext}`);
6178
6202
  const data = readFileSync3(sourcePath);
6179
- const iv = randomBytes(16);
6180
- const cipher = createCipheriv("aes-256-gcm", key, iv);
6181
- const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
6182
- const authTag = cipher.getAuthTag();
6183
- const destPath = join5(DOCUMENTS_DIR, `${entityId}.enc`);
6184
- const output = Buffer.concat([iv, authTag, encrypted]);
6185
- writeFileSync3(destPath, output);
6203
+ writeFileSync3(destPath, data);
6186
6204
  return destPath;
6187
6205
  }
6206
+ function getDocumentFilePath(entityId) {
6207
+ if (!existsSync5(DOCUMENTS_DIR))
6208
+ return null;
6209
+ const { readdirSync: readdirSync2 } = __require("fs");
6210
+ const files = readdirSync2(DOCUMENTS_DIR);
6211
+ const match = files.find((f) => f.startsWith(`${entityId}.`) && !f.endsWith(".enc"));
6212
+ return match ? join5(DOCUMENTS_DIR, match) : null;
6213
+ }
6188
6214
  function decryptFile(encPath) {
6189
6215
  const key = requireVault();
6190
6216
  const data = readFileSync3(encPath);
@@ -6224,11 +6250,11 @@ function addDocument(input, db) {
6224
6250
  const _db2 = db || getDatabase();
6225
6251
  const id = uuid();
6226
6252
  const { ciphertext, iv } = encrypt(input.value);
6227
- let encFilePath = null;
6253
+ let filePath = null;
6228
6254
  if (input.file_path) {
6229
- encFilePath = encryptFile(input.file_path, id);
6255
+ filePath = storeFile(input.file_path, id);
6230
6256
  }
6231
- _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, encFilePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
6257
+ _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, filePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
6232
6258
  return getDocument(id, _db2);
6233
6259
  }
6234
6260
  function getDocument(id, db) {
@@ -6269,6 +6295,7 @@ function rowToDoc(row) {
6269
6295
  label: row.label,
6270
6296
  value: decrypt(row.encrypted_value, row.iv),
6271
6297
  has_file: !!row.encrypted_file_path,
6298
+ file_path: row.encrypted_file_path,
6272
6299
  metadata: JSON.parse(row.metadata || "{}"),
6273
6300
  expires_at: row.expires_at,
6274
6301
  created_at: row.created_at,
@@ -8,6 +8,7 @@ export interface ContactDocument {
8
8
  label: string | null;
9
9
  value: string;
10
10
  has_file: boolean;
11
+ file_path: string | null;
11
12
  metadata: Record<string, unknown>;
12
13
  expires_at: string | null;
13
14
  created_at: string;
@@ -1 +1 @@
1
- {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/db/documents.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,cAAc,wSAMjB,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,eAAe,CAYtF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,eAAe,CAMtE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CASxF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAO9D"}
1
+ {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/db/documents.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,cAAc,wSAMjB,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,eAAe,CAYtF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,eAAe,CAMtE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,sBAAsB,EAAE,CASxF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAO9D"}
package/dist/index.d.ts CHANGED
@@ -62,7 +62,7 @@ export type { ParsedSignature } from "./lib/signature-parser.js";
62
62
  export { ingestMeetingParticipants } from "./lib/meeting-capture.js";
63
63
  export { findOrCreateContact } from "./db/contacts.js";
64
64
  export { saveImage, getImagePath, getImageAsBase64, deleteImage, listImages, getImagesDir } from "./lib/images.js";
65
- export { initVault, unlockVault, lockVault, isVaultUnlocked, isVaultInitialized, encrypt, decrypt, encryptFile, decryptFile, requireVault, getDocumentsDir } from "./lib/vault.js";
65
+ export { initVault, unlockVault, lockVault, isVaultUnlocked, isVaultInitialized, encrypt, decrypt, storeFile, getDocumentFilePath, decryptFile, requireVault, getDocumentsDir } from "./lib/vault.js";
66
66
  export { addDocument, getDocument, listDocuments, deleteDocument, DOCUMENT_TYPES } from "./db/documents.js";
67
67
  export type { DocumentType, ContactDocument, ContactDocumentSummary, CreateDocumentInput } from "./db/documents.js";
68
68
  export { setHealthData, getHealthData, deleteHealthData } from "./db/health.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ var __export = (target, all) => {
10
10
  });
11
11
  };
12
12
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
13
14
 
14
15
  // src/db/database.ts
15
16
  import { Database } from "bun:sqlite";
@@ -4617,20 +4618,23 @@ function decrypt(ciphertext, iv) {
4617
4618
  decrypted += decipher.final("utf8");
4618
4619
  return decrypted;
4619
4620
  }
4620
- function encryptFile(sourcePath, entityId) {
4621
- const key = requireVault();
4621
+ function storeFile(sourcePath, entityId) {
4622
4622
  if (!existsSync4(DOCUMENTS_DIR))
4623
4623
  mkdirSync3(DOCUMENTS_DIR, { recursive: true });
4624
+ const ext = sourcePath.split(".").pop() || "bin";
4625
+ const destPath = join4(DOCUMENTS_DIR, `${entityId}.${ext}`);
4624
4626
  const data = readFileSync3(sourcePath);
4625
- const iv = randomBytes(16);
4626
- const cipher = createCipheriv("aes-256-gcm", key, iv);
4627
- const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
4628
- const authTag = cipher.getAuthTag();
4629
- const destPath = join4(DOCUMENTS_DIR, `${entityId}.enc`);
4630
- const output = Buffer.concat([iv, authTag, encrypted]);
4631
- writeFileSync2(destPath, output);
4627
+ writeFileSync2(destPath, data);
4632
4628
  return destPath;
4633
4629
  }
4630
+ function getDocumentFilePath(entityId) {
4631
+ if (!existsSync4(DOCUMENTS_DIR))
4632
+ return null;
4633
+ const { readdirSync: readdirSync2 } = __require("fs");
4634
+ const files = readdirSync2(DOCUMENTS_DIR);
4635
+ const match = files.find((f) => f.startsWith(`${entityId}.`) && !f.endsWith(".enc"));
4636
+ return match ? join4(DOCUMENTS_DIR, match) : null;
4637
+ }
4634
4638
  function decryptFile(encPath) {
4635
4639
  const key = requireVault();
4636
4640
  const data = readFileSync3(encPath);
@@ -4675,11 +4679,11 @@ function addDocument(input, db) {
4675
4679
  const _db2 = db || getDatabase();
4676
4680
  const id = uuid();
4677
4681
  const { ciphertext, iv } = encrypt(input.value);
4678
- let encFilePath = null;
4682
+ let filePath = null;
4679
4683
  if (input.file_path) {
4680
- encFilePath = encryptFile(input.file_path, id);
4684
+ filePath = storeFile(input.file_path, id);
4681
4685
  }
4682
- _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, encFilePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
4686
+ _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, filePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
4683
4687
  return getDocument(id, _db2);
4684
4688
  }
4685
4689
  function getDocument(id, db) {
@@ -4720,6 +4724,7 @@ function rowToDoc(row) {
4720
4724
  label: row.label,
4721
4725
  value: decrypt(row.encrypted_value, row.iv),
4722
4726
  has_file: !!row.encrypted_file_path,
4727
+ file_path: row.encrypted_file_path,
4723
4728
  metadata: JSON.parse(row.metadata || "{}"),
4724
4729
  expires_at: row.expires_at,
4725
4730
  created_at: row.created_at,
@@ -4927,6 +4932,7 @@ export {
4927
4932
  unlockVault,
4928
4933
  unarchiveContact,
4929
4934
  unarchiveCompany,
4935
+ storeFile,
4930
4936
  setHealthData,
4931
4937
  setDealContactRole,
4932
4938
  semanticSearch,
@@ -5033,6 +5039,7 @@ export {
5033
5039
  getEvent,
5034
5040
  getEntityTeam,
5035
5041
  getDocumentsDir,
5042
+ getDocumentFilePath,
5036
5043
  getDocument,
5037
5044
  getDealsByStage,
5038
5045
  getDealTeam,
@@ -5060,7 +5067,6 @@ export {
5060
5067
  extractContactsFromEmailThread,
5061
5068
  exportFromApple,
5062
5069
  exportContacts,
5063
- encryptFile,
5064
5070
  encrypt,
5065
5071
  embedContact,
5066
5072
  embedAllContacts,
@@ -9,7 +9,16 @@ export declare function encrypt(plaintext: string): {
9
9
  iv: string;
10
10
  };
11
11
  export declare function decrypt(ciphertext: string, iv: string): string;
12
- export declare function encryptFile(sourcePath: string, entityId: string): string;
12
+ /**
13
+ * Store a file attachment (PLAIN, not encrypted) so agents can access it directly.
14
+ * Text values in the DB are encrypted; file attachments are plain for agent access.
15
+ * Returns the destination path.
16
+ */
17
+ export declare function storeFile(sourcePath: string, entityId: string): string;
18
+ /**
19
+ * Get the file path for a document attachment. Returns null if no file exists.
20
+ */
21
+ export declare function getDocumentFilePath(entityId: string): string | null;
13
22
  export declare function decryptFile(encPath: string): Buffer;
14
23
  export declare function getDocumentsDir(): string;
15
24
  //# sourceMappingURL=vault.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../src/lib/vault.ts"],"names":[],"mappings":"AAgDA,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAUlD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAUvD;AAED,wBAAgB,SAAS,IAAI,IAAI,CAGhC;AAED,wBAAgB,eAAe,IAAI,OAAO,CASzC;AAED,wBAAgB,YAAY,IAAI,MAAM,CASrC;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAQ7E;AAED,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAaxE;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,eAAe,IAAI,MAAM,CAGxC"}
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../src/lib/vault.ts"],"names":[],"mappings":"AAgDA,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAUlD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAUvD;AAED,wBAAgB,SAAS,IAAI,IAAI,CAGhC;AAED,wBAAgB,eAAe,IAAI,OAAO,CASzC;AAED,wBAAgB,YAAY,IAAI,MAAM,CASrC;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAQ7E;AAED,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,eAAe,IAAI,MAAM,CAGxC"}
package/dist/mcp/index.js CHANGED
@@ -4431,18 +4431,13 @@ function decrypt(ciphertext, iv) {
4431
4431
  decrypted += decipher.final("utf8");
4432
4432
  return decrypted;
4433
4433
  }
4434
- function encryptFile(sourcePath, entityId) {
4435
- const key = requireVault();
4434
+ function storeFile(sourcePath, entityId) {
4436
4435
  if (!existsSync4(DOCUMENTS_DIR))
4437
4436
  mkdirSync3(DOCUMENTS_DIR, { recursive: true });
4437
+ const ext = sourcePath.split(".").pop() || "bin";
4438
+ const destPath = join4(DOCUMENTS_DIR, `${entityId}.${ext}`);
4438
4439
  const data = readFileSync3(sourcePath);
4439
- const iv = randomBytes(16);
4440
- const cipher = createCipheriv("aes-256-gcm", key, iv);
4441
- const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
4442
- const authTag = cipher.getAuthTag();
4443
- const destPath = join4(DOCUMENTS_DIR, `${entityId}.enc`);
4444
- const output = Buffer.concat([iv, authTag, encrypted]);
4445
- writeFileSync2(destPath, output);
4440
+ writeFileSync2(destPath, data);
4446
4441
  return destPath;
4447
4442
  }
4448
4443
 
@@ -4475,11 +4470,11 @@ function addDocument(input, db) {
4475
4470
  const _db2 = db || getDatabase();
4476
4471
  const id = uuid();
4477
4472
  const { ciphertext, iv } = encrypt(input.value);
4478
- let encFilePath = null;
4473
+ let filePath = null;
4479
4474
  if (input.file_path) {
4480
- encFilePath = encryptFile(input.file_path, id);
4475
+ filePath = storeFile(input.file_path, id);
4481
4476
  }
4482
- _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, encFilePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
4477
+ _db2.query(`INSERT INTO contact_documents (id, contact_id, doc_type, label, encrypted_value, iv, encrypted_file_path, metadata, expires_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(id, input.contact_id, input.doc_type, input.label ?? null, ciphertext, iv, filePath, JSON.stringify(input.metadata || {}), input.expires_at ?? null, now(), now());
4483
4478
  return getDocument(id, _db2);
4484
4479
  }
4485
4480
  function getDocument(id, db) {
@@ -4520,6 +4515,7 @@ function rowToDoc(row) {
4520
4515
  label: row.label,
4521
4516
  value: decrypt(row.encrypted_value, row.iv),
4522
4517
  has_file: !!row.encrypted_file_path,
4518
+ file_path: row.encrypted_file_path,
4523
4519
  metadata: JSON.parse(row.metadata || "{}"),
4524
4520
  expires_at: row.expires_at,
4525
4521
  created_at: row.created_at,
@@ -6192,10 +6188,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
6192
6188
  { name: "vault_unlock", description: "Unlock the vault for this session with a passphrase.", inputSchema: { type: "object", properties: { passphrase: { type: "string" } }, required: ["passphrase"] } },
6193
6189
  { name: "vault_lock", description: "Lock the vault, clearing the encryption key from memory.", inputSchema: { type: "object", properties: {} } },
6194
6190
  { name: "vault_status", description: "Check vault initialization and lock status.", inputSchema: { type: "object", properties: {} } },
6195
- { name: "add_document", description: "Store an encrypted document for a contact (passport, tax_id, medical_record, etc.). Vault must be unlocked.", inputSchema: { type: "object", properties: { contact_id: { type: "string" }, doc_type: { type: "string", enum: [...DOCUMENT_TYPES] }, label: { type: "string" }, value: { type: "string", description: "Plaintext value (will be encrypted)" }, file_path: { type: "string", description: "Optional file to encrypt and attach" }, metadata: { type: "object" }, expires_at: { type: "string" } }, required: ["contact_id", "doc_type", "value"] } },
6196
- { name: "list_documents", description: "List documents for a contact (metadata only \u2014 no decryption needed).", inputSchema: { type: "object", properties: { contact_id: { type: "string" } }, required: ["contact_id"] } },
6197
- { name: "get_document", description: "Get a document with decrypted value. Vault must be unlocked.", inputSchema: { type: "object", properties: { document_id: { type: "string" } }, required: ["document_id"] } },
6198
- { name: "delete_document", description: "Delete a document and its encrypted file.", inputSchema: { type: "object", properties: { document_id: { type: "string" } }, required: ["document_id"] } },
6191
+ { name: "add_document", description: "Store a document for a contact (passport, tax_id, medical_record, etc.). Text values are encrypted; file attachments are stored plain so agents can read them. Vault must be unlocked.", inputSchema: { type: "object", properties: { contact_id: { type: "string" }, doc_type: { type: "string", enum: [...DOCUMENT_TYPES] }, label: { type: "string" }, value: { type: "string", description: "Plaintext value (will be encrypted in DB)" }, file_path: { type: "string", description: "File to attach \u2014 stored PLAIN in ~/.contacts/documents/ for agent access" }, metadata: { type: "object" }, expires_at: { type: "string" } }, required: ["contact_id", "doc_type", "value"] } },
6192
+ { name: "list_documents", description: "List documents for a contact (metadata only \u2014 no decryption needed). Returns file_path for attachments so agents can read them directly.", inputSchema: { type: "object", properties: { contact_id: { type: "string" } }, required: ["contact_id"] } },
6193
+ { name: "get_document", description: "Get a document with decrypted value and file_path. Vault must be unlocked for the text value; file is always accessible.", inputSchema: { type: "object", properties: { document_id: { type: "string" } }, required: ["document_id"] } },
6194
+ { name: "get_document_file", description: "Get the plain file path for a document attachment. Agents can read this file directly \u2014 it is NOT encrypted. Returns null if no file attached.", inputSchema: { type: "object", properties: { document_id: { type: "string" } }, required: ["document_id"] } },
6195
+ { name: "delete_document", description: "Delete a document and its file attachment.", inputSchema: { type: "object", properties: { document_id: { type: "string" } }, required: ["document_id"] } },
6199
6196
  { name: "scan_document", description: "Scan a document image using AI vision (OpenAI GPT-4o) to extract structured data. Optionally auto-save to vault.", inputSchema: { type: "object", properties: { image: { type: "string", description: "File path or base64 image data" }, doc_type: { type: "string", description: "Hint: passport, national_id, drivers_license, etc." }, contact_id: { type: "string", description: "Contact to associate scanned document with" }, auto_save: { type: "boolean", description: "Automatically save extracted data as a vault document" } }, required: ["image"] } },
6200
6197
  { name: "set_health_data", description: "Set or update health data for a contact. Vault must be unlocked.", inputSchema: { type: "object", properties: { contact_id: { type: "string" }, blood_type: { type: "string" }, allergies: { type: "array", items: { type: "string" } }, medical_conditions: { type: "array", items: { type: "string" } }, medications: { type: "array", items: { type: "string" } }, emergency_contacts: { type: "array", items: { type: "object", properties: { name: { type: "string" }, phone: { type: "string" }, relationship: { type: "string" } }, required: ["name", "phone", "relationship"] } }, health_insurance_provider: { type: "string" }, health_insurance_id: { type: "string" }, primary_physician: { type: "string" }, primary_physician_phone: { type: "string" }, organ_donor: { type: "boolean" }, notes: { type: "string" } }, required: ["contact_id"] } },
6201
6198
  { name: "get_health_data", description: "Get health data for a contact. Vault must be unlocked.", inputSchema: { type: "object", properties: { contact_id: { type: "string" } }, required: ["contact_id"] } },
@@ -7783,6 +7780,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
7783
7780
  const doc = getDocument(a.document_id);
7784
7781
  return { content: [{ type: "text", text: JSON.stringify(doc, null, 2) }] };
7785
7782
  }
7783
+ case "get_document_file": {
7784
+ const db = getDatabase();
7785
+ const row = db.query(`SELECT encrypted_file_path FROM contact_documents WHERE id = ?`).get(a.document_id);
7786
+ if (!row)
7787
+ return { content: [{ type: "text", text: JSON.stringify({ error: "Document not found" }) }], isError: true };
7788
+ const filePath = row.encrypted_file_path;
7789
+ return { content: [{ type: "text", text: JSON.stringify({ document_id: a.document_id, file_path: filePath, has_file: !!filePath }) }] };
7790
+ }
7786
7791
  case "delete_document": {
7787
7792
  deleteDocument(a.document_id);
7788
7793
  return { content: [{ type: "text", text: JSON.stringify({ deleted: true }) }] };
@@ -2035,6 +2035,25 @@ async function handleExport(req) {
2035
2035
  }
2036
2036
  });
2037
2037
  }
2038
+ function handleDocumentFiles(req, segments) {
2039
+ const docId = segments[2];
2040
+ const sub = segments[3];
2041
+ if (!docId)
2042
+ return apiError("Document ID required");
2043
+ if (req.method !== "GET")
2044
+ return apiError("Method not allowed", 405);
2045
+ if (sub === "file") {
2046
+ const db = getDatabase();
2047
+ const row = db.query(`SELECT encrypted_file_path FROM contact_documents WHERE id = ?`).get(docId);
2048
+ if (!row?.encrypted_file_path || !existsSync3(row.encrypted_file_path)) {
2049
+ return new Response("No file attachment", { status: 404 });
2050
+ }
2051
+ return new Response(Bun.file(row.encrypted_file_path), {
2052
+ headers: { "Cache-Control": "public, max-age=3600" }
2053
+ });
2054
+ }
2055
+ return apiError("Use /api/documents/:id/file to get the attachment", 400);
2056
+ }
2038
2057
  async function handleImages(req, _url, segments) {
2039
2058
  const entityId = segments[2];
2040
2059
  if (!entityId)
@@ -2131,6 +2150,9 @@ function startServer(port) {
2131
2150
  case "images":
2132
2151
  response = await handleImages(req, url, segments);
2133
2152
  break;
2153
+ case "documents":
2154
+ response = handleDocumentFiles(req, segments);
2155
+ break;
2134
2156
  default:
2135
2157
  response = apiError("Not found", 404);
2136
2158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAoVA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAyE9C"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AA2WA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA4E9C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/contacts",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Contact management for AI coding agents — CLI + MCP + Web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",