@hasna/contacts 0.7.0 → 0.9.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/README.md +93 -13
- package/dist/browser/cli.d.ts +4 -0
- package/dist/browser/cli.d.ts.map +1 -0
- package/dist/browser/identity.d.ts +3 -0
- package/dist/browser/identity.d.ts.map +1 -0
- package/dist/browser/install.d.ts +32 -0
- package/dist/browser/install.d.ts.map +1 -0
- package/dist/browser/native.d.ts +3 -0
- package/dist/browser/native.d.ts.map +1 -0
- package/dist/browser/native.js +822 -0
- package/dist/browser/protocol.d.ts +26 -0
- package/dist/browser/protocol.d.ts.map +1 -0
- package/dist/browser/values.d.ts +18 -0
- package/dist/browser/values.d.ts.map +1 -0
- package/dist/cli/commands/core.d.ts.map +1 -1
- package/dist/cli/index.js +479 -149
- package/dist/cli/status-domain.preload.d.ts +1 -1
- package/dist/cli/status-domain.preload.d.ts.map +1 -1
- package/dist/cli/status-fixture.d.ts +17 -0
- package/dist/cli/status-fixture.d.ts.map +1 -0
- package/dist/cloud/http-storage.d.ts +20 -12
- package/dist/cloud/http-storage.d.ts.map +1 -1
- package/dist/cloud/resolver-inputs.d.ts +51 -0
- package/dist/cloud/resolver-inputs.d.ts.map +1 -0
- package/dist/db/paths.d.ts +4 -4
- package/dist/db/paths.d.ts.map +1 -1
- package/dist/generated/storage-kit/backend.d.ts +19 -0
- package/dist/generated/storage-kit/backend.d.ts.map +1 -0
- package/dist/generated/storage-kit/index.d.ts +2 -1
- package/dist/generated/storage-kit/index.d.ts.map +1 -1
- package/dist/generated/storage-kit/migrations.d.ts +21 -0
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -1
- package/dist/generated/storage-kit/own.d.ts +11 -0
- package/dist/generated/storage-kit/own.d.ts.map +1 -0
- package/dist/generated/storage-kit/pool.d.ts +5 -17
- package/dist/generated/storage-kit/pool.d.ts.map +1 -1
- package/dist/generated/storage-kit/query.d.ts +1 -1
- package/dist/generated/storage-kit/query.d.ts.map +1 -1
- package/dist/generated/storage-kit/tls.d.ts +30 -3
- package/dist/generated/storage-kit/tls.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -28
- package/dist/lib/audience-contract.d.ts +9 -9
- package/dist/lib/compact-output.d.ts +67 -0
- package/dist/lib/compact-output.d.ts.map +1 -0
- package/dist/mcp/handlers/core.d.ts.map +1 -1
- package/dist/mcp/index.d.ts +11 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +490 -212
- package/dist/mcp/profile.d.ts +8 -0
- package/dist/mcp/profile.d.ts.map +1 -0
- package/dist/mcp/register-tools.d.ts +3 -1
- package/dist/mcp/register-tools.d.ts.map +1 -1
- package/dist/mcp/startup-gate.d.ts +48 -0
- package/dist/mcp/startup-gate.d.ts.map +1 -0
- package/dist/mcp/storage-tools.d.ts +2 -1
- package/dist/mcp/storage-tools.d.ts.map +1 -1
- package/dist/mcp/tools.d.ts +7 -45
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +70 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +990 -7
- package/dist/server/index.js +231 -59
- package/dist/server/pg-store.d.ts +1 -0
- package/dist/server/pg-store.d.ts.map +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/docs/chrome-autofill.md +45 -0
- package/extension/background.js +284 -0
- package/extension/content.js +387 -0
- package/extension/detect.js +228 -0
- package/extension/fill.js +112 -0
- package/extension/icons/128.png +0 -0
- package/extension/icons/16.png +0 -0
- package/extension/icons/32.png +0 -0
- package/extension/icons/48.png +0 -0
- package/extension/icons/icon.svg +17 -0
- package/extension/manifest.json +54 -0
- package/extension/popup.css +78 -0
- package/extension/popup.html +47 -0
- package/extension/popup.js +166 -0
- package/hasna.contract.json +20 -6
- package/package.json +10 -6
- package/dist/lib/config.d.ts +0 -7
- package/dist/lib/config.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -11,36 +11,100 @@ Contact management for AI coding agents — CLI + MCP + authenticated HTTP API
|
|
|
11
11
|
npm install -g @hasna/contacts
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
## Chrome extension
|
|
15
|
+
|
|
16
|
+
The package ships a Chrome extension that fills name, email, phone, company
|
|
17
|
+
and address fields from your contacts — from the toolbar popup or from the
|
|
18
|
+
Contacts badge that appears inside detected form fields. It uses the same
|
|
19
|
+
hosted API and credential as the CLI. Run `contacts browser install`, load the
|
|
20
|
+
printed `extensionPath` unpacked in `chrome://extensions`, and see
|
|
21
|
+
[docs/chrome-autofill.md](docs/chrome-autofill.md) for how detection, the
|
|
22
|
+
picker and the security boundaries work.
|
|
23
|
+
|
|
14
24
|
## Configure the client
|
|
15
25
|
|
|
16
26
|
Every CLI, MCP, and package data operation uses one authenticated HTTPS `/v1`
|
|
17
|
-
authority
|
|
27
|
+
authority resolved by the shared `@hasna/contracts` client chain
|
|
28
|
+
(hasna/apps#1720), resolved fresh on every request. There is no local database
|
|
29
|
+
fallback and no per-app env chain of its own.
|
|
30
|
+
|
|
31
|
+
Once a contacts API key resolves from any tier, the authority defaults to the
|
|
32
|
+
fleet gateway `https://api.hasna.com/contacts` — no URL configuration is
|
|
33
|
+
needed on a station. The credential tiers, in order:
|
|
34
|
+
|
|
35
|
+
1. explicit arguments / deliberate pointers — `HASNA_CONTACTS_API_KEY_OVERRIDE`, `HASNA_PROFILE`, `HASNA_CONTACTS_API_KEY_REF` (secrets vault)
|
|
36
|
+
2. macOS Keychain — `hasna.credentials.contacts.api-key` / `.api-url`, account `HASNA_STATION` → `hostname -s` → `$USER`
|
|
37
|
+
3. disk — `~/.hasna/contacts/config/credentials` (owner-only 0400/0600, `HASNA_CONTACTS_API_KEY=…` or the `HASNA_CONTACTS_API_URL=…` alias)
|
|
38
|
+
4. environment — `HASNA_CONTACTS_API_KEY`
|
|
39
|
+
|
|
40
|
+
| Env var | Meaning |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `HASNA_CONTACTS_API_URL` | Explicit API base URL (HTTPS; overrides the fleet gateway). Legacy alias: `CONTACTS_API_URL`. |
|
|
43
|
+
| `HASNA_CONTACTS_API_KEY` | API key (env tier). Legacy alias: `CONTACTS_API_KEY`. |
|
|
44
|
+
| `HASNA_CONTACTS_API_KEY_OVERRIDE` | Deliberate per-run override that outranks the Keychain and disk. |
|
|
45
|
+
| `HASNA_CONTACTS_API_KEY_REF` | Secrets-vault pointer (`namespace/app/live/api_key`); terminal when unresolvable. |
|
|
46
|
+
| `HASNA_PROFILE` | Selects which identity (`credentials-<profile>`) the disk tier reads. |
|
|
47
|
+
| `HASNA_STATION` | Keychain account when set; else short hostname, then `$USER`. |
|
|
48
|
+
| `HASNA_HOME` | Replaces `~` for the `~/.hasna/…` credential/disk root. |
|
|
49
|
+
| `HASNA_CONFIG_HOME` | Replaces `~/.hasna/<app>/config` entirely. |
|
|
18
50
|
|
|
19
51
|
```bash
|
|
52
|
+
# Fully explicit:
|
|
20
53
|
export HASNA_CONTACTS_API_URL="https://contacts.example.com"
|
|
21
|
-
#
|
|
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.
|
|
54
|
+
export HASNA_CONTACTS_API_KEY="…" # or configure the Keychain/disk tiers
|
|
24
55
|
contacts connection --json
|
|
25
56
|
```
|
|
26
57
|
|
|
27
|
-
An absent
|
|
28
|
-
`
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
An absent URL and key fails closed: operations exit non-zero and never open a
|
|
59
|
+
local store; `contacts connection` reports `transport: "unconfigured"`.
|
|
60
|
+
The fail-closed message starts on the FIRST stderr line — it names what is
|
|
61
|
+
missing and where the credential should live (`HASNA_CONTACTS_API_KEY`, the
|
|
62
|
+
Keychain item, the credentials-file path), never a value.
|
|
63
|
+
`HASNA_CONTACTS_STORAGE_MODE`, `CONTACTS_STORAGE_MODE`, contacts DB-path
|
|
64
|
+
variables, and contacts database URLs are rejected in client processes.
|
|
65
|
+
PostgreSQL URLs belong only to `contacts-serve` and the migration task.
|
|
31
66
|
|
|
32
67
|
## CLI Usage
|
|
33
68
|
|
|
34
69
|
```bash
|
|
35
|
-
contacts status # CLI version,
|
|
70
|
+
contacts status # CLI version, resolved /v1 authority + sources, storage mode, record counts
|
|
36
71
|
contacts status --json
|
|
37
72
|
contacts --help
|
|
38
73
|
```
|
|
39
74
|
|
|
40
|
-
`contacts status`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
`contacts status` reports the authority the shared resolver actually decided
|
|
76
|
+
(`api`, the `/v1` base URL) and where each half came from — `api_url_source`,
|
|
77
|
+
`api_key_source`, `api_key_tier`: an env key name, a Keychain item reference,
|
|
78
|
+
a credentials-file path, or `default` for the fleet gateway; never a value.
|
|
79
|
+
It answers even on a box without an API key: an unconfigured client reports
|
|
80
|
+
storage `unconfigured` with the resolver's `issue` (a failed request on a
|
|
81
|
+
configured box reports storage `error` with the failure message) instead of
|
|
82
|
+
crashing, so agents can observe the configuration drift the command exists to
|
|
83
|
+
expose. `status` and `connection` are diagnostics and exit 0 with that report;
|
|
84
|
+
every data verb fails closed (non-zero exit, no local store).
|
|
85
|
+
|
|
86
|
+
## SDK
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { createContactsClient, ContactsV1Client } from "@hasna/contacts/sdk";
|
|
90
|
+
|
|
91
|
+
// Through the fleet resolver — the same @hasna/contracts chain the CLI and MCP
|
|
92
|
+
// server use: credential and authority resolved at construction, the key
|
|
93
|
+
// re-resolved on every request, the authority pinned. Nothing resolving throws.
|
|
94
|
+
const client = createContactsClient();
|
|
95
|
+
const { contacts } = await client.listContacts();
|
|
96
|
+
|
|
97
|
+
// Explicit pin: a caller-supplied baseUrl always requires a caller-supplied
|
|
98
|
+
// apiKey — the SDK never attaches an ambient credential to it.
|
|
99
|
+
const pinned = new ContactsV1Client({ baseUrl: "https://contacts.example.com", apiKey: "…" });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`createContactsClient()` resolves the literal tiers only — an explicit
|
|
103
|
+
`apiKey`, `HASNA_CONTACTS_API_KEY_OVERRIDE`, the Keychain item, the
|
|
104
|
+
credentials file, `HASNA_CONTACTS_API_KEY`. The secrets-vault pointer
|
|
105
|
+
`HASNA_CONTACTS_API_KEY_REF` is refused with
|
|
106
|
+
`CONTACTS_CREDENTIAL_POINTER_UNSUPPORTED` (the SDK resolves synchronously per
|
|
107
|
+
request and cannot complete a vault lookup); the CLI and MCP server accept it.
|
|
44
108
|
|
|
45
109
|
|
|
46
110
|
## Audiences, consent, and suppression
|
|
@@ -76,6 +140,22 @@ suppressed addresses; the audience `--policy` (`opt_in`, `opt_out`,
|
|
|
76
140
|
contacts-mcp
|
|
77
141
|
```
|
|
78
142
|
|
|
143
|
+
`contacts-mcp` fails closed at startup: with no credential resolvable through
|
|
144
|
+
the chain above it exits non-zero BEFORE the stdio transport is connected or
|
|
145
|
+
the HTTP port is bound — an `initialize` request is never answered by an
|
|
146
|
+
unauthenticated server — and creates nothing under the app home. The first
|
|
147
|
+
stderr line names where the credential should live (the Keychain item, the
|
|
148
|
+
credentials-file path, `HASNA_CONTACTS_API_KEY`), never a value.
|
|
149
|
+
`--help` / `--version` answer ahead of the gate; every tool still re-resolves
|
|
150
|
+
the credential per request once the server is up.
|
|
151
|
+
|
|
152
|
+
The deliberate tiers are honoured at the gate as well. The secrets-vault
|
|
153
|
+
pointer `HASNA_CONTACTS_API_KEY_REF` is dereferenced once at startup (the
|
|
154
|
+
chain alone only checks the pointer's shape): a pointer the vault cannot
|
|
155
|
+
complete, a `HASNA_PROFILE` whose credentials file is missing, or an unsafe
|
|
156
|
+
(not owner-only) credentials file is a one-line refusal naming the pointer,
|
|
157
|
+
the file, or the item — never resolved around, never a stack trace.
|
|
158
|
+
|
|
79
159
|
## HTTP mode
|
|
80
160
|
|
|
81
161
|
Long-lived Streamable HTTP transport (stateless, bind `127.0.0.1` only):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/browser/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,gGAAgG;AAChG,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsB9D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/browser/identity.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,YAAY,qCAAqC,CAAC;AAC/D,eAAO,MAAM,SAAS,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare function hostDirectories(home?: string, userDataDir?: string): string[];
|
|
2
|
+
export interface InstallOptions {
|
|
3
|
+
userDataDir?: string;
|
|
4
|
+
/** Test seam: the home directory that owns ~/.hasna/contacts and the Chrome profiles. */
|
|
5
|
+
home?: string;
|
|
6
|
+
/** Test seam: the package root that holds extension/ and dist/. */
|
|
7
|
+
root?: string;
|
|
8
|
+
/** Test seam: the absolute runtime used in the host shebang. */
|
|
9
|
+
execPath?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function installBrowser(options?: InstallOptions): {
|
|
12
|
+
ok: true;
|
|
13
|
+
extensionId: string;
|
|
14
|
+
extensionPath: string;
|
|
15
|
+
nativeHost: string;
|
|
16
|
+
nativeManifests: string[];
|
|
17
|
+
next: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function browserStatus(options?: {
|
|
20
|
+
home?: string;
|
|
21
|
+
userDataDir?: string;
|
|
22
|
+
}): {
|
|
23
|
+
ok: true;
|
|
24
|
+
extensionId: string;
|
|
25
|
+
extensionInstalled: boolean;
|
|
26
|
+
nativeHostInstalled: boolean;
|
|
27
|
+
manifests: {
|
|
28
|
+
path: string;
|
|
29
|
+
present: boolean;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/browser/install.ts"],"names":[],"mappings":"AAgBA,wBAAgB,eAAe,CAAC,IAAI,SAAY,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAYhF;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,cAAmB;;;;;;;EAuC1D;AAED,wBAAgB,aAAa,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO;;;;;;;;;EAclF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../src/browser/native.ts"],"names":[],"mappings":""}
|