@hasna/contacts 0.6.36 → 0.7.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.
Files changed (50) hide show
  1. package/README.md +53 -69
  2. package/dist/cli/commands/advanced.d.ts.map +1 -1
  3. package/dist/cli/commands/core.d.ts +1 -1
  4. package/dist/cli/commands/core.d.ts.map +1 -1
  5. package/dist/cli/commands/crm.d.ts.map +1 -1
  6. package/dist/cli/index.js +9158 -39958
  7. package/dist/cli/legacy.d.ts +18 -0
  8. package/dist/cli/legacy.d.ts.map +1 -0
  9. package/dist/cli/status-domain.preload.d.ts +2 -0
  10. package/dist/cli/status-domain.preload.d.ts.map +1 -0
  11. package/dist/cli/storage.d.ts.map +1 -1
  12. package/dist/cloud/client-config.d.ts +6 -0
  13. package/dist/cloud/client-config.d.ts.map +1 -0
  14. package/dist/cloud/http-storage.d.ts +40 -69
  15. package/dist/cloud/http-storage.d.ts.map +1 -1
  16. package/dist/db/paths.d.ts +13 -7
  17. package/dist/db/paths.d.ts.map +1 -1
  18. package/dist/generated/storage-kit/index.d.ts +0 -1
  19. package/dist/generated/storage-kit/index.d.ts.map +1 -1
  20. package/dist/generated/storage-kit/pool.d.ts +13 -3
  21. package/dist/generated/storage-kit/pool.d.ts.map +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +373 -5713
  24. package/dist/lib/images.d.ts.map +1 -1
  25. package/dist/mcp/handlers/advanced.d.ts.map +1 -1
  26. package/dist/mcp/handlers/core.d.ts +1 -1
  27. package/dist/mcp/index.js +461 -5901
  28. package/dist/mcp/storage-tools.d.ts.map +1 -1
  29. package/dist/sdk/index.d.ts +15 -13
  30. package/dist/sdk/index.d.ts.map +1 -1
  31. package/dist/sdk/index.js +44 -1
  32. package/dist/server/cloud.d.ts +6 -7
  33. package/dist/server/cloud.d.ts.map +1 -1
  34. package/dist/server/index.d.ts +2 -1
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +3744 -35305
  37. package/dist/server/security.d.ts +1 -1
  38. package/dist/server/security.d.ts.map +1 -1
  39. package/dist/server/serve.d.ts.map +1 -1
  40. package/dist/store/index.d.ts +66 -93
  41. package/dist/store/index.d.ts.map +1 -1
  42. package/dist/types/store-dto.d.ts +273 -0
  43. package/dist/types/store-dto.d.ts.map +1 -0
  44. package/hasna.contract.json +63 -10
  45. package/package.json +23 -14
  46. package/dashboard/dist/assets/index-0l6aQb1t.css +0 -1
  47. package/dashboard/dist/assets/index-opnZdkVD.js +0 -229
  48. package/dashboard/dist/index.html +0 -13
  49. package/dist/generated/storage-kit/mode.d.ts +0 -48
  50. package/dist/generated/storage-kit/mode.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hasna/contacts
2
2
 
