@zhin.js/runtime 1.0.7 → 1.0.9

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.
@@ -119,12 +119,12 @@ export class ConfigComposer {
119
119
  const FRAMEWORK_ROLE_SCHEMA = Object.freeze({
120
120
  master: Object.freeze({
121
121
  type: ['string', 'number'],
122
- description: 'Endpoint owner (framework-level master role)',
122
+ description: 'Framework master user id (AI/tool privileges; not group owner/admin)',
123
123
  }),
124
124
  trusted: Object.freeze({
125
125
  type: 'array',
126
126
  items: Object.freeze({ type: ['string', 'number'] }),
127
- description: 'Trusted user ID list (framework-level trusted role)',
127
+ description: 'Framework trusted user id list (weaker than master)',
128
128
  }),
129
129
  });
130
130
  function hasArrayEndpoints(props) {
@@ -133,18 +133,50 @@ function hasArrayEndpoints(props) {
133
133
  return false;
134
134
  return ep.type === 'array';
135
135
  }
136
+ /** 顶层 + endpoints[].properties 注入 master/trusted(已声明则不覆盖) */
137
+ function injectFrameworkRoleSchema(properties) {
138
+ for (const [key, schema] of Object.entries(FRAMEWORK_ROLE_SCHEMA)) {
139
+ if (!Object.hasOwn(properties, key)) {
140
+ properties[key] = schema;
141
+ }
142
+ }
143
+ if (!hasArrayEndpoints(properties))
144
+ return;
145
+ const ep = properties.endpoints;
146
+ const items = ep.items;
147
+ if (!items || typeof items !== 'object' || Array.isArray(items))
148
+ return;
149
+ const itemsObj = items;
150
+ const rawProps = itemsObj.properties;
151
+ const itemProps = rawProps && typeof rawProps === 'object' && !Array.isArray(rawProps)
152
+ ? { ...rawProps }
153
+ : {};
154
+ let changed = false;
155
+ for (const [key, schema] of Object.entries(FRAMEWORK_ROLE_SCHEMA)) {
156
+ if (!Object.hasOwn(itemProps, key)) {
157
+ itemProps[key] = schema;
158
+ changed = true;
159
+ }
160
+ }
161
+ if (!changed)
162
+ return;
163
+ properties.endpoints = Object.freeze({
164
+ ...ep,
165
+ items: Object.freeze({
166
+ ...itemsObj,
167
+ properties: Object.freeze(itemProps),
168
+ }),
169
+ });
170
+ }
136
171
  async function composeNode(node, ownSchemas) {
137
172
  const own = await readOwnSchema(node);
138
173
  ownSchemas.set(node.id, own);
139
174
  const properties = { ...schemaProperties(own) };
140
175
  // Adapter plugins (schemas declaring array-typed `endpoints`) get
141
- // framework-level `master` / `trusted` injected when not already declared.
176
+ // framework-level `master` / `trusted` injected when not already declared
177
+ // (top-level and endpoints[].properties).
142
178
  if (hasArrayEndpoints(properties)) {
143
- for (const [key, schema] of Object.entries(FRAMEWORK_ROLE_SCHEMA)) {
144
- if (!Object.hasOwn(properties, key)) {
145
- properties[key] = schema;
146
- }
147
- }
179
+ injectFrameworkRoleSchema(properties);
148
180
  }
149
181
  for (const child of node.children) {
150
182
  if (Object.hasOwn(properties, child.instanceKey)) {
@@ -2,7 +2,7 @@ import { readdirSync, statSync, watch as watchDirectory, } from 'node:fs';
2
2
  import { extname, isAbsolute, relative, resolve, sep } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  const ignoredDirectories = new Set([
5
- '.git', '.zhin', 'coverage', 'dist', 'lib', 'node_modules',
5
+ '.git', '.zhin', 'coverage', 'data', 'dist', 'lib', 'node_modules',
6
6
  ]);
7
7
  const watchedExtensions = new Set([
8
8
  '.cjs', '.js', '.json', '.md', '.mjs', '.ts', '.tsx', '.yaml', '.yml',
@@ -12,6 +12,12 @@ export interface RootResourceContext {
12
12
  readonly lifecycle: DisposeStack;
13
13
  readonly handoff: GenerationHandoffRegistry;
14
14
  readonly config: PrimaryConfig;
15
+ /**
16
+ * Adds a root-owned capability to this shadow generation. The definition is
17
+ * validated and projected with convention/setup capabilities; it is never
18
+ * visible before the generation commits.
19
+ */
20
+ addFeature<TDefinition>(feature: FeatureId | string, localName: string, definition: TDefinition): void;
15
21
  }
16
22
  export type RootResourceInstaller = (context: RootResourceContext) => void | Promise<void>;
17
23
  export interface PluginAssemblySeed {
@@ -59,6 +59,7 @@ export class PluginScopeAssembler {
59
59
  // Every owner shadows the inherited EnvStore with its exact overlay view.
60
60
  const environment = this.#envStores.create(node.id);
61
61
  scope.provide(envStoreToken, environment);
62
+ const register = (feature, localName, capabilityDefinition) => this.#registerSetupCapability(node, manifest, feature, localName, capabilityDefinition);
62
63
  if (!node.parent) {
63
64
  scope.provide(runtimeEnvironmentToken, this.environment);
64
65
  const config = createPrimaryConfig(this.primaryConfigDocument, environment);
@@ -68,6 +69,7 @@ export class PluginScopeAssembler {
68
69
  lifecycle: scope.disposers,
69
70
  handoff: this.#handoffs,
70
71
  config,
72
+ addFeature: register,
71
73
  });
72
74
  }
73
75
  if (node.parent)
@@ -123,21 +125,6 @@ export class PluginScopeAssembler {
123
125
  throw new Error(`Missing resource ${token.id} for Plugin ${node.id}`);
124
126
  }
125
127
  }
126
- const register = (feature, localName, capabilityDefinition) => {
127
- const featureName = featureId(String(feature));
128
- const id = capabilityId(node.id, featureName, localName);
129
- if (this.#setupCapabilities.has(id)) {
130
- throw new Error(`Duplicate setup Capability: ${id}`);
131
- }
132
- this.#setupCapabilities.set(id, Object.freeze({
133
- id,
134
- owner: node.id,
135
- feature: featureName,
136
- localName,
137
- source: resolve(node.package.root, manifest.entry),
138
- definition: capabilityDefinition,
139
- }));
140
- };
141
128
  const setupContext = {
142
129
  plugin,
143
130
  config: view,
@@ -169,6 +156,21 @@ export class PluginScopeAssembler {
169
156
  for (const child of node.children)
170
157
  await this.setupTree(child);
171
158
  }
159
+ #registerSetupCapability(node, manifest, feature, localName, definition) {
160
+ const featureName = featureId(String(feature));
161
+ const id = capabilityId(node.id, featureName, localName);
162
+ if (this.#setupCapabilities.has(id)) {
163
+ throw new Error(`Duplicate setup Capability: ${id}`);
164
+ }
165
+ this.#setupCapabilities.set(id, Object.freeze({
166
+ id,
167
+ owner: node.id,
168
+ feature: featureName,
169
+ localName,
170
+ source: resolve(node.package.root, manifest.entry),
171
+ definition,
172
+ }));
173
+ }
172
174
  synchronizeTree(node) {
173
175
  const current = this.tree.get(node.id);
174
176
  if (!current)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/runtime",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Static Plugin graph, generation transaction and HMR Root runtime for Zhin.js",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -18,22 +18,22 @@
18
18
  "dependencies": {
19
19
  "ajv": "8.18.0",
20
20
  "semver": "7.8.5",
21
- "@zhin.js/feature-kit": "1.0.6",
22
- "@zhin.js/plugin-runtime": "1.1.3"
21
+ "@zhin.js/feature-kit": "1.0.8",
22
+ "@zhin.js/plugin-runtime": "1.1.5"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^26.1.2",
26
26
  "typescript": "^6.0.3",
27
- "@zhin.js/adapter": "1.1.5",
28
- "@zhin.js/agent-feature": "1.0.6",
29
- "@zhin.js/command": "1.0.7",
30
- "@zhin.js/component": "1.0.6",
31
- "@zhin.js/layout": "1.0.6",
32
- "@zhin.js/mcp-feature": "1.0.6",
33
- "@zhin.js/middleware": "1.0.6",
34
- "@zhin.js/page": "1.0.6",
35
- "@zhin.js/skill": "1.0.6",
36
- "@zhin.js/tool": "1.0.6"
27
+ "@zhin.js/adapter": "1.1.7",
28
+ "@zhin.js/agent-feature": "1.0.8",
29
+ "@zhin.js/command": "1.0.9",
30
+ "@zhin.js/component": "1.0.8",
31
+ "@zhin.js/layout": "1.0.8",
32
+ "@zhin.js/mcp-feature": "1.0.8",
33
+ "@zhin.js/middleware": "1.0.8",
34
+ "@zhin.js/page": "1.0.8",
35
+ "@zhin.js/skill": "1.0.8",
36
+ "@zhin.js/tool": "1.0.8"
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",