@zhin.js/host-http 1.0.12 → 1.0.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.
@@ -34,6 +34,7 @@ export interface ConsoleAgentIntrospection {
34
34
  components?(): readonly unknown[];
35
35
  bindings?(): readonly unknown[];
36
36
  tools?(): readonly unknown[];
37
+ promptSections?(): readonly unknown[];
37
38
  mcp?(): {
38
39
  rows: readonly unknown[];
39
40
  note?: string;
@@ -6,6 +6,7 @@ const INTROSPECTION_PAGE_SIZES = {
6
6
  middlewares: 30,
7
7
  components: 30,
8
8
  tools: 15,
9
+ 'prompt-sections': 20,
9
10
  endpoints: 30,
10
11
  bindings: 30,
11
12
  mcp: 30,
@@ -384,7 +385,7 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
384
385
  const collectors = [
385
386
  {
386
387
  kind: 'commands',
387
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.commands?.() ?? []) }),
388
+ collect: (value) => ({ rows: value?.commands?.() ?? [] }),
388
389
  fields: [
389
390
  (c) => stringProp(c, 'pattern'),
390
391
  (c) => stringProp(c, 'desc'),
@@ -393,7 +394,7 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
393
394
  },
394
395
  {
395
396
  kind: 'middlewares',
396
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.middlewares?.() ?? []) }),
397
+ collect: (value) => ({ rows: value?.middlewares?.() ?? [] }),
397
398
  fields: [
398
399
  (m) => stringProp(m, 'name'),
399
400
  (m) => stringProp(m, 'owner'),
@@ -404,7 +405,7 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
404
405
  },
405
406
  {
406
407
  kind: 'components',
407
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.components?.() ?? []) }),
408
+ collect: (value) => ({ rows: value?.components?.() ?? [] }),
408
409
  fields: [
409
410
  (c) => stringProp(c, 'name'),
410
411
  (c) => stringProp(c, 'owner'),
@@ -425,7 +426,7 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
425
426
  },
426
427
  {
427
428
  kind: 'bindings',
428
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.bindings?.() ?? []) }),
429
+ collect: (value) => ({ rows: value?.bindings?.() ?? [] }),
429
430
  fields: [
430
431
  (a) => stringProp(a, 'name'),
431
432
  (a) => stringProp(a, 'provider'),
@@ -434,17 +435,30 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
434
435
  },
435
436
  {
436
437
  kind: 'tools',
437
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.tools?.() ?? []) }),
438
+ collect: (value) => ({ rows: value?.tools?.() ?? [] }),
438
439
  fields: [
439
440
  (t) => stringProp(t, 'name'),
440
441
  (t) => stringProp(t, 'source'),
441
442
  (t) => stringProp(t, 'description'),
442
443
  ],
443
444
  },
