@zhin.js/plugin-runtime 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,11 @@ import {
12
12
  } from '@zhin.js/plugin-runtime';
13
13
  ```
14
14
 
15
+ `PluginSetupContext.addFeature(feature, localName, definition)` 是约定目录之外的内存
16
+ Capability 写入口。它仍由上层 Runtime 交给对应 Feature provider 校验和投影;Feature
17
+ 通过 `authoring.setupMethod` 和 module augmentation 提供强类型 `addCommand`、
18
+ `addComponent`、`addTool` 等别名。底座只保存通用注册记录,不理解 IM。
19
+
15
20
  ## 生命周期
16
21
 
17
22
  ```text
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * Plugin-contributed Agent tool registered against the Agent Host.
3
3
  * Captured at setup() time — execute closures must never call plugin locators.
4
+ *
5
+ * Access vocabulary (platforms / scopes / permissions / hidden) mirrors the
6
+ * `@zhin.js/tool` ToolIndex descriptor and is enforced per message by the
7
+ * Agent runtime via Core `canAccessTool` — one predicate for both paths.
4
8
  */
5
9
  export interface AgentToolRegistration {
6
10
  /** Runtime tool name exposed to the model (e.g. `lottery_sync`). */
@@ -10,7 +14,12 @@ export interface AgentToolRegistration {
10
14
  readonly inputSchema?: unknown;
11
15
  readonly keywords?: readonly string[];
12
16
  readonly tags?: readonly string[];
17
+ /** Limit to these adapter platforms (e.g. `['icqq']`); empty = all. */
18
+ readonly platforms?: readonly string[];
19
+ /** Limit to these channel scopes; empty = all. */
20
+ readonly scopes?: readonly ('private' | 'group' | 'channel')[];
13
21
  readonly permissions?: readonly string[];
22
+ /** Registered but never offered to the model (callable by name only). */
14
23
  readonly hidden?: boolean;
15
24
  /** Per-tool approval policy; stacks with ExecPolicy. */
16
25
  readonly approval?: 'never' | 'always';
@@ -6,5 +6,16 @@ export interface CapabilitySlot<T = unknown> {
6
6
  readonly localName: string;
7
7
  readonly source: string;
8
8
  readonly definition: T;
9
+ /** Setup-owned slots follow their Plugin Scope instead of file-slot HMR. */
10
+ readonly origin?: 'setup';
11
+ }
12
+ /** A capability declared imperatively while its owning Plugin is assembled. */
13
+ export interface SetupCapabilityRegistration<T = unknown> {
14
+ readonly id: CapabilityId;
15
+ readonly owner: PluginId;
16
+ readonly feature: FeatureId;
17
+ readonly localName: string;
18
+ readonly source: string;
19
+ readonly definition: T;
9
20
  }
10
21
  export declare function createCapabilitySlot<T>(input: Omit<CapabilitySlot<T>, 'id'>): Readonly<CapabilitySlot<T>>;
@@ -17,6 +17,11 @@ export interface DatabaseHostModel {
17
17
  update(patch: Record<string, unknown>): {
18
18
  where(query: Record<string, unknown>): Promise<unknown>;
19
19
  };
20
+ /**
21
+ * DB 侧计数(聚合下推,避免为计数整表加载)。
22
+ * 可选:轻量 test/memory host 可不实现,调用方降级为 select 计数。
23
+ */
24
+ count?(where?: Record<string, unknown>): Promise<number>;
20
25
  }
21
26
  export type DatabaseHostType = 'related' | 'document' | 'keyvalue';
22
27
  export interface DatabaseHostTable {
@@ -0,0 +1,32 @@
1
+ import { DisposeStack, type Dispose } from './dispose.js';
2
+ /**
3
+ * Minimal structural view of a plugin setup context: anything owning a
4
+ * generation-scoped lifecycle (e.g. PluginSetupContext) can provide values.
5
+ */
6
+ export interface GenerationStoreContext {
7
+ readonly lifecycle: DisposeStack;
8
+ }
9
+ export interface GenerationStore<T> {
10
+ /**
11
+ * Publish `value` as the current generation's value. The registration is
12
+ * removed automatically when `context.lifecycle` disposes (generation end);
13
+ * the returned Dispose unregisters manually and is idempotent.
14
+ */
15
+ provide(context: GenerationStoreContext, value: T): Dispose;
16
+ /** Latest live value; throws a store-named error when none was provided. */
17
+ use(): T;
18
+ /** Latest live value, or `undefined` when none was provided. */
19
+ tryUse(): T | undefined;
20
+ /** Drop every registration across all generations. Mainly for tests. */
21
+ clear(): void;
22
+ }
23
+ /**
24
+ * Generation-scoped replacement for module-level `let _x` singletons.
25
+ *
26
+ * Provided values form a stack: the newest live registration wins, and when a
27
+ * generation ends its registration is removed via `context.lifecycle`,
28
+ * re-exposing the previous generation's value. This structurally prevents
29
+ * stale references to an already disposed generation (the repeater singleton
30
+ * / rss `_db` class of bugs).
31
+ */
32
+ export declare function createGenerationStore<T>(name: string): GenerationStore<T>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Generation-scoped replacement for module-level `let _x` singletons.
3
+ *
4
+ * Provided values form a stack: the newest live registration wins, and when a
5
+ * generation ends its registration is removed via `context.lifecycle`,
6
+ * re-exposing the previous generation's value. This structurally prevents
7
+ * stale references to an already disposed generation (the repeater singleton
8
+ * / rss `_db` class of bugs).
9
+ */
10
+ export function createGenerationStore(name) {
11
+ const registrations = [];
12
+ const unregister = (registration) => {
13
+ const index = registrations.lastIndexOf(registration);
14
+ if (index >= 0)
15
+ registrations.splice(index, 1);
16
+ };
17
+ return {
18
+ provide(context, value) {
19
+ const registration = Object.freeze({ value });
20
+ registrations.push(registration);
21
+ context.lifecycle.add(() => unregister(registration));
22
+ return () => unregister(registration);
23
+ },
24
+ use() {
25
+ const latest = registrations[registrations.length - 1];
26
+ if (!latest) {
27
+ throw new Error(`Generation store "${name}" has no live value — call provide(context, value) during plugin setup`);
28
+ }
29
+ return latest.value;
30
+ },
31
+ tryUse() {
32
+ return registrations[registrations.length - 1]?.value;
33
+ },
34
+ clear() {
35
+ registrations.length = 0;
36
+ },
37
+ };
38
+ }
package/lib/index.d.ts CHANGED
@@ -1,16 +1,25 @@
1
+ /** @internal Runtime 内部:CapabilitySlot(feature 与 projection 之间的载体)。 */
1
2
  export * from './capability.js';
2
3
  export * from './dispose.js';
3
4
  export * from './identity.js';
5
+ export * from './generation-store.js';
4
6
  export * from './handoff.js';
7
+ /** @public 用户侧创作面:`definePlugin`(`plugin.ts` 约定入口,承诺 semver)。 */
5
8
  export * from './plugin.js';
9
+ /** @internal Runtime 内部:RootRuntime / RootController。 */
6
10
  export * from './root-controller.js';
7
11
  export * from './shared-lifetime.js';
12
+ /** @internal Runtime 内部:SnapshotStore / RuntimeSnapshot。 */
8
13
  export * from './snapshot.js';
9
14
  export * from './token.js';
15
+ /** @public Host token:`scheduleHostToken`(承诺 semver)。 */
10
16
  export * from './schedule-host.js';
17
+ /** @public Host token:`databaseHostToken`(承诺 semver)。 */
11
18
  export * from './database-host.js';
19
+ /** @public Host token:`agentToolsHostToken`(experimental)。 */
12
20
  export * from './agent-tools-host.js';
13
21
  export * from './html-renderer.js';
22
+ /** @public Host token:`outboundHostToken`(承诺 semver)。 */
14
23
  export * from './outbound-host.js';
15
24
  export * from './inbox.js';
16
25
  export * from './system-log.js';
package/lib/index.js CHANGED
@@ -1,16 +1,25 @@
1
+ /** @internal Runtime 内部:CapabilitySlot(feature 与 projection 之间的载体)。 */
1
2
  export * from './capability.js';
2
3
  export * from './dispose.js';
3
4
  export * from './identity.js';
5
+ export * from './generation-store.js';
4
6
  export * from './handoff.js';
7
+ /** @public 用户侧创作面:`definePlugin`(`plugin.ts` 约定入口,承诺 semver)。 */
5
8
  export * from './plugin.js';
9
+ /** @internal Runtime 内部:RootRuntime / RootController。 */
6
10
  export * from './root-controller.js';
7
11
  export * from './shared-lifetime.js';
12
+ /** @internal Runtime 内部:SnapshotStore / RuntimeSnapshot。 */
8
13
  export * from './snapshot.js';
9
14
  export * from './token.js';
15
+ /** @public Host token:`scheduleHostToken`(承诺 semver)。 */
10
16
  export * from './schedule-host.js';
17
+ /** @public Host token:`databaseHostToken`(承诺 semver)。 */
11
18
  export * from './database-host.js';
19
+ /** @public Host token:`agentToolsHostToken`(experimental)。 */
12
20
  export * from './agent-tools-host.js';
13
21
  export * from './html-renderer.js';
22
+ /** @public Host token:`outboundHostToken`(承诺 semver)。 */
14
23
  export * from './outbound-host.js';
15
24
  export * from './inbox.js';
16
25
  export * from './system-log.js';
package/lib/plugin.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Dispose, DisposeStack } from './dispose.js';
2
2
  import type { GenerationHandoffRegistry } from './handoff.js';
3
- import type { PluginId } from './identity.js';
3
+ import type { FeatureId, PluginId } from './identity.js';
4
4
  import type { Scope, Token } from './token.js';
5
5
  export interface PluginMetadata {
6
6
  readonly displayName?: string;
@@ -23,6 +23,11 @@ export interface PluginSetupContext<TConfig = unknown> {
23
23
  readonly resources: Scope;
24
24
  readonly lifecycle: DisposeStack;
25
25
  readonly handoff: GenerationHandoffRegistry;
26
+ /**
27
+ * Registers an in-memory definition through the same validation and
28
+ * projection transaction used by convention-discovered capabilities.
29
+ */
30
+ addFeature<TDefinition>(feature: FeatureId | string, localName: string, definition: TDefinition): void;
26
31
  }
27
32
  export interface PluginDefinition<TConfig = unknown> {
28
33
  readonly name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-runtime",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Zero-dependency Plugin tree, Scope and atomic generation runtime for Zhin",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",