@avasapp/agent-bridge 0.3.0 → 0.4.1
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 +24 -225
- package/dist/adapters/ably.cjs +22 -4
- package/dist/adapters/ably.d.cts +8 -1
- package/dist/adapters/expo-router.cjs +22 -1
- package/dist/adapters/expo-router.d.cts +5 -1
- package/dist/adapters/react-native-mmkv.cjs +1 -0
- package/dist/adapters/react-native-mmkv.d.cts +1 -1
- package/dist/adapters/react-native-webview.cjs +672 -0
- package/dist/adapters/react-native-webview.d.cts +79 -0
- package/dist/adapters/socket-io.cjs +3 -1
- package/dist/adapters/socket-io.d.cts +1 -1
- package/dist/adapters/tanstack-query.cjs +256 -17
- package/dist/adapters/tanstack-query.d.cts +1 -1
- package/dist/adapters/zustand.cjs +152 -12
- package/dist/adapters/zustand.d.cts +19 -3
- package/dist/{chunk-S2FYN2R5.js → chunk-AJD3XTNT.js} +223 -57
- package/dist/cli.js +817 -56
- package/dist/client/index.cjs +218 -56
- package/dist/client/index.d.ts +20 -2
- package/dist/client/index.js +1 -1
- package/dist/expo/index.d.cts +1 -1
- package/dist/network/index.cjs +254 -51
- package/dist/network/index.d.cts +9 -2
- package/dist/noop/index.cjs +3 -0
- package/dist/noop/react-native-webview.cjs +38 -0
- package/dist/realtime/index.cjs +2 -1
- package/dist/realtime/index.d.cts +3 -1
- package/dist/runtime/index.cjs +860 -100
- package/dist/runtime/index.d.cts +31 -5
- package/dist/{types-6kKQsLC1.d.cts → types-BmpykP1P.d.cts} +23 -1
- package/entries/react-native-webview.cjs +9 -0
- package/package.json +17 -6
- package/skills/agent-bridge/SKILL.md +196 -5
|
@@ -23,15 +23,70 @@ __export(zustand_exports, {
|
|
|
23
23
|
storeTools: () => storeTools
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(zustand_exports);
|
|
26
|
+
|
|
27
|
+
// src/runtime/to-json.ts
|
|
28
|
+
function toJson(value) {
|
|
29
|
+
if (value === void 0) return null;
|
|
30
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
31
|
+
const text = JSON.stringify(value, (_key, v) => {
|
|
32
|
+
if (typeof v === "bigint") return v.toString();
|
|
33
|
+
if (typeof v === "function" || typeof v === "symbol") return void 0;
|
|
34
|
+
if (v instanceof Error) return { name: v.name, message: v.message };
|
|
35
|
+
if (v instanceof Map) return Object.fromEntries(v);
|
|
36
|
+
if (v instanceof Set) return [...v];
|
|
37
|
+
if (v && typeof v === "object") {
|
|
38
|
+
if (seen.has(v)) return "[Circular]";
|
|
39
|
+
seen.add(v);
|
|
40
|
+
}
|
|
41
|
+
return v;
|
|
42
|
+
});
|
|
43
|
+
return text === void 0 ? null : JSON.parse(text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/adapters/zustand.ts
|
|
26
47
|
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
27
48
|
var isObject = (value) => typeof value === "object" && value !== null;
|
|
28
|
-
function
|
|
29
|
-
if (
|
|
30
|
-
|
|
49
|
+
function toPath(part) {
|
|
50
|
+
if (typeof part === "string") return part === "" ? [] : part.split(".");
|
|
51
|
+
if (typeof part === "number") return [part];
|
|
52
|
+
if (Array.isArray(part) && part.every((p) => typeof p === "string" || typeof p === "number"))
|
|
53
|
+
return part;
|
|
54
|
+
throw new Error(
|
|
55
|
+
`A store path is a dotted string or an array of segments, got ${JSON.stringify(part)}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
function at(value, path) {
|
|
59
|
+
return path.reduce(
|
|
31
60
|
(v, k) => v?.[k],
|
|
32
61
|
value
|
|
33
62
|
);
|
|
34
63
|
}
|
|
64
|
+
var kindOf = (v) => v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
|
|
65
|
+
function readState(state, given) {
|
|
66
|
+
const args = given.filter((a) => a != null);
|
|
67
|
+
const last = args.at(-1);
|
|
68
|
+
const isOptions = isObject(last) && !Array.isArray(last);
|
|
69
|
+
const options = isOptions ? last : {};
|
|
70
|
+
const unknown = Object.keys(options).filter((k) => k !== "pick" && k !== "keys");
|
|
71
|
+
if (unknown.length)
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Unknown store.get option ${unknown.map((k) => `"${k}"`).join(", ")}. Options: pick, keys`
|
|
74
|
+
);
|
|
75
|
+
const value = at(state, (isOptions ? args.slice(0, -1) : args).flatMap(toPath));
|
|
76
|
+
if (options.pick !== void 0) {
|
|
77
|
+
if (!Array.isArray(options.pick))
|
|
78
|
+
throw new Error("store.get pick is an array of paths");
|
|
79
|
+
return Object.fromEntries(
|
|
80
|
+
options.pick.map((p) => [
|
|
81
|
+
Array.isArray(p) ? p.join(".") : String(p),
|
|
82
|
+
at(value, toPath(p))
|
|
83
|
+
])
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (options.keys)
|
|
87
|
+
return isObject(value) ? Object.fromEntries(Object.entries(value).map(([k, v]) => [k, kindOf(v)])) : kindOf(value);
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
35
90
|
function restore(store, snapshot) {
|
|
36
91
|
const current = store.getState();
|
|
37
92
|
if (!isObject(snapshot) || !isObject(current)) {
|
|
@@ -43,7 +98,47 @@ function restore(store, snapshot) {
|
|
|
43
98
|
);
|
|
44
99
|
store.setState({ ...snapshot, ...actions }, true);
|
|
45
100
|
}
|
|
46
|
-
|
|
101
|
+
var PREVIEW = 200;
|
|
102
|
+
function preview(value) {
|
|
103
|
+
try {
|
|
104
|
+
const safe = toJson(value);
|
|
105
|
+
const text = JSON.stringify(safe);
|
|
106
|
+
if (text.length <= PREVIEW) return safe;
|
|
107
|
+
return `${text.slice(0, PREVIEW)}\u2026 (${text.length} chars)`;
|
|
108
|
+
} catch {
|
|
109
|
+
return "[unserializable]";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function differences(snapshot, current, show) {
|
|
113
|
+
if (!isObject(snapshot) || !isObject(current)) return {};
|
|
114
|
+
const out = {};
|
|
115
|
+
for (const k of /* @__PURE__ */ new Set([...Object.keys(snapshot), ...Object.keys(current)])) {
|
|
116
|
+
const a = snapshot[k];
|
|
117
|
+
const b = current[k];
|
|
118
|
+
if (typeof a === "function" || typeof b === "function") continue;
|
|
119
|
+
if (!Object.is(a, b))
|
|
120
|
+
out[k] = { snapshot: preview(show(k, a)), current: preview(show(k, b)) };
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
var REDACTED = "[redacted]";
|
|
125
|
+
function redactValue(redact, name, value, path, seen = []) {
|
|
126
|
+
if (!redact || typeof value === "function") return value;
|
|
127
|
+
if (typeof redact === "function") {
|
|
128
|
+
if (path) value = redact(name, path, value);
|
|
129
|
+
} else if (path && redact[name]?.some((p) => path === p || path.startsWith(`${p}.`))) {
|
|
130
|
+
return REDACTED;
|
|
131
|
+
}
|
|
132
|
+
if (!isObject(value) || seen.includes(value)) return value;
|
|
133
|
+
const next = [...seen, value];
|
|
134
|
+
const entries = Object.entries(value).map(([k, v]) => [
|
|
135
|
+
k,
|
|
136
|
+
redactValue(redact, name, v, path ? `${path}.${k}` : k, next)
|
|
137
|
+
]);
|
|
138
|
+
return Array.isArray(value) ? entries.map(([, v]) => v) : Object.fromEntries(entries);
|
|
139
|
+
}
|
|
140
|
+
function storeTools(stores, options = {}) {
|
|
141
|
+
const out = (name, value, path = "") => redactValue(options.redact, name, value, path);
|
|
47
142
|
const get = (name) => {
|
|
48
143
|
const store = stores[name];
|
|
49
144
|
if (!store)
|
|
@@ -58,34 +153,79 @@ function storeTools(stores) {
|
|
|
58
153
|
return {
|
|
59
154
|
"store.list": {
|
|
60
155
|
description: "Store names.",
|
|
156
|
+
maxArgs: 0,
|
|
61
157
|
run: () => Object.keys(stores)
|
|
62
158
|
},
|
|
63
159
|
"store.get": {
|
|
64
|
-
description: 'State of a store, or
|
|
65
|
-
|
|
160
|
+
description: 'State of a store, or a path inside it: ("auth", "auth.isLoggedIn"), ("auth", "auth", "isLoggedIn") or ("auth", ["auth", "isLoggedIn"]). A last { pick: ["a.b", "c"] } returns just those fields; { keys: true } lists keys and their types without values. Paths configured with redact print as "[redacted]".',
|
|
161
|
+
// Redact the whole state first, so paths, pick and keys all see it.
|
|
162
|
+
run: (name, ...rest) => readState(out(name, get(name).getState()), rest)
|
|
66
163
|
},
|
|
67
164
|
"store.set": {
|
|
68
|
-
description: "Shallow-merge a partial into a store.",
|
|
165
|
+
description: "Shallow-merge a partial into a store. Returns only the keys you set, with their new values, not the whole store. A store is snapshotted on its first store.set or store.call since the last restore (or store.commit); bridge.restore puts that snapshot back. Changes made before that, e.g. by tapping the UI, are not in it: run store.set <store> {} first to snapshot early, and see bridge.pending.",
|
|
69
166
|
run: (name, partial) => {
|
|
70
167
|
const store = get(name);
|
|
71
168
|
beforeChange(store);
|
|
72
169
|
store.setState(partial);
|
|
73
|
-
|
|
170
|
+
const state = store.getState();
|
|
171
|
+
return out(
|
|
172
|
+
name,
|
|
173
|
+
Object.fromEntries(Object.keys(partial).map((k) => [k, state[k]]))
|
|
174
|
+
);
|
|
74
175
|
}
|
|
75
176
|
},
|
|
76
177
|
"store.call": {
|
|
77
|
-
description:
|
|
78
|
-
run: (name, action, ...args) => {
|
|
178
|
+
description: `Call an action on a store, e.g. ("settings", "setColorScheme", "dark"). Returns the action's return value, or { changed: [keys] } when it returns nothing or the store state. Snapshots the store first, like store.set: the first store.set or store.call since the last restore is the state bridge.restore returns to.`,
|
|
179
|
+
run: async (name, action, ...args) => {
|
|
79
180
|
const store = get(name);
|
|
80
181
|
const fn = store.getState()[action];
|
|
81
182
|
if (typeof fn !== "function")
|
|
82
183
|
throw new Error(`Store "${name}" has no action "${action}"`);
|
|
83
184
|
beforeChange(store);
|
|
84
|
-
|
|
185
|
+
const before = store.getState();
|
|
186
|
+
const result = await fn(...args);
|
|
187
|
+
const after = store.getState();
|
|
188
|
+
if (result !== void 0 && result !== before && result !== after) {
|
|
189
|
+
const key = isObject(after) ? Object.keys(after).find((k) => after[k] === result) : void 0;
|
|
190
|
+
return out(name, result, key);
|
|
191
|
+
}
|
|
192
|
+
const a = before;
|
|
193
|
+
const b = after;
|
|
194
|
+
return {
|
|
195
|
+
changed: Object.keys(b).filter(
|
|
196
|
+
(k) => typeof b[k] !== "function" && !Object.is(a?.[k], b[k])
|
|
197
|
+
)
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"store.commit": {
|
|
202
|
+
maxArgs: 1,
|
|
203
|
+
description: "Keep a store as it is now: drops its pending snapshot, so bridge.restore leaves it alone and the next store.set or store.call snapshots again from this state. Use it after repairing a value that was already wrong when the snapshot was taken. Returns { store, committed } (committed: false when nothing was pending).",
|
|
204
|
+
run: (name) => {
|
|
205
|
+
const store = get(name);
|
|
206
|
+
return { store: name, committed: snapshots.delete(store) };
|
|
85
207
|
}
|
|
86
208
|
},
|
|
87
209
|
"store.restore": {
|
|
88
|
-
|
|
210
|
+
maxArgs: 0,
|
|
211
|
+
// Per store, its snapshot against now (secrets redacted), so an agent can
|
|
212
|
+
// tell what a restore will put back before it does.
|
|
213
|
+
pending: ({ detail } = {}) => {
|
|
214
|
+
const changed = Object.entries(stores).filter(([, s]) => snapshots.has(s));
|
|
215
|
+
if (!changed.length) return false;
|
|
216
|
+
if (!detail) return true;
|
|
217
|
+
return Object.fromEntries(
|
|
218
|
+
changed.map(([name, store]) => [
|
|
219
|
+
name,
|
|
220
|
+
differences(
|
|
221
|
+
snapshots.get(store),
|
|
222
|
+
store.getState(),
|
|
223
|
+
(key, value) => out(name, value, key)
|
|
224
|
+
)
|
|
225
|
+
])
|
|
226
|
+
);
|
|
227
|
+
},
|
|
228
|
+
description: "Undo the agent: put back each store changed with store.set or store.call, to its state at the first of those (store.commit drops a snapshot). Returns their names.",
|
|
89
229
|
run: () => Object.entries(stores).flatMap(([name, store]) => {
|
|
90
230
|
if (!snapshots.has(store)) return [];
|
|
91
231
|
restore(store, snapshots.get(store));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as Tools } from '../types-
|
|
1
|
+
import { T as Tools } from '../types-BmpykP1P.cjs';
|
|
2
2
|
|
|
3
3
|
/** Anything with zustand's store shape. */
|
|
4
4
|
type StoreLike = {
|
|
@@ -9,7 +9,23 @@ type StoreLike = {
|
|
|
9
9
|
*/
|
|
10
10
|
setState(partial: Record<string, unknown>, replace?: boolean): void;
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Keeps secrets out of what store.* prints. Either dotted paths per store
|
|
14
|
+
* (`{ auth: ['accessToken', 'user.phone'] }`), or a hook called for the store
|
|
15
|
+
* value and every nested value with its dotted path; what it returns is
|
|
16
|
+
* printed instead.
|
|
17
|
+
*
|
|
18
|
+
* Paths are store paths. A `store.call` result that is a piece of the store's
|
|
19
|
+
* state (same object, e.g. `() => get().user`) is matched by where it lives; a
|
|
20
|
+
* copy or derived value (`() => ({ ...get().user })`) is not, so its paths are
|
|
21
|
+
* matched relative to the result and store paths like `user.phone` won't apply.
|
|
22
|
+
* Use the hook, or don't return secrets from actions.
|
|
23
|
+
*/
|
|
24
|
+
type Redact = Record<string, string[]> | ((store: string, path: string, value: unknown) => unknown);
|
|
25
|
+
type StoreToolsOptions = {
|
|
26
|
+
redact?: Redact;
|
|
27
|
+
};
|
|
12
28
|
/** Read, merge into, and call actions on named stores. */
|
|
13
|
-
declare function storeTools(stores: Record<string, StoreLike
|
|
29
|
+
declare function storeTools(stores: Record<string, StoreLike>, options?: StoreToolsOptions): Tools;
|
|
14
30
|
|
|
15
|
-
export { type StoreLike, storeTools };
|
|
31
|
+
export { type Redact, type StoreLike, type StoreToolsOptions, storeTools };
|