clavarium-tether 0.1.0-next.13 → 0.1.0-next.14
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/host/connectors/contacts.mjs +10 -2
- package/package.json +1 -1
- package/server/name.mjs +1 -1
|
@@ -65,10 +65,18 @@ export function contacts({ fetch: fetchImpl = globalThis.fetch } = {}) {
|
|
|
65
65
|
|
|
66
66
|
async function googleList(target, ctx) {
|
|
67
67
|
const base = CARDDAV(userOf(target));
|
|
68
|
+
const basePath = (() => { try { return new URL(base).pathname.replace(/\/+$/, ''); } catch { return ''; } })();
|
|
68
69
|
const listed = await req(target, ctx, 'PROPFIND', base, { headers: { Depth: '1', 'Content-Type': 'application/xml; charset=utf-8' }, body: PROPFIND });
|
|
69
70
|
if (!listed.ok) no(`${target.title}: the address book could not be read (${listed.status})`);
|
|
70
|
-
/* The collection lists itself and its contacts; keep the
|
|
71
|
-
|
|
71
|
+
/* The collection lists itself and its contacts; keep the entries, whatever
|
|
72
|
+
they are named (Google uses an id, not a .vcf suffix). A contact is any
|
|
73
|
+
href under the collection that is not the collection itself. */
|
|
74
|
+
const hrefs = hrefsIn(await listed.text()).filter((h) => {
|
|
75
|
+
const clean = h.replace(/[?#].*$/, '');
|
|
76
|
+
if (!clean || clean.endsWith('/')) return false;
|
|
77
|
+
let p; try { p = new URL(h, base).pathname.replace(/\/+$/, ''); } catch { p = clean.replace(/\/+$/, ''); }
|
|
78
|
+
return p !== basePath;
|
|
79
|
+
}).slice(0, LIST_MAX);
|
|
72
80
|
if (!hrefs.length) return [];
|
|
73
81
|
const body = `<?xml version="1.0" encoding="utf-8"?><C:addressbook-multiget xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"><D:prop><D:getetag/><C:address-data/></D:prop>${hrefs.map((h) => `<D:href>${h.replace(/&/g, '&').replace(/</g, '<')}</D:href>`).join('')}</C:addressbook-multiget>`;
|
|
74
82
|
const res = await req(target, ctx, 'REPORT', base, { headers: { Depth: '1', 'Content-Type': 'application/xml; charset=utf-8' }, body });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clavarium-tether",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.14",
|
|
4
4
|
"description": "Clavarium Tether: an AI agent acts outside its own machine on a tether: levels per target, a person's approval, a journal and a stop (a command and an MCP server for agents, a keeper and a screen for the application). One dependency: ssh2, for the SSH connector.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/clavarium/clavarium-tether#readme",
|
package/server/name.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export const NAME = 'tether';
|
|
7
7
|
export const PRODUCT = 'Clavarium Tether';
|
|
8
8
|
export const PACKAGE = `clavarium-${NAME}`;
|
|
9
|
-
export const VERSION = '0.1.0-next.
|
|
9
|
+
export const VERSION = '0.1.0-next.14';
|
|
10
10
|
/* The agent's folder: where its asks and the keeper's answers are written. */
|
|
11
11
|
export const FOLDER = `.${NAME}`;
|
|
12
12
|
/* $TETHER_DIR: the agent's folder; $TETHER_STORE: the keeper's store (serve). */
|