@agent-surface/react 0.1.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/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +320 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wiseair S.r.l.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @agent-surface/react
|
|
2
|
+
|
|
3
|
+
React bindings for [agent-surface](https://github.com/Wiseair-srl/agent-surface): lifecycle-correct hooks that tie capability registrations to component mounts. Registration happens once per mount in an effect; handlers are read through a ref at invocation time — no dependency arrays, no `useCallback`, no stale closures. Strict Mode, Suspense, SSR and concurrent rendering all work without special cases.
|
|
4
|
+
|
|
5
|
+
Docs: https://agent-surface-docs.vercel.app
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @agent-surface/core @agent-surface/react
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { AgentSurfaceProvider, useAgentComponent, usePendingConfirmations } from "@agent-surface/react";
|
|
17
|
+
import { action, observation } from "@agent-surface/core";
|
|
18
|
+
|
|
19
|
+
function DevicesTable() {
|
|
20
|
+
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
|
21
|
+
useAgentComponent({
|
|
22
|
+
type: "devices.table",
|
|
23
|
+
description: "Table of the devices visible on the current page",
|
|
24
|
+
observations: {
|
|
25
|
+
readState: observation({
|
|
26
|
+
description: "Visible rows and selection",
|
|
27
|
+
output: TableStateSchema,
|
|
28
|
+
read: () => ({ visibleRows, selectedIds }),
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
actions: {
|
|
32
|
+
selectRows: action({
|
|
33
|
+
description: "Replace the current row selection",
|
|
34
|
+
input: SelectRowsSchema,
|
|
35
|
+
effect: "local-state",
|
|
36
|
+
execute: ({ ids }) => setSelectedIds(ids),
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return <Table />;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
While mounted, an agent sees two typed capabilities; on unmount they are gone and late invocations fail with typed `COMPONENT_UNMOUNTED`. Availability (`when`, `enabled`) is re-evaluated per commit and pushed to the registry.
|
|
45
|
+
|
|
46
|
+
Full specification: [docs](https://github.com/Wiseair-srl/agent-surface/tree/main/docs).
|
|
47
|
+
|
|
48
|
+
MIT © Wiseair S.r.l.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AgentSurfaceRegistry, AgentComponentDefinition, PendingConfirmation, JsonValue, AgentActionDefinition, AgentObservationDefinition } from '@agent-surface/core';
|
|
3
|
+
|
|
4
|
+
interface AgentSurfaceProviderProps {
|
|
5
|
+
registry: AgentSurfaceRegistry;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The application creates the registry ONCE (module scope or top-level
|
|
10
|
+
* useState initializer) and passes it down — registry creation is where
|
|
11
|
+
* environment, policies, audit and route wiring live (docs/04).
|
|
12
|
+
*/
|
|
13
|
+
declare function AgentSurfaceProvider(props: AgentSurfaceProviderProps): ReactNode;
|
|
14
|
+
/** Access the registry from context. Throws if no provider is mounted. */
|
|
15
|
+
declare function useAgentSurface(): AgentSurfaceRegistry;
|
|
16
|
+
|
|
17
|
+
interface UseAgentComponentConfig extends Omit<AgentComponentDefinition, "procedures"> {
|
|
18
|
+
/**
|
|
19
|
+
* Gate for "mounted but not presented" (inactive tab, keep-alive, exit
|
|
20
|
+
* animation). false ⇒ all capabilities visible-disabled. Default true.
|
|
21
|
+
*/
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface AgentComponentHandle {
|
|
25
|
+
/** Current registrationId; changes on remount/re-register. */
|
|
26
|
+
registrationId: string | undefined;
|
|
27
|
+
status: "active" | "rejected" | "unregistered" | "pending";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* One aggregated hook per agent component (docs/04, the recommended default):
|
|
31
|
+
* one registration, one atomic descriptor, one lifecycle.
|
|
32
|
+
*
|
|
33
|
+
* Registration happens once per mount, in an effect; handlers are read through
|
|
34
|
+
* a ref at invocation time (D3) — no dependency arrays, no useCallback, no
|
|
35
|
+
* stale closures. Structure is frozen per registration (D2): changing it on a
|
|
36
|
+
* live registration logs an error and re-registers.
|
|
37
|
+
*/
|
|
38
|
+
declare function useAgentComponent(config: UseAgentComponentConfig): AgentComponentHandle;
|
|
39
|
+
|
|
40
|
+
interface PendingConfirmationView extends PendingConfirmation {
|
|
41
|
+
approve(): void;
|
|
42
|
+
deny(reason?: string): void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reactive list of pending confirmations for host-rendered dialogs. The
|
|
46
|
+
* dialog is representation, not policy: approving calls
|
|
47
|
+
* registry.confirmations.resolve, which mints the single-use evidence
|
|
48
|
+
* (docs/04, docs/06).
|
|
49
|
+
*/
|
|
50
|
+
declare function usePendingConfirmations(): PendingConfirmationView[];
|
|
51
|
+
|
|
52
|
+
interface AgentComponentScopeProps {
|
|
53
|
+
config: Omit<UseAgentComponentConfig, "observations" | "actions">;
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
}
|
|
56
|
+
/** Establishes a component scope; children attach capabilities to it. */
|
|
57
|
+
declare function AgentComponentScope(props: AgentComponentScopeProps): ReactNode;
|
|
58
|
+
declare function useAgentAction<TIn extends JsonValue, TOut extends JsonValue | void = void>(name: string, def: AgentActionDefinition<TIn, TOut>): void;
|
|
59
|
+
declare function useAgentObservation<TOut extends JsonValue>(name: string, def: AgentObservationDefinition<TOut>): void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Best-effort render-scope link between useAgentComponent and a following
|
|
63
|
+
* useAgentProcedure in the SAME component function (docs/05): the component
|
|
64
|
+
* hook records its identity during render; the procedure hook reads it.
|
|
65
|
+
*
|
|
66
|
+
* React exposes no public per-instance identity shared across independent
|
|
67
|
+
* hook calls, so this is a heuristic: it is precise for the canonical
|
|
68
|
+
* pattern (both hooks in one component) and clears itself at the end of the
|
|
69
|
+
* synchronous render pass. A sibling component rendering later in the same
|
|
70
|
+
* pass with only useAgentProcedure may pick up a stale link — cosmetic only
|
|
71
|
+
* (the link is descriptor metadata, never authority).
|
|
72
|
+
*/
|
|
73
|
+
interface RenderScopeContext {
|
|
74
|
+
type: string;
|
|
75
|
+
instanceId: string;
|
|
76
|
+
}
|
|
77
|
+
declare function setRenderScopeContext(context: RenderScopeContext): void;
|
|
78
|
+
declare function readRenderScopeContext(): RenderScopeContext | undefined;
|
|
79
|
+
|
|
80
|
+
export { type AgentComponentHandle, AgentComponentScope, type AgentComponentScopeProps, AgentSurfaceProvider, type AgentSurfaceProviderProps, type PendingConfirmationView, type RenderScopeContext as UnstableRenderScopeContext, type UseAgentComponentConfig, readRenderScopeContext as unstable_readRenderScopeContext, setRenderScopeContext as unstable_setRenderScopeContext, useAgentAction, useAgentComponent, useAgentObservation, useAgentSurface, usePendingConfirmations };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/context.ts
|
|
4
|
+
import { createContext, createElement, useContext } from "react";
|
|
5
|
+
var AgentSurfaceContext = createContext(null);
|
|
6
|
+
function AgentSurfaceProvider(props) {
|
|
7
|
+
return createElement(AgentSurfaceContext.Provider, { value: props.registry }, props.children);
|
|
8
|
+
}
|
|
9
|
+
function useAgentSurface() {
|
|
10
|
+
const registry = useContext(AgentSurfaceContext);
|
|
11
|
+
if (!registry) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"useAgentSurface: no <AgentSurfaceProvider> found above this component. Wrap your app in a provider with an explicitly created registry."
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return registry;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/use-agent-component.ts
|
|
20
|
+
import { useEffect, useRef, useState } from "react";
|
|
21
|
+
|
|
22
|
+
// src/render-scope.ts
|
|
23
|
+
var current = null;
|
|
24
|
+
function setRenderScopeContext(context) {
|
|
25
|
+
const token = {};
|
|
26
|
+
current = { context, token };
|
|
27
|
+
queueMicrotask(() => {
|
|
28
|
+
if (current?.token === token) current = null;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function readRenderScopeContext() {
|
|
32
|
+
return current?.context;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/use-agent-component.ts
|
|
36
|
+
function useAgentComponent(config) {
|
|
37
|
+
const registry = useAgentSurface();
|
|
38
|
+
const type = config.type;
|
|
39
|
+
const instanceId = config.instanceId ?? "default";
|
|
40
|
+
const latest = useRef(config);
|
|
41
|
+
latest.current = config;
|
|
42
|
+
setRenderScopeContext({ type, instanceId });
|
|
43
|
+
const [nonce, setNonce] = useState(0);
|
|
44
|
+
const handleRef = useRef(null);
|
|
45
|
+
const fingerprintRef = useRef(null);
|
|
46
|
+
const lastPushedAvailability = useRef({});
|
|
47
|
+
const lastPushedEnabled = useRef(null);
|
|
48
|
+
const [state, setState] = useState({
|
|
49
|
+
registrationId: void 0,
|
|
50
|
+
status: "pending"
|
|
51
|
+
});
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const definition = buildDelegatingDefinition(latest);
|
|
54
|
+
const handle = registry.register(definition);
|
|
55
|
+
handleRef.current = handle;
|
|
56
|
+
fingerprintRef.current = structuralFingerprint(latest.current);
|
|
57
|
+
lastPushedAvailability.current = {};
|
|
58
|
+
lastPushedEnabled.current = latest.current.enabled !== false;
|
|
59
|
+
const registrationId = handle.status === "active" ? handle.registrationId : void 0;
|
|
60
|
+
const status = handle.status === "active" ? "active" : "rejected";
|
|
61
|
+
setState(
|
|
62
|
+
(prev) => prev.registrationId === registrationId && prev.status === status ? prev : { registrationId, status }
|
|
63
|
+
);
|
|
64
|
+
if (handle.status === "active") {
|
|
65
|
+
pushAvailability(handle, latest.current, lastPushedAvailability, lastPushedEnabled);
|
|
66
|
+
}
|
|
67
|
+
return () => {
|
|
68
|
+
handle.unregister();
|
|
69
|
+
handleRef.current = null;
|
|
70
|
+
fingerprintRef.current = null;
|
|
71
|
+
};
|
|
72
|
+
}, [registry, type, instanceId, nonce]);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
const handle = handleRef.current;
|
|
75
|
+
if (!handle || handle.status !== "active") return;
|
|
76
|
+
const fingerprint = structuralFingerprint(latest.current);
|
|
77
|
+
if (fingerprintRef.current !== null && fingerprint !== fingerprintRef.current) {
|
|
78
|
+
console.error(
|
|
79
|
+
`[agent-surface] structural config change detected on live registration "${type}" (${instanceId}). Structure (names, schemas, descriptions, effects, policies) is frozen per registration (D2); keep it static per mount and put dynamism in when/enabled/handlers. Re-registering with a new registrationId.`
|
|
80
|
+
);
|
|
81
|
+
setNonce((n) => n + 1);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
pushAvailability(handle, latest.current, lastPushedAvailability, lastPushedEnabled);
|
|
85
|
+
});
|
|
86
|
+
return state;
|
|
87
|
+
}
|
|
88
|
+
function buildDelegatingDefinition(latest) {
|
|
89
|
+
const cfg = latest.current;
|
|
90
|
+
const observations = {};
|
|
91
|
+
for (const [name, obs] of Object.entries(cfg.observations ?? {})) {
|
|
92
|
+
observations[name] = {
|
|
93
|
+
description: obs.description,
|
|
94
|
+
output: obs.output,
|
|
95
|
+
read: (ctx) => {
|
|
96
|
+
const live = latest.current.observations?.[name];
|
|
97
|
+
if (!live) throw new Error(`observation "${name}" disappeared from the config`);
|
|
98
|
+
return live.read(ctx);
|
|
99
|
+
},
|
|
100
|
+
...obs.when !== void 0 ? { when: () => latest.current.observations?.[name]?.when?.() !== false } : {},
|
|
101
|
+
...obs.unavailableReason !== void 0 ? {
|
|
102
|
+
unavailableReason: () => evaluateReason(latest.current.observations?.[name]?.unavailableReason)
|
|
103
|
+
} : {},
|
|
104
|
+
...obs.policies ? { policies: obs.policies } : {},
|
|
105
|
+
...obs.meta ? { meta: obs.meta } : {},
|
|
106
|
+
...obs.timeoutMs !== void 0 ? { timeoutMs: obs.timeoutMs } : {}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const actions = {};
|
|
110
|
+
for (const [name, act] of Object.entries(cfg.actions ?? {})) {
|
|
111
|
+
actions[name] = {
|
|
112
|
+
description: act.description,
|
|
113
|
+
input: act.input,
|
|
114
|
+
...act.output ? { output: act.output } : {},
|
|
115
|
+
effect: act.effect,
|
|
116
|
+
...act.idempotent !== void 0 ? { idempotent: act.idempotent } : {},
|
|
117
|
+
...act.reversible !== void 0 ? { reversible: act.reversible } : {},
|
|
118
|
+
...act.confirmation !== void 0 ? { confirmation: act.confirmation } : {},
|
|
119
|
+
...act.audit !== void 0 ? { audit: act.audit } : {},
|
|
120
|
+
...act.when !== void 0 ? { when: () => latest.current.actions?.[name]?.when?.() !== false } : {},
|
|
121
|
+
...act.unavailableReason !== void 0 ? {
|
|
122
|
+
unavailableReason: () => evaluateReason(latest.current.actions?.[name]?.unavailableReason)
|
|
123
|
+
} : {},
|
|
124
|
+
...act.precondition !== void 0 ? {
|
|
125
|
+
precondition: (input, ctx) => latest.current.actions?.[name]?.precondition?.(input, ctx)
|
|
126
|
+
} : {},
|
|
127
|
+
execute: (input, ctx) => {
|
|
128
|
+
const live = latest.current.actions?.[name];
|
|
129
|
+
if (!live) throw new Error(`action "${name}" disappeared from the config`);
|
|
130
|
+
return live.execute(input, ctx);
|
|
131
|
+
},
|
|
132
|
+
...act.policies ? { policies: act.policies } : {},
|
|
133
|
+
...act.meta ? { meta: act.meta } : {},
|
|
134
|
+
...act.timeoutMs !== void 0 ? { timeoutMs: act.timeoutMs } : {}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
type: cfg.type,
|
|
139
|
+
...cfg.instanceId !== void 0 ? { instanceId: cfg.instanceId } : {},
|
|
140
|
+
description: cfg.description,
|
|
141
|
+
...cfg.parent ? { parent: cfg.parent } : {},
|
|
142
|
+
...cfg.meta ? { meta: cfg.meta } : {},
|
|
143
|
+
...cfg.internal ? { internal: cfg.internal } : {},
|
|
144
|
+
...cfg.policies ? { policies: cfg.policies } : {},
|
|
145
|
+
...cfg.origin !== void 0 ? { origin: cfg.origin } : {},
|
|
146
|
+
...cfg.priority !== void 0 ? { priority: cfg.priority } : {},
|
|
147
|
+
...cfg.enabled !== void 0 ? { enabled: cfg.enabled } : {},
|
|
148
|
+
...Object.keys(observations).length > 0 ? { observations } : {},
|
|
149
|
+
...Object.keys(actions).length > 0 ? { actions } : {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function evaluateReason(reason) {
|
|
153
|
+
try {
|
|
154
|
+
if (typeof reason === "function") return reason();
|
|
155
|
+
if (typeof reason === "string") return reason;
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
return "Currently unavailable";
|
|
159
|
+
}
|
|
160
|
+
function structuralFingerprint(cfg) {
|
|
161
|
+
const capability = (def) => ({
|
|
162
|
+
description: def.description,
|
|
163
|
+
output: "output" in def && def.output ? def.output.jsonSchema : void 0,
|
|
164
|
+
input: "input" in def ? def.input.jsonSchema : void 0,
|
|
165
|
+
effect: "effect" in def ? def.effect : void 0,
|
|
166
|
+
idempotent: "idempotent" in def ? def.idempotent : void 0,
|
|
167
|
+
reversible: "reversible" in def ? def.reversible : void 0,
|
|
168
|
+
confirmation: "confirmation" in def ? def.confirmation : void 0,
|
|
169
|
+
audit: "audit" in def ? def.audit : void 0,
|
|
170
|
+
timeoutMs: def.timeoutMs,
|
|
171
|
+
hasWhen: def.when !== void 0,
|
|
172
|
+
hasPrecondition: "precondition" in def && def.precondition !== void 0,
|
|
173
|
+
policies: (def.policies ?? []).map((p) => p.name)
|
|
174
|
+
});
|
|
175
|
+
return JSON.stringify({
|
|
176
|
+
type: cfg.type,
|
|
177
|
+
instanceId: cfg.instanceId ?? "default",
|
|
178
|
+
description: cfg.description,
|
|
179
|
+
parent: cfg.parent,
|
|
180
|
+
meta: cfg.meta,
|
|
181
|
+
origin: cfg.origin,
|
|
182
|
+
priority: cfg.priority,
|
|
183
|
+
policies: (cfg.policies ?? []).map((p) => p.name),
|
|
184
|
+
observations: Object.fromEntries(
|
|
185
|
+
Object.entries(cfg.observations ?? {}).map(([name, def]) => [name, capability(def)])
|
|
186
|
+
),
|
|
187
|
+
actions: Object.fromEntries(
|
|
188
|
+
Object.entries(cfg.actions ?? {}).map(([name, def]) => [name, capability(def)])
|
|
189
|
+
)
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function pushAvailability(handle, cfg, lastPushed, lastEnabled) {
|
|
193
|
+
const patch = {};
|
|
194
|
+
const enabled = cfg.enabled !== false;
|
|
195
|
+
if (lastEnabled.current !== enabled) {
|
|
196
|
+
patch.enabled = enabled;
|
|
197
|
+
lastEnabled.current = enabled;
|
|
198
|
+
}
|
|
199
|
+
const availability = {};
|
|
200
|
+
const evaluate = (name, def) => {
|
|
201
|
+
if (!def.when) return;
|
|
202
|
+
let available = true;
|
|
203
|
+
try {
|
|
204
|
+
available = def.when() !== false;
|
|
205
|
+
} catch {
|
|
206
|
+
available = false;
|
|
207
|
+
}
|
|
208
|
+
const entry = available ? { available: true } : { available: false, reason: evaluateReason(def.unavailableReason) };
|
|
209
|
+
const prev = lastPushed.current[name];
|
|
210
|
+
if (!prev || prev.available !== entry.available || prev.reason !== entry.reason) {
|
|
211
|
+
availability[name] = entry;
|
|
212
|
+
lastPushed.current[name] = entry;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
for (const [name, def] of Object.entries(cfg.observations ?? {})) evaluate(name, def);
|
|
216
|
+
for (const [name, def] of Object.entries(cfg.actions ?? {})) evaluate(name, def);
|
|
217
|
+
if (Object.keys(availability).length > 0) patch.availability = availability;
|
|
218
|
+
if (patch.enabled !== void 0 || patch.availability) handle.update(patch);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/confirmations.ts
|
|
222
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
223
|
+
function usePendingConfirmations() {
|
|
224
|
+
const registry = useAgentSurface();
|
|
225
|
+
const [pending, setPending] = useState2(
|
|
226
|
+
() => registry.confirmations.pending()
|
|
227
|
+
);
|
|
228
|
+
useEffect2(() => {
|
|
229
|
+
setPending(registry.confirmations.pending());
|
|
230
|
+
return registry.confirmations.subscribe((next) => {
|
|
231
|
+
setPending(next);
|
|
232
|
+
});
|
|
233
|
+
}, [registry]);
|
|
234
|
+
return pending.map((record) => ({
|
|
235
|
+
...record,
|
|
236
|
+
approve: () => registry.confirmations.resolve(record.confirmationId, { approved: true }),
|
|
237
|
+
deny: (reason) => registry.confirmations.resolve(record.confirmationId, {
|
|
238
|
+
approved: false,
|
|
239
|
+
...reason !== void 0 ? { reason } : {}
|
|
240
|
+
})
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// src/granular.ts
|
|
245
|
+
import {
|
|
246
|
+
createContext as createContext2,
|
|
247
|
+
createElement as createElement2,
|
|
248
|
+
useContext as useContext2,
|
|
249
|
+
useEffect as useEffect3,
|
|
250
|
+
useMemo,
|
|
251
|
+
useState as useState3
|
|
252
|
+
} from "react";
|
|
253
|
+
var ScopeContext = createContext2(null);
|
|
254
|
+
function AgentComponentScope(props) {
|
|
255
|
+
const [, setVersion] = useState3(0);
|
|
256
|
+
const store = useMemo(() => {
|
|
257
|
+
const observations = /* @__PURE__ */ new Map();
|
|
258
|
+
const actions = /* @__PURE__ */ new Map();
|
|
259
|
+
const bump = () => setVersion((v) => v + 1);
|
|
260
|
+
return {
|
|
261
|
+
observations,
|
|
262
|
+
actions,
|
|
263
|
+
bump,
|
|
264
|
+
add(kind, name, def) {
|
|
265
|
+
const map = kind === "observation" ? observations : actions;
|
|
266
|
+
map.set(name, def);
|
|
267
|
+
bump();
|
|
268
|
+
return () => {
|
|
269
|
+
map.delete(name);
|
|
270
|
+
bump();
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}, []);
|
|
275
|
+
return createElement2(
|
|
276
|
+
ScopeContext.Provider,
|
|
277
|
+
{ value: store },
|
|
278
|
+
createElement2(ScopeRegistrar, { store, config: props.config }),
|
|
279
|
+
props.children
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function ScopeRegistrar(props) {
|
|
283
|
+
useAgentComponent({
|
|
284
|
+
...props.config,
|
|
285
|
+
observations: Object.fromEntries(props.store.observations),
|
|
286
|
+
actions: Object.fromEntries(props.store.actions)
|
|
287
|
+
});
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
function useScope(hook) {
|
|
291
|
+
const store = useContext2(ScopeContext);
|
|
292
|
+
if (!store) {
|
|
293
|
+
throw new Error(`${hook} must be used inside an <AgentComponentScope>`);
|
|
294
|
+
}
|
|
295
|
+
return store;
|
|
296
|
+
}
|
|
297
|
+
function useAgentAction(name, def) {
|
|
298
|
+
const store = useScope("useAgentAction");
|
|
299
|
+
if (store.actions.has(name)) store.actions.set(name, def);
|
|
300
|
+
useEffect3(() => store.add("action", name, def), [store, name]);
|
|
301
|
+
}
|
|
302
|
+
function useAgentObservation(name, def) {
|
|
303
|
+
const store = useScope("useAgentObservation");
|
|
304
|
+
if (store.observations.has(name)) {
|
|
305
|
+
store.observations.set(name, def);
|
|
306
|
+
}
|
|
307
|
+
useEffect3(() => store.add("observation", name, def), [store, name]);
|
|
308
|
+
}
|
|
309
|
+
export {
|
|
310
|
+
AgentComponentScope,
|
|
311
|
+
AgentSurfaceProvider,
|
|
312
|
+
readRenderScopeContext as unstable_readRenderScopeContext,
|
|
313
|
+
setRenderScopeContext as unstable_setRenderScopeContext,
|
|
314
|
+
useAgentAction,
|
|
315
|
+
useAgentComponent,
|
|
316
|
+
useAgentObservation,
|
|
317
|
+
useAgentSurface,
|
|
318
|
+
usePendingConfirmations
|
|
319
|
+
};
|
|
320
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/use-agent-component.ts","../src/render-scope.ts","../src/confirmations.ts","../src/granular.ts"],"sourcesContent":["import { createContext, createElement, useContext, type ReactNode } from \"react\";\nimport type { AgentSurfaceRegistry } from \"@agent-surface/core\";\n\nconst AgentSurfaceContext = createContext<AgentSurfaceRegistry | null>(null);\n\nexport interface AgentSurfaceProviderProps {\n registry: AgentSurfaceRegistry;\n children: ReactNode;\n}\n\n/**\n * The application creates the registry ONCE (module scope or top-level\n * useState initializer) and passes it down — registry creation is where\n * environment, policies, audit and route wiring live (docs/04).\n */\nexport function AgentSurfaceProvider(props: AgentSurfaceProviderProps): ReactNode {\n return createElement(AgentSurfaceContext.Provider, { value: props.registry }, props.children);\n}\n\n/** Access the registry from context. Throws if no provider is mounted. */\nexport function useAgentSurface(): AgentSurfaceRegistry {\n const registry = useContext(AgentSurfaceContext);\n if (!registry) {\n throw new Error(\n \"useAgentSurface: no <AgentSurfaceProvider> found above this component. Wrap your app in a provider with an explicitly created registry.\",\n );\n }\n return registry;\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type {\n AgentActionContext,\n AgentActionDefinition,\n AgentComponentDefinition,\n AgentObservationDefinition,\n AgentReadContext,\n AgentRegistrationHandle,\n JsonValue,\n} from \"@agent-surface/core\";\nimport { useAgentSurface } from \"./context.js\";\nimport { setRenderScopeContext } from \"./render-scope.js\";\n\nexport interface UseAgentComponentConfig\n extends Omit<AgentComponentDefinition, \"procedures\"> {\n /**\n * Gate for \"mounted but not presented\" (inactive tab, keep-alive, exit\n * animation). false ⇒ all capabilities visible-disabled. Default true.\n */\n enabled?: boolean;\n}\n\nexport interface AgentComponentHandle {\n /** Current registrationId; changes on remount/re-register. */\n registrationId: string | undefined;\n status: \"active\" | \"rejected\" | \"unregistered\" | \"pending\";\n}\n\n/**\n * One aggregated hook per agent component (docs/04, the recommended default):\n * one registration, one atomic descriptor, one lifecycle.\n *\n * Registration happens once per mount, in an effect; handlers are read through\n * a ref at invocation time (D3) — no dependency arrays, no useCallback, no\n * stale closures. Structure is frozen per registration (D2): changing it on a\n * live registration logs an error and re-registers.\n */\nexport function useAgentComponent(config: UseAgentComponentConfig): AgentComponentHandle {\n const registry = useAgentSurface();\n const type = config.type;\n const instanceId = config.instanceId ?? \"default\";\n\n // D3 latest-ref: every render writes the fresh config; the registered\n // definition's handlers delegate through it at invocation time.\n const latest = useRef(config);\n latest.current = config;\n\n // Record the render-scope link for a following useAgentProcedure call.\n setRenderScopeContext({ type, instanceId });\n\n const [nonce, setNonce] = useState(0);\n const handleRef = useRef<AgentRegistrationHandle | null>(null);\n const fingerprintRef = useRef<string | null>(null);\n const lastPushedAvailability = useRef<Record<string, { available: boolean; reason?: string }>>({});\n const lastPushedEnabled = useRef<boolean | null>(null);\n const [state, setState] = useState<AgentComponentHandle>({\n registrationId: undefined,\n status: \"pending\",\n });\n\n useEffect(() => {\n const definition = buildDelegatingDefinition(latest);\n const handle = registry.register(definition);\n handleRef.current = handle;\n fingerprintRef.current = structuralFingerprint(latest.current);\n lastPushedAvailability.current = {};\n lastPushedEnabled.current = latest.current.enabled !== false;\n const registrationId = handle.status === \"active\" ? handle.registrationId : undefined;\n const status = handle.status === \"active\" ? \"active\" : \"rejected\";\n setState((prev) =>\n prev.registrationId === registrationId && prev.status === status\n ? prev\n : { registrationId, status },\n );\n if (handle.status === \"active\") {\n pushAvailability(handle, latest.current, lastPushedAvailability, lastPushedEnabled);\n }\n return () => {\n handle.unregister();\n handleRef.current = null;\n fingerprintRef.current = null;\n };\n // Identity keys: (registry, type, instanceId) + explicit re-register nonce.\n }, [registry, type, instanceId, nonce]);\n\n // Availability is reactive (docs/04): re-evaluated on every commit and\n // PUSHED on change, so the surface version bumps and adapters refresh.\n useEffect(() => {\n const handle = handleRef.current;\n if (!handle || handle.status !== \"active\") return;\n const fingerprint = structuralFingerprint(latest.current);\n if (fingerprintRef.current !== null && fingerprint !== fingerprintRef.current) {\n // Structural change on a live registration violates D2. Re-register so\n // the surface never lies about what this registrationId can do.\n // eslint-disable-next-line no-console\n console.error(\n `[agent-surface] structural config change detected on live registration \"${type}\" (${instanceId}). ` +\n \"Structure (names, schemas, descriptions, effects, policies) is frozen per registration (D2); \" +\n \"keep it static per mount and put dynamism in when/enabled/handlers. Re-registering with a new registrationId.\",\n );\n setNonce((n) => n + 1);\n return;\n }\n pushAvailability(handle, latest.current, lastPushedAvailability, lastPushedEnabled);\n });\n\n return state;\n}\n\n/* ────────────────────────────── internals ────────────────────────────── */\n\ntype LatestRef = { current: UseAgentComponentConfig };\n\nfunction buildDelegatingDefinition(latest: LatestRef): AgentComponentDefinition {\n const cfg = latest.current;\n const observations: Record<string, AgentObservationDefinition<any>> = {};\n for (const [name, obs] of Object.entries(cfg.observations ?? {})) {\n observations[name] = {\n description: obs.description,\n output: obs.output,\n read: (ctx: AgentReadContext) => {\n const live = latest.current.observations?.[name];\n if (!live) throw new Error(`observation \"${name}\" disappeared from the config`);\n return live.read(ctx);\n },\n ...(obs.when !== undefined\n ? { when: () => latest.current.observations?.[name]?.when?.() !== false }\n : {}),\n ...(obs.unavailableReason !== undefined\n ? {\n unavailableReason: () =>\n evaluateReason(latest.current.observations?.[name]?.unavailableReason),\n }\n : {}),\n ...(obs.policies ? { policies: obs.policies } : {}),\n ...(obs.meta ? { meta: obs.meta } : {}),\n ...(obs.timeoutMs !== undefined ? { timeoutMs: obs.timeoutMs } : {}),\n };\n }\n const actions: Record<string, AgentActionDefinition<any, any>> = {};\n for (const [name, act] of Object.entries(cfg.actions ?? {})) {\n actions[name] = {\n description: act.description,\n input: act.input,\n ...(act.output ? { output: act.output } : {}),\n effect: act.effect,\n ...(act.idempotent !== undefined ? { idempotent: act.idempotent } : {}),\n ...(act.reversible !== undefined ? { reversible: act.reversible } : {}),\n ...(act.confirmation !== undefined ? { confirmation: act.confirmation } : {}),\n ...(act.audit !== undefined ? { audit: act.audit } : {}),\n ...(act.when !== undefined\n ? { when: () => latest.current.actions?.[name]?.when?.() !== false }\n : {}),\n ...(act.unavailableReason !== undefined\n ? {\n unavailableReason: () =>\n evaluateReason(latest.current.actions?.[name]?.unavailableReason),\n }\n : {}),\n ...(act.precondition !== undefined\n ? {\n precondition: (input: JsonValue, ctx: AgentReadContext) =>\n latest.current.actions?.[name]?.precondition?.(input, ctx),\n }\n : {}),\n execute: (input: JsonValue, ctx: AgentActionContext) => {\n const live = latest.current.actions?.[name];\n if (!live) throw new Error(`action \"${name}\" disappeared from the config`);\n return live.execute(input, ctx);\n },\n ...(act.policies ? { policies: act.policies } : {}),\n ...(act.meta ? { meta: act.meta } : {}),\n ...(act.timeoutMs !== undefined ? { timeoutMs: act.timeoutMs } : {}),\n };\n }\n return {\n type: cfg.type,\n ...(cfg.instanceId !== undefined ? { instanceId: cfg.instanceId } : {}),\n description: cfg.description,\n ...(cfg.parent ? { parent: cfg.parent } : {}),\n ...(cfg.meta ? { meta: cfg.meta } : {}),\n ...(cfg.internal ? { internal: cfg.internal } : {}),\n ...(cfg.policies ? { policies: cfg.policies } : {}),\n ...(cfg.origin !== undefined ? { origin: cfg.origin } : {}),\n ...(cfg.priority !== undefined ? { priority: cfg.priority } : {}),\n ...(cfg.enabled !== undefined ? { enabled: cfg.enabled } : {}),\n ...(Object.keys(observations).length > 0 ? { observations } : {}),\n ...(Object.keys(actions).length > 0 ? { actions } : {}),\n };\n}\n\nfunction evaluateReason(\n reason: string | (() => string) | undefined,\n): string {\n try {\n if (typeof reason === \"function\") return reason();\n if (typeof reason === \"string\") return reason;\n } catch {\n /* fall through */\n }\n return \"Currently unavailable\";\n}\n\n/** Structural fingerprint per D2 (handlers and when() results excluded). */\nfunction structuralFingerprint(cfg: UseAgentComponentConfig): string {\n const capability = (\n def:\n | AgentObservationDefinition<any>\n | AgentActionDefinition<any, any>,\n ): unknown => ({\n description: def.description,\n output: \"output\" in def && def.output ? def.output.jsonSchema : undefined,\n input: \"input\" in def ? def.input.jsonSchema : undefined,\n effect: \"effect\" in def ? def.effect : undefined,\n idempotent: \"idempotent\" in def ? def.idempotent : undefined,\n reversible: \"reversible\" in def ? def.reversible : undefined,\n confirmation: \"confirmation\" in def ? def.confirmation : undefined,\n audit: \"audit\" in def ? def.audit : undefined,\n timeoutMs: def.timeoutMs,\n hasWhen: def.when !== undefined,\n hasPrecondition: \"precondition\" in def && def.precondition !== undefined,\n policies: (def.policies ?? []).map((p) => p.name),\n });\n return JSON.stringify({\n type: cfg.type,\n instanceId: cfg.instanceId ?? \"default\",\n description: cfg.description,\n parent: cfg.parent,\n meta: cfg.meta,\n origin: cfg.origin,\n priority: cfg.priority,\n policies: (cfg.policies ?? []).map((p) => p.name),\n observations: Object.fromEntries(\n Object.entries(cfg.observations ?? {}).map(([name, def]) => [name, capability(def)]),\n ),\n actions: Object.fromEntries(\n Object.entries(cfg.actions ?? {}).map(([name, def]) => [name, capability(def)]),\n ),\n });\n}\n\nfunction pushAvailability(\n handle: AgentRegistrationHandle,\n cfg: UseAgentComponentConfig,\n lastPushed: { current: Record<string, { available: boolean; reason?: string }> },\n lastEnabled: { current: boolean | null },\n): void {\n const patch: {\n enabled?: boolean;\n availability?: Record<string, { available: boolean; reason?: string }>;\n } = {};\n\n const enabled = cfg.enabled !== false;\n if (lastEnabled.current !== enabled) {\n patch.enabled = enabled;\n lastEnabled.current = enabled;\n }\n\n const availability: Record<string, { available: boolean; reason?: string }> = {};\n const evaluate = (\n name: string,\n def: { when?: () => boolean; unavailableReason?: string | (() => string) },\n ): void => {\n if (!def.when) return; // no predicate ⇒ availability governed by enabled only\n let available = true;\n try {\n available = def.when() !== false;\n } catch {\n available = false;\n }\n const entry = available\n ? { available: true as const }\n : { available: false as const, reason: evaluateReason(def.unavailableReason) };\n const prev = lastPushed.current[name];\n if (!prev || prev.available !== entry.available || prev.reason !== entry.reason) {\n availability[name] = entry;\n lastPushed.current[name] = entry;\n }\n };\n for (const [name, def] of Object.entries(cfg.observations ?? {})) evaluate(name, def);\n for (const [name, def] of Object.entries(cfg.actions ?? {})) evaluate(name, def);\n\n if (Object.keys(availability).length > 0) patch.availability = availability;\n if (patch.enabled !== undefined || patch.availability) handle.update(patch);\n}\n","/**\n * Best-effort render-scope link between useAgentComponent and a following\n * useAgentProcedure in the SAME component function (docs/05): the component\n * hook records its identity during render; the procedure hook reads it.\n *\n * React exposes no public per-instance identity shared across independent\n * hook calls, so this is a heuristic: it is precise for the canonical\n * pattern (both hooks in one component) and clears itself at the end of the\n * synchronous render pass. A sibling component rendering later in the same\n * pass with only useAgentProcedure may pick up a stale link — cosmetic only\n * (the link is descriptor metadata, never authority).\n */\n\nexport interface RenderScopeContext {\n type: string;\n instanceId: string;\n}\n\ninterface Slot {\n context: RenderScopeContext;\n token: object;\n}\n\nlet current: Slot | null = null;\n\nexport function setRenderScopeContext(context: RenderScopeContext): void {\n const token = {};\n current = { context, token };\n queueMicrotask(() => {\n if (current?.token === token) current = null;\n });\n}\n\nexport function readRenderScopeContext(): RenderScopeContext | undefined {\n return current?.context;\n}\n","import { useEffect, useState } from \"react\";\nimport type { PendingConfirmation } from \"@agent-surface/core\";\nimport { useAgentSurface } from \"./context.js\";\n\nexport interface PendingConfirmationView extends PendingConfirmation {\n approve(): void;\n deny(reason?: string): void;\n}\n\n/**\n * Reactive list of pending confirmations for host-rendered dialogs. The\n * dialog is representation, not policy: approving calls\n * registry.confirmations.resolve, which mints the single-use evidence\n * (docs/04, docs/06).\n */\nexport function usePendingConfirmations(): PendingConfirmationView[] {\n const registry = useAgentSurface();\n const [pending, setPending] = useState<PendingConfirmation[]>(() =>\n registry.confirmations.pending(),\n );\n\n useEffect(() => {\n setPending(registry.confirmations.pending());\n return registry.confirmations.subscribe((next) => {\n setPending(next);\n });\n }, [registry]);\n\n return pending.map((record) => ({\n ...record,\n approve: () => registry.confirmations.resolve(record.confirmationId, { approved: true }),\n deny: (reason?: string) =>\n registry.confirmations.resolve(record.confirmationId, {\n approved: false,\n ...(reason !== undefined ? { reason } : {}),\n }),\n }));\n}\n","import {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from \"react\";\nimport type {\n AgentActionDefinition,\n AgentObservationDefinition,\n JsonValue,\n} from \"@agent-surface/core\";\nimport { useAgentComponent, type UseAgentComponentConfig } from \"./use-agent-component.js\";\n\n/**\n * Granular composition — Experimental (docs/04): capabilities contributed\n * from separate files/subcomponents. Late-added capabilities are structural\n * changes, so each attach/detach re-registers the scope (new registrationId).\n * The aggregated useAgentComponent hook remains the recommended default.\n */\n\ninterface ScopeStore {\n observations: Map<string, AgentObservationDefinition<any>>;\n actions: Map<string, AgentActionDefinition<any, any>>;\n bump(): void;\n add(kind: \"observation\" | \"action\", name: string, def: unknown): () => void;\n}\n\nconst ScopeContext = createContext<ScopeStore | null>(null);\n\nexport interface AgentComponentScopeProps {\n config: Omit<UseAgentComponentConfig, \"observations\" | \"actions\">;\n children: ReactNode;\n}\n\n/** Establishes a component scope; children attach capabilities to it. */\nexport function AgentComponentScope(props: AgentComponentScopeProps): ReactNode {\n const [, setVersion] = useState(0);\n const store = useMemo<ScopeStore>(() => {\n const observations = new Map<string, AgentObservationDefinition<any>>();\n const actions = new Map<string, AgentActionDefinition<any, any>>();\n const bump = (): void => setVersion((v) => v + 1);\n return {\n observations,\n actions,\n bump,\n add(kind, name, def) {\n const map = kind === \"observation\" ? observations : actions;\n map.set(name, def as never);\n bump();\n return () => {\n map.delete(name);\n bump();\n };\n },\n };\n }, []);\n\n return createElement(\n ScopeContext.Provider,\n { value: store },\n createElement(ScopeRegistrar, { store, config: props.config }),\n props.children,\n );\n}\n\nfunction ScopeRegistrar(props: {\n store: ScopeStore;\n config: Omit<UseAgentComponentConfig, \"observations\" | \"actions\">;\n}): null {\n // Child effects run before this parent effect, so attachments within one\n // commit are coalesced into a single (re-)registration.\n useAgentComponent({\n ...props.config,\n observations: Object.fromEntries(props.store.observations),\n actions: Object.fromEntries(props.store.actions),\n });\n return null;\n}\n\nfunction useScope(hook: string): ScopeStore {\n const store = useContext(ScopeContext);\n if (!store) {\n throw new Error(`${hook} must be used inside an <AgentComponentScope>`);\n }\n return store;\n}\n\nexport function useAgentAction<TIn extends JsonValue, TOut extends JsonValue | void = void>(\n name: string,\n def: AgentActionDefinition<TIn, TOut>,\n): void {\n const store = useScope(\"useAgentAction\");\n // Keep the stored definition fresh without re-registering (D3 handlers are\n // read through the aggregated hook's latest-ref at invocation time).\n if (store.actions.has(name)) store.actions.set(name, def as AgentActionDefinition<any, any>);\n useEffect(() => store.add(\"action\", name, def), [store, name]);\n}\n\nexport function useAgentObservation<TOut extends JsonValue>(\n name: string,\n def: AgentObservationDefinition<TOut>,\n): void {\n const store = useScope(\"useAgentObservation\");\n if (store.observations.has(name)) {\n store.observations.set(name, def as AgentObservationDefinition<any>);\n }\n useEffect(() => store.add(\"observation\", name, def), [store, name]);\n}\n"],"mappings":"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","names":["useEffect","useState","useState","useEffect","createContext","createElement","useContext","useEffect","useState","createContext","useState","createElement","useContext","useEffect"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-surface/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React bindings for agent-surface: lifecycle-correct registration hooks",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@agent-surface/core": "^0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"react": ">=18.2"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"react": "^19.1.1",
|
|
28
|
+
"react-dom": "^19.1.1",
|
|
29
|
+
"@types/react": "^19.1.9",
|
|
30
|
+
"@testing-library/react": "^16.3.0",
|
|
31
|
+
"zod": "^4.1.5"
|
|
32
|
+
},
|
|
33
|
+
"author": "Paolo Barbato",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20.19.0"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/Wiseair-srl/agent-surface.git",
|
|
40
|
+
"directory": "packages/react"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://agent-surface-docs.vercel.app",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/Wiseair-srl/agent-surface/issues"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"agent-surface",
|
|
51
|
+
"agent",
|
|
52
|
+
"ai",
|
|
53
|
+
"llm",
|
|
54
|
+
"frontend",
|
|
55
|
+
"capabilities",
|
|
56
|
+
"typescript",
|
|
57
|
+
"react",
|
|
58
|
+
"hooks"
|
|
59
|
+
],
|
|
60
|
+
"size-limit": [
|
|
61
|
+
{
|
|
62
|
+
"path": "dist/index.js",
|
|
63
|
+
"limit": "4 kB",
|
|
64
|
+
"ignore": [
|
|
65
|
+
"@agent-surface/core",
|
|
66
|
+
"react"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsup",
|
|
72
|
+
"typecheck": "tsc --noEmit",
|
|
73
|
+
"size": "size-limit"
|
|
74
|
+
}
|
|
75
|
+
}
|