dsh-plugin-subagent-director 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/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/lib/bridge-contract.d.ts +41 -0
- package/lib/bridge-contract.d.ts.map +1 -0
- package/lib/bridge-contract.js +7 -0
- package/lib/bridge-contract.js.map +1 -0
- package/lib/bridge-entry.d.ts +29 -0
- package/lib/bridge-entry.d.ts.map +1 -0
- package/lib/bridge-entry.js +10 -0
- package/lib/bridge-entry.js.map +1 -0
- package/lib/client/RoleCard.d.ts +23 -0
- package/lib/client/RoleCard.d.ts.map +1 -0
- package/lib/client/RoleCard.js +72 -0
- package/lib/client/RoleCard.js.map +1 -0
- package/lib/client/SubagentModelDock.d.ts +29 -0
- package/lib/client/SubagentModelDock.d.ts.map +1 -0
- package/lib/client/SubagentModelDock.js +32 -0
- package/lib/client/SubagentModelDock.js.map +1 -0
- package/lib/client/SubagentOptionsSection.d.ts +23 -0
- package/lib/client/SubagentOptionsSection.d.ts.map +1 -0
- package/lib/client/SubagentOptionsSection.js +164 -0
- package/lib/client/SubagentOptionsSection.js.map +1 -0
- package/lib/client/index.d.ts +44 -0
- package/lib/client/index.d.ts.map +1 -0
- package/lib/client/index.js +1541 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/locales.d.ts +13 -0
- package/lib/client/locales.d.ts.map +1 -0
- package/lib/client/locales.js +107 -0
- package/lib/client/locales.js.map +1 -0
- package/lib/client/store-logic.d.ts +105 -0
- package/lib/client/store-logic.d.ts.map +1 -0
- package/lib/client/store-logic.js +143 -0
- package/lib/client/store-logic.js.map +1 -0
- package/lib/client/store.d.ts +104 -0
- package/lib/client/store.d.ts.map +1 -0
- package/lib/client/store.js +223 -0
- package/lib/client/store.js.map +1 -0
- package/lib/client/subagent-model.d.ts +47 -0
- package/lib/client/subagent-model.d.ts.map +1 -0
- package/lib/client/subagent-model.js +81 -0
- package/lib/client/subagent-model.js.map +1 -0
- package/lib/client/ui.d.ts +26 -0
- package/lib/client/ui.d.ts.map +1 -0
- package/lib/client/ui.js +102 -0
- package/lib/client/ui.js.map +1 -0
- package/lib/config.d.ts +63 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +26 -0
- package/lib/config.js.map +1 -0
- package/lib/delegation-tool.d.ts +169 -0
- package/lib/delegation-tool.d.ts.map +1 -0
- package/lib/delegation-tool.js +404 -0
- package/lib/delegation-tool.js.map +1 -0
- package/lib/envelope.d.ts +97 -0
- package/lib/envelope.d.ts.map +1 -0
- package/lib/envelope.js +136 -0
- package/lib/envelope.js.map +1 -0
- package/lib/guidance.d.ts +37 -0
- package/lib/guidance.d.ts.map +1 -0
- package/lib/guidance.js +46 -0
- package/lib/guidance.js.map +1 -0
- package/lib/index.d.ts +29 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +63 -0
- package/lib/index.js.map +1 -0
- package/lib/remote.d.ts +102 -0
- package/lib/remote.d.ts.map +1 -0
- package/lib/remote.js +254 -0
- package/lib/remote.js.map +1 -0
- package/lib/route-resolver.d.ts +118 -0
- package/lib/route-resolver.d.ts.map +1 -0
- package/lib/route-resolver.js +71 -0
- package/lib/route-resolver.js.map +1 -0
- package/lib/settings.d.ts +157 -0
- package/lib/settings.d.ts.map +1 -0
- package/lib/settings.js +118 -0
- package/lib/settings.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire envelope parsing/validation/response helpers for the self-published
|
|
3
|
+
* "/subagent-director" settings bridge (src/remote.ts). Pure, zero-dependency
|
|
4
|
+
* (no cordis): every function here is unit-testable in a plain node
|
|
5
|
+
* environment and reused verbatim by the host route handler.
|
|
6
|
+
*
|
|
7
|
+
* The wire contract mirrors the generic Connection RPC channel that the client
|
|
8
|
+
* already speaks (dsh-client-connection/lib/client.js:10094-10113): the browser
|
|
9
|
+
* POSTs a "client-request" envelope and expects a "server-response" envelope
|
|
10
|
+
* echoing the same rpcId with an RpcResult in the result slot. We implement the
|
|
11
|
+
* host side directly on a webServer prefix route (kind:"prefix",
|
|
12
|
+
* path:"/subagent-director") instead of via connection.rpc, so a tree-external
|
|
13
|
+
* plugin needs no apiproxy changes.
|
|
14
|
+
*
|
|
15
|
+
* Referenced semantics: dsh-client-connection/lib/index.js:275-300
|
|
16
|
+
* (rpcFetchHandler) and 322-328 (fullResponse).
|
|
17
|
+
*/
|
|
18
|
+
import type { RpcResult } from '@deepseek-ai/dsh-host-apiproxy/api';
|
|
19
|
+
/** The rpcId the host uses for envelopes that fail top-level validation. */
|
|
20
|
+
export declare const INVALID_REQUEST_RPC_ID = "invalid-request";
|
|
21
|
+
/** Wire "client-request" envelope a browser rpc.call sends to the channel. */
|
|
22
|
+
export interface ClientRequestEnvelope {
|
|
23
|
+
type: 'client-request';
|
|
24
|
+
rpcId: string;
|
|
25
|
+
method: string;
|
|
26
|
+
payload: unknown;
|
|
27
|
+
}
|
|
28
|
+
/** Wire "server-response" envelope the host answers with. */
|
|
29
|
+
export interface ServerResponseEnvelope<T = unknown> {
|
|
30
|
+
type: 'server-response';
|
|
31
|
+
rpcId: string;
|
|
32
|
+
result: RpcResult<T>;
|
|
33
|
+
}
|
|
34
|
+
/** Outcome of parsing/validating a "client-request" envelope body. */
|
|
35
|
+
export type EnvelopeParseResult = {
|
|
36
|
+
ok: true;
|
|
37
|
+
envelope: ClientRequestEnvelope;
|
|
38
|
+
} | {
|
|
39
|
+
ok: false;
|
|
40
|
+
issues: string[];
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Parse and validate a decoded JSON body as a "client-request" envelope.
|
|
44
|
+
* Accepts only an object whose `type` is exactly "client-request", with string
|
|
45
|
+
* `rpcId` and `method`. Returns a structured outcome so the caller can build
|
|
46
|
+
* an "invalid client-request message" bad-request response.
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseClientRequestEnvelope(body: unknown): EnvelopeParseResult;
|
|
49
|
+
/**
|
|
50
|
+
* Build the "server-response" envelope for the requested rpcId carrying an
|
|
51
|
+
* RpcResult, mirroring dsh-client-connection/lib/index.js:322-328 (fullResponse).
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildServerResponse<T>(rpcId: string, result: RpcResult<T>): ServerResponseEnvelope<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Build the bad-request "server-response" for a malformed client-request
|
|
56
|
+
* envelope. The host cannot trust the caller's rpcId on a malformed message,
|
|
57
|
+
* so it uses the fixed INVALID_REQUEST_RPC_ID (mirroring
|
|
58
|
+
* invalidEnvelopeResponse in dsh-client-connection/lib/index.js:302-309).
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildBadRequestResponse(issues: readonly string[]): ServerResponseEnvelope;
|
|
61
|
+
/**
|
|
62
|
+
* Build the bad-request "server-response" for a message whose `method` does not
|
|
63
|
+
* match the path-derived endpoint (mirroring
|
|
64
|
+
* dsh-client-connection/lib/index.js:289-293).
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildMethodMismatchResponse(rpcId: string, method: unknown, endpoint: string): ServerResponseEnvelope;
|
|
67
|
+
/**
|
|
68
|
+
* Whether a WHATWG URL hostname names the local loopback authority.
|
|
69
|
+
* Accepts "localhost", the IPv6 loopback literal "[::1]" (brackets retained, as
|
|
70
|
+
* WHATWG URL hostname does), or any IPv4 address in the 127/8 range. Rejects
|
|
71
|
+
* everything else. Mirrors the client-connection predicate
|
|
72
|
+
* (dsh-client-connection/lib/client.js:10135-10139).
|
|
73
|
+
*/
|
|
74
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Classify a raw "Host" request header as loopback. Strips a port suffix and
|
|
77
|
+
* bracket-normalizes the authority before delegating to
|
|
78
|
+
* {@link isLoopbackHostname}. With no port present the header is treated as a
|
|
79
|
+
* bare hostname.
|
|
80
|
+
*/
|
|
81
|
+
export declare function isLoopbackHost(rawHost: string): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Derive the endpoint segment from a pathname under the channel prefix.
|
|
84
|
+
* Returns undefined when the path is not "<channel>/<single-valid-segment>",
|
|
85
|
+
* mirroring the endpointFromPath semantics in
|
|
86
|
+
* dsh-client-connection/lib/index.js:310-315 but without a global pattern
|
|
87
|
+
* import. A valid endpoint is one non-empty segment with no "/", "." or ".."
|
|
88
|
+
* traversal segments.
|
|
89
|
+
*/
|
|
90
|
+
export declare function endpointFromPath(channel: string, pathname: string): string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* The absolute path our bridge owns on the Host web server. Kept here (rather
|
|
93
|
+
* than only in bridge-contract) so the pure helpers and route handler share one
|
|
94
|
+
* literal.
|
|
95
|
+
*/
|
|
96
|
+
export declare const SUBAGENT_DIRECTOR_ROUTE_PATH = "/subagent-director";
|
|
97
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAEV,SAAS,EACV,MAAM,oCAAoC,CAAC;AAE5C,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AAExD,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,sBAAsB,CAAC,CAAC,GAAG,OAAO;IACjD,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;CACtB;AAED,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,qBAAqB,CAAA;CAAE,GAC7C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEpC;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,OAAO,GAAG,mBAAmB,CAyB7E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAErG;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,sBAAsB,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,GACf,sBAAsB,CAOxB;AAID;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQ5D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAcvD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQtF;AAED;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,uBAAuB,CAAC"}
|
package/lib/envelope.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/** The rpcId the host uses for envelopes that fail top-level validation. */
|
|
2
|
+
export const INVALID_REQUEST_RPC_ID = 'invalid-request';
|
|
3
|
+
/**
|
|
4
|
+
* Parse and validate a decoded JSON body as a "client-request" envelope.
|
|
5
|
+
* Accepts only an object whose `type` is exactly "client-request", with string
|
|
6
|
+
* `rpcId` and `method`. Returns a structured outcome so the caller can build
|
|
7
|
+
* an "invalid client-request message" bad-request response.
|
|
8
|
+
*/
|
|
9
|
+
export function parseClientRequestEnvelope(body) {
|
|
10
|
+
if (body === null || typeof body !== 'object' || Array.isArray(body)) {
|
|
11
|
+
return { ok: false, issues: ['body must be a JSON object'] };
|
|
12
|
+
}
|
|
13
|
+
const record = body;
|
|
14
|
+
const issues = [];
|
|
15
|
+
if (record.type !== 'client-request') {
|
|
16
|
+
issues.push('type must equal "client-request"');
|
|
17
|
+
}
|
|
18
|
+
if (typeof record.rpcId !== 'string') {
|
|
19
|
+
issues.push('rpcId must be a string');
|
|
20
|
+
}
|
|
21
|
+
if (typeof record.method !== 'string') {
|
|
22
|
+
issues.push('method must be a string');
|
|
23
|
+
}
|
|
24
|
+
if (issues.length > 0)
|
|
25
|
+
return { ok: false, issues };
|
|
26
|
+
return {
|
|
27
|
+
ok: true,
|
|
28
|
+
envelope: {
|
|
29
|
+
type: 'client-request',
|
|
30
|
+
rpcId: record.rpcId,
|
|
31
|
+
method: record.method,
|
|
32
|
+
payload: record.payload,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the "server-response" envelope for the requested rpcId carrying an
|
|
38
|
+
* RpcResult, mirroring dsh-client-connection/lib/index.js:322-328 (fullResponse).
|
|
39
|
+
*/
|
|
40
|
+
export function buildServerResponse(rpcId, result) {
|
|
41
|
+
return { type: 'server-response', rpcId, result };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the bad-request "server-response" for a malformed client-request
|
|
45
|
+
* envelope. The host cannot trust the caller's rpcId on a malformed message,
|
|
46
|
+
* so it uses the fixed INVALID_REQUEST_RPC_ID (mirroring
|
|
47
|
+
* invalidEnvelopeResponse in dsh-client-connection/lib/index.js:302-309).
|
|
48
|
+
*/
|
|
49
|
+
export function buildBadRequestResponse(issues) {
|
|
50
|
+
const error = {
|
|
51
|
+
code: 'bad-request',
|
|
52
|
+
message: 'invalid client-request message',
|
|
53
|
+
details: { issues: [] },
|
|
54
|
+
};
|
|
55
|
+
return buildServerResponse(INVALID_REQUEST_RPC_ID, { ok: false, error });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build the bad-request "server-response" for a message whose `method` does not
|
|
59
|
+
* match the path-derived endpoint (mirroring
|
|
60
|
+
* dsh-client-connection/lib/index.js:289-293).
|
|
61
|
+
*/
|
|
62
|
+
export function buildMethodMismatchResponse(rpcId, method, endpoint) {
|
|
63
|
+
const error = {
|
|
64
|
+
code: 'bad-request',
|
|
65
|
+
message: 'method ' + JSON.stringify(method) + ' does not match endpoint ' + JSON.stringify(endpoint),
|
|
66
|
+
details: { issues: [] },
|
|
67
|
+
};
|
|
68
|
+
return buildServerResponse(rpcId, { ok: false, error });
|
|
69
|
+
}
|
|
70
|
+
const IPV4_OCTET = /^\d{1,3}$/;
|
|
71
|
+
/**
|
|
72
|
+
* Whether a WHATWG URL hostname names the local loopback authority.
|
|
73
|
+
* Accepts "localhost", the IPv6 loopback literal "[::1]" (brackets retained, as
|
|
74
|
+
* WHATWG URL hostname does), or any IPv4 address in the 127/8 range. Rejects
|
|
75
|
+
* everything else. Mirrors the client-connection predicate
|
|
76
|
+
* (dsh-client-connection/lib/client.js:10135-10139).
|
|
77
|
+
*/
|
|
78
|
+
export function isLoopbackHostname(hostname) {
|
|
79
|
+
if (hostname === 'localhost' || hostname === '[::1]')
|
|
80
|
+
return true;
|
|
81
|
+
const parts = hostname.split('.');
|
|
82
|
+
return (parts.length === 4 &&
|
|
83
|
+
parts[0] === '127' &&
|
|
84
|
+
parts.every((part) => IPV4_OCTET.test(part) && Number(part) <= 255));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Classify a raw "Host" request header as loopback. Strips a port suffix and
|
|
88
|
+
* bracket-normalizes the authority before delegating to
|
|
89
|
+
* {@link isLoopbackHostname}. With no port present the header is treated as a
|
|
90
|
+
* bare hostname.
|
|
91
|
+
*/
|
|
92
|
+
export function isLoopbackHost(rawHost) {
|
|
93
|
+
let host = rawHost.trim();
|
|
94
|
+
if (host.length === 0)
|
|
95
|
+
return false;
|
|
96
|
+
// IPv6 bracket literal may carry a trailing port: [::1]:3090
|
|
97
|
+
if (host.startsWith('[')) {
|
|
98
|
+
const close = host.indexOf(']');
|
|
99
|
+
if (close === -1)
|
|
100
|
+
return false;
|
|
101
|
+
host = host.slice(0, close + 1);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Split off the first colon that separates host:port (plain hostnames/IPv4).
|
|
105
|
+
const colon = host.indexOf(':');
|
|
106
|
+
if (colon !== -1)
|
|
107
|
+
host = host.slice(0, colon);
|
|
108
|
+
}
|
|
109
|
+
return isLoopbackHostname(host);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Derive the endpoint segment from a pathname under the channel prefix.
|
|
113
|
+
* Returns undefined when the path is not "<channel>/<single-valid-segment>",
|
|
114
|
+
* mirroring the endpointFromPath semantics in
|
|
115
|
+
* dsh-client-connection/lib/index.js:310-315 but without a global pattern
|
|
116
|
+
* import. A valid endpoint is one non-empty segment with no "/", "." or ".."
|
|
117
|
+
* traversal segments.
|
|
118
|
+
*/
|
|
119
|
+
export function endpointFromPath(channel, pathname) {
|
|
120
|
+
if (!pathname.startsWith(channel + '/'))
|
|
121
|
+
return undefined;
|
|
122
|
+
const endpoint = pathname.slice(channel.length + 1);
|
|
123
|
+
if (endpoint.length === 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
if (endpoint.split('/').some((segment) => segment.length === 0 || segment === '.' || segment === '..')) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
return endpoint;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The absolute path our bridge owns on the Host web server. Kept here (rather
|
|
132
|
+
* than only in bridge-contract) so the pure helpers and route handler share one
|
|
133
|
+
* literal.
|
|
134
|
+
*/
|
|
135
|
+
export const SUBAGENT_DIRECTOR_ROUTE_PATH = '/subagent-director';
|
|
136
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-agent role guidance section (design section 8).
|
|
3
|
+
*
|
|
4
|
+
* Registers a system-prompt section listing the configured Subagent Director
|
|
5
|
+
* role templates so the main agent knows which roles exist, what each does,
|
|
6
|
+
* and how to delegate to one. The section order (117) sits just after
|
|
7
|
+
* dsh-tool-subagent's tool paragraph (116.5) to stay locally associated.
|
|
8
|
+
*
|
|
9
|
+
* Dependency handling: ctx.systemPrompt is optional. When the service is not
|
|
10
|
+
* mounted we skip registration entirely (zero intrusion). When it is mounted
|
|
11
|
+
* but there are no roles, the section text provider renders empty and
|
|
12
|
+
* renderPrompt drops it — the observable AC-6.1 behaviour (no roles, no
|
|
13
|
+
* section) while staying robust to roles appearing at runtime.
|
|
14
|
+
*/
|
|
15
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import type { SubagentDirectorSettings } from './settings.js';
|
|
17
|
+
/** Prompt order: just after dsh-tool-subagent's 116.5 tool section. */
|
|
18
|
+
export declare const GUIDANCE_SECTION_ORDER = 117;
|
|
19
|
+
/** Stable, unique section name (configuration changes only affect new assemblies). */
|
|
20
|
+
export declare const GUIDANCE_SECTION_NAME = "subagent-director:roles";
|
|
21
|
+
/**
|
|
22
|
+
* Pure projection of the role settings onto the guidance prose the main agent
|
|
23
|
+
* reads. Returns '' when there are no roles so the assembled section is dropped.
|
|
24
|
+
* @param settings - current resolved settings snapshot.
|
|
25
|
+
* @param toolName - the configured model-facing delegation tool name.
|
|
26
|
+
*/
|
|
27
|
+
export declare function renderRolesGuidance(settings: SubagentDirectorSettings, toolName: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Register the role guidance section, or no-op when the systemPrompt service
|
|
30
|
+
* is absent. Evalutes roles from the live settings snapshot at each assembly.
|
|
31
|
+
* @param ctx - plugin context.
|
|
32
|
+
* @param getSettings - returns the current settings snapshot.
|
|
33
|
+
* @param toolName - the configured model-facing tool name.
|
|
34
|
+
* @returns the exact section disposer, or undefined when skipped.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyGuidance(ctx: Context, getSettings: () => SubagentDirectorSettings, toolName: string): (() => void) | undefined;
|
|
37
|
+
//# sourceMappingURL=guidance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../src/guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAE9D,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiBhG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,MAAM,wBAAwB,EAC3C,QAAQ,EAAE,MAAM,GACf,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAQ1B"}
|
package/lib/guidance.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Prompt order: just after dsh-tool-subagent's 116.5 tool section. */
|
|
2
|
+
export const GUIDANCE_SECTION_ORDER = 117;
|
|
3
|
+
/** Stable, unique section name (configuration changes only affect new assemblies). */
|
|
4
|
+
export const GUIDANCE_SECTION_NAME = 'subagent-director:roles';
|
|
5
|
+
/**
|
|
6
|
+
* Pure projection of the role settings onto the guidance prose the main agent
|
|
7
|
+
* reads. Returns '' when there are no roles so the assembled section is dropped.
|
|
8
|
+
* @param settings - current resolved settings snapshot.
|
|
9
|
+
* @param toolName - the configured model-facing delegation tool name.
|
|
10
|
+
*/
|
|
11
|
+
export function renderRolesGuidance(settings, toolName) {
|
|
12
|
+
const roles = settings.roles ?? {};
|
|
13
|
+
const entries = Object.entries(roles).filter(([, role]) => role !== undefined);
|
|
14
|
+
if (entries.length === 0)
|
|
15
|
+
return '';
|
|
16
|
+
const lines = [
|
|
17
|
+
'Subagent Director roles — delegate one of these role-bound subagents when the task matches its description. Each role may bind a model; when it does, the subagent runs on that model route.',
|
|
18
|
+
];
|
|
19
|
+
for (const [id, role] of entries) {
|
|
20
|
+
const bound = role.provider !== undefined && role.provider !== '' ?
|
|
21
|
+
role.model !== undefined && role.model !== '' ? ` (model: ${role.provider}/${role.model})` : ` (provider: ${role.provider})` :
|
|
22
|
+
'';
|
|
23
|
+
lines.push(`- ${role.displayName || id}${bound}: ${role.description}`);
|
|
24
|
+
lines.push(` Delegate with: ${toolName}({ role: "${id}", prompt: "..." })`);
|
|
25
|
+
}
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Register the role guidance section, or no-op when the systemPrompt service
|
|
30
|
+
* is absent. Evalutes roles from the live settings snapshot at each assembly.
|
|
31
|
+
* @param ctx - plugin context.
|
|
32
|
+
* @param getSettings - returns the current settings snapshot.
|
|
33
|
+
* @param toolName - the configured model-facing tool name.
|
|
34
|
+
* @returns the exact section disposer, or undefined when skipped.
|
|
35
|
+
*/
|
|
36
|
+
export function applyGuidance(ctx, getSettings, toolName) {
|
|
37
|
+
const systemPrompt = ctx.get('systemPrompt');
|
|
38
|
+
if (systemPrompt === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
return systemPrompt.section({
|
|
41
|
+
name: GUIDANCE_SECTION_NAME,
|
|
42
|
+
order: GUIDANCE_SECTION_ORDER,
|
|
43
|
+
text: () => renderRolesGuidance(getSettings(), toolName),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=guidance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guidance.js","sourceRoot":"","sources":["../src/guidance.ts"],"names":[],"mappings":"AAiBA,uEAAuE;AACvE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,yBAAyB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAkC,EAAE,QAAgB;IACtF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAC/E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAa;QACtB,8LAA8L;KAC/L,CAAC;IACF,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC;QACjC,MAAM,KAAK,GACT,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YAC9H,EAAE,CAAC;QACP,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW,IAAI,EAAE,GAAG,KAAK,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACvE,KAAK,CAAC,IAAI,CAAC,sBAAsB,QAAQ,aAAa,EAAE,qBAAqB,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAY,EACZ,WAA2C,EAC3C,QAAgB;IAEhB,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC7C,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACjD,OAAO,YAAY,CAAC,OAAO,CAAC;QAC1B,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,sBAAsB;QAC7B,IAAI,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC;KACzD,CAAC,CAAC;AACL,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent Director — host plugin composition entry (design section 3).
|
|
3
|
+
*
|
|
4
|
+
* Wires the settings section, the role-guidance section, and the subagent_role
|
|
5
|
+
* delegation tool. Reads user settings live; a deployment without a settings
|
|
6
|
+
* provider degrades to an empty resolved section (zero intrusion).
|
|
7
|
+
*
|
|
8
|
+
* Dependency posture: tools/subagents/llm/settings are required through inject
|
|
9
|
+
* (both web and headless bundles mount the settings service); systemPrompt
|
|
10
|
+
* remains optional and is acquired lazily so its absence does not block the
|
|
11
|
+
* rest. The webServer-dependent HTTP bridge lives in the separate
|
|
12
|
+
* \`subagent-director-bridge\` entry (src/bridge-entry.ts).
|
|
13
|
+
*
|
|
14
|
+
* Background modes: 'one-shot' defaults calls to foreground and runs background
|
|
15
|
+
* calls as a plain Task; 'continuable' defaults them to background via
|
|
16
|
+
* ctx.subagents.startContinuable() and requires the transport provider's
|
|
17
|
+
* prepareContinuable capability, which is validated at mount time (mirrors
|
|
18
|
+
* dsh-tool-subagent).
|
|
19
|
+
*/
|
|
20
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
21
|
+
export { Config } from './config.js';
|
|
22
|
+
export type { DirectorConfig } from './config.js';
|
|
23
|
+
export { assertDelegationCapabilities, buildSubagentRequest, createDelegationParameters, createDelegationOutputSchema, createDelegationTool, DELEGATION_TOOL_PREFIX, resolveDelegationMode, renderDelegationResult, type DelegationToolArgs, type DelegationResult, type DelegationRoute, type DelegationModeDecision, type SubagentRequestParts, } from './delegation-tool.js';
|
|
24
|
+
export { applyGuidance, renderRolesGuidance, GUIDANCE_SECTION_ORDER, GUIDANCE_SECTION_NAME } from './guidance.js';
|
|
25
|
+
export { SUBAGENT_DIRECTOR_SETTINGS_NAMESPACE, SettingsSchema, validateDirectorSettings, installDirectorSettings, type RoleTemplate, type SubagentDirectorSettings, } from './settings.js';
|
|
26
|
+
export declare const name = "subagent-director";
|
|
27
|
+
export declare const inject: string[];
|
|
28
|
+
export declare function apply(ctx: Context, config: import('./config.js').DirectorConfig): void;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAQnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,4BAA4B,EAC5B,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAClH,OAAO,EACL,oCAAoC,EACpC,cAAc,EACd,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,IAAI,sBAAsB,CAAC;AAExC,eAAO,MAAM,MAAM,UAA4C,CAAC;AAEhE,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,aAAa,EAAE,cAAc,QAuD/E"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { assertSubagentMaxDepth } from '@deepseek-ai/dsh-subagent';
|
|
2
|
+
import { createDelegationTool } from './delegation-tool.js';
|
|
3
|
+
import { applyGuidance } from './guidance.js';
|
|
4
|
+
import { installDirectorSettings } from './settings.js';
|
|
5
|
+
export { Config } from './config.js';
|
|
6
|
+
export { assertDelegationCapabilities, buildSubagentRequest, createDelegationParameters, createDelegationOutputSchema, createDelegationTool, DELEGATION_TOOL_PREFIX, resolveDelegationMode, renderDelegationResult, } from './delegation-tool.js';
|
|
7
|
+
export { applyGuidance, renderRolesGuidance, GUIDANCE_SECTION_ORDER, GUIDANCE_SECTION_NAME } from './guidance.js';
|
|
8
|
+
export { SUBAGENT_DIRECTOR_SETTINGS_NAMESPACE, SettingsSchema, validateDirectorSettings, installDirectorSettings, } from './settings.js';
|
|
9
|
+
export const name = 'subagent-director';
|
|
10
|
+
export const inject = ['tools', 'subagents', 'llm', 'settings'];
|
|
11
|
+
export function apply(ctx, config) {
|
|
12
|
+
const backgroundMode = config.backgroundMode ?? 'one-shot';
|
|
13
|
+
const toolName = config.toolName ?? 'subagent_role';
|
|
14
|
+
const providerName = config.subagentProvider ?? 'spawn';
|
|
15
|
+
// NOTE: the /subagent-director settings bridge route is installed by the
|
|
16
|
+
// separate `subagent-director-bridge` plugin entry (src/bridge-entry.ts),
|
|
17
|
+
// which injects webServer — tree-external plugins cannot see that service
|
|
18
|
+
// through ctx.get(). The main entry must not touch webServer, or headless
|
|
19
|
+
// profiles would lose the delegation tool.
|
|
20
|
+
// ---- settings snapshot -------------------------------------------------
|
|
21
|
+
let settings = {};
|
|
22
|
+
installDirectorSettings(ctx, {}, {
|
|
23
|
+
setSource: (current) => {
|
|
24
|
+
settings = current();
|
|
25
|
+
},
|
|
26
|
+
onChange: () => {
|
|
27
|
+
// snapshot already updated by setSource; nothing further to do in M1.
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
const getSettings = () => settings;
|
|
31
|
+
// ---- role guidance ----------------------------------------------------
|
|
32
|
+
applyGuidance(ctx, getSettings, toolName);
|
|
33
|
+
// ---- delegation tool registration ------------------------------------
|
|
34
|
+
if (typeof config.maxDepth === 'number')
|
|
35
|
+
assertSubagentMaxDepth(config.maxDepth);
|
|
36
|
+
let disposeTool;
|
|
37
|
+
const mount = (provider) => {
|
|
38
|
+
if (typeof config.maxDepth === 'number' && !provider.capabilities.depthLimit) {
|
|
39
|
+
throw new Error('subagent-director: provider "' + provider.name + '" cannot enforce maxDepth (no depthLimit capability) — set maxDepth: \'provider-managed\'');
|
|
40
|
+
}
|
|
41
|
+
if (backgroundMode === 'continuable' && provider.prepareContinuable === undefined) {
|
|
42
|
+
throw new Error('subagent-director: provider "' + provider.name + '" does not support backgroundMode: continuable — switch the subagent provider or use backgroundMode: "one-shot"');
|
|
43
|
+
}
|
|
44
|
+
ctx.logger.info('[' + name + '] registering ' + toolName + ' on subagent transport ' + '"' + providerName + '"' + ' with backgroundMode ' + '"' + backgroundMode + '"');
|
|
45
|
+
disposeTool = ctx.tools.register(createDelegationTool({ ctx, config, provider, getSettings }));
|
|
46
|
+
};
|
|
47
|
+
ctx.on('subagent/provider-added', (provider) => {
|
|
48
|
+
if (provider.name === providerName && disposeTool === undefined)
|
|
49
|
+
mount(provider);
|
|
50
|
+
});
|
|
51
|
+
ctx.on('subagent/provider-removed', (name2) => {
|
|
52
|
+
if (name2 !== providerName || disposeTool === undefined)
|
|
53
|
+
return;
|
|
54
|
+
disposeTool();
|
|
55
|
+
disposeTool = undefined;
|
|
56
|
+
});
|
|
57
|
+
const present = ctx.subagents.getProvider(providerName);
|
|
58
|
+
if (present !== undefined)
|
|
59
|
+
mount(present);
|
|
60
|
+
else
|
|
61
|
+
ctx.logger.info('[' + name + '] subagent provider ' + '"' + providerName + '" not registered yet; the "' + toolName + '" tool will register when it appears');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/remote.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent Director — self-published setting bridge on the Host web server
|
|
3
|
+
* (design fix: "namespace not exposed").
|
|
4
|
+
*
|
|
5
|
+
* The Web settings client read/writes the plugin's `subagent-director`
|
|
6
|
+
* namespace via a dedicated "/subagent-director" webServer prefix route instead
|
|
7
|
+
* of the Host apiproxy's settings.describe/mutate, which the API proxy gates
|
|
8
|
+
* behind its hard-coded exposedNamespaces() allowlist
|
|
9
|
+
* (dsh-host-apiproxy). A tree-external plugin cannot add its own namespace to
|
|
10
|
+
* that list, so those calls answer `settings-not-exposed`. To bypass the
|
|
11
|
+
* allowlist without touching apiproxy, this module self-publishes a prefix
|
|
12
|
+
* route (kind:"prefix", path:"/subagent-director") via `ctx.webServer.register`
|
|
13
|
+
* (dsh-host-webserver/lib/index.js:53-60) and reads/writes `ctx.settings`
|
|
14
|
+
* itself.
|
|
15
|
+
*
|
|
16
|
+
* The wire contract mirrors the settings domain slice apiproxy exposes for
|
|
17
|
+
* one namespace: `settingsView` returns `{ writable, view }` where `view` is a
|
|
18
|
+
* `SettingsNamespaceView` (redacted), and `settingsMutate` applies path ops
|
|
19
|
+
* with an optimistic `expectedRevision` and returns the new redacted view, or
|
|
20
|
+
* an error with the same `settings-conflict` / `settings-rejected` semantics so
|
|
21
|
+
* the existing client conflict-reload logic works unchanged. The client already
|
|
22
|
+
* speaks this contract unchanged (dsh-client-connection/lib/client.js:10094-10113
|
|
23
|
+
* and src/client/store.ts), so no client change is required.
|
|
24
|
+
*
|
|
25
|
+
* Pure mapping / wire-envelope helpers live at the top (no cordis) so they are
|
|
26
|
+
* unit-testable in a plain node environment. The route handler is a node:http
|
|
27
|
+
* (req, res) handler, mirroring the Connection channel semantics in
|
|
28
|
+
* dsh-client-connection/lib/index.js:275-300 and 322-328, plus a lightweight
|
|
29
|
+
* loopback Host fence.
|
|
30
|
+
*/
|
|
31
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
32
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
33
|
+
import { SettingsConflictError, type SettingsDescriptor, type SettingsProvider } from '@deepseek-ai/dsh-settings';
|
|
34
|
+
import type { RpcResult, RpcError, SettingsNamespaceView, SettingsPathOpView } from '@deepseek-ai/dsh-host-apiproxy/api';
|
|
35
|
+
import { SettingsSchema } from './settings.js';
|
|
36
|
+
import { SUBAGENT_DIRECTOR_RPC_VIEW, SUBAGENT_DIRECTOR_RPC_MUTATE, type DirectorMutateRequest, type DirectorViewSuccess } from './bridge-contract.js';
|
|
37
|
+
import { SUBAGENT_DIRECTOR_ROUTE_PATH } from './envelope.js';
|
|
38
|
+
/** Wire route path the bridge owns on the Host web server. */
|
|
39
|
+
export { SUBAGENT_DIRECTOR_ROUTE_PATH as SUBAGENT_DIRECTOR_RPC_CHANNEL };
|
|
40
|
+
/** Endpoint that returns the namespace's redacted wire view. */
|
|
41
|
+
export { SUBAGENT_DIRECTOR_RPC_VIEW };
|
|
42
|
+
/** Endpoint that applies one path-op mutation. */
|
|
43
|
+
export { SUBAGENT_DIRECTOR_RPC_MUTATE };
|
|
44
|
+
/** Request payload for the settingsMutate bridge endpoint. */
|
|
45
|
+
export type { DirectorMutateRequest, DirectorViewSuccess };
|
|
46
|
+
/**
|
|
47
|
+
* Map one redacted settings descriptor to its wire view — mirrors apiproxy's
|
|
48
|
+
* `namespaceView` (dsh-host-apiproxy/lib/index.js:2385-2399) exactly, so the
|
|
49
|
+
* client store sees the same `SettingsNamespaceView` shape it already renders.
|
|
50
|
+
*/
|
|
51
|
+
export declare function toDirectorNamespaceView(descriptor: SettingsDescriptor): SettingsNamespaceView;
|
|
52
|
+
/**
|
|
53
|
+
* Find the Subagent Director namespace in a redacted describe result and map
|
|
54
|
+
* it to its wire view; `undefined` when the namespace is not registered.
|
|
55
|
+
*/
|
|
56
|
+
export declare function pickDirectorNamespaceView(descriptors: readonly SettingsDescriptor[]): SettingsNamespaceView | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Read the current redacted namespace view straight from the settings seam.
|
|
59
|
+
* Exported for reuse by tests and by the bridge handler.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readDirectorNamespaceView(settings: SettingsProvider): DirectorViewSuccess;
|
|
62
|
+
/** Build the `settings-rejected` RPC error for one seam failure. */
|
|
63
|
+
export declare function directorRejected(ns: string, error: unknown): RpcError;
|
|
64
|
+
/** Build the `settings-conflict` RPC error, mirroring apiproxy's mapping. */
|
|
65
|
+
export declare function directorConflict(conflict: SettingsConflictError): RpcError;
|
|
66
|
+
/**
|
|
67
|
+
* Build the ok payload for the settingsView endpoint.
|
|
68
|
+
* Mirrors the apiproxy `settings.describe` value minus `hasDocument` (the
|
|
69
|
+
* bridge does not own the document affordance; the client ignores it).
|
|
70
|
+
*/
|
|
71
|
+
export declare function directorViewOk(settings: SettingsProvider): RpcResult<DirectorViewSuccess>;
|
|
72
|
+
/**
|
|
73
|
+
* Execute one path-op mutation against the settings seam and map the outcome
|
|
74
|
+
* to an RpcResult carrying the new redacted view (or a `settings-conflict` /
|
|
75
|
+
* `settings-rejected` error). Pure over the injected primitives for testing.
|
|
76
|
+
*/
|
|
77
|
+
export declare function directorMutate(mutate: SettingsProvider['mutate'], describe: SettingsProvider['describe'], ns: string, ops: readonly SettingsPathOpView[], expectedRevision: number | undefined): Promise<RpcResult<SettingsNamespaceView>>;
|
|
78
|
+
/** Re-export the wire-envelope helpers so tests import them from one place. */
|
|
79
|
+
export { parseClientRequestEnvelope, isLoopbackHost, isLoopbackHostname, endpointFromPath, buildServerResponse, buildMethodMismatchResponse, buildBadRequestResponse, INVALID_REQUEST_RPC_ID, } from './envelope.js';
|
|
80
|
+
/**
|
|
81
|
+
* The node:http handler for the "/subagent-director" prefix route. Owns the
|
|
82
|
+
* full response lifecycle. Wire contract mirrors the generic Connection RPC
|
|
83
|
+
* channel (dsh-client-connection/lib/index.js:275-328):
|
|
84
|
+
* - non-POST → 404 "not found"
|
|
85
|
+
* - wrong content-type → 415
|
|
86
|
+
* - unparseable JSON body → 400 "body is not JSON"
|
|
87
|
+
* - malformed client-request envelope → 200 bad-request (fixed rpcId)
|
|
88
|
+
* - method vs endpoint mismatch → 200 bad-request
|
|
89
|
+
* - non-loopback Host header → 403 "forbidden" (lightweight trust fence)
|
|
90
|
+
* - dispatch error → 500 "handler failure: ..."
|
|
91
|
+
*/
|
|
92
|
+
export declare function handleDirectorBridgeRequest(settings: SettingsProvider, req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Install the Subagent Director setting bridge on the Host web server via a
|
|
95
|
+
* self-published prefix route. Lazy-acquires `ctx.webServer`; a deployment
|
|
96
|
+
* without that service (e.g. headless) logs a debug line naming the missing
|
|
97
|
+
* service and installs nothing. Returns a disposer.
|
|
98
|
+
*/
|
|
99
|
+
export declare function installDirectorRemoteBridge(ctx: Context): () => void;
|
|
100
|
+
/** Convenience re-export for the namespaced schema used to document the view. */
|
|
101
|
+
export { SettingsSchema };
|
|
102
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,qBAAqB,EAErB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACV,SAAS,EACT,QAAQ,EACR,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,cAAc,EAEf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,4BAA4B,EAQ7B,MAAM,eAAe,CAAC;AAEvB,8DAA8D;AAC9D,OAAO,EAAE,4BAA4B,IAAI,6BAA6B,EAAE,CAAC;AACzE,gEAAgE;AAChE,OAAO,EAAE,0BAA0B,EAAE,CAAC;AACtC,kDAAkD;AAClD,OAAO,EAAE,4BAA4B,EAAE,CAAC;AACxC,8DAA8D;AAC9D,YAAY,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,qBAAqB,CAc7F;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,SAAS,kBAAkB,EAAE,GACzC,qBAAqB,GAAG,SAAS,CAOnC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,mBAAmB,CAMzF;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAMrE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,QAAQ,CAa1E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAEzF;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAClC,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,EACtC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,SAAS,kBAAkB,EAAE,EAClC,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC,CAwB3C;AAED,+EAA+E;AAC/E,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAEf;AAqFD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,IAAI,CA2BpE;AAiCD,iFAAiF;AACjF,OAAO,EAAE,cAAc,EAAE,CAAC"}
|