445
+ {
446
+ kind: 'prompt-sections',
447
+ collect: (value) => ({ rows: value?.promptSections?.() ?? [] }),
448
+ fields: [
449
+ (section) => stringProp(section, 'name'),
450
+ (section) => stringProp(section, 'qualifiedName'),
451
+ (section) => stringProp(section, 'title'),
452
+ (section) => stringProp(section, 'owner'),
453
+ (section) => stringProp(section, 'layer'),
454
+ (section) => stringProp(section, 'retention'),
455
+ (section) => stringProp(section, 'source'),
456
+ ],
457
+ },
444
458
  {
445
459
  kind: 'mcp',
446
- collect: () => {
447
- const result = withAgentIntrospection(ctx, (value) => value?.mcp?.());
460
+ collect: (value) => {
461
+ const result = value?.mcp?.();
448
462
  if (result == null)
449
463
  return { rows: [] };
450
464
  // readonly 数组不能用 Array.isArray 收窄,按对象形状判断
@@ -458,15 +472,17 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
458
472
  ];
459
473
  for (const { kind, collect, fields } of collectors) {
460
474
  route('GET', `${base}/introspection/${kind}`, async (_request, response, url) => {
475
+ const lease = kind === 'endpoints' ? null : ctx.acquireAgentRuntime?.() ?? null;
461
476
  try {
462
- const { rows, note } = collect();
477
+ const introspection = lease?.value.introspection;
478
+ const { rows, note } = collect(introspection);
463
479
  const query = url.searchParams;
464
480
  const filter = query.get('filter')?.trim() || undefined;
465
481
  const filtered = filterByFields([...rows], filter, fields);
466
482
  const slice = paginateItems(filtered, parsePositiveInt(query.get('page'), 1), parsePositiveInt(query.get('pageSize'), INTROSPECTION_PAGE_SIZES[kind]));
467
483
  const missing = kind === 'endpoints'
468
484
  ? !ctx.getEndpoints
469
- : !hasAgentIntrospection(ctx);
485
+ : !introspection;
470
486
  const degradedNote = note ?? (missing
471
487
  ? kind === 'endpoints'
472
488
  ? 'Endpoints 数据源未接线(ctx.getEndpoints 缺失)'
@@ -484,6 +500,9 @@ function registerIntrospectionRoutes(route, base, ctx, options) {
484
500
  error: err instanceof Error ? err.message : String(err),
485
501
  });
486
502
  }
503
+ finally {
504
+ lease?.release();
505
+ }
487
506
  }, { summary: `Introspection: ${kind}`, tags: ['console', 'introspection'] });
488
507
  }
489
508
  let activeComponentPreviews = 0;
@@ -608,20 +627,6 @@ function assertPreviewOutput(output, maxBytes) {
608
627
  throw new ComponentPreviewLimitError(`Component preview 超过 ${byteLimit} bytes`);
609
628
  }
610
629
  }
611
- function withAgentIntrospection(ctx, operation) {
612
- const lease = ctx.acquireAgentRuntime?.();
613
- if (!lease)
614
- return operation(undefined);
615
- try {
616
- return operation(lease.value.introspection);
617
- }
618
- finally {
619
- lease.release();
620
- }
621
- }
622
- function hasAgentIntrospection(ctx) {
623
- return withAgentIntrospection(ctx, (value) => value !== undefined);
624
- }
625
630
  // ---------------------------------------------------------------------------
626
631
  // agent sessions(legacy agent-sessions-rest-api.ts;ADR 0010 D3)
627
632
  // ---------------------------------------------------------------------------
@@ -722,5 +722,6 @@ const DEMO_INTROSPECTION_PATHS = new Set([
722
722
  '/introspection/endpoints',
723
723
  '/introspection/bindings',
724
724
  '/introspection/tools',
725
+ '/introspection/prompt-sections',
725
726
  '/introspection/mcp',
726
727
  ]);
@@ -38,16 +38,21 @@ export type HttpHandler = (request: IncomingMessage, response: ServerResponse, u
38
38
  export interface HttpRouteRegistration {
39
39
  (): void;
40
40
  }
41
- export interface HttpHost extends GenerationAdmissionBindable<HttpHost> {
41
+ /** @public Stable HTTP and WebSocket Host contract resolved through `httpHostToken`. */
42
+ export interface HttpHost {
42
43
  ws(path: string): WsHandle;
43
44
  route(method: string, path: string, handler: HttpHandler, meta?: RouteMeta): HttpRouteRegistration;
44
45
  listRoutes(): readonly ListedRoute[];
45
46
  get address(): HttpHostAddress | undefined;
47
+ /** @internal Console authentication registry owned by the process Host. */
46
48
  get tokenRegistry(): TokenRegistry;
47
49
  }
48
- export interface ProcessHttpHost extends HttpHost {
50
+ /** @internal Process-root lifecycle and generation admission surface. */
51
+ export interface ProcessHttpHost extends HttpHost, GenerationAdmissionBindable<HttpHost> {
49
52
  listen(): Promise<HttpHostAddress>;
50
53
  close(): Promise<void>;
51
54
  }
55
+ /** @public Stable Plugin Runtime HTTP Host token. */
52
56
  export declare const httpHostToken: import("@zhin.js/plugin-runtime").Token<HttpHost>;
57
+ /** @internal CLI composition-root factory. */
53
58
  export declare function createHttpHost(options?: HttpHostOptions): ProcessHttpHost;
package/lib/http-host.js CHANGED
@@ -9,7 +9,9 @@ import { HttpBodyError } from './json-body.js';
9
9
  const logger = getLogger('http');
10
10
  export const REMOTE_CONSOLE_ORIGIN = 'https://console.zhin.dev';
11
11
  const DEFAULT_CORS_ORIGINS = Object.freeze([REMOTE_CONSOLE_ORIGIN]);
12
+ /** @public Stable Plugin Runtime HTTP Host token. */
12
13
  export const httpHostToken = createToken('zhin.host.http');
14
+ /** @internal CLI composition-root factory. */
13
15
  export function createHttpHost(options = {}) {
14
16
  const host = options.host ?? '127.0.0.1';
15
17
  const port = options.port ?? 8086;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Plugin-facing HTTP Host contract exposed from `@zhin.js/host-http`.
3
+ * @module @zhin.js/host-http
4
+ */
5
+ export { httpHostToken, type HttpHandler, type HttpHost, type HttpHostAddress, type HttpRouteRegistration, type WsConnection, type WsHandle, } from './http-host.js';
6
+ export type { AuthenticatedTokenPrincipal, AuthScope } from './token-registry.js';
7
+ export type { ListedRoute, OpenApiParameter, RouteMeta } from './openapi.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Plugin-facing HTTP Host contract exposed from `@zhin.js/host-http`.
3
+ * @module @zhin.js/host-http
4
+ */
5
+ export { httpHostToken, } from './http-host.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/host-http",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Minimal HTTP and WebSocket host for Plugin Runtime (no Koa)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -20,8 +20,8 @@
20
20
  "ws": "^8.21.1",
21
21
  "@zhin.js/console-protocol": "1.1.4",
22
22
  "@zhin.js/host-http-contract": "1.0.1",
23
- "@zhin.js/logger": "1.0.76",
24
- "@zhin.js/plugin-runtime": "1.1.7"
23
+ "@zhin.js/logger": "1.0.77",
24
+ "@zhin.js/plugin-runtime": "1.1.8"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^26.1.2",
@@ -51,6 +51,7 @@ export interface ConsoleAgentIntrospection {
51
51
  components?(): readonly unknown[];
52
52
  bindings?(): readonly unknown[];
53
53
  tools?(): readonly unknown[];
54
+ promptSections?(): readonly unknown[];
54
55
  mcp?(): { rows: readonly unknown[]; note?: string } | readonly unknown[];
55
56
  renderComponent?(input: Readonly<{
56
57
  requester: string;
@@ -122,6 +123,7 @@ const INTROSPECTION_PAGE_SIZES = {
122
123
  middlewares: 30,
123
124
  components: 30,
124
125
  tools: 15,
126
+ 'prompt-sections': 20,
125
127
  endpoints: 30,
126
128
  bindings: 30,
127
129
  mcp: 30,
@@ -567,12 +569,12 @@ function registerIntrospectionRoutes(
567
569
  ): void {
568
570
  const collectors: Array<{
569
571
  kind: IntrospectionKind;
570
- collect: () => { rows: readonly unknown[]; note?: string };
572
+ collect: (introspection: ConsoleAgentIntrospection | undefined) => { rows: readonly unknown[]; note?: string };
571
573
  fields: Array<(item: unknown) => string | undefined>;
572
574
  }> = [
573
575
  {
574
576
  kind: 'commands',
575
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.commands?.() ?? []) }),
577
+ collect: (value) => ({ rows: value?.commands?.() ?? [] }),
576
578
  fields: [
577
579
  (c) => stringProp(c, 'pattern'),
578
580
  (c) => stringProp(c, 'desc'),
@@ -581,7 +583,7 @@ function registerIntrospectionRoutes(
581
583
  },
582
584
  {
583
585
  kind: 'middlewares',
584
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.middlewares?.() ?? []) }),
586
+ collect: (value) => ({ rows: value?.middlewares?.() ?? [] }),
585
587
  fields: [
586
588
  (m) => stringProp(m, 'name'),
587
589
  (m) => stringProp(m, 'owner'),
@@ -592,7 +594,7 @@ function registerIntrospectionRoutes(
592
594
  },
593
595
  {
594
596
  kind: 'components',
595
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.components?.() ?? []) }),
597
+ collect: (value) => ({ rows: value?.components?.() ?? [] }),
596
598
  fields: [
597
599
  (c) => stringProp(c, 'name'),
598
600
  (c) => stringProp(c, 'owner'),
@@ -613,7 +615,7 @@ function registerIntrospectionRoutes(
613
615
  },
614
616
  {
615
617
  kind: 'bindings',
616
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.bindings?.() ?? []) }),
618
+ collect: (value) => ({ rows: value?.bindings?.() ?? [] }),
617
619
  fields: [
618
620
  (a) => stringProp(a, 'name'),
619
621
  (a) => stringProp(a, 'provider'),
@@ -622,17 +624,30 @@ function registerIntrospectionRoutes(
622
624
  },
623
625
  {
624
626
  kind: 'tools',
625
- collect: () => ({ rows: withAgentIntrospection(ctx, (value) => value?.tools?.() ?? []) }),
627
+ collect: (value) => ({ rows: value?.tools?.() ?? [] }),
626
628
  fields: [
627
629
  (t) => stringProp(t, 'name'),
628
630
  (t) => stringProp(t, 'source'),
629
631
  (t) => stringProp(t, 'description'),
630
632
  ],
631
633
  },
634
+ {
635
+ kind: 'prompt-sections',
636
+ collect: (value) => ({ rows: value?.promptSections?.() ?? [] }),
637
+ fields: [
638
+ (section) => stringProp(section, 'name'),
639
+ (section) => stringProp(section, 'qualifiedName'),
640
+ (section) => stringProp(section, 'title'),
641
+ (section) => stringProp(section, 'owner'),
642
+ (section) => stringProp(section, 'layer'),
643
+ (section) => stringProp(section, 'retention'),
644
+ (section) => stringProp(section, 'source'),
645
+ ],
646
+ },
632
647
  {
633
648
  kind: 'mcp',
634
- collect: () => {
635
- const result = withAgentIntrospection(ctx, (value) => value?.mcp?.());
649
+ collect: (value) => {
650
+ const result = value?.mcp?.();
636
651
  if (result == null) return { rows: [] as readonly unknown[] };
637
652
  // readonly 数组不能用 Array.isArray 收窄,按对象形状判断
638
653
  if (typeof result === 'object' && 'rows' in result) {
@@ -646,8 +661,10 @@ function registerIntrospectionRoutes(
646
661
 
647
662
  for (const { kind, collect, fields } of collectors) {
648
663
  route('GET', `${base}/introspection/${kind}`, async (_request, response, url) => {
664
+ const lease = kind === 'endpoints' ? null : ctx.acquireAgentRuntime?.() ?? null;
649
665
  try {
650
- const { rows, note } = collect();
666
+ const introspection = lease?.value.introspection;
667
+ const { rows, note } = collect(introspection);
651
668
  const query = url.searchParams;
652
669
  const filter = query.get('filter')?.trim() || undefined;
653
670
  const filtered = filterByFields([...rows], filter, fields);
@@ -658,7 +675,7 @@ function registerIntrospectionRoutes(
658
675
  );
659
676
  const missing = kind === 'endpoints'
660
677
  ? !ctx.getEndpoints
661
- : !hasAgentIntrospection(ctx);
678
+ : !introspection;
662
679
  const degradedNote = note ?? (missing
663
680
  ? kind === 'endpoints'
664
681
  ? 'Endpoints 数据源未接线(ctx.getEndpoints 缺失)'
@@ -674,6 +691,8 @@ function registerIntrospectionRoutes(
674
691
  data: { items: [], page: 1, pageSize: 0, total: 0, totalPages: 0 },
675
692
  error: err instanceof Error ? err.message : String(err),
676
693
  });
694
+ } finally {
695
+ lease?.release();
677
696
  }
678
697
  }, { summary: `Introspection: ${kind}`, tags: ['console', 'introspection'] });
679
698
  }
@@ -800,23 +819,6 @@ function assertPreviewOutput(output: unknown, maxBytes: number): void {
800
819
  }
801
820
  }
802
821
 
803
- function withAgentIntrospection<T>(
804
- ctx: ConsoleRestCtx,
805
- operation: (value: ConsoleAgentIntrospection | undefined) => T,
806
- ): T {
807
- const lease = ctx.acquireAgentRuntime?.();
808
- if (!lease) return operation(undefined);
809
- try {
810
- return operation(lease.value.introspection);
811
- } finally {
812
- lease.release();
813
- }
814
- }
815
-
816
- function hasAgentIntrospection(ctx: ConsoleRestCtx): boolean {
817
- return withAgentIntrospection(ctx, (value) => value !== undefined);
818
- }
819
-
820
822
  // ---------------------------------------------------------------------------
821
823
  // agent sessions(legacy agent-sessions-rest-api.ts;ADR 0010 D3)
822
824
  // ---------------------------------------------------------------------------
@@ -819,5 +819,6 @@ const DEMO_INTROSPECTION_PATHS: ReadonlySet<string> = new Set([
819
819
  '/introspection/endpoints',
820
820
  '/introspection/bindings',
821
821
  '/introspection/tools',
822
+ '/introspection/prompt-sections',
822
823
  '/introspection/mcp',
823
824
  ]);
package/src/http-host.ts CHANGED
@@ -81,7 +81,8 @@ export interface HttpRouteRegistration {
81
81
  (): void;
82
82
  }
83
83
 
84
- export interface HttpHost extends GenerationAdmissionBindable<HttpHost> {
84
+ /** @public Stable HTTP and WebSocket Host contract resolved through `httpHostToken`. */
85
+ export interface HttpHost {
85
86
  ws(path: string): WsHandle;
86
87
  route(
87
88
  method: string,
@@ -91,10 +92,12 @@ export interface HttpHost extends GenerationAdmissionBindable<HttpHost> {
91
92
  ): HttpRouteRegistration;
92
93
  listRoutes(): readonly ListedRoute[];
93
94
  get address(): HttpHostAddress | undefined;
95
+ /** @internal Console authentication registry owned by the process Host. */
94
96
  get tokenRegistry(): TokenRegistry;
95
97
  }
96
98
 
97
- export interface ProcessHttpHost extends HttpHost {
99
+ /** @internal Process-root lifecycle and generation admission surface. */
100
+ export interface ProcessHttpHost extends HttpHost, GenerationAdmissionBindable<HttpHost> {
98
101
  listen(): Promise<HttpHostAddress>;
99
102
  close(): Promise<void>;
100
103
  }
@@ -109,13 +112,17 @@ interface HttpRoute {
109
112
  readonly admission?: GenerationAdmissionGate;
110
113
  }
111
114
 
115
+ interface AdmissionBoundHttpHost extends HttpHost, GenerationAdmissionBindable<HttpHost> {}
116
+
112
117
  interface WsRoute {
113
118
  readonly listener: (connection: WsConnection) => void;
114
119
  readonly admission?: GenerationAdmissionGate;
115
120
  }
116
121
 
122
+ /** @public Stable Plugin Runtime HTTP Host token. */
117
123
  export const httpHostToken = createToken<HttpHost>('zhin.host.http');
118
124
 
125
+ /** @internal CLI composition-root factory. */
119
126
  export function createHttpHost(options: HttpHostOptions = {}): ProcessHttpHost {
120
127
  const host = options.host ?? '127.0.0.1';
121
128
  const port = options.port ?? 8086;
@@ -453,8 +460,8 @@ export function createHttpHost(options: HttpHostOptions = {}): ProcessHttpHost {
453
460
 
454
461
  function createBoundHost(
455
462
  admission: GenerationAdmissionGate,
456
- ): HttpHost {
457
- const bound: HttpHost = {
463
+ ): AdmissionBoundHttpHost {
464
+ const bound: AdmissionBoundHttpHost = {
458
465
  [generationAdmissionBinder]: (next) => createBoundHost(next),
459
466
  ws: (path) => registerWs(path, admission),
460
467
  route: (method, path, handler, meta) => registerRoute(
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Plugin-facing HTTP Host contract exposed from `@zhin.js/host-http`.
3
+ * @module @zhin.js/host-http
4
+ */
5
+ export {
6
+ httpHostToken,
7
+ type HttpHandler,
8
+ type HttpHost,
9
+ type HttpHostAddress,
10
+ type HttpRouteRegistration,
11
+ type WsConnection,
12
+ type WsHandle,
13
+ } from './http-host.js';
14
+ export type { AuthenticatedTokenPrincipal, AuthScope } from './token-registry.js';
15
+ export type { ListedRoute, OpenApiParameter, RouteMeta } from './openapi.js';