3
- Contact management for AI coding agents — CLI + MCP + Web
3
+ Contact management for AI coding agents — CLI + MCP + authenticated HTTP API
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@hasna/contacts)](https://www.npmjs.com/package/@hasna/contacts)
6
6
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
@@ -11,12 +11,38 @@ Contact management for AI coding agents — CLI + MCP + Web
11
11
  npm install -g @hasna/contacts
12
12
  ```
13
13
 
14
+ ## Configure the client
15
+
16
+ Every CLI, MCP, and package data operation uses one authenticated HTTPS `/v1`
17
+ authority. There is no built-in hosted URL and no local database fallback.
18
+
19
+ ```bash
20
+ export HASNA_CONTACTS_API_URL="https://contacts.example.com"
21
+ # Provision the API key through the @hasna/contracts credential chain. For
22
+ # example, put HASNA_CONTACTS_API_KEY in the shared fleet/config credential chain,
23
+ # or configure HASNA_CONTACTS_API_KEY_REF for the secrets client.
24
+ contacts connection --json
25
+ ```
26
+
27
+ An absent or invalid URL/key fails closed. `HASNA_CONTACTS_STORAGE_MODE`,
28
+ `CONTACTS_STORAGE_MODE`, contacts DB-path variables, and contacts database URLs
29
+ are rejected in client processes. PostgreSQL URLs belong only to
30
+ `contacts-serve` and the migration task.
31
+
14
32
  ## CLI Usage
15
33
 
16
34
  ```bash
35
+ contacts status # CLI version, API endpoint, storage mode, record counts
36
+ contacts status --json
17
37
  contacts --help
18
38
  ```
19
39
 
40
+ `contacts status` answers even on a box without an API key: an unconfigured
41
+ client reports storage `unconfigured` (a failed request on a configured box
42
+ reports storage `error` with the failure message) instead of crashing, so
43
+ agents can observe the configuration drift the command exists to expose.
44
+
45
+
20
46
  ## Audiences, consent, and suppression
21
47
 
22
48
  Audience segments implement the `hasna.audience.v1` contract (distribution
@@ -63,7 +89,7 @@ MCP_HTTP=1 contacts-mcp
63
89
  - Health: `GET http://127.0.0.1:8809/health`
64
90
  - MCP: `http://127.0.0.1:8809/mcp`
65
91
 
66
- The REST server (`contacts-serve`) also exposes `/health` and `/mcp` when running.
92
+ The REST server is a separate authenticated `/v1` surface.
67
93
 
68
94
  ## REST API
69
95
 
@@ -72,83 +98,41 @@ contacts-serve
72
98
  ```
73
99
 
74
100
  `contacts-serve` binds to `127.0.0.1` by default. Use `--host <host>` or
75
- `CONTACTS_HOST=<host>` only when intentionally exposing it beyond loopback.
76
- Shared binds still fail closed unless a valid contacts token is configured and
77
- sent with the request. The unauthenticated local development fallback is disabled
78
- by default and only activates when all of the following are true:
79
-
80
- - no contacts API token environment variable is configured
81
- - `CONTACTS_ALLOW_UNAUTHENTICATED_LOOPBACK=1`
82
- - the server is explicitly bound to a loopback host
83
-
84
- The fallback does not trust the HTTP `Host` header.
101
+ `CONTACTS_HOST=<host>` only when intentionally exposing it beyond loopback. The
102
+ server requires PostgreSQL configuration and API-key signing configuration;
103
+ readiness fails closed when either is unavailable.
85
104
 
86
- ## Storage
105
+ ## Storage and legacy data
87
106
 
88
- Contacts owns its local SQLite storage directly. It does not depend on shared
89
- cloud runtime commands or MCP tools.
107
+ The client never opens SQLite or PostgreSQL. The server owns PostgreSQL and all
108
+ authoritative data remains server-side. Inspect the value-free connection state
109
+ with:
90
110
 
91
111
  ```bash
92
- contacts storage status
93
- contacts storage status --json
94
- contacts storage push --tables contacts,companies
95
- contacts storage pull --tables contacts,companies
96
- contacts storage sync
112
+ contacts connection --json
97
113
  ```
98
114
 
99
- Optional cross-machine sync uses contacts-owned PostgreSQL storage. Set one of:
115
+ Retired local databases are never auto-adopted or silently ignored. The
116
+ explicit migration aid only inspects and copies them; it never opens, changes,
117
+ deletes, or selects one as the live store:
100
118
 
101
119
  ```bash
102
- export HASNA_CONTACTS_POSTGRES_URL="postgres://..."
103
- # or OPEN_CONTACTS_POSTGRES_URL / CONTACTS_POSTGRES_URL
120
+ contacts legacy inspect --json
121
+ contacts legacy preserve --source /exact/path/contacts.db \
122
+ --output /existing/directory/contacts.db.pre-https.20260901
104
123
  ```
105
124
 
106
- Remote PostgreSQL connections require verified TLS for non-local hosts. Local
107
- PostgreSQL development URLs can disable TLS explicitly.
108
-
109
- By default, remote sync covers contacts, companies, tags, and the other
110
- non-sensitive relationship tables. `webhooks`, `contact_documents`, and
111
- `contact_health` are excluded until explicitly requested with `--tables` and
112
- `HASNA_CONTACTS_ALLOW_SENSITIVE_SYNC=1`. Sync inserts or updates rows with
113
- timestamp conflict protection. Deletes for `contacts`, `companies`, and `tags`
114
- write `_contacts_tombstones`; push/pull sync carries those tombstones and pull
115
- applies them unless the local row has a newer `updated_at`.
116
-
117
- Shared REST/dashboard deployments must set one of
118
- `HASNA_CONTACTS_API_TOKENS`, `OPEN_CONTACTS_API_TOKENS`, or
119
- `CONTACTS_API_TOKENS`. Values are comma-separated `token=scope scope` records.
120
- Supported scopes include `contacts:read`, `contacts:write`,
121
- `contacts:import`, `contacts:export`, `contacts:export:full`,
122
- `documents:read`, `images:read`, `images:write`, `companies:*`, `tags:*`,
123
- `stats:read`, `dashboard:read`, and `mcp:access`. Loopback-only development
124
- without configured tokens remains allowed; shared hosts fail closed.
125
-
126
- Server exports are redacted by default: email addresses, phone numbers,
127
- addresses, notes, birthdays, social profiles, and custom fields are withheld.
128
- Full exports require both `contacts:export` and `contacts:export:full`. Export,
129
- import, document file read, image mutation, contact mutation, company mutation,
130
- and tag mutation routes write audit entries. Document attachments are served
131
- only from the managed contacts documents directory and use private `no-store`
132
- cache headers.
133
-
134
- `contacts cloud status`, `contacts cloud push`, `contacts cloud pull`, and
135
- `contacts cloud sync` remain compatibility aliases for the contacts-owned
136
- storage commands. They do not load or depend on the deprecated shared cloud
137
- runtime. `contacts cloud feedback` saves feedback locally in the contacts
138
- database.
139
-
140
- ## Data Directory
141
-
142
- On-box data resolves through the XDG dirs per `@hasna/paths`:
143
-
144
- - documents, the SQLite store, `config.json` and the vault config live in the
145
- **XDG data root**: `~/.local/share/hasna/contacts/` (or `$HASNA_DATA_HOME/contacts`).
146
- - the vault session state lives in the **XDG state root**:
147
- `~/.local/state/hasna/contacts/` (or `$HASNA_STATE_HOME/contacts`).
148
-
149
- The legacy `~/.hasna/contacts/` home is never written to; on first use any
150
- pre-existing legacy store is adopted into the XDG roots (never clobbering an
151
- existing XDG store).
125
+ If a SQLite WAL, journal, or shared-memory sidecar is present, preservation
126
+ refuses to proceed until every legacy process is stopped and the old client has checkpointed the database. To move
127
+ portable contact records, use a legacy release against the preserved copy to
128
+ export JSON, then run `contacts import exported.json` with the HTTPS client
129
+ configured. Existing files are never overwritten.
130
+
131
+ Preservation rejects source, ancestor, or output replacement races and verifies
132
+ the copied bytes with SHA-256 and stable output metadata before success. If a copy
133
+ fails after output creation, any private partial output is left untouched and
134
+ reported as unverified for manual inspection; the command never deletes a
135
+ pathname that another process might have replaced.
152
136
 
153
137
  ## License
154
138
 
@@ -1 +1 @@
1
- {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/advanced.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAs5B/D"}
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/advanced.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAq5B/D"}
@@ -1,3 +1,3 @@
1
1
  import type { Command } from "commander";
2
- export declare function registerCoreCommands(program: Command): void;
2
+ export declare function registerCoreCommands(program: Command, version: string): void;
3
3
  //# sourceMappingURL=core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/core.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA87B3D"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/core.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAg4B5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"crm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAm+B1D"}
1
+ {"version":3,"file":"crm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAi+B1D"}