@nelsonlongxiang/dsh-open-a2a-net 0.5.13

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.
@@ -0,0 +1,113 @@
1
+ /**
2
+ * A2A node extension (decentralized topology): registers the `a2a_teams` and
3
+ * `a2a_route` model tools over verified peer agent cards and direct peer
4
+ * routes, publishes this node's card and joined session teams, and dispatches
5
+ * inbound direct routes into live agent sessions.
6
+ * @module @nelsonlongxiang/dsh-open-a2a-net
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis';
9
+ import s from '@deepseek-ai/schemastery';
10
+ export type * from './types.ts';
11
+ export { A2aClient } from './a2a-client.ts';
12
+ export type { A2aClientOptions, A2aFetch, A2aSchedule } from './a2a-client.ts';
13
+ export declare const name = "a2a";
14
+ export declare const inject: string[];
15
+ /** One signed zone delegation published on this node's agent card. */
16
+ export interface DelegateConfig {
17
+ /** The delegated name; resolves zone-relatively at route time. */
18
+ readonly name: string;
19
+ /** Base URL of the zone the name resolves in. */
20
+ readonly url: string;
21
+ /** Base64 SPKI DER binding to the target zone's card key; `''` leaves the delegation unbound. */
22
+ readonly publicKey: string;
23
+ }
24
+ /** Deployment-varying A2A node facts; every field has a declared default. */
25
+ export interface Config {
26
+ /** `X-API-Key` value sent on peer requests and required by the control routes; empty disables the header. */
27
+ readonly apiKey: string;
28
+ /**
29
+ * This node's caller label. `''` (the default) derives `dsh-host-<8 hex>`
30
+ * from a per-home node id created on first use, so two deployments mounting
31
+ * defaults do not collide while a persisted home keeps the label stable
32
+ * across restarts.
33
+ */
34
+ readonly session: string;
35
+ /** Team name this node exposes for direct routing. */
36
+ readonly team: string;
37
+ /**
38
+ * Publish this node's `/.well-known/agent-card.json` on the shared web
39
+ * server (peer discovery). Requires the web server in the composition;
40
+ * the card carries this node's team, capabilities, referral list, and
41
+ * joined session teams so peers find it without a central directory.
42
+ */
43
+ readonly announce: boolean;
44
+ /** Human-facing name published on the agent card. */
45
+ readonly agentName: string;
46
+ /**
47
+ * Base URLs of seed peer nodes. `a2a_teams` lists teams discovered from
48
+ * the peers' agent cards and `a2a_route` connects to the owning peer's
49
+ * `/a2a/direct` endpoint. The list is a seed set: referral URLs learned
50
+ * from fetched cards join a bounded, quality-scored peer store persisted
51
+ * at `<dsh-home>/a2a/peers.json`.
52
+ */
53
+ readonly peers: string[];
54
+ /**
55
+ * Zone delegation records published (signed) on this node's agent card:
56
+ * each entry publishes `name` as resolvable in the zone at `url`, so a
57
+ * route for `name` walks the delegation chain (at most 5 hops, cycles
58
+ * fail closed).
59
+ */
60
+ readonly delegates: DelegateConfig[];
61
+ /**
62
+ * Harness home slice for the node keypair and peer store; `''` (the
63
+ * default) uses the process DSH home. The Ed25519 key lives at
64
+ * `<home>/a2a/node-key.pem` and is generated on first announce; a
65
+ * persisted key keeps the node's card identity stable across restarts.
66
+ */
67
+ readonly dshHome: string;
68
+ /**
69
+ * Agent-card validity. Announce re-signs at TTL/4 so three lost refreshes
70
+ * still leave a live card; a node silent for one TTL disappears from every
71
+ * peer's discovery without manual eviction.
72
+ */
73
+ readonly cardTtlMs: number;
74
+ /**
75
+ * Enable per-session A2A nodes: each live top-level session can join the
76
+ * network explicitly — label `<session>-<agentId8>`, team
77
+ * `<team>/<agentId8>`, node facts carrying the session title and a
78
+ * recent-activity excerpt. Joining is opt-in through the sidebar control's
79
+ * host routes; joined teams ride this node's card and dispatch through
80
+ * its `/a2a/direct` endpoint.
81
+ */
82
+ readonly sessionNodes: boolean;
83
+ /**
84
+ * Wake every cold joined session's agent when the plugin mounts (dev boxes
85
+ * and always-on collaboration hosts that restart often: the network state
86
+ * returns without opening each session). Each wake materializes a full
87
+ * agent — log replay plus composed preset world — so the default stays
88
+ * off for deployments that would rather pay on demand (wake-on-route and
89
+ * the sidebar's wake button remain available).
90
+ */
91
+ readonly wakeJoinedOnBoot: boolean;
92
+ /**
93
+ * `final` reply budget: how long an inbound direct route waits for the
94
+ * session's next assistant message before answering with a timeout
95
+ * notice. Without it a session that never idles (or never produces text)
96
+ * leaves the caller hanging until `routeTimeoutMs` expires.
97
+ */
98
+ readonly flushTimeoutMs: number;
99
+ /**
100
+ * `a2a_route` execution budget: how long a call may plausibly wait for a
101
+ * remote session's reply (default 30 minutes).
102
+ */
103
+ readonly routeTimeoutMs: number;
104
+ }
105
+ /** Schemastery configuration for the A2A client plugin row. */
106
+ export declare const Config: s<Config>;
107
+ /**
108
+ * Register the outbound peer tools, the direct-route endpoint, and (when
109
+ * composed) the announced card and session-node control surface.
110
+ * @param ctx - registrant context carrying the tool registry and timer.
111
+ * @param config - deployment's A2A node facts.
112
+ */
113
+ export declare function apply(ctx: Context, config: Config): void;
@@ -0,0 +1,8 @@
1
+ /** Package-owned invariant companion. @module @nelsonlongxiang/dsh-open-a2a-net/invariant */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ /** Cordis companion plugin name. */
4
+ export declare const name = "a2a-invariant";
5
+ /** Service required before the companion can reserve package ownership. */
6
+ export declare const inject: string[];
7
+ /** Register this package's invariant companion. */
8
+ export declare const apply: (ctx: Context) => Promise<() => void>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Persisted session-node join intent (`<dsh-home>/a2a/joined.json`). A join
3
+ * is a user gesture over a durable session, but the node it mounts lives and
4
+ * dies with the session's Agent instance — page reloads and host restarts
5
+ * dispose Agents, which silently dropped every join. The store keeps the
6
+ * intent across those lifecycles: the plugin remounts the node whenever the
7
+ * session's Agent comes back, until the user leaves (the only intent
8
+ * remover; disposal alone never unpersists).
9
+ * @module @nelsonlongxiang/dsh-open-a2a-net/joined-store
10
+ */
11
+ /**
12
+ * Hard cap on remembered join intents. Ids of deleted sessions linger
13
+ * harmlessly (no Agent ever comes back for them); the cap bounds the file,
14
+ * keeping the most recent intents (peer-store's bound rationale).
15
+ */
16
+ export declare const JOIN_CAP = 64;
17
+ /** The persisted intent document (whole-file read/write, small by design). */
18
+ export interface JoinedSnapshot {
19
+ readonly sessions: readonly string[];
20
+ }
21
+ /**
22
+ * Bounded set of session ids whose user joined them to the A2A network,
23
+ * with whole-file persistence. Pure of any registry knowledge: callers ask
24
+ * {@link has} when an Agent appears and record {@link add} / {@link remove}
25
+ * on the join and leave operations.
26
+ */
27
+ export declare class JoinedSessions {
28
+ private readonly path;
29
+ /** Session ids, most recently joined first. */
30
+ private ids;
31
+ /**
32
+ * @param path - persistence file (`<dsh-home>/a2a/joined.json`); empty = no persistence.
33
+ */
34
+ constructor(path: string);
35
+ /**
36
+ * Whether the session's join intent is remembered.
37
+ * @param id - the session id to check.
38
+ * @returns whether the intent is present.
39
+ */
40
+ has(id: string): boolean;
41
+ /**
42
+ * Every remembered join intent, most recently joined first.
43
+ * @returns the remembered session ids.
44
+ */
45
+ list(): readonly string[];
46
+ /**
47
+ * Remember one join intent, most-recent first, bounded by {@link JOIN_CAP}
48
+ * (the oldest intent beyond the cap is forgotten).
49
+ * @param id - the joined session id.
50
+ */
51
+ add(id: string): void;
52
+ /**
53
+ * Forget one join intent (the leave operation; a no-op when absent).
54
+ * @param id - the session id whose intent is removed.
55
+ */
56
+ remove(id: string): void;
57
+ /** Load a persisted snapshot on construction, if present. */
58
+ private restore;
59
+ /** Persist the intent set (no-op when no path was configured). */
60
+ private persist;
61
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Bounded, quality-scored peer store (GNUnet hostlist semantics, slice 2).
3
+ * The configured peer list is a seed set, not the network: referral URLs
4
+ * learned from fetched cards join the store, are bounded and quality-scored,
5
+ * and persist across restarts. Failed fetches degrade a peer; a bad peer that
6
+ * keeps failing is evicted, while seeds stay for the lifetime of the config
7
+ * that named them. Design basis:
8
+ * .agents/notes/proposed/feature/2026-08-16-gnunet-prior-art-for-a2a-topology.md.
9
+ * @module @nelsonlongxiang/dsh-open-a2a-net/peer-store
10
+ */
11
+ /** Hard cap on tracked peers, seeds included (hostlist bound: 30). */
12
+ export declare const PEER_CAP = 30;
13
+ /** Initial quality score of a seed or newly offered peer. */
14
+ export declare const INITIAL_SCORE = 10000;
15
+ /** Quality penalty on a failed fetch. */
16
+ export declare const FAILURE_PENALTY = 100;
17
+ /** Quality reward on a successful fetch. */
18
+ export declare const SUCCESS_REWARD = 100;
19
+ /** Score floor: at or below this a non-seed peer is evicted. */
20
+ export declare const EVICTION_FLOOR = 0;
21
+ /** One tracked peer. */
22
+ export interface PeerRecord {
23
+ readonly url: string;
24
+ score: number;
25
+ readonly seed: boolean;
26
+ }
27
+ /** The persisted store document (whole-file read/write, small by design). */
28
+ export interface PeerStoreSnapshot {
29
+ readonly peers: readonly PeerRecord[];
30
+ }
31
+ /**
32
+ * Bounded, quality-scored peer collection with whole-file persistence.
33
+ * Pure of any network: the caller drives fetch outcomes through
34
+ * {@link noteFailure} / {@link noteSuccess} and feeds referral URLs through
35
+ * {@link offer}.
36
+ */
37
+ export declare class PeerStore {
38
+ private readonly path;
39
+ private readonly cap;
40
+ private readonly peers;
41
+ /**
42
+ * @param seeds - the configured seed URLs; always retained (never evicted).
43
+ * @param path - persistence file (`<dsh-home>/a2a/peers.json`); empty = no persistence.
44
+ * @param cap - peer bound, seeds included (default {@link PEER_CAP}).
45
+ */
46
+ constructor(seeds: readonly string[], path: string, cap?: number);
47
+ /**
48
+ * Every tracked peer URL: seeds first (in first-tracked order), then
49
+ * offered peers by score descending (equal scores keep first-tracked order).
50
+ * @returns the ordered peer URLs.
51
+ */
52
+ list(): readonly string[];
53
+ /** Whether the store has room for one more peer. */
54
+ private hasRoom;
55
+ /**
56
+ * Offer a referral URL learned from a fetched card. Bounded: an unknown
57
+ * URL only joins when under the cap; a known URL changes nothing.
58
+ * @param url - the referred card URL.
59
+ * @returns whether the peer is tracked (freshly joined or already known).
60
+ */
61
+ offer(url: string): boolean;
62
+ /**
63
+ * Drop one tracked peer outright — a self-referral (a peer listing this
64
+ * node's own URL back at it) must not linger as a tracked peer. Seeds are
65
+ * config-owned and stay.
66
+ * @param url - the peer to forget.
67
+ */
68
+ drop(url: string): void;
69
+ /**
70
+ * Note a failed fetch of one peer. A non-seed's score drops; an
71
+ * at-or-below-floor peer is evicted, so a bad referral disappears rather
72
+ * than degrading forever. Seeds are config-owned and never penalized.
73
+ * @param url - the peer that failed.
74
+ */
75
+ noteFailure(url: string): void;
76
+ /**
77
+ * Note a successful fetch of one peer.
78
+ * @param url - the peer that answered with a verified card.
79
+ */
80
+ noteSuccess(url: string): void;
81
+ /**
82
+ * The current quality score of one tracked peer, for state reporting.
83
+ * @param url - the peer URL.
84
+ * @returns the score, or undefined when the peer is not tracked.
85
+ */
86
+ score(url: string): number | undefined;
87
+ /** Load a persisted snapshot on construction, if present. */
88
+ private restore;
89
+ /** Persist the current peer set (no-op when no path was configured). */
90
+ private persist;
91
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Wire and configuration vocabulary for the A2A client extension.
3
+ * @module @nelsonlongxiang/dsh-open-a2a-net/types
4
+ */
5
+ /** One peer node's agent card — the decentralized discovery record. */
6
+ export interface A2aPeerCard {
7
+ /** Human-facing peer name. */
8
+ readonly name: string;
9
+ /** The team this peer exposes. */
10
+ readonly team: string;
11
+ /** The peer's session id (diagnostics and signing identity). */
12
+ readonly session: string;
13
+ /** Capability flags the peer published, verbatim. */
14
+ readonly capabilities: unknown;
15
+ /** Epoch ms after which the card is stale; enforced at every parse. */
16
+ readonly expiresAt: number;
17
+ /**
18
+ * Card URLs of other nodes the publisher knows (discovery referrals).
19
+ * Unsigned and optional: a referral is fetched and verified as its own
20
+ * card before it is trusted, so its integrity is checked at that fetch,
21
+ * not by this card's signature.
22
+ */
23
+ readonly peers?: readonly string[];
24
+ /**
25
+ * Joined session teams this peer currently dispatches. Unsigned and
26
+ * optional: served fresh at read time, each entry is a team name the
27
+ * peer's `/a2a/direct` endpoint routes to that session, with the
28
+ * session's title and recent-activity excerpt as facts.
29
+ */
30
+ readonly sessionTeams?: readonly A2aSessionTeamInfo[];
31
+ /**
32
+ * The publishing host's LAN IPv4. Unsigned and optional: served fresh, it
33
+ * lets peers group and tell machines apart in a same-team fleet.
34
+ */
35
+ readonly lanIp?: string;
36
+ /** Base64 SPKI DER of the signing node's Ed25519 public key. */
37
+ readonly publicKey: string;
38
+ /**
39
+ * Zone records delegating names to other zones. Signed with the card: a
40
+ * record is an authority claim over the name (GNS DELEGATE semantics),
41
+ * unlike the unsigned `peers` referral hints.
42
+ */
43
+ readonly records?: readonly ZoneRecord[];
44
+ /** Base64 Ed25519 signature over the card's committed fields. */
45
+ readonly signature: string;
46
+ }
47
+ /** One joined session team advertised on a peer's card. */
48
+ export interface A2aSessionTeamInfo {
49
+ /** Session team name (`<team>/<agentId8>`); the route target. */
50
+ readonly team: string;
51
+ /** The session's title at read time. */
52
+ readonly name: string;
53
+ /** One-line excerpt of the session's newest user or assistant text. */
54
+ readonly description: string;
55
+ /** The session's working directory, when the publishing node shares it. */
56
+ readonly workspace?: string;
57
+ }
58
+ /**
59
+ * One zone record: a delegation of a name into another zone. The delegating
60
+ * zone's card signature commits the record, so only the zone key holder can
61
+ * publish or retire the name.
62
+ */
63
+ export interface ZoneRecord {
64
+ readonly type: 'delegate';
65
+ /** The delegated name; resolves zone-relatively. */
66
+ readonly name: string;
67
+ /** Base URL of the zone the name resolves in. */
68
+ readonly url: string;
69
+ /**
70
+ * Expected base64 SPKI public key of the target zone's card. When bound,
71
+ * a target card whose key differs fails resolution closed.
72
+ */
73
+ readonly publicKey?: string;
74
+ }
75
+ /** Canonical `a2a_route` success value. */
76
+ export interface A2aRouteOk {
77
+ readonly ok: true;
78
+ readonly team: string;
79
+ /** Reply text the remote team produced. */
80
+ readonly reply: string;
81
+ /** The answering peer's task id (diagnostics). */
82
+ readonly task_id: string;
83
+ /** Context id for continuing this conversation in a later `a2a_route` call. */
84
+ readonly context_id: string;
85
+ readonly task_status: string;
86
+ }
87
+ /** Canonical `a2a_route` failure value. */
88
+ export interface A2aRouteError {
89
+ readonly ok: false;
90
+ /** Peer or transport failure text. */
91
+ readonly error: string;
92
+ /** A2A JSON-RPC-style code when the peer supplied one. */
93
+ readonly code?: number;
94
+ readonly task_id?: string;
95
+ }
96
+ /** Canonical `a2a_route` value: success or explicit failure. */
97
+ export type A2aRouteResult = A2aRouteOk | A2aRouteError;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Zone-relative name resolution over agent cards (GNUnet semantics, slice 3).
3
+ * A name resolves in a zone: the zone's own team matches first, then its
4
+ * signed delegate records, recursively. The walk is bounded by a hard depth
5
+ * cap and by visited-URL cycle detection — both fail closed with a reason,
6
+ * never a hang. Design basis:
7
+ * .agents/notes/proposed/feature/2026-08-16-gnunet-prior-art-for-a2a-topology.md.
8
+ * @module @nelsonlongxiang/dsh-open-a2a-net/zone
9
+ */
10
+ import type { A2aPeerCard } from './types.ts';
11
+ /** Hard delegation-walk bound in hops (GNS `loop_threshold`). */
12
+ export declare const ZONE_DEPTH_CAP = 5;
13
+ /** Why a resolution failed; every failure mode is closed. */
14
+ export type ZoneResolutionReason = 'not-found' | 'depth' | 'cycle' | 'key-mismatch' | 'unreachable';
15
+ /** The resolution outcome: the owning zone, or the closed-failure reason. */
16
+ export type ZoneResolution = {
17
+ readonly ok: true;
18
+ readonly url: string;
19
+ readonly card: A2aPeerCard;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly reason: ZoneResolutionReason;
23
+ readonly detail: string;
24
+ };
25
+ /**
26
+ * Fetch one zone's verified card; returns undefined when unreachable or the
27
+ * card fails verification. The caller owns scoring and referral intake.
28
+ */
29
+ export type ZoneCardFetch = (url: string) => Promise<A2aPeerCard | undefined>;
30
+ /**
31
+ * Resolve one name starting from a zone's base URL.
32
+ * @param fetchCard - verified-card fetch for one zone URL.
33
+ * @param startUrl - base URL of the zone the name resolves in.
34
+ * @param name - the zone-relative name (a team name).
35
+ * @returns the resolved zone URL with its verified card, or the closed-failure reason.
36
+ */
37
+ export declare function resolveZone(fetchCard: ZoneCardFetch, startUrl: string, name: string): Promise<ZoneResolution>;
package/lib/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Wire and configuration vocabulary for the A2A client extension.
3
+ * @module @nelsonlongxiang/dsh-open-a2a-net/types
4
+ */
5
+ export {};
package/lib/zone.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Zone-relative name resolution over agent cards (GNUnet semantics, slice 3).
3
+ * A name resolves in a zone: the zone's own team matches first, then its
4
+ * signed delegate records, recursively. The walk is bounded by a hard depth
5
+ * cap and by visited-URL cycle detection — both fail closed with a reason,
6
+ * never a hang. Design basis:
7
+ * .agents/notes/proposed/feature/2026-08-16-gnunet-prior-art-for-a2a-topology.md.
8
+ * @module @nelsonlongxiang/dsh-open-a2a-net/zone
9
+ */
10
+ /** Hard delegation-walk bound in hops (GNS `loop_threshold`). */
11
+ export const ZONE_DEPTH_CAP = 5;
12
+ /**
13
+ * Resolve one name starting from a zone's base URL.
14
+ * @param fetchCard - verified-card fetch for one zone URL.
15
+ * @param startUrl - base URL of the zone the name resolves in.
16
+ * @param name - the zone-relative name (a team name).
17
+ * @returns the resolved zone URL with its verified card, or the closed-failure reason.
18
+ */
19
+ export async function resolveZone(fetchCard, startUrl, name) {
20
+ if (name === '')
21
+ return { ok: false, reason: 'not-found', detail: 'empty name' };
22
+ return walk(fetchCard, startUrl, name, undefined, new Set([startUrl]), 0);
23
+ }
24
+ /**
25
+ * One delegation hop. The zone's own team is authoritative for the name;
26
+ * a delegate record hands the name to another zone.
27
+ * @param fetchCard - verified-card fetch for one zone URL.
28
+ * @param url - the zone being consulted.
29
+ * @param name - the zone-relative name.
30
+ * @param expectedKey - base64 SPKI key the consulted card must present when the delegating record bound one.
31
+ * @param visited - zone URLs already consulted (cycle detection).
32
+ * @param depth - delegations already walked.
33
+ * @returns the resolved zone, or the closed-failure reason.
34
+ */
35
+ async function walk(fetchCard, url, name, expectedKey, visited, depth) {
36
+ if (depth > ZONE_DEPTH_CAP) {
37
+ return { ok: false, reason: 'depth', detail: `delegation walk exceeded ${String(ZONE_DEPTH_CAP)} hops at ${url}` };
38
+ }
39
+ const card = await fetchCard(url);
40
+ if (card === undefined)
41
+ return { ok: false, reason: 'unreachable', detail: url };
42
+ if (expectedKey !== undefined && card.publicKey !== expectedKey) {
43
+ return { ok: false, reason: 'key-mismatch', detail: `${url} does not present the delegating zone's bound key` };
44
+ }
45
+ if (card.team === name)
46
+ return { ok: true, url, card };
47
+ const delegate = (card.records ?? []).find(record => record.name === name);
48
+ if (delegate === undefined)
49
+ return { ok: false, reason: 'not-found', detail: `zone ${url} publishes no ${name}` };
50
+ if (visited.has(delegate.url)) {
51
+ return { ok: false, reason: 'cycle', detail: `delegation cycle through ${delegate.url}` };
52
+ }
53
+ visited.add(delegate.url);
54
+ return walk(fetchCard, delegate.url, name, delegate.publicKey, visited, depth + 1);
55
+ }
package/package.json ADDED
@@ -0,0 +1,157 @@
1
+ {
2
+ "name": "@nelsonlongxiang/dsh-open-a2a-net",
3
+ "version": "0.5.13",
4
+ "description": "Open A2A network plugin for DeepSeek Harness: signed agent cards, decentralized peer/zone discovery, direct routing model tools, and joinable session nodes with a sidebar control",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/types/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./invariant": {
14
+ "types": "./lib/types/invariant.d.ts",
15
+ "default": "./lib/invariant.js"
16
+ },
17
+ "./client": {
18
+ "types": "./lib/types/client/index.d.ts",
19
+ "default": "./lib/client.js"
20
+ },
21
+ "./cordis.patch.yml": "./cordis.patch.yml",
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "lib",
26
+ "images",
27
+ "README_zh.md",
28
+ "cordis.patch.yml",
29
+ "README.md"
30
+ ],
31
+ "dsh": {
32
+ "bundle": {
33
+ "patch": "./cordis.patch.yml"
34
+ },
35
+ "client": {
36
+ "platform": "web",
37
+ "inject": [
38
+ "@deepseek-ai/dsh-client-runtime",
39
+ "@deepseek-ai/dsh-client-locale",
40
+ "@deepseek-ai/dsh-client-ui-slots",
41
+ "@deepseek-ai/dsh-client-ui-sidebar"
42
+ ]
43
+ }
44
+ },
45
+ "scripts": {
46
+ "prepare": "pnpm build",
47
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && tsdown",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
49
+ "test": "vitest run",
50
+ "test:build-layout": "vitest run tests/build-layout.spec.ts",
51
+ "verify": "pnpm typecheck && pnpm build && pnpm test && pnpm test:build-layout"
52
+ },
53
+ "peerDependencies": {
54
+ "@deepseek-ai/cordis": ">=4.0.1",
55
+ "@deepseek-ai/cordis-plugin-loader": ">=1.0.2",
56
+ "@deepseek-ai/cordis-plugin-timer": ">=1.1.3",
57
+ "@deepseek-ai/dsh-agent": ">=0.1.0-rc.6",
58
+ "@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.6",
59
+ "@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.6",
60
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.0-rc.6",
61
+ "@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.0-rc.6",
62
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.6",
63
+ "@deepseek-ai/dsh-home-paths": ">=0.1.0-rc.6",
64
+ "@deepseek-ai/dsh-host-apiproxy": ">=0.1.0-rc.6",
65
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.6",
66
+ "@deepseek-ai/dsh-invariants": ">=0.1.0-rc.6",
67
+ "@deepseek-ai/dsh-llm": ">=0.1.0-rc.6",
68
+ "@deepseek-ai/dsh-session": ">=0.1.0-rc.6",
69
+ "@deepseek-ai/dsh-session-persistence": ">=0.1.0-rc.6",
70
+ "@deepseek-ai/dsh-session-title": ">=0.1.0-rc.6",
71
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.6",
72
+ "@deepseek-ai/schemastery": ">=3.18.1",
73
+ "react": "^18.2.0"
74
+ },
75
+ "peerDependenciesMeta": {
76
+ "@deepseek-ai/cordis": {
77
+ "optional": true
78
+ },
79
+ "@deepseek-ai/cordis-plugin-loader": {
80
+ "optional": true
81
+ },
82
+ "@deepseek-ai/cordis-plugin-timer": {
83
+ "optional": true
84
+ },
85
+ "@deepseek-ai/dsh-agent": {
86
+ "optional": true
87
+ },
88
+ "@deepseek-ai/dsh-client-locale": {
89
+ "optional": true
90
+ },
91
+ "@deepseek-ai/dsh-client-runtime": {
92
+ "optional": true
93
+ },
94
+ "@deepseek-ai/dsh-client-ui-primitives": {
95
+ "optional": true
96
+ },
97
+ "@deepseek-ai/dsh-client-ui-sidebar": {
98
+ "optional": true
99
+ },
100
+ "@deepseek-ai/dsh-client-ui-slots": {
101
+ "optional": true
102
+ },
103
+ "@deepseek-ai/dsh-home-paths": {
104
+ "optional": true
105
+ },
106
+ "@deepseek-ai/dsh-host-apiproxy": {
107
+ "optional": true
108
+ },
109
+ "@deepseek-ai/dsh-host-webserver": {
110
+ "optional": true
111
+ },
112
+ "@deepseek-ai/dsh-invariants": {
113
+ "optional": true
114
+ },
115
+ "@deepseek-ai/dsh-llm": {
116
+ "optional": true
117
+ },
118
+ "@deepseek-ai/dsh-session": {
119
+ "optional": true
120
+ },
121
+ "@deepseek-ai/dsh-session-persistence": {
122
+ "optional": true
123
+ },
124
+ "@deepseek-ai/dsh-session-title": {
125
+ "optional": true
126
+ },
127
+ "@deepseek-ai/dsh-tools": {
128
+ "optional": true
129
+ },
130
+ "@deepseek-ai/schemastery": {
131
+ "optional": true
132
+ },
133
+ "react": {
134
+ "optional": true
135
+ }
136
+ },
137
+ "devDependencies": {
138
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.6",
139
+ "@testing-library/react": "^16.3.0",
140
+ "@types/node": "^24.13.3",
141
+ "@types/react": "~18.3.1",
142
+ "@types/react-dom": "^18.3.7",
143
+ "clsx": "^2.1.1",
144
+ "jsdom": "^26.1.0",
145
+ "lightningcss": "^1.33.0",
146
+ "react": "^18.2.0",
147
+ "react-dom": "^18.2.0",
148
+ "tsdown": "0.22.2",
149
+ "typescript": "^5.9.3",
150
+ "vitest": "^4.1.8"
151
+ },
152
+ "license": "MIT",
153
+ "repository": {
154
+ "type": "git",
155
+ "url": "git+https://gitee.com/NelsonLongXiang/dsh-open-a2a-net.git"
156
+ }
157
+ }