clawdi 0.13.1 → 0.13.3
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/index.js +478 -436
- package/dist/skills/clawdi/SKILL.md +32 -6
- package/dist/skills/hosted/clawdi/SKILL.md +52 -0
- package/egress-addon/clawdi_egress_addon.py +31 -2
- package/package.json +2 -2
|
@@ -79,12 +79,38 @@ When the user's request is **conceptual** ("how do I usually do X"), prefer `mem
|
|
|
79
79
|
|
|
80
80
|
## Connectors
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
Use the Composio Tool Router meta-tools returned by `tools/list` on the `clawdi` MCP server.
|
|
83
|
+
Treat their live names and schemas as authoritative; never assume a fixed meta-tool set.
|
|
84
|
+
|
|
85
|
+
1. Start each external-app workflow with `COMPOSIO_SEARCH_TOOLS`. Follow its exposed
|
|
86
|
+
`queries` and `session` schema, reuse the returned session ID throughout that workflow,
|
|
87
|
+
and use only the exact toolkit and tool slugs it returns. If a required schema is absent
|
|
88
|
+
or incomplete, call `COMPOSIO_GET_TOOL_SCHEMAS`; never invent fields or inputs.
|
|
89
|
+
2. Before a side effect, require a complete target identity and all schema-required inputs.
|
|
90
|
+
Explicit intent authorizes the exact requested action and target, but never authorizes
|
|
91
|
+
guessing a missing recipient, account, resource, or other target. Ask only for what is
|
|
92
|
+
missing, and do not request redundant confirmation once the exact action is authorized.
|
|
93
|
+
3. When search reports no active connection, call `COMPOSIO_MANAGE_CONNECTIONS` with its
|
|
94
|
+
exposed schema and interpret only the fields it returns. Continue on `active`. On
|
|
95
|
+
`initiated`, present its non-empty `redirect_url` as a clickable authentication link with
|
|
96
|
+
a concise explanation that authorization is pending; the link URL must be exactly that
|
|
97
|
+
value. If `initiated` has no non-empty `redirect_url`, report that authorization cannot
|
|
98
|
+
continue and stop. On `failed`, report the returned error and stop. Never construct a
|
|
99
|
+
substitute link, ask for OAuth credentials, API keys, or tokens, or suggest an
|
|
100
|
+
out-of-band fallback.
|
|
101
|
+
4. Use a wait or status operation only when `tools/list` exposes one. Follow its actual schema
|
|
102
|
+
and status values without inventing polling arguments. Continue only when it reports an
|
|
103
|
+
active connection; keep waiting only for a non-terminal status its schema defines, and
|
|
104
|
+
report any terminal failure. If none is exposed, stop until the user reports completing
|
|
105
|
+
authorization, then re-run search to verify the active connection before continuing.
|
|
106
|
+
5. Execute exact returned slugs through `COMPOSIO_MULTI_EXECUTE_TOOL` with schema-compliant
|
|
107
|
+
arguments. Batch only independent calls. Keep ordinary results inline. Set
|
|
108
|
+
`sync_response_to_workbench` only when a result may be large or needs later remote
|
|
109
|
+
processing; use `COMPOSIO_REMOTE_WORKBENCH` / `COMPOSIO_REMOTE_BASH_TOOL` only for large
|
|
110
|
+
responses saved remotely or remote artifacts.
|
|
111
|
+
6. Preserve dependencies and returned semantics. Follow signed-file metadata, pagination
|
|
112
|
+
fields, and termination signals exactly as exposed. Select an account only when the schema
|
|
113
|
+
supports it, and use additional or future meta-tools only according to their live schemas.
|
|
88
114
|
|
|
89
115
|
## Vault CLI
|
|
90
116
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clawdi
|
|
3
|
+
description: "Find and read the user's past agent sessions across Claude Code, Codex, OpenClaw, and Hermes; use connected-service tools such as Gmail, GitHub, Notion, Drive, and Calendar; and read Clawdi share URLs (https://cloud.clawdi.ai/s/...) the user pastes."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Clawdi Cloud
|
|
7
|
+
|
|
8
|
+
Use Clawdi Cloud tools through the `clawdi` MCP server.
|
|
9
|
+
|
|
10
|
+
## Sessions
|
|
11
|
+
|
|
12
|
+
- Use `session_search` to find past agent conversations by keyword and obtain session UUIDs.
|
|
13
|
+
- Use `session_read` to read a session by UUID or Clawdi share URL.
|
|
14
|
+
|
|
15
|
+
Call `session_read` when the user provides a Clawdi share URL. When the user refers to a
|
|
16
|
+
past conversation without a UUID, call `session_search` first and then read the matching
|
|
17
|
+
session. Do not use a generic web fetcher for Clawdi share URLs.
|
|
18
|
+
|
|
19
|
+
## Connectors
|
|
20
|
+
|
|
21
|
+
Use the Composio Tool Router meta-tools returned by `tools/list` on the `clawdi` MCP server.
|
|
22
|
+
Treat their live names and schemas as authoritative; never assume a fixed meta-tool set.
|
|
23
|
+
|
|
24
|
+
1. Start each external-app workflow with `COMPOSIO_SEARCH_TOOLS`. Follow its exposed
|
|
25
|
+
`queries` and `session` schema, reuse the returned session ID throughout that workflow,
|
|
26
|
+
and use only the exact toolkit and tool slugs it returns. If a required schema is absent
|
|
27
|
+
or incomplete, call `COMPOSIO_GET_TOOL_SCHEMAS`; never invent fields or inputs.
|
|
28
|
+
2. Before a side effect, require a complete target identity and all schema-required inputs.
|
|
29
|
+
Explicit intent authorizes the exact requested action and target, but never authorizes
|
|
30
|
+
guessing a missing recipient, account, resource, or other target. Ask only for what is
|
|
31
|
+
missing, and do not request redundant confirmation once the exact action is authorized.
|
|
32
|
+
3. When search reports no active connection, call `COMPOSIO_MANAGE_CONNECTIONS` with its
|
|
33
|
+
exposed schema and interpret only the fields it returns. Continue on `active`. On
|
|
34
|
+
`initiated`, present its non-empty `redirect_url` as a clickable authentication link with
|
|
35
|
+
a concise explanation that authorization is pending; the link URL must be exactly that
|
|
36
|
+
value. If `initiated` has no non-empty `redirect_url`, report that authorization cannot
|
|
37
|
+
continue and stop. On `failed`, report the returned error and stop. Never construct a
|
|
38
|
+
substitute link, ask for OAuth credentials, API keys, or tokens, or suggest an
|
|
39
|
+
out-of-band fallback.
|
|
40
|
+
4. Use a wait or status operation only when `tools/list` exposes one. Follow its actual schema
|
|
41
|
+
and status values without inventing polling arguments. Continue only when it reports an
|
|
42
|
+
active connection; keep waiting only for a non-terminal status its schema defines, and
|
|
43
|
+
report any terminal failure. If none is exposed, stop until the user reports completing
|
|
44
|
+
authorization, then re-run search to verify the active connection before continuing.
|
|
45
|
+
5. Execute exact returned slugs through `COMPOSIO_MULTI_EXECUTE_TOOL` with schema-compliant
|
|
46
|
+
arguments. Batch only independent calls. Keep ordinary results inline. Set
|
|
47
|
+
`sync_response_to_workbench` only when a result may be large or needs later remote
|
|
48
|
+
processing; use `COMPOSIO_REMOTE_WORKBENCH` / `COMPOSIO_REMOTE_BASH_TOOL` only for large
|
|
49
|
+
responses saved remotely or remote artifacts.
|
|
50
|
+
6. Preserve dependencies and returned semantics. Follow signed-file metadata, pagination
|
|
51
|
+
fields, and termination signals exactly as exposed. Select an account only when the schema
|
|
52
|
+
supports it, and use additional or future meta-tools only according to their live schemas.
|
|
@@ -12,7 +12,7 @@ import os
|
|
|
12
12
|
import re
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any
|
|
15
|
-
from urllib.parse import parse_qs,
|
|
15
|
+
from urllib.parse import parse_qs, urlsplit
|
|
16
16
|
|
|
17
17
|
try: # pragma: no cover - exercised only under mitmdump.
|
|
18
18
|
from mitmproxy import ctx, http
|
|
@@ -114,6 +114,7 @@ class ClawdiEgressAddon:
|
|
|
114
114
|
self.secret_file_path = Path(secret_file) if secret_file else None
|
|
115
115
|
self.profiles = load_profiles(self.profile_bundle_path)
|
|
116
116
|
self.secrets = load_secrets(self.secret_file_path)
|
|
117
|
+
validate_profile_secrets(self.profiles, self.secrets)
|
|
117
118
|
self.profile_hosts = profile_host_set(self.profiles)
|
|
118
119
|
|
|
119
120
|
def should_intercept_sni(self, server_name: str) -> bool:
|
|
@@ -205,6 +206,30 @@ def load_secrets(path: Path | None) -> dict[str, str]:
|
|
|
205
206
|
return {str(key): str(value) for key, value in raw.items() if isinstance(value, str)}
|
|
206
207
|
|
|
207
208
|
|
|
209
|
+
def validate_profile_secrets(
|
|
210
|
+
profiles: list[dict[str, Any]], secrets: dict[str, str]
|
|
211
|
+
) -> None:
|
|
212
|
+
required: set[str] = set()
|
|
213
|
+
for profile in profiles:
|
|
214
|
+
collect_secret_refs(profile, required)
|
|
215
|
+
missing = sorted(ref for ref in required if not secrets.get(ref))
|
|
216
|
+
if missing:
|
|
217
|
+
raise ConfigError(f"egress profile secrets are missing: {', '.join(missing)}")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def collect_secret_refs(value: Any, refs: set[str]) -> None:
|
|
221
|
+
if isinstance(value, list):
|
|
222
|
+
for item in value:
|
|
223
|
+
collect_secret_refs(item, refs)
|
|
224
|
+
return
|
|
225
|
+
if not isinstance(value, dict):
|
|
226
|
+
return
|
|
227
|
+
for key, entry in value.items():
|
|
228
|
+
if isinstance(entry, str) and (key == "secretRef" or key.endswith("SecretRef")):
|
|
229
|
+
refs.add(entry)
|
|
230
|
+
collect_secret_refs(entry, refs)
|
|
231
|
+
|
|
232
|
+
|
|
208
233
|
def profile_host_set(profiles: list[dict[str, Any]]) -> set[str]:
|
|
209
234
|
hosts: set[str] = set()
|
|
210
235
|
for profile in profiles:
|
|
@@ -297,9 +322,13 @@ def host_matches(flow: Any, profile: dict[str, Any]) -> bool:
|
|
|
297
322
|
match = profile.get("match")
|
|
298
323
|
if not isinstance(match, dict):
|
|
299
324
|
return False
|
|
300
|
-
|
|
325
|
+
expected_authority = str(match.get("host", "")).strip().lower()
|
|
326
|
+
expected_host, expected_port = split_authority(expected_authority)
|
|
327
|
+
expected = normalize_host(expected_host)
|
|
301
328
|
if not expected:
|
|
302
329
|
return False
|
|
330
|
+
if expected_port is not None and getattr(flow.request, "port", None) != expected_port:
|
|
331
|
+
return False
|
|
303
332
|
return expected in request_host_candidates(flow)
|
|
304
333
|
|
|
305
334
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawdi",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "iCloud for AI Agents — cross-agent sessions, skills, memory, and vault.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"dev": "bun run src/index.ts",
|
|
26
|
-
"build": "rm -rf dist && bun build src/index.ts --outdir dist --target node --minify --define 'process.env.CLAWDI_DEFAULT_API_URL=\"https://cloud-api.clawdi.ai\"' && cp -r skills dist/skills",
|
|
26
|
+
"build": "rm -rf dist && bun build src/index.ts --outdir dist --target node --minify --define 'process.env.CLAWDI_DEFAULT_API_URL=\"https://cloud-api.clawdi.ai\"' --define 'process.env.CLAWDI_DEFAULT_DEPLOY_API_URL=\"https://api.clawdi.ai\"' && cp -r skills dist/skills",
|
|
27
27
|
"build:binary": "bun run scripts/build-binary.mjs",
|
|
28
28
|
"package:binary-release": "bun run scripts/package-binary-release.mjs",
|
|
29
29
|
"build:dev": "rm -rf dist && bun build src/index.ts --outdir dist --target node && cp -r skills dist/skills",
|